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(¤t->sigmask_lock);
siginitsetinv (¤t->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