1 /* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
5 Tree Access Pointer (tap).
7 tap is data structure combining coord and lock handle (mostly). It is
8 useful when one has to scan tree nodes (for example, in readdir, or flush),
9 for tap functions allow to move tap in either direction transparently
10 crossing unit/item/node borders.
12 Tap doesn't provide automatic synchronization of its fields as it is
13 supposed to be per-thread object.
23 #include "tree_walk.h"
26 static int tap_invariant(const tap_t
*tap
);
27 static void tap_check(const tap_t
*tap
);
29 #define tap_check(tap) noop
32 /** load node tap is pointing to, if not loaded already */
33 int reiser4_tap_load(tap_t
*tap
)
36 if (tap
->loaded
== 0) {
39 result
= zload_ra(tap
->coord
->node
, &tap
->ra_info
);
42 coord_clear_iplug(tap
->coord
);
49 /** release node tap is pointing to. Dual to tap_load() */
50 void reiser4_tap_relse(tap_t
*tap
)
53 if (tap
->loaded
> 0) {
56 zrelse(tap
->coord
->node
);
62 * init tap to consist of @coord and @lh. Locks on nodes will be acquired with
65 void reiser4_tap_init(tap_t
*tap
, coord_t
*coord
, lock_handle
* lh
,
72 INIT_LIST_HEAD(&tap
->linkage
);
73 reiser4_init_ra_info(&tap
->ra_info
);
76 /** add @tap to the per-thread list of all taps */
77 void reiser4_tap_monitor(tap_t
*tap
)
79 assert("nikita-2623", tap
!= NULL
);
81 list_add(&tap
->linkage
, reiser4_taps_list());
85 /* duplicate @src into @dst. Copy lock handle. @dst is not initially
87 void reiser4_tap_copy(tap_t
*dst
, tap_t
*src
)
89 assert("nikita-3193", src
!= NULL
);
90 assert("nikita-3194", dst
!= NULL
);
92 *dst
->coord
= *src
->coord
;
94 copy_lh(dst
->lh
, src
->lh
);
95 dst
->mode
= src
->mode
;
97 INIT_LIST_HEAD(&dst
->linkage
);
98 dst
->ra_info
= src
->ra_info
;
101 /** finish with @tap */
102 void reiser4_tap_done(tap_t
*tap
)
104 assert("nikita-2565", tap
!= NULL
);
107 zrelse(tap
->coord
->node
);
110 list_del_init(&tap
->linkage
);
111 tap
->coord
->node
= NULL
;
115 * move @tap to the new node, locked with @target. Load @target, if @tap was
118 int reiser4_tap_move(tap_t
*tap
, lock_handle
* target
)
122 assert("nikita-2567", tap
!= NULL
);
123 assert("nikita-2568", target
!= NULL
);
124 assert("nikita-2570", target
->node
!= NULL
);
125 assert("nikita-2569", tap
->coord
->node
== tap
->lh
->node
);
129 result
= zload_ra(target
->node
, &tap
->ra_info
);
133 zrelse(tap
->coord
->node
);
135 copy_lh(tap
->lh
, target
);
136 tap
->coord
->node
= target
->node
;
137 coord_clear_iplug(tap
->coord
);
144 * move @tap to @target. Acquire lock on @target, if @tap was already
147 static int tap_to(tap_t
*tap
, znode
* target
)
151 assert("nikita-2624", tap
!= NULL
);
152 assert("nikita-2625", target
!= NULL
);
156 if (tap
->coord
->node
!= target
) {
160 result
= longterm_lock_znode(&here
, target
,
161 tap
->mode
, ZNODE_LOCK_HIPRI
);
163 result
= reiser4_tap_move(tap
, &here
);
172 * move @tap to given @target, loading and locking @target->node if
175 int tap_to_coord(tap_t
*tap
, coord_t
*target
)
180 result
= tap_to(tap
, target
->node
);
182 coord_dup(tap
->coord
, target
);
187 /** return list of all taps */
188 struct list_head
*reiser4_taps_list(void)
190 return &get_current_context()->taps
;
193 /** helper function for go_{next,prev}_{item,unit,node}() */
194 int go_dir_el(tap_t
*tap
, sideof dir
, int units_p
)
200 int (*coord_dir
) (coord_t
*);
201 int (*get_dir_neighbor
) (lock_handle
*, znode
*, int, int);
202 void (*coord_init
) (coord_t
*, const znode
*);
203 ON_DEBUG(int (*coord_check
) (const coord_t
*));
205 assert("nikita-2556", tap
!= NULL
);
206 assert("nikita-2557", tap
->coord
!= NULL
);
207 assert("nikita-2558", tap
->lh
!= NULL
);
208 assert("nikita-2559", tap
->coord
->node
!= NULL
);
211 if (dir
== LEFT_SIDE
) {
212 coord_dir
= units_p
? coord_prev_unit
: coord_prev_item
;
213 get_dir_neighbor
= reiser4_get_left_neighbor
;
214 coord_init
= coord_init_last_unit
;
216 coord_dir
= units_p
? coord_next_unit
: coord_next_item
;
217 get_dir_neighbor
= reiser4_get_right_neighbor
;
218 coord_init
= coord_init_first_unit
;
220 ON_DEBUG(coord_check
=
221 units_p
? coord_is_existing_unit
: coord_is_existing_item
);
222 assert("nikita-2560", coord_check(tap
->coord
));
225 coord_dup(&dup
, coord
);
226 if (coord_dir(&dup
) != 0) {
228 /* move to the left neighboring node */
233 get_dir_neighbor(&dup
, coord
->node
, (int)tap
->mode
,
234 GN_CAN_USE_UPPER_LEVELS
);
236 result
= reiser4_tap_move(tap
, &dup
);
238 coord_init(tap
->coord
, dup
.node
);
241 /* skip empty nodes */
242 } while ((result
== 0) && node_is_empty(coord
->node
));
245 coord_dup(coord
, &dup
);
247 assert("nikita-2564", ergo(!result
, coord_check(tap
->coord
)));
253 * move @tap to the next unit, transparently crossing item and node
256 int go_next_unit(tap_t
*tap
)
258 return go_dir_el(tap
, RIGHT_SIDE
, 1);
262 * move @tap to the previous unit, transparently crossing item and node
265 int go_prev_unit(tap_t
*tap
)
267 return go_dir_el(tap
, LEFT_SIDE
, 1);
271 * @shift times apply @actor to the @tap. This is used to move @tap by
272 * @shift units (or items, or nodes) in either direction.
274 static int rewind_to(tap_t
*tap
, go_actor_t actor
, int shift
)
278 assert("nikita-2555", shift
>= 0);
279 assert("nikita-2562", tap
->coord
->node
== tap
->lh
->node
);
282 result
= reiser4_tap_load(tap
);
286 for (; shift
> 0; --shift
) {
288 assert("nikita-2563", tap
->coord
->node
== tap
->lh
->node
);
292 reiser4_tap_relse(tap
);
297 /** move @tap @shift units rightward */
298 int rewind_right(tap_t
*tap
, int shift
)
300 return rewind_to(tap
, go_next_unit
, shift
);
303 /** move @tap @shift units leftward */
304 int rewind_left(tap_t
*tap
, int shift
)
306 return rewind_to(tap
, go_prev_unit
, shift
);
310 /** debugging function: print @tap content in human readable form */
311 static void print_tap(const char *prefix
, const tap_t
*tap
)
314 printk("%s: null tap\n", prefix
);
317 printk("%s: loaded: %i, in-list: %i, node: %p, mode: %s\n", prefix
,
318 tap
->loaded
, (&tap
->linkage
== tap
->linkage
.next
&&
319 &tap
->linkage
== tap
->linkage
.prev
),
321 lock_mode_name(tap
->mode
));
322 print_coord("\tcoord", tap
->coord
, 0);
325 /** check [tap-sane] invariant */
326 static int tap_invariant(const tap_t
*tap
)
328 /* [tap-sane] invariant */
332 /* tap->mode is one of
334 * {ZNODE_NO_LOCK, ZNODE_READ_LOCK, ZNODE_WRITE_LOCK}, and
336 if (tap
->mode
!= ZNODE_NO_LOCK
&&
337 tap
->mode
!= ZNODE_READ_LOCK
&& tap
->mode
!= ZNODE_WRITE_LOCK
)
339 /* tap->coord != NULL, and */
340 if (tap
->coord
== NULL
)
342 /* tap->lh != NULL, and */
345 /* tap->loaded > 0 => znode_is_loaded(tap->coord->node), and */
346 if (!ergo(tap
->loaded
, znode_is_loaded(tap
->coord
->node
)))
348 /* tap->coord->node == tap->lh->node if tap->lh->node is not 0 */
349 if (tap
->lh
->node
!= NULL
&& tap
->coord
->node
!= tap
->lh
->node
)
354 /** debugging function: check internal @tap consistency */
355 static void tap_check(const tap_t
*tap
)
359 result
= tap_invariant(tap
);
361 print_tap("broken", tap
);
362 reiser4_panic("nikita-2831", "tap broken: %i\n", result
);
369 c-indentation-style: "K&R"