mtd/fs/jffs2 build.c,1.39,1.40 gc.c,1.81,1.82 nodelist.c,1.49,1.50 nodelist.h,1.77,1.78 read.c,1.25,1.26 readinode.c,1.76,1.77

David Woodhouse dwmw2 at infradead.org
Mon Sep 2 20:08:54 EDT 2002


Update of /home/cvs/mtd/fs/jffs2
In directory phoenix.infradead.org:/tmp/cvs-serv20956

Modified Files:
	build.c gc.c nodelist.c nodelist.h read.c readinode.c 
Log Message:
Wheee. The code use Red/Black trees for inode fragment lists finally 
compiles. NFC if it works yet, of course -- Thomas will probably tell me 
in the morning.


Index: build.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/build.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -r1.39 -r1.40
--- build.c	1 Sep 2002 15:47:04 -0000	1.39
+++ build.c	3 Sep 2002 00:08:51 -0000	1.40
@@ -121,7 +121,7 @@
 {
 	struct jffs2_tmp_dnode_info *tn;
 	struct jffs2_full_dirent *fd;
-	struct jffs2_node_frag *fraglist = NULL;
+	rb_root_t fragtree = RB_ROOT;
 	struct jffs2_tmp_dnode_info *metadata = NULL;
 
 	D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
@@ -147,7 +147,7 @@
 		}
 			
 		if (tn->fn->size) {
-			jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn);
+			jffs2_add_full_dnode_to_fraglist (c, &fragtree, tn->fn);
 			jffs2_free_tmp_dnode_info(tn);
 		} else {
 			if (!metadata) {
@@ -169,7 +169,7 @@
 		/* It's a regular file, so truncate it to the last known
 		   i_size, if necessary */
 		D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 truncating fraglist to 0x%08x\n", ic->scan->isize));
-		jffs2_truncate_fraglist(c, &fraglist, ic->scan->isize);
+		jffs2_truncate_fraglist(c, &fragtree, ic->scan->isize);
 	}
 	
 	/* OK. Now clear up */
@@ -179,17 +179,7 @@
 	}
 	metadata = NULL;
 
-	/* RBTREE */
-	while (fraglist) {
-		struct jffs2_node_frag *frag;
-		frag = fraglist;
-		fraglist = fraglist->fnext;
-		
-		if (frag->node && !(--frag->node->frags)) {
-			jffs2_free_full_dnode(frag->node);
-		}
-		jffs2_free_node_frag(frag);
-	}
+	jffs2_kill_fragtree(&fragtree, NULL);
 
 	/* Now for each child, increase nlink */
 	for(fd=ic->scan->dents; fd; fd = fd->next) {

Index: gc.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/gc.c,v
retrieving revision 1.81
retrieving revision 1.82
diff -u -r1.81 -r1.82
--- gc.c	1 Sep 2002 15:47:04 -0000	1.81
+++ gc.c	3 Sep 2002 00:08:51 -0000	1.82
@@ -202,7 +202,7 @@
 	}
 
 	/* FIXME. Read node and do lookup? */
-	for (frag = frag_first(f->fragtree); frag; frag = frag_next(frag)) {
+	for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
 		if (frag->node && frag->node->raw == raw) {
 			fn = frag->node;
 			end = frag->ofs + frag->size;
@@ -626,7 +626,7 @@
 		       je32_to_cpu(ri.ino));
 	});
 
-	for (frag = jffs2_lookup_node_frag(f->fragtree, fn->ofs); 
+	for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); 
 	     frag; frag = frag_next(frag)) {
 		if (frag->ofs > fn->size + fn->ofs)
 			break;

Index: nodelist.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/nodelist.c,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -r1.49 -r1.50
--- nodelist.c	1 Sep 2002 15:47:04 -0000	1.49
+++ nodelist.c	3 Sep 2002 00:08:51 -0000	1.50
@@ -15,6 +15,7 @@
 #include <linux/fs.h>
 #include <linux/mtd/mtd.h>
 #include <linux/interrupt.h>
+#include <linux/rbtree.h>
 #include "nodelist.h"
 
 void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
@@ -371,13 +372,136 @@
 	}
 }
 	
