2 * JFFS2 -- Journalling Flash File System, Version 2.
4 * Copyright (C) 2001-2003 Red Hat, Inc.
6 * Created by David Woodhouse <dwmw2@infradead.org>
8 * For licensing information, see the file 'LICENCE' in this directory.
10 * $Id: nodelist.c,v 1.97 2005/07/06 15:18:41 dwmw2 Exp $
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
17 #include <linux/mtd/mtd.h>
18 #include <linux/rbtree.h>
19 #include <linux/crc32.h>
20 #include <linux/slab.h>
21 #include <linux/pagemap.h>
24 void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
26 struct jffs2_full_dirent **prev = list;
27 D1(printk(KERN_DEBUG "jffs2_add_fd_to_list( %p, %p (->%p))\n", new, list, *list));
29 while ((*prev) && (*prev)->nhash <= new->nhash) {
30 if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) {
31 /* Duplicate. Free one */
32 if (new->version < (*prev)->version) {
33 D1(printk(KERN_DEBUG "Eep! Marking new dirent node obsolete\n"));
34 D1(printk(KERN_DEBUG "New dirent is \"%s\"->ino #%u. Old is \"%s\"->ino #%u\n", new->name, new->ino, (*prev)->name, (*prev)->ino));
35 jffs2_mark_node_obsolete(c, new->raw);
36 jffs2_free_full_dirent(new);
38 D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) obsolete\n", (*prev)->ino));
39 new->next = (*prev)->next;
40 jffs2_mark_node_obsolete(c, ((*prev)->raw));
41 jffs2_free_full_dirent(*prev);
46 prev = &((*prev)->next);
53 printk(KERN_DEBUG "Dirent \"%s\" (hash 0x%08x, ino #%u\n", (*list)->name, (*list)->nhash, (*list)->ino);
54 list = &(*list)->next;
58 /* Put a new tmp_dnode_info into the list, keeping the list in
59 order of increasing version
62 static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct rb_root *list)
64 struct rb_node **p = &list->rb_node;
65 struct rb_node * parent = NULL;
66 struct jffs2_tmp_dnode_info *this;
70 this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
72 /* There may actually be a collision here, but it doesn't
73 actually matter. As long as the two nodes with the same
74 version are together, it's all fine. */
75 if (tn->version < this->version)
81 rb_link_node(&tn->rb, parent, p);
82 rb_insert_color(&tn->rb, list);
85 static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
88 struct jffs2_tmp_dnode_info *tn;
92 /* Now at bottom of tree */
96 else if (this->rb_right)
97 this = this->rb_right;
99 tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb);
100 jffs2_free_full_dnode(tn->fn);
101 jffs2_free_tmp_dnode_info(tn);
103 this = this->rb_parent;
107 if (this->rb_left == &tn->rb)
108 this->rb_left = NULL;
109 else if (this->rb_right == &tn->rb)
110 this->rb_right = NULL;
114 list->rb_node = NULL;
117 static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
119 struct jffs2_full_dirent *next;
123 jffs2_free_full_dirent(fd);
128 /* Returns first valid node after 'ref'. May return 'ref' */
129 static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref)
131 while (ref && ref->next_in_ino) {
132 if (!ref_obsolete(ref))
134 D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
135 ref = ref->next_in_ino;
140 /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
141 with this ino, returning the former in order of version */
143 int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
144 struct rb_root *tnp, struct jffs2_full_dirent **fdp,
145 uint32_t *highest_version, uint32_t *latest_mctime,
146 uint32_t *mctime_ver)
148 struct jffs2_raw_node_ref *ref, *valid_ref;
149 struct jffs2_tmp_dnode_info *tn;
150 struct rb_root ret_tn = RB_ROOT;
151 struct jffs2_full_dirent *fd, *ret_fd = NULL;
152 union jffs2_node_union node;
158 D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino));
160 spin_lock(&c->erase_completion_lock);
162 valid_ref = jffs2_first_valid_node(f->inocache->nodes);
164 if (!valid_ref && (f->inocache->ino != 1))
165 printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino);
168 /* We can hold a pointer to a non-obsolete node without the spinlock,
169 but _obsolete_ nodes may disappear at any time, if the block
170 they're in gets erased. So if we mark 'ref' obsolete while we're
171 not holding the lock, it can go away immediately. For that reason,
172 we find the next valid node first, before processing 'ref'.
175 valid_ref = jffs2_first_valid_node(ref->next_in_ino);
176 spin_unlock(&c->erase_completion_lock);
181 err = jffs2_flash_read(c, (ref_offset(ref)),
182 min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)),
183 &retlen, (void *)&node);
185 printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
190 /* Check we've managed to read at least the common node header */
191 if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) {
192 printk(KERN_WARNING "short read in get_inode_nodes()\n");
197 switch (je16_to_cpu(node.u.nodetype)) {
198 case JFFS2_NODETYPE_DIRENT:
199 D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)));
200 if (ref_flags(ref) == REF_UNCHECKED) {
201 printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref));
204 if (retlen < sizeof(node.d)) {
205 printk(KERN_WARNING "short read in get_inode_nodes()\n");
210 if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) {
211 printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n",
212 ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen));
213 jffs2_mark_node_obsolete(c, ref);
214 spin_lock(&c->erase_completion_lock);
217 if (je32_to_cpu(node.d.version) > *highest_version)
218 *highest_version = je32_to_cpu(node.d.version);
219 if (ref_obsolete(ref)) {
220 /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
221 printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n",
226 fd = jffs2_alloc_full_dirent(node.d.nsize+1);
232 fd->version = je32_to_cpu(node.d.version);
233 fd->ino = je32_to_cpu(node.d.ino);
234 fd->type = node.d.type;
236 /* Pick out the mctime of the latest dirent */
237 if(fd->version > *mctime_ver) {
238 *mctime_ver = fd->version;
239 *latest_mctime = je32_to_cpu(node.d.mctime);
242 /* memcpy as much of the name as possible from the raw
243 dirent we've already read from the flash
245 if (retlen > sizeof(struct jffs2_raw_dirent))
246 memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
248 /* Do we need to copy any more of the name directly
251 if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
253 int already = retlen - sizeof(struct jffs2_raw_dirent);
255 err = jffs2_flash_read(c, (ref_offset(ref)) + retlen,
256 node.d.nsize - already, &retlen, &fd->name[already]);
257 if (!err && retlen != node.d.nsize - already)
261 printk(KERN_WARNING "Read remainder of name in jffs2_get_inode_nodes(): error %d\n", err);
262 jffs2_free_full_dirent(fd);
266 fd->nhash = full_name_hash(fd->name, node.d.nsize);
268 fd->name[node.d.nsize] = '\0';
269 /* Wheee. We now have a complete jffs2_full_dirent structure, with
270 the name in it and everything. Link it into the list
272 D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino));
273 jffs2_add_fd_to_list(c, fd, &ret_fd);
276 case JFFS2_NODETYPE_INODE:
277 D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)));
278 if (retlen < sizeof(node.i)) {
279 printk(KERN_WARNING "read too short for dnode\n");
283 if (je32_to_cpu(node.i.version) > *highest_version)
284 *highest_version = je32_to_cpu(node.i.version);
285 D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version));
287 if (ref_obsolete(ref)) {
288 /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
289 printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n",
294 /* If we've never checked the CRCs on this node, check them now. */
295 if (ref_flags(ref) == REF_UNCHECKED) {
297 struct jffs2_eraseblock *jeb;
299 crc = crc32(0, &node, sizeof(node.i)-8);
300 if (crc != je32_to_cpu(node.i.node_crc)) {
301 printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
302 ref_offset(ref), je32_to_cpu(node.i.node_crc), crc);
303 jffs2_mark_node_obsolete(c, ref);
304 spin_lock(&c->erase_completion_lock);
309 if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) ||
310 PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) {
311 printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n",
312 ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino),
313 je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize),
314 je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize));
315 jffs2_mark_node_obsolete(c, ref);
316 spin_lock(&c->erase_completion_lock);
320 if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) {
321 unsigned char *buf=NULL;
322 uint32_t pointed = 0;
325 err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
327 if (!err && retlen < je32_to_cpu(node.i.csize)) {
328 D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
329 c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
331 D1(printk(KERN_DEBUG "MTD point failed %d\n", err));
333 pointed = 1; /* succefully pointed to device */
337 buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL);
341 err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
343 if (!err && retlen != je32_to_cpu(node.i.csize))
350 crc = crc32(0, buf, je32_to_cpu(node.i.csize));
355 c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
358 if (crc != je32_to_cpu(node.i.data_crc)) {
359 printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
360 ref_offset(ref), je32_to_cpu(node.i.data_crc), crc);
361 jffs2_mark_node_obsolete(c, ref);
362 spin_lock(&c->erase_completion_lock);
368 /* Mark the node as having been checked and fix the accounting accordingly */
369 spin_lock(&c->erase_completion_lock);
370 jeb = &c->blocks[ref->flash_offset / c->sector_size];
371 len = ref_totlen(c, jeb, ref);
373 jeb->used_size += len;
374 jeb->unchecked_size -= len;
376 c->unchecked_size -= len;
378 /* If node covers at least a whole page, or if it starts at the
379 beginning of a page and runs to the end of the file, or if
380 it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
382 If it's actually overlapped, it'll get made NORMAL (or OBSOLETE)
383 when the overlapping node(s) get added to the tree anyway.
385 if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) ||
386 ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) &&
387 (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) {
388 D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref)));
389 ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
391 D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref)));
392 ref->flash_offset = ref_offset(ref) | REF_NORMAL;
394 spin_unlock(&c->erase_completion_lock);
397 tn = jffs2_alloc_tmp_dnode_info();
399 D1(printk(KERN_DEBUG "alloc tn failed\n"));
404 tn->fn = jffs2_alloc_full_dnode();
406 D1(printk(KERN_DEBUG "alloc fn failed\n"));
408 jffs2_free_tmp_dnode_info(tn);
411 tn->version = je32_to_cpu(node.i.version);
412 tn->fn->ofs = je32_to_cpu(node.i.offset);
413 /* There was a bug where we wrote hole nodes out with
414 csize/dsize swapped. Deal with it */
415 if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize))
416 tn->fn->size = je32_to_cpu(node.i.csize);
417 else // normal case...
418 tn->fn->size = je32_to_cpu(node.i.dsize);
420 D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n",
421 ref_offset(ref), je32_to_cpu(node.i.version),
422 je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize)));
423 jffs2_add_tn_to_list(tn, &ret_tn);
427 if (ref_flags(ref) == REF_UNCHECKED) {
428 struct jffs2_eraseblock *jeb;
431 printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n",
432 je16_to_cpu(node.u.nodetype), ref_offset(ref));
434 /* Mark the node as having been checked and fix the accounting accordingly */
435 spin_lock(&c->erase_completion_lock);
436 jeb = &c->blocks[ref->flash_offset / c->sector_size];
437 len = ref_totlen(c, jeb, ref);
439 jeb->used_size += len;
440 jeb->unchecked_size -= len;
442 c->unchecked_size -= len;
444 mark_ref_normal(ref);
445 spin_unlock(&c->erase_completion_lock);
447 node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype));
448 if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) {
449 /* Hmmm. This should have been caught at scan time. */
450 printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n",
452 printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n",
453 je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen),
454 je32_to_cpu(node.u.hdr_crc));
455 jffs2_mark_node_obsolete(c, ref);
456 } else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) {
457 case JFFS2_FEATURE_INCOMPAT:
458 printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
462 case JFFS2_FEATURE_ROCOMPAT:
463 printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
464 if (!(c->flags & JFFS2_SB_FLAG_RO))
467 case JFFS2_FEATURE_RWCOMPAT_COPY:
468 printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
470 case JFFS2_FEATURE_RWCOMPAT_DELETE:
471 printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
472 jffs2_mark_node_obsolete(c, ref);
477 spin_lock(&c->erase_completion_lock);
480 spin_unlock(&c->erase_completion_lock);
487 jffs2_free_tmp_dnode_info_list(&ret_tn);
488 jffs2_free_full_dirent_list(ret_fd);
492 void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
494 spin_lock(&c->inocache_lock);
496 wake_up(&c->inocache_wq);
497 spin_unlock(&c->inocache_lock);
500 /* During mount, this needs no locking. During normal operation, its
501 callers want to do other stuff while still holding the inocache_lock.
502 Rather than introducing special case get_ino_cache functions or
503 callbacks, we just let the caller do the locking itself. */
505 struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
507 struct jffs2_inode_cache *ret;
509 D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino));
511 ret = c->inocache_list[ino % INOCACHE_HASHSIZE];
512 while (ret && ret->ino < ino) {
516 if (ret && ret->ino != ino)
519 D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino));
523 void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new)
525 struct jffs2_inode_cache **prev;
527 spin_lock(&c->inocache_lock);
529 new->ino = ++c->highest_ino;
531 D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
533 prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE];
535 while ((*prev) && (*prev)->ino < new->ino) {
536 prev = &(*prev)->next;
541 spin_unlock(&c->inocache_lock);
544 void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
546 struct jffs2_inode_cache **prev;
547 D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
548 spin_lock(&c->inocache_lock);
550 prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE];
552 while ((*prev) && (*prev)->ino < old->ino) {
553 prev = &(*prev)->next;
555 if ((*prev) == old) {
559 /* Free it now unless it's in READING or CLEARING state, which
560 are the transitions upon read_inode() and clear_inode(). The
561 rest of the time we know nobody else is looking at it, and
562 if it's held by read_inode() or clear_inode() they'll free it
564 if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING)
565 jffs2_free_inode_cache(old);
567 spin_unlock(&c->inocache_lock);
570 void jffs2_free_ino_caches(struct jffs2_sb_info *c)
573 struct jffs2_inode_cache *this, *next;
575 for (i=0; i<INOCACHE_HASHSIZE; i++) {
576 this = c->inocache_list[i];
579 jffs2_free_inode_cache(this);
582 c->inocache_list[i] = NULL;
586 void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
589 struct jffs2_raw_node_ref *this, *next;
591 for (i=0; i<c->nr_blocks; i++) {
592 this = c->blocks[i].first_node;
594 next = this->next_phys;
595 jffs2_free_raw_node_ref(this);
598 c->blocks[i].first_node = c->blocks[i].last_node = NULL;
602 struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset)
604 /* The common case in lookup is that there will be a node
605 which precisely matches. So we go looking for that first */
606 struct rb_node *next;
607 struct jffs2_node_frag *prev = NULL;
608 struct jffs2_node_frag *frag = NULL;
610 D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset));
612 next = fragtree->rb_node;
615 frag = rb_entry(next, struct jffs2_node_frag, rb);
617 D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n",
618 frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right));
619 if (frag->ofs + frag->size <= offset) {
620 D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n",
621 frag->ofs, frag->ofs+frag->size));
622 /* Remember the closest smaller match on the way down */
623 if (!prev || frag->ofs > prev->ofs)
625 next = frag->rb.rb_right;
626 } else if (frag->ofs > offset) {
627 D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n",
628 frag->ofs, frag->ofs+frag->size));
629 next = frag->rb.rb_left;
631 D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n",
632 frag->ofs, frag->ofs+frag->size));
637 /* Exact match not found. Go back up looking at each parent,
638 and return the closest smaller one */
641 D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n",
642 prev->ofs, prev->ofs+prev->size));
644 D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n"));
649 /* Pass 'c' argument to indicate that nodes should be marked obsolete as
651 void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
653 struct jffs2_node_frag *frag;
654 struct jffs2_node_frag *parent;
659 frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb));
662 if (frag->rb.rb_left) {
663 D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n",
664 frag, frag->ofs, frag->ofs+frag->size));
665 frag = frag_left(frag);
668 if (frag->rb.rb_right) {
669 D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n",
670 frag, frag->ofs, frag->ofs+frag->size));
671 frag = frag_right(frag);
675 D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n",
676 frag->ofs, frag->ofs+frag->size, frag->node,
677 frag->node?frag->node->frags:0));
679 if (frag->node && !(--frag->node->frags)) {
680 /* Not a hole, and it's the final remaining frag
681 of this node. Free the node */
683 jffs2_mark_node_obsolete(c, frag->node->raw);
685 jffs2_free_full_dnode(frag->node);
687 parent = frag_parent(frag);
689 if (frag_left(parent) == frag)
690 parent->rb.rb_left = NULL;
692 parent->rb.rb_right = NULL;
695 jffs2_free_node_frag(frag);
702 void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base)
704 struct rb_node *parent = &base->rb;
705 struct rb_node **link = &parent;
707 D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag,
708 newfrag->ofs, newfrag->ofs+newfrag->size, base));
712 base = rb_entry(parent, struct jffs2_node_frag, rb);
714 D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs));
715 if (newfrag->ofs > base->ofs)
716 link = &base->rb.rb_right;
717 else if (newfrag->ofs < base->ofs)
718 link = &base->rb.rb_left;
720 printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base);
725 rb_link_node(&newfrag->rb, &base->rb, link);