4 * Copyright (C) 2001 Theodore Ts'o. This file may be
5 * redistributed under the terms of the GNU Public License.
19 #include "ext2fs/rbtree.h"
22 * The strategy we use for keeping track of EA refcounts is as
23 * follows. We keep the first EA blocks and its reference counts
24 * in the rb-tree. Once the refcount has dropped to zero, it is
25 * removed from the rb-tree to save memory space. Once the EA block is
26 * checked, its bit is set in the block_ea_map bitmap.
28 struct ea_refcount_el {
30 /* ea_key could either be an inode number or block number. */
37 struct rb_node *cursor;
40 void ea_refcount_free(ext2_refcount_t refcount)
42 struct ea_refcount_el *el;
43 struct rb_node *node, *next;
48 for (node = ext2fs_rb_first(&refcount->root); node; node = next) {
49 next = ext2fs_rb_next(node);
50 el = ext2fs_rb_entry(node, struct ea_refcount_el, node);
51 ext2fs_rb_erase(node, &refcount->root);
54 ext2fs_free_mem(&refcount);
57 errcode_t ea_refcount_create(ext2_refcount_t *ret)
59 ext2_refcount_t refcount;
62 retval = ext2fs_get_memzero(sizeof(struct ea_refcount), &refcount);
65 refcount->root = RB_ROOT;
72 * get_refcount_el() --- given an block number, try to find refcount
73 * information in the rb-tree. If the create flag is set,
74 * and we can't find an entry, create and add it to rb-tree.
76 static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
77 ea_key_t ea_key, int create)
79 struct rb_node **node;
80 struct rb_node *parent = NULL;
81 struct ea_refcount_el *el;
87 node = &refcount->root.rb_node;
89 el = ext2fs_rb_entry(*node, struct ea_refcount_el, node);
92 if (ea_key < el->ea_key)
93 node = &(*node)->rb_left;
94 else if (ea_key > el->ea_key)
95 node = &(*node)->rb_right;
103 retval = ext2fs_get_memzero(sizeof(struct ea_refcount_el), &el);
109 ext2fs_rb_link_node(&el->node, parent, node);
110 ext2fs_rb_insert_color(&el->node, &refcount->root);
115 errcode_t ea_refcount_fetch(ext2_refcount_t refcount, ea_key_t ea_key,
118 struct ea_refcount_el *el;
120 el = get_refcount_el(refcount, ea_key, 0);
129 errcode_t ea_refcount_increment(ext2_refcount_t refcount, ea_key_t ea_key,
132 struct ea_refcount_el *el;
134 el = get_refcount_el(refcount, ea_key, 1);
136 return EXT2_ET_NO_MEMORY;
144 errcode_t ea_refcount_decrement(ext2_refcount_t refcount, ea_key_t ea_key,
147 struct ea_refcount_el *el;
149 el = get_refcount_el(refcount, ea_key, 0);
151 return EXT2_ET_INVALID_ARGUMENT;
158 if (el->ea_value == 0) {
159 ext2fs_rb_erase(&el->node, &refcount->root);
160 ext2fs_free_mem(&el);
165 errcode_t ea_refcount_store(ext2_refcount_t refcount, ea_key_t ea_key,
168 struct ea_refcount_el *el;
171 * Get the refcount element
173 el = get_refcount_el(refcount, ea_key, ea_value ? 1 : 0);
175 return ea_value ? EXT2_ET_NO_MEMORY : 0;
176 el->ea_value = ea_value;
177 if (el->ea_value == 0) {
178 ext2fs_rb_erase(&el->node, &refcount->root);
179 ext2fs_free_mem(&el);
184 void ea_refcount_intr_begin(ext2_refcount_t refcount)
186 refcount->cursor = 0;
189 ea_key_t ea_refcount_intr_next(ext2_refcount_t refcount,
192 struct ea_refcount_el *el;
193 struct rb_node *node = refcount->cursor;
196 node = ext2fs_rb_first(&refcount->root);
198 node = ext2fs_rb_next(node);
201 refcount->cursor = node;
202 el = ext2fs_rb_entry(node, struct ea_refcount_el, node);
214 errcode_t ea_refcount_validate(ext2_refcount_t refcount, FILE *out)
216 struct ea_refcount_el *el;
217 struct rb_node *node;
220 const char *bad = "bad refcount";
222 for (node = ext2fs_rb_first(&refcount->root); node != NULL;
223 node = ext2fs_rb_next(node)) {
224 el = ext2fs_rb_entry(node, struct ea_refcount_el, node);
225 if (prev_valid && prev >= el->ea_key) {
227 "%s: prev.ea_key=%llu, curr.ea_key=%llu\n",
229 (unsigned long long) prev,
230 (unsigned long long) el->ea_key);
231 return EXT2_ET_INVALID_ARGUMENT;
241 #define BCODE_CREATE 1
243 #define BCODE_STORE 3
246 #define BCODE_FETCH 6
247 #define BCODE_VALIDATE 7
250 int bcode_program[] = {
284 int main(int argc, char **argv)
287 ext2_refcount_t refcount;
293 switch (bcode_program[i++]) {
297 retval = ea_refcount_create(&refcount);
299 com_err("ea_refcount_create", retval,
300 "while creating refcount");
303 printf("Creating refcount\n");
306 ea_refcount_free(refcount);
308 printf("Freeing refcount\n");
311 ea_key = (size_t) bcode_program[i++];
312 arg = bcode_program[i++];
313 printf("Storing ea_key %llu with value %llu\n",
314 (unsigned long long) ea_key,
315 (unsigned long long) arg);
316 retval = ea_refcount_store(refcount, ea_key, arg);
318 com_err("ea_refcount_store", retval,
319 "while storing ea_key %llu",
320 (unsigned long long) ea_key);
323 ea_key = (size_t) bcode_program[i++];
324 retval = ea_refcount_fetch(refcount, ea_key, &arg);
326 com_err("ea_refcount_fetch", retval,
327 "while fetching ea_key %llu",
328 (unsigned long long) ea_key);
330 printf("bcode_fetch(%llu) returns %llu\n",
331 (unsigned long long) ea_key,
332 (unsigned long long) arg);
335 ea_key = (size_t) bcode_program[i++];
336 retval = ea_refcount_increment(refcount, ea_key, &arg);
338 com_err("ea_refcount_increment", retval,
339 "while incrementing ea_key %llu",
340 (unsigned long long) ea_key);
342 printf("bcode_increment(%llu) returns %llu\n",
343 (unsigned long long) ea_key,
344 (unsigned long long) arg);
347 ea_key = (size_t) bcode_program[i++];
348 retval = ea_refcount_decrement(refcount, ea_key, &arg);
350 com_err("ea_refcount_decrement", retval,
351 "while decrementing ea_key %llu",
352 (unsigned long long) ea_key);
354 printf("bcode_decrement(%llu) returns %llu\n",
355 (unsigned long long) ea_key,
356 (unsigned long long) arg);
359 retval = ea_refcount_validate(refcount, stderr);
361 com_err("ea_refcount_validate", retval,
364 printf("Refcount validation OK.\n");
367 ea_refcount_intr_begin(refcount);
369 ea_key = ea_refcount_intr_next(refcount, &arg);
372 printf("\tea_key=%llu, count=%llu\n",
373 (unsigned long long) ea_key,
374 (unsigned long long) arg);