-struct jffs2_node_frag *jffs2_lookup_node_frag(struct jffs2_node_frag *fragtree, uint32_t offset)
+struct jffs2_node_frag *jffs2_lookup_node_frag(rb_root_t *fragtree, uint32_t offset)
 {
-	struct jffs2_node_frag *frag = fragtree;
+	/* The common case in lookup is that there will be a node 
+	   which precisely matches. So we go looking for that first */
+	rb_node_t *next = &(frag_first(fragtree))->rb;
+	struct jffs2_node_frag *ret;
+	struct jffs2_node_frag *frag;
+
+	D1(printk(KERN_DEBUG "jffs2_lookup_node_frag(%d)\n", offset));
+
+	do {
+		frag = rb_entry(next, struct jffs2_node_frag, rb);
+
+		if (frag->ofs + frag->size <= offset) {
+			D1(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n",
+				  frag->ofs, frag->ofs+frag->size));
+			next = frag->rb.rb_right;
+		} else if (frag->ofs > offset) {
+			D1(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n",
+				  frag->ofs, frag->ofs+frag->size));
+			next = frag->rb.rb_left;
+		} else {
+			D1(printk(KERN_DEBUG "Returning frag %d,%d, matched\n",
+				  frag->ofs, frag->ofs+frag->size));
+			return frag;
+		}
+	} while(next);
+
+	/* Exact match not found. Go back up looking at each parent,
+	   and return the closest smaller one */
+
+	D1(printk(KERN_DEBUG "No match. Looking for closest previous frag\n"));
+
+	ret = frag;
 
-	while(frag && frag->ofs + frag->size  <= offset) {
-		D2(printk(KERN_DEBUG "skipping frag %d-%d; before the region we care about\n", frag->ofs, frag->ofs + frag->size));
-		frag = frag_next(frag);
+	while (frag) {
+		D1(printk(KERN_DEBUG "Considering frag %d-%d.\n",
+			  frag->ofs, frag->ofs+frag->size));
+		if (frag->ofs < offset && frag->ofs > ret->ofs)
+			ret = frag;
+
+		frag = frag_parent(frag);
 	}
-	return frag;
+	D1(printk(KERN_DEBUG "Returning frag %d,%d, closest previous\n",
+		  frag->ofs, frag->ofs+frag->size));
+	
+	return ret;
+}
+
+/* Pass 'c' argument to indicate that nodes should be marked obsolete as
+   they're killed. */
+void jffs2_kill_fragtree(rb_root_t *root, struct jffs2_sb_info *c)
+{
+	struct jffs2_node_frag *frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb));
+	struct jffs2_node_frag *parent;
+
+	while(frag) {
+		if (frag_left(frag)) {
+			frag = frag_left(frag);
+			continue;
+		}
+		if (frag_right(frag)) {
+			frag = frag_right(frag);
+			continue;
+		}
+
+		D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n",
+			  frag->ofs, frag->ofs+frag->size, frag->node,
+			  frag->node?frag->node->frags:0));
+			
+		if (frag->node && !(--frag->node->frags)) {
+			/* Not a hole, and it's the final remaining frag 
+			   of this node. Free the node */
+			if (c)
+				jffs2_mark_node_obsolete(c, frag->node->raw);
+			
+			jffs2_free_full_dnode(frag->node);
+		}
+		parent = frag_parent(frag);
+		if (frag_left(parent) == frag)
+			parent->rb.rb_left = NULL;
+		else 
+			parent->rb.rb_right = NULL;
+
+		jffs2_free_node_frag(frag);
+		frag = parent;
+	}
+}
+
+void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base)
+{
+	rb_node_t *parent = &base->rb;
+	rb_node_t **link = &parent;
+
+	while (*link) {
+		parent = *link;
+		base = rb_entry(parent, struct jffs2_node_frag, rb);
+	
+		if (newfrag->ofs > base->ofs)
+			link = &base->rb.rb_right;
+		else if (newfrag->ofs > base->ofs)
+			link = &base->rb.rb_left;
+		else {
+			printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base);
+			BUG();
+		}
+	}
+
+	rb_link_node(&newfrag->rb, &base->rb, link);
+}
+
+rb_node_t *rb_next(rb_node_t *node)
+{
+	/* If we have a right-hand child, go down and then left as far
+	   as we can. */
+	if (node->rb_right) {
+		node = node->rb_right; 
+		while (node->rb_left)
+			node=node->rb_left;
+		return node;
+	}
+
+	/* No right-hand children.  Everything down and left is
+	   smaller than us, so any 'next' node must be in the general
+	   direction of our parent. Go up the tree; any time the
+	   ancestor is a right-hand child of its parent, keep going
+	   up. First time it's a left-hand child of its parent, said
+	   parent is our 'next' node. */
+	while (node->rb_parent && node == node->rb_parent->rb_right)
+		node = node->rb_parent;
+
+	return node->rb_parent;
 }

