JFFS1/MTD bug-fixes

Aleksander Sanochkin asanochkin at Lnxw.COM
Fri Nov 30 12:29:22 EST 2001


Hi!

We've been working with JFFS1 on various boards
and have made what we believe is a number of assorted
bug-fixes and small improvements in the JFFS1/MTD code.

Attached is a diff against the current CVS.

Regards.
-------------- next part --------------
diff -ur cvs/drivers/mtd/chips/cfi_cmdset_0002.c other/drivers/mtd/chips/cfi_cmdset_0002.c
--- cvs/drivers/mtd/chips/cfi_cmdset_0002.c	Wed Oct 24 13:37:30 2001
+++ other/drivers/mtd/chips/cfi_cmdset_0002.c	Wed Nov 21 12:58:47 2001
@@ -162,10 +162,7 @@
 	/* Also select the correct geometry setup too */ 
 	mtd->size = devsize * cfi->numchips;
 	
-	if (cfi->cfiq->NumEraseRegions == 1) {
-		/* No need to muck about with multiple erase sizes */
-		mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave;
-	} else {
+	{
 		unsigned long offset = 0;
 		int i,j;
 
diff -ur cvs/drivers/mtd/devices/mtdram.c other/drivers/mtd/devices/mtdram.c
--- cvs/drivers/mtd/devices/mtdram.c	Tue Oct  2 19:05:13 2001
+++ other/drivers/mtd/devices/mtdram.c	Wed Nov 21 12:59:45 2001
@@ -123,7 +123,7 @@
    // Allocate some memory
    mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
    if (!mtd_info)
-      return 0;
+      return -ENOMEM;
    
    memset(mtd_info, 0, sizeof(*mtd_info));
 
diff -ur cvs/drivers/mtd/mtdchar-compat.c other/drivers/mtd/mtdchar-compat.c
--- cvs/drivers/mtd/mtdchar-compat.c	Tue Oct  2 19:05:11 2001
+++ other/drivers/mtd/mtdchar-compat.c	Wed Nov 21 13:03:59 2001
@@ -480,7 +480,7 @@
 		
 	default:
 		DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
-		ret = -ENOTTY;
+		ret = -ENOIOCTLCMD;
 	}
 
 	return ret;
diff -ur cvs/drivers/mtd/mtdchar.c other/drivers/mtd/mtdchar.c
--- cvs/drivers/mtd/mtdchar.c	Tue Oct  2 19:05:11 2001
+++ other/drivers/mtd/mtdchar.c	Wed Nov 21 13:04:10 2001
@@ -437,7 +437,7 @@
 		
 	default:
 		DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
-		ret = -ENOTTY;
+		ret = -ENOIOCTLCMD;
 	}
 
 	return ret;
diff -ur cvs/drivers/mtd/mtdcore.c other/drivers/mtd/mtdcore.c
--- cvs/drivers/mtd/mtdcore.c	Tue Oct  2 19:05:11 2001
+++ other/drivers/mtd/mtdcore.c	Wed Nov 21 17:37:04 2001
@@ -51,6 +51,7 @@
 			struct mtd_notifier *not=mtd_notifiers;
 
 			mtd_table[i] = mtd;
+			mtd->usage_counter = 0;
 			mtd->index = i;
 			DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
 			while (not)
