[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Ramblings on NAND flash support.




dwmw2@xxxxxxx.org said:
>  Look through the  physical nodes belonging to the parent directory.
> For each one that's  marked (in the jffs2_raw_node_ref in memory)
> obsolete, read it and check  whether it is obsoleted by the one you're
> trying to GC (i.e. check if the  name matches). Repeat. If you find
> one that _is_ still obsoleted by the  deletion dirent you're trying to
> GC, you need to write that deletion dirent  out to the flash again. If
> you don't find one, you can just let it get  erased as we currently
> do. 20-odd lines of code.  

OK, I lied about 20-odd lines. Something like this...

Index: gc.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/gc.c,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -r1.58 -r1.59
--- gc.c	2002/01/09 13:25:57	1.58
+++ gc.c	2002/01/19 23:31:29	1.59
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: gc.c,v 1.58 2002/01/09 13:25:57 dwmw2 Exp $
+ * $Id: gc.c,v 1.59 2002/01/19 23:31:29 dwmw2 Exp $
  *
  */
 
@@ -381,13 +381,103 @@
 	struct jffs2_full_dirent **fdp = &f->dents;
 	int found = 0;
 
-	/* FIXME: When we run on NAND flash, we need to work out whether
-	   this deletion dirent is still needed to actively delete a
-	   'real' dirent with the same name that's still somewhere else
-	   on the flash. For now, we know that we've actually obliterated
-	   all the older dirents when they became obsolete, so we didn't
-	   really need to write the deletion to flash in the first place.
-	*/
+	/* On a medium where we can't actually mark nodes obsolete
+	   pernamently, such as NAND flash, we need to work out
+	   whether this deletion dirent is still needed to actively
+	   delete a 'real' dirent with the same name that's still
+	   somewhere else on the flash. */
+	if (!jffs2_can_mark_obsolete(c)) {
+		struct jffs2_raw_dirent rd;
+		struct jffs2_raw_node_ref *raw;
+		int ret;
+		size_t retlen;
+		int name_len = strlen(fd->name);
+		uint32_t name_crc = crc32(0, fd->name, name_len);
+		char *namebuf = NULL;
+
+		for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
+			/* We only care about obsolete ones */
+			if (!(raw->flash_offset & 1))
+				continue;
+
+			/* Doesn't matter if there's one in the same erase block. We're going to 
+			   delete it too at the same time. */
+			if ((raw->flash_offset & ~(c->sector_size-1)) ==
+			    (fd->raw->flash_offset & ~(c->sector_size-1)))
+				continue;
+
+			/* This is an obsolete node belonging to the same directory */
+			ret = jffs2_flash_read(c, raw->flash_offset & ~3, sizeof(struct jffs2_unknown_node), &retlen, (char *)&rd);
+			if (ret) {
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading header from obsolete node at %08x\n", ret, raw->flash_offset & ~3);
+				/* If we can't read it, we don't need to continune to obsolete it. Continue */
+				continue;
+			}
+			if (retlen != sizeof(struct jffs2_unknown_node)) {
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading header from obsolete node at %08x\n",
+				       retlen, sizeof(struct jffs2_unknown_node), raw->flash_offset & ~3);
+				continue;
+			}
+			if (rd.nodetype != JFFS2_NODETYPE_DIRENT ||
+			    PAD(rd.totlen) != PAD(sizeof(rd) + name_len))
+				continue;
+
+			/* OK, it's a dirent node, it's the right length. We have to take a 
+			   closer look at it... */
+			ret = jffs2_flash_read(c, raw->flash_offset & ~3, sizeof(rd), &retlen, (char *)&rd);
+			if (ret) {
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading from obsolete node at %08x\n", ret, raw->flash_offset & ~3);
+				/* If we can't read it, we don't need to continune to obsolete it. Continue */
+				continue;
+			}
+			if (retlen != sizeof(struct jffs2_unknown_node)) {
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading from obsolete node at %08x\n",
+				       retlen, sizeof(struct jffs2_unknown_node), raw->flash_offset & ~3);
+				continue;
+			}
+
+			/* If the name CRC doesn't match, skip */
+			if (rd.name_crc != name_crc)
+				continue;
+			/* If the name length doesn't match, or it's another deletion dirent, skip */
+			if (rd.nsize != name_len || !rd.ino)
+				continue;
+
+			/* OK, check the actual name now */
+			if (!namebuf) {
+				namebuf = kmalloc(name_len + 1, GFP_KERNEL);
+				if (!namebuf)
+					return -ENOMEM;
+			}
+			/* We read the extra byte before it so it's a word-aligned read */
+			ret = jffs2_flash_read(c, (raw->flash_offset & ~3)+sizeof(rd)-1, name_len+1, &retlen, namebuf);
+			if (ret) {
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading name from obsolete node at %08x\n", ret, raw->flash_offset & ~3);
+				/* If we can't read it, we don't need to continune to obsolete it. Continue */
+				continue;
+			}
+			if (retlen != sizeof(rd)) {
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading name from obsolete node at %08x\n",
+				       retlen, name_len, raw->flash_offset & ~3);
+				continue;
+			}
+			if (memcmp(namebuf+1, fd->name, name_len))
+				continue;
+
+			/* OK. The name really does match. There really is still an older node on
+			   the flash which our deletion dirent obsoletes. So we have to write out
+			   a new deletion dirent to replace it */
+			
+			if (namebuf)
+				kfree(namebuf);
+
+			return jffs2_garbage_collect_dirent(c, jeb, inode, fd);
+		}
+		if (namebuf) 
+			kfree(namebuf);
+	}
+
+	/* No need for it any more. Just mark it obsolete and remove it from the list */
 	while (*fdp) {
 		if ((*fdp) == fd) {
 			found = 1;



--
dwmw2



To unsubscribe from this list: send the line "unsubscribe jffs-dev" in
the body of a message to majordomo@xxxxxxx.com