Index: nodelist.h
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/nodelist.h,v
retrieving revision 1.77
retrieving revision 1.78
diff -u -r1.77 -r1.78
--- nodelist.h	1 Sep 2002 15:47:04 -0000	1.77
+++ nodelist.h	3 Sep 2002 00:08:51 -0000	1.78
@@ -146,15 +146,12 @@
 */
 struct jffs2_node_frag
 {
-	struct jffs2_node_frag *fnext;
+	rb_node_t rb;
 	struct jffs2_full_dnode *node; /* NULL for holes */
 	uint32_t size;
 	uint32_t ofs; /* Don't really need this, but optimisation */
 };
 
-#define frag_next(f) ((f)->fnext)
-#define frag_first(f) (f)
-	
 struct jffs2_eraseblock
 {
 	struct list_head list;
@@ -238,6 +235,23 @@
 	return ((struct jffs2_inode_cache *)raw)->ino;
 }
 
+static inline struct jffs2_node_frag *frag_first(rb_root_t *root)
+{
+	rb_node_t *node = root->rb_node;
+
+	if (!node)
+		return NULL;
+	while(node->rb_left)
+		node = node->rb_left;
+	return rb_entry(node, struct jffs2_node_frag, rb);
+}
+#define rb_parent(rb) ((rb)->rb_parent)
+#define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb)
+#define frag_parent(frag) rb_entry(rb_parent(&(frag)->rb), struct jffs2_node_frag, rb)
+#define frag_left(frag) rb_entry(&(frag)->rb.rb_left, struct jffs2_node_frag, rb)
+#define frag_right(frag) rb_entry(&(frag)->rb.rb_right, struct jffs2_node_frag, rb)
+#define frag_erase(frag, list) rb_erase(&frag->rb, list);
+
 /* nodelist.c */
 D1(void jffs2_print_frag_list(struct jffs2_inode_info *f));
 void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
@@ -251,7 +265,10 @@
 void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old);
 void jffs2_free_ino_caches(struct jffs2_sb_info *c);
 void jffs2_free_raw_node_refs(struct jffs2_sb_info *c);
-struct jffs2_node_frag *jffs2_lookup_node_frag(struct jffs2_node_frag *fragtree, uint32_t offset);
+struct jffs2_node_frag *jffs2_lookup_node_frag(rb_root_t *fragtree, uint32_t offset);
+void jffs2_kill_fragtree(rb_root_t *root, struct jffs2_sb_info *c_delete);
+void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base);
+rb_node_t *rb_next(rb_node_t *);
 
 /* nodemgmt.c */
 int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
@@ -274,8 +291,8 @@
 
 
 /* readinode.c */
-void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, uint32_t size);
-int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn);
+void jffs2_truncate_fraglist (struct jffs2_sb_info *c, rb_root_t *list, uint32_t size);
+int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, rb_root_t *list, struct jffs2_full_dnode *fn);
 int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
 int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 
 			uint32_t ino, struct jffs2_raw_inode *latest_node);

Index: read.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/read.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- read.c	1 Sep 2002 15:47:04 -0000	1.25
+++ read.c	3 Sep 2002 00:08:51 -0000	1.26
@@ -157,7 +157,7 @@
 	D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n",
 		  f->inocache->ino, offset, offset+len));
 
