mm-only debug patch...
[mmotm.git] / fs / reiser4 / tap.c
blob1234188c3871ae0e35ec09227a6ef72ab5b8e5ee
1 /* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by
2 * reiser4/README */
4 /*
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.
16 #include "forward.h"
17 #include "debug.h"
18 #include "coord.h"
19 #include "tree.h"
20 #include "context.h"
21 #include "tap.h"
22 #include "znode.h"
23 #include "tree_walk.h"
25 #if REISER4_DEBUG
26 static int tap_invariant(const tap_t *tap);
27 static void tap_check(const tap_t *tap);
28 #else
29 #define tap_check(tap) noop
30 #endif
32 /** load node tap is pointing to, if not loaded already */
33 int reiser4_tap_load(tap_t *tap)
35 tap_check(tap);
36 if (tap->loaded == 0) {
37 int result;
39 result = zload_ra(tap->coord->node, &tap->ra_info);
40 if (result != 0)
41 return result;
42 coord_clear_iplug(tap->coord);
44 ++tap->loaded;
45 tap_check(tap);
46 return 0;
49 /** release node tap is pointing to. Dual to tap_load() */
50 void reiser4_tap_relse(tap_t *tap)
52 tap_check(tap);
53 if (tap->loaded > 0) {
54 --tap->loaded;
55 if (tap->loaded == 0)
56 zrelse(tap->coord->node);
58 tap_check(tap);
61 /**
62 * init tap to consist of @coord and @lh. Locks on nodes will be acquired with
63 * @mode
65 void reiser4_tap_init(tap_t *tap, coord_t *coord, lock_handle * lh,
66 znode_lock_mode mode)
68 tap->coord = coord;
69 tap->lh = lh;
70 tap->mode = mode;
71 tap->loaded = 0;
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);
80 tap_check(tap);
81 list_add(&tap->linkage, reiser4_taps_list());
82 tap_check(tap);
85 /* duplicate @src into @dst. Copy lock handle. @dst is not initially
86 * loaded. */
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;
93 if (src->lh->node)
94 copy_lh(dst->lh, src->lh);
95 dst->mode = src->mode;
96 dst->loaded = 0;
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);
105 tap_check(tap);
106 if (tap->loaded > 0)
107 zrelse(tap->coord->node);
108 done_lh(tap->lh);
109 tap->loaded = 0;
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
116 * already loaded.
118 int reiser4_tap_move(tap_t *tap, lock_handle * target)
120 int result = 0;
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);
127 tap_check(tap);
128 if (tap->loaded > 0)
129 result = zload_ra(target->node, &tap->ra_info);
131 if (result == 0) {
132 if (tap->loaded > 0)
133 zrelse(tap->coord->node);
134 done_lh(tap->lh);
135 copy_lh(tap->lh, target);
136 tap->coord->node = target->node;
137 coord_clear_iplug(tap->coord);
139 tap_check(tap);
140 return result;
144 * move @tap to @target. Acquire lock on @target, if @tap was already
145 * loaded.
147 static int tap_to(tap_t *tap, znode * target)
149 int result;
151 assert("nikita-2624", tap != NULL);
152 assert("nikita-2625", target != NULL);
154 tap_check(tap);
155 result = 0;
156 if (tap->coord->node != target) {
157 lock_handle here;
159 init_lh(&here);
160 result = longterm_lock_znode(&here, target,
161 tap->mode, ZNODE_LOCK_HIPRI);
162 if (result == 0) {
163 result = reiser4_tap_move(tap, &here);
164 done_lh(&here);
167 tap_check(tap);
168 return result;
172 * move @tap to given @target, loading and locking @target->node if
173 * necessary
175 int tap_to_coord(tap_t *tap, coord_t *target)
177 int result;
179 tap_check(tap);
180 result = tap_to(tap, target->node);
181 if (result == 0)
182 coord_dup(tap->coord, target);
183 tap_check(tap);
184 return result;
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)
196 coord_t dup;
197 coord_t *coord;
198 int result;
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);
210 tap_check(tap);
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;
215 } else {
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));
224 coord = tap->coord;
225 coord_dup(&dup, coord);
226 if (coord_dir(&dup) != 0) {
227 do {
228 /* move to the left neighboring node */
229 lock_handle dup;
231 init_lh(&dup);
232 result =
233 get_dir_neighbor(&dup, coord->node, (int)tap->mode,
234 GN_CAN_USE_UPPER_LEVELS);
235 if (result == 0) {
236 result = reiser4_tap_move(tap, &dup);
237 if (result == 0)
238 coord_init(tap->coord, dup.node);
239 done_lh(&dup);
241 /* skip empty nodes */
242 } while ((result == 0) && node_is_empty(coord->node));
243 } else {
244 result = 0;
245 coord_dup(coord, &dup);
247 assert("nikita-2564", ergo(!result, coord_check(tap->coord)));
248 tap_check(tap);
249 return result;
253 * move @tap to the next unit, transparently crossing item and node
254 * boundaries
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
263 * boundaries
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)
276 int result;
278 assert("nikita-2555", shift >= 0);
279 assert("nikita-2562", tap->coord->node == tap->lh->node);
281 tap_check(tap);
282 result = reiser4_tap_load(tap);
283 if (result != 0)
284 return result;
286 for (; shift > 0; --shift) {
287 result = actor(tap);
288 assert("nikita-2563", tap->coord->node == tap->lh->node);
289 if (result != 0)
290 break;
292 reiser4_tap_relse(tap);
293 tap_check(tap);
294 return result;
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);
309 #if REISER4_DEBUG
310 /** debugging function: print @tap content in human readable form */
311 static void print_tap(const char *prefix, const tap_t *tap)
313 if (tap == NULL) {
314 printk("%s: null tap\n", prefix);
315 return;
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),
320 tap->lh->node,
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 */
330 if (tap == NULL)
331 return 1;
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)
338 return 2;
339 /* tap->coord != NULL, and */
340 if (tap->coord == NULL)
341 return 3;
342 /* tap->lh != NULL, and */
343 if (tap->lh == NULL)
344 return 4;
345 /* tap->loaded > 0 => znode_is_loaded(tap->coord->node), and */
346 if (!ergo(tap->loaded, znode_is_loaded(tap->coord->node)))
347 return 5;
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)
350 return 6;
351 return 0;
354 /** debugging function: check internal @tap consistency */
355 static void tap_check(const tap_t *tap)
357 int result;
359 result = tap_invariant(tap);
360 if (result != 0) {
361 print_tap("broken", tap);
362 reiser4_panic("nikita-2831", "tap broken: %i\n", result);
365 #endif
367 /* Make Linus happy.
368 Local variables:
369 c-indentation-style: "K&R"
370 mode-name: "LC"
371 c-basic-offset: 8
372 tab-width: 8
373 fill-column: 120
374 scroll-step: 1
375 End: