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) {
55 if (tap
->loaded
== 0) {
56 zrelse(tap
->coord
->node
);
63 * init tap to consist of @coord and @lh. Locks on nodes will be acquired with
66 void reiser4_tap_init(tap_t
* tap
, coord_t
* coord
, lock_handle
* lh
,
73 INIT_LIST_HEAD(&tap
->linkage
);
74 reiser4_init_ra_info(&tap
->ra_info
);
77 /** add @tap to the per-thread list of all taps */
78 void reiser4_tap_monitor(tap_t
* tap
)
80 assert("nikita-2623", tap
!= NULL
);
82 list_add(&tap
->linkage
, reiser4_taps_list());
86 /* duplicate @src into @dst. Copy lock handle. @dst is not initially
88 void reiser4_tap_copy(tap_t
* dst
, tap_t
* src
)
90 assert("nikita-3193", src
!= NULL
);
91 assert("nikita-3194", dst
!= NULL
);
93 *dst
->coord
= *src
->coord
;
95 copy_lh(dst
->lh
, src
->lh
);
96 dst
->mode
= src
->mode
;
98 INIT_LIST_HEAD(&dst
->linkage
);
99 dst
->ra_info
= src
->ra_info
;
102 /** finish with @tap */
103 void reiser4_tap_done(tap_t
* tap
)
105 assert("nikita-2565", tap
!= NULL
);
108 zrelse(tap
->coord
->node
);
111 list_del_init(&tap
->linkage
);
112 tap
->coord
->node
= NULL
;
116 * move @tap to the new node, locked with @target. Load @target, if @tap was
119 int reiser4_tap_move(tap_t
* tap
, lock_handle
* target
)
123 assert("nikita-2567", tap
!= NULL
);
124 assert("nikita-2568", target
!= NULL
);
125 assert("nikita-2570", target
->node
!= NULL
);
126 assert("nikita-2569", tap
->coord
->node
== tap
->lh
->node
);
130 result
= zload_ra(target
->node
, &tap
->ra_info
);
134 zrelse(tap
->coord
->node
);
136 copy_lh(tap
->lh
, target
);
137 tap
->coord
->node
= target
->node
;
138 coord_clear_iplug(tap
->coord
);
145 * move @tap to @target. Acquire lock on @target, if @tap was already
148 static int tap_to(tap_t
* tap
, znode
* target
)
152 assert("nikita-2624", tap
!= NULL
);
153 assert("nikita-2625", target
!= NULL
);
157 if (tap
->coord
->node
!= target
) {
161 result
= longterm_lock_znode(&here
, target
,
162 tap
->mode
, ZNODE_LOCK_HIPRI
);
164 result
= reiser4_tap_move(tap
, &here
);
173 * move @tap to given @target, loading and locking @target->node if
176 int tap_to_coord(tap_t
* tap
, coord_t
* target
)
181 result
= tap_to(tap
, target
->node
);
183 coord_dup(tap
->coord
, target
);
188 /** return list of all taps */
189 struct list_head
*reiser4_taps_list(void)
191 return &get_current_context()->taps
;
194 /** helper function for go_{next,prev}_{item,unit,node}() */
195 int go_dir_el(tap_t
* tap
, sideof dir
, int units_p
)
201 int (*coord_dir
) (coord_t
*);
202 int (*get_dir_neighbor
) (lock_handle
*, znode
*, int, int);
203 void (*coord_init
) (coord_t
*, const znode
*);
204 ON_DEBUG(int (*coord_check
) (const coord_t
*));
206 assert("nikita-2556", tap
!= NULL
);
207 assert("nikita-2557", tap
->coord
!= NULL
);
208 assert("nikita-2558", tap
->lh
!= NULL
);
209 assert("nikita-2559", tap
->coord
->node
!= NULL
);
212 if (dir
== LEFT_SIDE
) {
213 coord_dir
= units_p
? coord_prev_unit
: coord_prev_item
;
214 get_dir_neighbor
= reiser4_get_left_neighbor
;
215 coord_init
= coord_init_last_unit
;
217 coord_dir
= units_p
? coord_next_unit
: coord_next_item
;
218 get_dir_neighbor
= reiser4_get_right_neighbor
;
219 coord_init
= coord_init_first_unit
;
221 ON_DEBUG(coord_check
=
222 units_p
? coord_is_existing_unit
: coord_is_existing_item
);
223 assert("nikita-2560", coord_check(tap
->coord
));
226 coord_dup(&dup
, coord
);
227 if (coord_dir(&dup
) != 0) {
229 /* move to the left neighboring node */
234 get_dir_neighbor(&dup
, coord
->node
, (int)tap
->mode
,
235 GN_CAN_USE_UPPER_LEVELS
);
237 result
= reiser4_tap_move(tap
, &dup
);
239 coord_init(tap
->coord
, dup
.node
);
242 /* skip empty nodes */
243 } while ((result
== 0) && node_is_empty(coord
->node
));
246 coord_dup(coord
, &dup
);
248 assert("nikita-2564", ergo(!result
, coord_check(tap
->coord
)));
254 * move @tap to the next unit, transparently crossing item and node
257 int go_next_unit(tap_t
* tap
)
259 return go_dir_el(tap
, RIGHT_SIDE
, 1);
263 * move @tap to the previous unit, transparently crossing item and node
266 int go_prev_unit(tap_t
* tap
)
268 return go_dir_el(tap
, LEFT_SIDE
, 1);
272 * @shift times apply @actor to the @tap. This is used to move @tap by
273 * @shift units (or items, or nodes) in either direction.
275 static int rewind_to(tap_t
* tap
, go_actor_t actor
, int shift
)
279 assert("nikita-2555", shift
>= 0);
280 assert("nikita-2562", tap
->coord
->node
== tap
->lh
->node
);
283 result
= reiser4_tap_load(tap
);
287 for (; shift
> 0; --shift
) {
289 assert("nikita-2563", tap
->coord
->node
== tap
->lh
->node
);
293 reiser4_tap_relse(tap
);
298 /** move @tap @shift units rightward */
299 int rewind_right(tap_t
* tap
, int shift
)
301 return rewind_to(tap
, go_next_unit
, shift
);
304 /** move @tap @shift units leftward */
305 int rewind_left(tap_t
* tap
, int shift
)
307 return rewind_to(tap
, go_prev_unit
, shift
);
311 /** debugging function: print @tap content in human readable form */
312 static void print_tap(const char *prefix
, const tap_t
* tap
)
315 printk("%s: null tap\n", prefix
);
318 printk("%s: loaded: %i, in-list: %i, node: %p, mode: %s\n", prefix
,
319 tap
->loaded
, (&tap
->linkage
== tap
->linkage
.next
&&
320 &tap
->linkage
== tap
->linkage
.prev
),
322 lock_mode_name(tap
->mode
));
323 print_coord("\tcoord", tap
->coord
, 0);
326 /** check [tap-sane] invariant */
327 static int tap_invariant(const tap_t
* tap
)
329 /* [tap-sane] invariant */
333 /* tap->mode is one of
335 * {ZNODE_NO_LOCK, ZNODE_READ_LOCK, ZNODE_WRITE_LOCK}, and
337 if (tap
->mode
!= ZNODE_NO_LOCK
&&
338 tap
->mode
!= ZNODE_READ_LOCK
&& tap
->mode
!= ZNODE_WRITE_LOCK
)
340 /* tap->coord != NULL, and */
341 if (tap
->coord
== NULL
)
343 /* tap->lh != NULL, and */
346 /* tap->loaded > 0 => znode_is_loaded(tap->coord->node), and */
347 if (!ergo(tap
->loaded
, znode_is_loaded(tap
->coord
->node
)))
349 /* tap->coord->node == tap->lh->node if tap->lh->node is not 0 */
350 if (tap
->lh
->node
!= NULL
&& tap
->coord
->node
!= tap
->lh
->node
)
355 /** debugging function: check internal @tap consistency */
356 static void tap_check(const tap_t
* tap
)
360 result
= tap_invariant(tap
);
362 print_tap("broken", tap
);
363 reiser4_panic("nikita-2831", "tap broken: %i\n", result
);
370 c-indentation-style: "K&R"