-	frag = jffs2_lookup_node_frag(f->fragtree, offset);
+	frag = jffs2_lookup_node_frag(&f->fragtree, offset);
 
 	/* XXX FIXME: Where a single physical node actually shows up in two
 	   frags, we read it twice. Don't do that. */

Index: readinode.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/readinode.c,v
retrieving revision 1.76
retrieving revision 1.77
diff -u -r1.76 -r1.77
--- readinode.c	1 Sep 2002 15:47:04 -0000	1.76
+++ readinode.c	3 Sep 2002 00:08:52 -0000	1.77
@@ -22,7 +22,7 @@
 
 D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)
 {
-	struct jffs2_node_frag *this = frag_first(f->fragtree);
+	struct jffs2_node_frag *this = frag_first(&f->fragtree);
 
 	while(this) {
 		if (this->node)
@@ -72,14 +72,12 @@
 }
 
 /* Doesn't set inode->i_size */
-int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn)
+int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, rb_root_t *list, struct jffs2_full_dnode *fn)
 {
-	
-	struct jffs2_node_frag *this, **prev, *old;
-	struct jffs2_node_frag *newfrag, *newfrag2;
+	struct jffs2_node_frag *this;
+	struct jffs2_node_frag *newfrag;
 	uint32_t lastend = 0;
 
-
 	newfrag = jffs2_alloc_node_frag();
 	if (!newfrag) {
 		return -ENOMEM;
@@ -90,33 +88,27 @@
 	else
 		printk(KERN_DEBUG "adding hole node %04x-%04x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, newfrag));
 	
-	prev = list;
-	this = *list;
-
 	if (!fn->size) {
 		jffs2_free_node_frag(newfrag);
 		return 0;
 	}
 
-	/* RBTREE */
 	newfrag->ofs = fn->ofs;
 	newfrag->size = fn->size;
 	newfrag->node = fn;
 	newfrag->node->frags = 1;
-	newfrag->fnext = (void *)0xdeadbeef;
 
 	/* Skip all the nodes which are completed before this one starts */
-	while(this && fn->ofs >= this->ofs+this->size) {
-		lastend = this->ofs + this->size;
+	this = jffs2_lookup_node_frag(list, fn->ofs);
+
+	D1(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
+		  this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this));
 
-		D2(printk(KERN_DEBUG "j_a_f_d_t_f: skipping frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", 
-			  this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this));
-		prev = &this->fnext;
-		this = this->fnext;
-	}
+
+	lastend = this->ofs + this->size;
 
 	/* See if we ran off the end of the list */
-	if (!this) {
+	if (lastend <= newfrag->ofs) {
 		/* We did */
 		if (lastend < fn->ofs) {
 			/* ... and we need to put a hole in before the new node */
@@ -125,27 +117,31 @@
 				return -ENOMEM;
 			holefrag->ofs = lastend;
 			holefrag->size = fn->ofs - lastend;
-			holefrag->fnext = NULL;
 			holefrag->node = NULL;
-			*prev = holefrag;
-			prev = &holefrag->fnext;
-		}
-		newfrag->fnext = NULL;
-		*prev = newfrag;
+			/* By definition, the 'this' node has no right-hand child.
+			   And that's where we want to put the hole */
+			rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right);
+			rb_insert_color(&holefrag->rb, list);
+			this = holefrag;
+		}
+		/* By definition, the 'this' node has no right-hand child.
+		   And that's where we want to put the new node */
+		rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
+		rb_insert_color(&newfrag->rb, list);
 		return 0;
 	}
 
 	D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", 
 		  this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this));
 
-	/* OK. 'this' is pointing at the first frag that fn->ofs at least partially obsoletes,
-	 * - i.e. fn->ofs < this->ofs+this->size && fn->ofs >= this->ofs  
+	/* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes,
+	 * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs  
 	 */