@@ -88,6 +89,11 @@
 	{
 		if (mtd_table[i] == mtd)
 		{
+			if (mtd->usage_counter)
+			{
+				up(&mtd_table_mutex);
+				return -EBUSY;
+			}
 			while (not)
 			{
 				(*(not->remove))(mtd);
@@ -316,6 +322,8 @@
 
 /*====================================================================*/
 /* Init code */
+
+extern int init_mtd_devices(void);
 
 int __init init_mtd(void)
 {
diff -ur cvs/drivers/mtd/mtdpart.c other/drivers/mtd/mtdpart.c
--- cvs/drivers/mtd/mtdpart.c	Wed Nov  7 04:20:58 2001
+++ other/drivers/mtd/mtdpart.c	Wed Nov 21 17:46:29 2001
@@ -140,6 +140,7 @@
 {
 	struct list_head *node;
 	struct mtd_part *slave;
+	int err;
 
 	for (node = mtd_partitions.next;
 	     node != &mtd_partitions;
@@ -147,8 +148,11 @@
 		slave = list_entry(node, struct mtd_part, list);
 		if (slave->master == master) {
 			struct list_head *prev = node->prev;
+			err = del_mtd_device(&slave->mtd);
+			if (err)
+				return err;
 			__list_del(prev, node->next);
-			del_mtd_device(&slave->mtd);
+			kfree(slave->mtd.eraseregions);
 			kfree(slave);
 			node = prev;
 		}
@@ -171,6 +175,7 @@
 	struct mtd_part *slave;
 	u_int32_t cur_offset = 0;
 	int i;
+	int err;
 
 	printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
 
@@ -272,6 +277,17 @@
 			/* Single erase size */
 			slave->mtd.erasesize = master->erasesize;
 		}
+		slave->mtd.numeraseregions = 1;
+		if (! (slave->mtd.eraseregions = kmalloc(sizeof
+			 (struct mtd_erase_region_info), GFP_KERNEL))) {
+			kfree(slave);
+			del_mtd_partitions(master);
+			return -ENOMEM;
+		}
+		slave->mtd.eraseregions->offset = 0;
+		slave->mtd.eraseregions->numblocks =
+			slave->mtd.size / slave->mtd.erasesize;
+		slave->mtd.eraseregions->erasesize = slave->mtd.erasesize;
 
 		if ((slave->mtd.flags & MTD_WRITEABLE) && 
 		    (slave->offset % slave->mtd.erasesize)) {
@@ -289,7 +305,13 @@
 		}
 
 		/* register our partition */
-		add_mtd_device(&slave->mtd);
+		err = add_mtd_device(&slave->mtd);
+		if (err) {
+			kfree(slave->mtd.eraseregions);
+			kfree(slave);
+			del_mtd_partitions(master);
+			return err;
+		}
 	}
 
 	return 0;
diff -ur cvs/fs/jffs/inode-v23.c other/fs/jffs/inode-v23.c
--- cvs/fs/jffs/inode-v23.c	Tue Oct  2 13:16:02 2001
+++ other/fs/jffs/inode-v23.c	Wed Nov 21 18:36:46 2001
@@ -137,10 +137,22 @@
 	if (c->gc_maxdirty_threshold < c->fmc->sector_size)
 		c->gc_maxdirty_threshold = c->fmc->sector_size;
 
+	init_completion(&c->gc_thread_comp);
+	c->gc_task = 0;
 
 	c->thread_pid = kernel_thread (jffs_garbage_collect_thread, 
 				        (void *) c, 
 				        CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	/* Ensure that the garbage collection thread is actually started. */
+	if (c->thread_pid <= 0)
+	{
+		printk(KERN_ERR "Could not start GC thread. Code = %d\n", c->thread_pid);
+		goto jffs_sb_err3;
+	}
+	while (! c->gc_task)
+	{
+		schedule();
+	}
 	D1(printk(KERN_NOTICE "JFFS: GC thread pid=%d.\n", (int) c->thread_pid));
 
 	D1(printk(KERN_NOTICE "JFFS: Successfully mounted device %s.\n",
@@ -391,6 +403,15 @@
 	buf->f_bfree = (jffs_free_size1(fmc) + jffs_free_size2(fmc) +
 		       fmc->dirty_size - fmc->min_free_size)
 			       >> PAGE_CACHE_SHIFT;
+	/* statfs() is prevented from reporting negative sizes. */
+	if (buf->f_bfree < 0)
+	{
+		buf->f_bfree = 0;
+	}
+	if (buf->f_blocks < 0)
+	{
+		buf->f_blocks = 0;
+	}
 	buf->f_bavail = buf->f_bfree;
 
 	/* Find out how many files there are in the filesystem.  */
@@ -1348,6 +1369,22 @@
 		  "filp: 0x%p, buf: 0x%p, count: %d\n",
 		  inode, inode->i_ino, filp, buf, count));
 
+	/* The following two checks are stolen from fs/ext2/file.c
+	 * POSIX: mtime/ctime may not change for 0 count
+	 */
+	if (!count)
+	{
+		return 0;
+	}
+
+	/* This makes the bounds-checking arithmetic later on much more
+	 * sane.
+	 */
+	if (((signed) count) < 0)
+	{
+		return -EINVAL;
+	}
+
 #if 0
 	if (inode->i_sb->s_flags & MS_RDONLY) {
 		D(printk("jffs_file_write(): MS_RDONLY\n"));
@@ -1385,6 +1422,31 @@
 	D3(printk (KERN_NOTICE "file_write(): down biglock\n"));
 	down(&c->fmc->biglock);
 
+	/* Check whether there is enough free space to complete the call
+	 * before writing anything to Flash.
+	 */
+	if (
+	      /* If only a single chunk is about to be written,
+	       * the check performed by jffs_write_node() lately is enough.
+	       */
+	    count != thiscount &&
+	    !JFFS_ENOUGH_SPACE(c, count +
+	        (count / thiscount + 1) * sizeof(raw_inode) +
+	          /* Currently the name is written along with every raw_inode.
+	           */
+	        (count / thiscount + 1) * JFFS_PAD(f->nsize) +
+	          /* Only the last chunk could have unaligned data size.
+	           */
+	        JFFS_GET_PAD_BYTES(count) +
+	          /* One extra max_chunk_size that we leave to be able to
+	           * remove files later.
+	           */
+	        c->fmc->max_chunk_size))
+	{
+		err = -ENOSPC;
+		goto out;
+	}
+
 	/* Urgh. POSIX says we can do short writes if we feel like it. 
 	 * In practice, we can't. Nothing will cope. So we loop until
 	 * we're done.
@@ -1473,6 +1535,8 @@
 	D3(printk (KERN_NOTICE "file_write(): up biglock\n"));
 	up(&c->fmc->biglock);
 
+	*ppos = pos;		
+
 	/* Fix things in the real inode.  */
 	if (pos > inode->i_size) {
 		inode->i_size = pos;
@@ -1483,6 +1547,8 @@
 	invalidate_inode_pages(inode);
 
  out_isem:
+	if (written)
+		return written;
 	return err;
 } /* jffs_file_write()  */
 
@@ -1552,8 +1618,9 @@
 			fst.size = fmc->flash_size;
 			fst.used = fmc->used_size;
 			fst.dirty = fmc->dirty_size;
-			fst.begin = fmc->head->offset;
-			fst.end = fmc->tail->offset + fmc->tail->size;
+			fst.begin = fmc->head ? fmc->head->offset : 0;
+			fst.end = fmc->tail ? fmc->tail->offset +
+			                      fmc->tail->size : 0;
 			printk("size: %d, used: %d, dirty: %d, "
 			       "begin: %d, end: %d\n",
 			       fst.size, fst.used, fst.dirty,
@@ -1614,6 +1681,7 @@
 static struct file_operations jffs_dir_operations =
 {
 	readdir:	jffs_readdir,
+	ioctl:   	jffs_ioctl,
 };
 
 
diff -ur cvs/fs/jffs/intrep.c other/fs/jffs/intrep.c
--- cvs/fs/jffs/intrep.c	Mon Sep 24 03:28:36 2001
+++ other/fs/jffs/intrep.c	Wed Nov 21 20:01:55 2001
@@ -116,7 +116,7 @@
 		int i;
 
 		printk("%ld:", (long) pos);
-		for (j = 0; j < 16; j++) {
+		for (j = 0; j < (size > 16 ? 16 : size); j++) {
 			line[j] = flash_read_u8(mtd, pos++);
 		}
 		for (i = 0; i < j; i++) {
@@ -256,6 +256,7 @@
 {
 	static unsigned char pattern[64];
 	int i;
+ 	int err;
 
 	/* fill up pattern */
 
@@ -265,7 +266,12 @@
 	/* write as many 64-byte chunks as we can */
 
 	while (size >= 64) {
-		flash_safe_write(mtd, to, pattern, 64);
+		err = flash_safe_write(mtd, to, pattern, 64);
+		if (err)
+		{
+			D(printk("flash_safe_write() failed\n"));
+			return err;
+		}
 		size -= 64;
 		to += 64;
 	}
@@ -273,7 +279,14 @@
 	/* and the rest */
 
 	if(size)
-		flash_safe_write(mtd, to, pattern, size);
+ 	{
+		err = flash_safe_write(mtd, to, pattern, size);
+		if (err)
+		{
+			D(printk("2flash_safe_write() failed\n"));
+			return err;
+		}
+	}
 
 	return size;
 }
@@ -1411,7 +1424,11 @@
 		   -- dwmw2
 		*/
 		if (node->data_size || node->removed_size) {
-			jffs_update_file(f, node);
+			int err;
+			if ((err = jffs_update_file(f, node)) < 0)
+			{
+				return err;
+			}
 		}
 		jffs_remove_redundant_nodes(f);
 
@@ -1802,6 +1819,7 @@
 		
 		if (err == -ENOSPC) {
 			/* Just out of space. GC and try again */
+			jffs_fm_write_unlock(fmc);
 			if (fmc->dirty_size < fmc->sector_size) {
 				D(printk("jffs_write_node(): jffs_fmalloc(0x%p, %u) "
 					 "failed, no dirty space to GC\n", fmc,
@@ -1815,7 +1833,6 @@
 				D(printk("jffs_write_node(): jffs_garbage_collect_now() failed\n"));
 				return err;
 			}
-			jffs_fm_write_lock(fmc);
 			continue;
 		} 
 
@@ -1831,8 +1848,6 @@
 			/* The jffs_fm struct that we got is not good enough.
 			   Make that space dirty and try again  */
 			if ((err = jffs_write_dummy_node(c, fm)) < 0) {
-				kfree(fm);
-				DJM(no_jffs_fm--);
 				jffs_fm_write_unlock(fmc);
 				D(printk("jffs_write_node(): "
 					 "jffs_write_dummy_node(): Failed!\n"));
@@ -2141,7 +2156,11 @@
 		  f->ino, (f->name ? f->name : "")));
 
 	for (n = f->version_head; n; n = n->version_next) {
-		jffs_update_file(f, n);
+		int err;
+		if ((err = jffs_update_file(f, n)) < 0)
+		{
+			return err;
+		}
 	}
 	return 0;
 }
@@ -2716,9 +2735,7 @@
 		} else {
 			err = -ENOSPC;
 		}
-		DJM(no_jffs_fm--);
 		jffs_fm_write_unlock(fmc);
-		kfree(fm);
 		
 		return err;
 	}
@@ -3349,7 +3366,6 @@
 
 	current->session = 1;
 	current->pgrp = 1;
-	init_completion(&c->gc_thread_comp); /* barrier */ 
 	spin_lock_irq(&current->sigmask_lock);
 	siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
 	recalc_sigpending(current);
diff -ur cvs/include/linux/mtd/mtd.h other/include/linux/mtd/mtd.h
--- cvs/include/linux/mtd/mtd.h	Sat Jun  9 04:08:59 2001
+++ other/include/linux/mtd/mtd.h	Wed Nov 21 19:08:06 2001
@@ -199,6 +199,9 @@
 	int (*suspend) (struct mtd_info *mtd);
 	void (*resume) (struct mtd_info *mtd);
 
+	/* Partition usage counter. */
+	int usage_counter;
+
 	void *priv;
 };
 
@@ -219,13 +222,18 @@
 	if (ret && ret->module && !try_inc_mod_count(ret->module))
 		return NULL;
 
+	if (ret)
+		ret->usage_counter++;
+
 	return ret;
 }
 
 static inline void put_mtd_device(struct mtd_info *mtd)
 {
-       if (mtd->module)
-	       __MOD_DEC_USE_COUNT(mtd->module);
+	if (mtd->module)
+		__MOD_DEC_USE_COUNT(mtd->module);
+	if (mtd->usage_counter)
+		mtd->usage_counter--;
 }
 
 


More information about the linux-mtd mailing list