-	if (fn->ofs > this->ofs) {
+	if (newfrag->ofs > this->ofs) {
 		/* This node isn't completely obsoleted. The start of it remains valid */
-		if (this->ofs + this->size > fn->ofs + fn->size) {
+		if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
 			/* The new node splits 'this' frag into two */
-			newfrag2 = jffs2_alloc_node_frag();
+			struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag();
 			if (!newfrag2) {
 				jffs2_free_node_frag(newfrag);
 				return -ENOMEM;
@@ -156,39 +152,55 @@
 			else 
 				printk("hole\n");
 			   )
-			newfrag2->ofs = fn->ofs + fn->size;
+			/* Adjust size of original 'this' */
+			this->size = newfrag->ofs - this->ofs;
+			
+			/* New second frag pointing to 'this's node */
+			newfrag2->ofs = newfrag->ofs + newfrag->size;
 			newfrag2->size = (this->ofs+this->size) - newfrag2->ofs;
-			newfrag2->fnext = this->fnext;
 			newfrag2->node = this->node;
 			if (this->node)
 				this->node->frags++;
-			newfrag->fnext = newfrag2;
-			this->fnext = newfrag;
-			this->size = newfrag->ofs - this->ofs;
+
+			/* Now, we know there's no node with offset greater than newfrag2->ofs, for
+			   obvious reasons. So we can do a tree insert from this to insert newfrag,
+			   and a tree insert from newfrag to insert newfrag2. */
+			jffs2_fragtree_insert(newfrag, this);
+			rb_insert_color(&newfrag->rb, list);
+			
+			jffs2_fragtree_insert(newfrag2, this);
+			rb_insert_color(&newfrag2->rb, list);
+			
 			return 0;
 		}
 		/* New node just reduces 'this' frag in size, doesn't split it */
-		this->size = fn->ofs - this->ofs;
-		newfrag->fnext = this->fnext;
-		this->fnext = newfrag;
-		this = newfrag->fnext;
+		this->size = newfrag->ofs - this->ofs;
+
+		/* Again, we know it lives down here in the tree */
+		jffs2_fragtree_insert(newfrag, this);
+		rb_insert_color(&newfrag->rb, list);
 	} else {
 		D2(printk(KERN_DEBUG "Inserting newfrag (*%p) in before 'this' (*%p)\n", newfrag, this));
-		*prev = newfrag;
-	        newfrag->fnext = this;
+		struct jffs2_node_frag *parent = frag_parent(this);
+		
+		if (this == frag_left(parent))
+			parent->rb.rb_left = &newfrag->rb;
+		else
+			parent->rb.rb_right = &newfrag->rb;
+
+		newfrag->rb = this->rb;
+		jffs2_obsolete_node_frag(c, this);
 	}
-	/* OK, now we have newfrag added in the correct place in the list, but
-	   newfrag->fnext points to a fragment which may be overlapping it
+	/* OK, now we have newfrag added in the correct place in the tree, but
+	   frag_next(newfrag) may be a fragment which is overlapped by it 
 	*/
-	while (this && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
-		/* 'this' frag is obsoleted. */
-		old = this;
-		this = old->fnext;
-		jffs2_obsolete_node_frag(c, old);
+	while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
+		/* 'this' frag is obsoleted completely. */
+		rb_erase(&this->rb, list);
+		jffs2_obsolete_node_frag(c, this);
 	}
 	/* Now we're pointing at the first frag which isn't totally obsoleted by 
 	   the new frag */
-	newfrag->fnext = this;
 
 	if (!this || newfrag->ofs + newfrag->size == this->ofs) {
 		return 0;
@@ -196,25 +208,29 @@
 	/* Still some overlap */
 	this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
 	this->ofs = newfrag->ofs + newfrag->size;
+
 	return 0;
 }
 
-void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, uint32_t size)
+void jffs2_truncate_fraglist (struct jffs2_sb_info *c, rb_root_t *list, uint32_t size)
 {
+	struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
+
 	D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size));
 
-	while (*list) {
-		if ((*list)->ofs >= size) {
-			struct jffs2_node_frag *this = *list;
-			*list = this->fnext;
-			D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", this->ofs, this->ofs+this->size));
-			jffs2_obsolete_node_frag(c, this);
-			continue;
-		} else if ((*list)->ofs + (*list)->size > size) {
-			D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", (*list)->ofs, (*list)->ofs + (*list)->size));
-			(*list)->size = size - (*list)->ofs;
-		}
-		list = &(*list)->fnext;
+	/* We know frag->ofs <= size. That's what lookup does for us */
+	if (frag && frag->ofs != size && frag->ofs+frag->size > size) {
+		D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
+		frag->size = size - frag->ofs;
+		frag = frag_next(frag);
+	}
+	while (frag) {
+		struct jffs2_node_frag *next = frag_next(frag);
+
+		D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
+		frag_erase(frag, list);
+		jffs2_obsolete_node_frag(c, frag);
+		frag = next;
 	}
 }
 
@@ -361,14 +377,14 @@
 			jffs2_do_clear_inode(c, f);
 			return -EIO;
 		}
-		if (!frag_first(f->fragtree)) {
+		if (!frag_first(&f->fragtree)) {
 			printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", ino, je32_to_cpu(latest_node->mode));
 			up(&f->sem);
 			jffs2_do_clear_inode(c, f);
 			return -EIO;
 		}
 		/* ASSERT: f->fraglist != NULL */
-		if (frag_next(frag_first(f->fragtree))) {
+		if (frag_next(frag_first(&f->fragtree))) {
 			printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had more than one node\n", ino, je32_to_cpu(latest_node->mode));
 			/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
 			up(&f->sem);
@@ -376,52 +392,37 @@
 			return -EIO;
 		}
 		/* OK. We're happy */
-		f->metadata = frag_first(f->fragtree)->node;
-		jffs2_free_node_frag(frag_first(f->fragtree));
-		f->fragtree = NULL;
+		f->metadata = frag_first(&f->fragtree)->node;
+		jffs2_free_node_frag(frag_first(&f->fragtree));
+		f->fragtree = RB_ROOT;
 		break;
 	}
 
 	return 0;
 }
 
-
 void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
 {
-	struct jffs2_node_frag *frag, *frags;
 	struct jffs2_full_dirent *fd, *fds;
+	/* I don't think we care about the potential race due to reading this
+	   without f->sem. It can never get undeleted. */
+	int deleted = f->inocache && !f->inocache->nlink;
 
 	/* If it's a deleted inode, grab the alloc_sem to keep the
 	   (maybe temporary) BUG() in jffs2_mark_node_obsolete() 
 	   from triggering */
-	if(f->inocache && !f->inocache->nlink)
+	if(deleted)
 		down(&c->alloc_sem);
 
 	down(&f->sem);
 
 	if (f->metadata) {
-		if (f->inocache && !f->inocache->nlink)
+		if (deleted)
 			jffs2_mark_node_obsolete(c, f->metadata->raw);
 		jffs2_free_full_dnode(f->metadata);
 	}
 
-	/* RBTREE */
-	frags = frag_first(f->fragtree);
-
-	while (frags) {
-		frag = frags;
-		frags = frag_next(frag);
-		D2(printk(KERN_DEBUG "jffs2_do_clear_inode: frag at 0x%x-0x%x: node %p, frags %d--\n", frag->ofs, frag->ofs+frag->size, frag->node, frag->node?frag->node->frags:0));
-
-		if (frag->node && !(--frag->node->frags)) {
-			/* Not a hole, and it's the final remaining frag of this node. Free the node */
-			if (f->inocache && !f->inocache->nlink)
-				jffs2_mark_node_obsolete(c, frag->node->raw);
-
-			jffs2_free_full_dnode(frag->node);
-		}
-		jffs2_free_node_frag(frag);
-	}
+	jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
 
 	fds = f->dents;
 
@@ -431,11 +432,8 @@
 		jffs2_free_full_dirent(fd);
 	}
 
-	/* Urgh. Is there a nicer way to do this? */
-	if(f->inocache && !f->inocache->nlink) {
-		up(&f->sem);
+	up(&f->sem);
+
+	if(deleted)
 		up(&c->alloc_sem);
-	} else {
-		up(&f->sem);
-	}
 }





More information about the linux-mtd-cvs mailing list