From 33672f72b24191fb17c3666ec1c620f3fa617b50 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 10 May 2007 22:51:53 -0700 Subject: [MTD] [MAPS] don't force uclinux mtd map to be root dev The cheesy uclinux mtd maps can be used for more than just the root device, so I think we should drop the forcing. Also, I feel like this is a policy decision that shouldnt be in the kernel in the first place. People who have been lazy and boot with uclinux mtd maps and dont put root= into their commandline can simply add the appropriate root= line either into their bootloader or into the compiled in bootargs. Signed-off-by: Mike Frysinger Acked-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/maps/uclinux.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 389fea28b9a6..14ffb1a9302a 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -89,10 +88,6 @@ int __init uclinux_mtd_init(void) uclinux_ram_mtdinfo = mtd; add_mtd_partitions(mtd, uclinux_romfs, NUM_PARTITIONS); - printk("uclinux[mtd]: set %s to be root filesystem\n", - uclinux_romfs[0].name); - ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0); - return(0); } -- cgit v1.2.2 From acaebfd8a7af0019b2edfcf4045c56c3e18375c5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 10 May 2007 22:51:50 -0700 Subject: [MTD] generalise the handling of MTD-specific superblocks Generalise the handling of MTD-specific superblocks so that JFFS2 and ROMFS can both share it. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- drivers/mtd/Makefile | 3 +- drivers/mtd/mtdsuper.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++ fs/jffs2/super.c | 194 ++++---------------------------------- include/linux/fs.h | 1 + include/linux/mtd/super.h | 30 ++++++ 5 files changed, 283 insertions(+), 177 deletions(-) create mode 100644 drivers/mtd/mtdsuper.c create mode 100644 include/linux/mtd/super.h diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 92055405cb30..451adcc52b3c 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -1,10 +1,9 @@ # # Makefile for the memory technology device drivers. # -# $Id: Makefile.common,v 1.7 2005/07/11 10:39:27 gleixner Exp $ # Core functionality. -mtd-y := mtdcore.o +mtd-y := mtdcore.o mtdsuper.o mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o obj-$(CONFIG_MTD) += $(mtd-y) diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c new file mode 100644 index 000000000000..a279540ba87a --- /dev/null +++ b/drivers/mtd/mtdsuper.c @@ -0,0 +1,232 @@ +/* MTD-based superblock management + * + * Copyright © 2001-2007 Red Hat, Inc. All Rights Reserved. + * Written by: David Howells + * David Woodhouse + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include + +/* + * compare superblocks to see if they're equivalent + * - they are if the underlying MTD device is the same + */ +static int get_sb_mtd_compare(struct super_block *sb, void *_mtd) +{ + struct mtd_info *mtd = _mtd; + + if (sb->s_mtd == mtd) { + DEBUG(2, "MTDSB: Match on device %d (\"%s\")\n", + mtd->index, mtd->name); + return 1; + } + + DEBUG(2, "MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", + sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name); + return 0; +} + +/* + * mark the superblock by the MTD device it is using + * - set the device number to be the correct MTD block device for pesuperstence + * of NFS exports + */ +static int get_sb_mtd_set(struct super_block *sb, void *_mtd) +{ + struct mtd_info *mtd = _mtd; + + sb->s_mtd = mtd; + sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, mtd->index); + return 0; +} + +/* + * get a superblock on an MTD-backed filesystem + */ +static int get_sb_mtd_aux(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + struct mtd_info *mtd, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt) +{ + struct super_block *sb; + int ret; + + sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, mtd); + if (IS_ERR(sb)) + goto out_error; + + if (sb->s_root) + goto already_mounted; + + /* fresh new superblock */ + DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n", + mtd->index, mtd->name); + + ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0); + if (ret < 0) { + up_write(&sb->s_umount); + deactivate_super(sb); + return ret; + } + + /* go */ + sb->s_flags |= MS_ACTIVE; + return simple_set_mnt(mnt, sb); + + /* new mountpoint for an already mounted superblock */ +already_mounted: + DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n", + mtd->index, mtd->name); + ret = simple_set_mnt(mnt, sb); + goto out_put; + +out_error: + ret = PTR_ERR(sb); +out_put: + put_mtd_device(mtd); + return ret; +} + +/* + * get a superblock on an MTD-backed filesystem by MTD device number + */ +static int get_sb_mtd_nr(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, int mtdnr, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt) +{ + struct mtd_info *mtd; + + mtd = get_mtd_device(NULL, mtdnr); + if (!mtd) { + DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr); + return -EINVAL; + } + + return get_sb_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super, + mnt); +} + +/* + * set up an MTD-based superblock + */ +int get_sb_mtd(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt) +{ + struct nameidata nd; + int mtdnr, ret; + + if (!dev_name) + return -EINVAL; + + DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name); + + /* the preferred way of mounting in future; especially when + * CONFIG_BLOCK=n - we specify the underlying MTD device by number or + * by name, so that we don't require block device support to be present + * in the kernel. */ + if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { + if (dev_name[3] == ':') { + struct mtd_info *mtd; + + /* mount by MTD device name */ + DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"\n", + dev_name + 4); + + for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { + mtd = get_mtd_device(NULL, mtdnr); + if (mtd) { + if (!strcmp(mtd->name, dev_name + 4)) + return get_sb_mtd_aux( + fs_type, flags, + dev_name, data, mtd, + fill_super, mnt); + + put_mtd_device(mtd); + } + } + + printk(KERN_NOTICE "MTD:" + " MTD device with name \"%s\" not found.\n", + dev_name + 4); + + } else if (isdigit(dev_name[3])) { + /* mount by MTD device number name */ + char *endptr; + + mtdnr = simple_strtoul(dev_name + 3, &endptr, 0); + if (!*endptr) { + /* It was a valid number */ + DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n", + mtdnr); + return get_sb_mtd_nr(fs_type, flags, + dev_name, data, + mtdnr, fill_super, mnt); + } + } + } + + /* try the old way - the hack where we allowed users to mount + * /dev/mtdblock$(n) but didn't actually _use_ the blockdev + */ + ret = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); + + DEBUG(1, "MTDSB: path_lookup() returned %d, inode %p\n", + ret, nd.dentry ? nd.dentry->d_inode : NULL); + + if (ret) + return ret; + + ret = -EINVAL; + + if (!S_ISBLK(nd.dentry->d_inode->i_mode)) + goto out; + + if (nd.mnt->mnt_flags & MNT_NODEV) { + ret = -EACCES; + goto out; + } + + if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) + goto not_an_MTD_device; + + mtdnr = iminor(nd.dentry->d_inode); + path_release(&nd); + + return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, + mnt); + +not_an_MTD_device: + if (!(flags & MS_SILENT)) + printk(KERN_NOTICE + "MTD: Attempt to mount non-MTD device \"%s\"\n", + dev_name); +out: + path_release(&nd); + return ret; + +} + +EXPORT_SYMBOL_GPL(get_sb_mtd); + +/* + * destroy an MTD-based superblock + */ +void kill_mtd_super(struct super_block *sb) +{ + generic_shutdown_super(sb); + put_mtd_device(sb->s_mtd); + sb->s_mtd = NULL; +} + +EXPORT_SYMBOL_GPL(kill_mtd_super); diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index e51164a8a8d4..e3c69e659efb 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include "compr.h" @@ -78,69 +78,27 @@ static const struct super_operations jffs2_super_operations = .sync_fs = jffs2_sync_fs, }; -static int jffs2_sb_compare(struct super_block *sb, void *data) -{ - struct jffs2_sb_info *p = data; - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - - /* The superblocks are considered to be equivalent if the underlying MTD - device is the same one */ - if (c->mtd == p->mtd) { - D1(printk(KERN_DEBUG "jffs2_sb_compare: match on device %d (\"%s\")\n", p->mtd->index, p->mtd->name)); - return 1; - } else { - D1(printk(KERN_DEBUG "jffs2_sb_compare: No match, device %d (\"%s\"), device %d (\"%s\")\n", - c->mtd->index, c->mtd->name, p->mtd->index, p->mtd->name)); - return 0; - } -} - -static int jffs2_sb_set(struct super_block *sb, void *data) -{ - struct jffs2_sb_info *p = data; - - /* For persistence of NFS exports etc. we use the same s_dev - each time we mount the device, don't just use an anonymous - device */ - sb->s_fs_info = p; - p->os_priv = sb; - sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, p->mtd->index); - - return 0; -} - -static int jffs2_get_sb_mtd(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, struct mtd_info *mtd, - struct vfsmount *mnt) +/* + * fill in the superblock + */ +static int jffs2_fill_super(struct super_block *sb, void *data, int silent) { - struct super_block *sb; struct jffs2_sb_info *c; - int ret; + + D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():" + " New superblock for device %d (\"%s\")\n", + sb->s_mtd->index, sb->s_mtd->name)); c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) return -ENOMEM; - c->mtd = mtd; - - sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c); - - if (IS_ERR(sb)) - goto out_error; - - if (sb->s_root) { - /* New mountpoint for JFFS2 which is already mounted */ - D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n", - mtd->index, mtd->name)); - ret = simple_set_mnt(mnt, sb); - goto out_put; - } - D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n", - mtd->index, mtd->name)); + c->mtd = sb->s_mtd; + c->os_priv = sb; + sb->s_fs_info = c; - /* Initialize JFFS2 superblock locks, the further initialization will be - * done later */ + /* Initialize JFFS2 superblock locks, the further initialization will + * be done later */ init_MUTEX(&c->alloc_sem); init_MUTEX(&c->erase_free_sem); init_waitqueue_head(&c->erase_wait); @@ -149,133 +107,20 @@ static int jffs2_get_sb_mtd(struct file_system_type *fs_type, spin_lock_init(&c->inocache_lock); sb->s_op = &jffs2_super_operations; - sb->s_flags = flags | MS_NOATIME; + sb->s_flags = sb->s_flags | MS_NOATIME; sb->s_xattr = jffs2_xattr_handlers; #ifdef CONFIG_JFFS2_FS_POSIX_ACL sb->s_flags |= MS_POSIXACL; #endif - ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); - - if (ret) { - /* Failure case... */ - up_write(&sb->s_umount); - deactivate_super(sb); - return ret; - } - - sb->s_flags |= MS_ACTIVE; - return simple_set_mnt(mnt, sb); - -out_error: - ret = PTR_ERR(sb); - out_put: - kfree(c); - put_mtd_device(mtd); - - return ret; -} - -static int jffs2_get_sb_mtdnr(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, int mtdnr, - struct vfsmount *mnt) -{ - struct mtd_info *mtd; - - mtd = get_mtd_device(NULL, mtdnr); - if (IS_ERR(mtd)) { - D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr)); - return PTR_ERR(mtd); - } - - return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); + return jffs2_do_fill_super(sb, data, silent); } static int jffs2_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - int err; - struct nameidata nd; - int mtdnr; - - if (!dev_name) - return -EINVAL; - - D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name)); - - /* The preferred way of mounting in future; especially when - CONFIG_BLK_DEV is implemented - we specify the underlying - MTD device by number or by name, so that we don't require - block device support to be present in the kernel. */ - - /* FIXME: How to do the root fs this way? */ - - if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { - /* Probably mounting without the blkdev crap */ - if (dev_name[3] == ':') { - struct mtd_info *mtd; - - /* Mount by MTD device name */ - D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4)); - for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { - mtd = get_mtd_device(NULL, mtdnr); - if (!IS_ERR(mtd)) { - if (!strcmp(mtd->name, dev_name+4)) - return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); - put_mtd_device(mtd); - } - } - printk(KERN_NOTICE "jffs2_get_sb(): MTD device with name \"%s\" not found.\n", dev_name+4); - } else if (isdigit(dev_name[3])) { - /* Mount by MTD device number name */ - char *endptr; - - mtdnr = simple_strtoul(dev_name+3, &endptr, 0); - if (!*endptr) { - /* It was a valid number */ - D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr)); - return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); - } - } - } - - /* Try the old way - the hack where we allowed users to mount - /dev/mtdblock$(n) but didn't actually _use_ the blkdev */ - - err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); - - D1(printk(KERN_DEBUG "jffs2_get_sb(): path_lookup() returned %d, inode %p\n", - err, nd.dentry->d_inode)); - - if (err) - return err; - - err = -EINVAL; - - if (!S_ISBLK(nd.dentry->d_inode->i_mode)) - goto out; - - if (nd.mnt->mnt_flags & MNT_NODEV) { - err = -EACCES; - goto out; - } - - if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) { - if (!(flags & MS_SILENT)) - printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n", - dev_name); - goto out; - } - - mtdnr = iminor(nd.dentry->d_inode); - path_release(&nd); - - return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); - -out: - path_release(&nd); - return err; + return get_sb_mtd(fs_type, flags, dev_name, data, jffs2_fill_super, + mnt); } static void jffs2_put_super (struct super_block *sb) @@ -310,8 +155,7 @@ static void jffs2_kill_sb(struct super_block *sb) struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); if (!(sb->s_flags & MS_RDONLY)) jffs2_stop_garbage_collect_thread(c); - generic_shutdown_super(sb); - put_mtd_device(c->mtd); + kill_mtd_super(sb); kfree(c); } diff --git a/include/linux/fs.h b/include/linux/fs.h index 095a9c9a64fb..151739a55eaf 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -937,6 +937,7 @@ struct super_block { struct list_head s_files; struct block_device *s_bdev; + struct mtd_info *s_mtd; struct list_head s_instances; struct quota_info s_dquot; /* Diskquota specific options */ diff --git a/include/linux/mtd/super.h b/include/linux/mtd/super.h new file mode 100644 index 000000000000..4016dd6fe336 --- /dev/null +++ b/include/linux/mtd/super.h @@ -0,0 +1,30 @@ +/* MTD-based superblock handling + * + * Copyright © 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __MTD_SUPER_H__ +#define __MTD_SUPER_H__ + +#ifdef __KERNEL__ + +#include +#include +#include + +extern int get_sb_mtd(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt); +extern void kill_mtd_super(struct super_block *sb); + + +#endif /* __KERNEL__ */ + +#endif /* __MTD_SUPER_H__ */ -- cgit v1.2.2 From 8ae5d31263c746f1680d005b33a82d167cdb9eb6 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 5 May 2007 17:50:25 +0100 Subject: [JFFS2] Fix BUG() caused by failing to discard xattrs on deleted files. When we cannot mark nodes as obsolete, such as on NAND flash, we end up having to delete inodes with !nlink in jffs2_build_remove_unlinked_inode(). However, jffs2_build_xattr_subsystem() runs later than this, and will attach an xref to the dead inode. Then later when the last nodes of that dead inode are erased we hit a BUG() in jffs2_del_ino_cache() because we're not supposed to get there with an xattr still attached to the inode which is being killed. The simple fix is to refrain from attaching xattrs to inodes with zero nlink, in jffs2_build_xattr_subsystem(). It's it's OK to trust nlink here because the file system isn't actually mounted yet, so there's no chance that a zero-nlink file could actually be alive still because it's open. Signed-off-by: David Woodhouse --- fs/jffs2/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 78fc08893a6c..073469856d4e 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -825,7 +825,7 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) ref->xd and ref->ic are not valid yet. */ xd = jffs2_find_xattr_datum(c, ref->xid); ic = jffs2_get_ino_cache(c, ref->ino); - if (!xd || !ic) { + if (!xd || !ic || !ic->nlink) { dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n", ref->ino, ref->xid, ref->xseqno); ref->xseqno |= XREF_DELETE_MARKER; -- cgit v1.2.2 From 2ad8ee713566671875216ebcec64f2eda47bd19d Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 8 May 2007 00:12:58 +0100 Subject: [JFFS2] Fix potential memory leak of dead xattrs on unmount. An xattr_datum which ends up orphaned should be freed by the GC thread. But if we umount before the GC thread is finished, or if we mount read-only and the GC thread never runs, they might never be freed. Clean them up during unmount, if there are any left. Signed-off-by: David Woodhouse --- fs/jffs2/xattr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 073469856d4e..e48665984cb3 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -754,6 +754,10 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c) list_del(&xd->xindex); jffs2_free_xattr_datum(xd); } + list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) { + list_del(&xd->xindex); + jffs2_free_xattr_datum(xd); + } } #define XREF_TMPHASH_SIZE (128) -- cgit v1.2.2 From ea55d30798ac206c9f584ac264b6b8eb093d237a Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 30 May 2007 12:08:14 +0300 Subject: [JFFS2] Fix buffer length calculations in jffs2_get_inode_nodes() If we have already read enough bytes, no need to call read_more(). Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- fs/jffs2/readinode.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 4884d5edfe65..5663e8c7a959 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -1044,7 +1044,8 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf case JFFS2_NODETYPE_DIRENT: - if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) { + if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent) && + len < sizeof(struct jffs2_raw_dirent)) { err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf); if (unlikely(err)) goto free_out; @@ -1058,7 +1059,8 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf case JFFS2_NODETYPE_INODE: - if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) { + if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode) && + len < sizeof(struct jffs2_raw_inode)) { err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf); if (unlikely(err)) goto free_out; @@ -1071,7 +1073,8 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf break; default: - if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) { + if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node) && + len < sizeof(struct jffs2_unknown_node)) { err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf); if (unlikely(err)) goto free_out; -- cgit v1.2.2 From 718ea8361b15aec5f4cb559d63ba34bc5a58d8f9 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 1 Jun 2007 19:21:59 +0100 Subject: [MTD] Fix error checking after get_mtd_device() in get_sb_mtd functions It returns ERR_PTR(foo) on error, not just NULL. Signed-off-by: David Woodhouse --- drivers/mtd/mtdsuper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index a279540ba87a..aca331971201 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -106,9 +106,9 @@ static int get_sb_mtd_nr(struct file_system_type *fs_type, int flags, struct mtd_info *mtd; mtd = get_mtd_device(NULL, mtdnr); - if (!mtd) { + if (IS_ERR(mtd)) { DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr); - return -EINVAL; + return PTR_ERR(mtd); } return get_sb_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super, @@ -145,7 +145,7 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { mtd = get_mtd_device(NULL, mtdnr); - if (mtd) { + if (!IS_ERR(mtd)) { if (!strcmp(mtd->name, dev_name + 4)) return get_sb_mtd_aux( fs_type, flags, -- cgit v1.2.2 From 0477d24e2a87a9077b62298b01b031929f5cf2a2 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 1 Jun 2007 20:04:43 +0100 Subject: [JFFS2] Fix obsoletion of metadata nodes in jffs2_add_tn_to_tree() We should keep the mdata node with higher version number, not just the one we happen to find latest. Doh. Signed-off-by: David Woodhouse --- fs/jffs2/readinode.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 5663e8c7a959..12e83f67eee4 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -229,9 +229,16 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, check anyway. */ if (!tn->fn->size) { if (rii->mdata_tn) { - /* We had a candidate mdata node already */ - dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version); - jffs2_kill_tn(c, rii->mdata_tn); + if (rii->mdata_tn->version < tn->version) { + /* We had a candidate mdata node already */ + dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version); + jffs2_kill_tn(c, rii->mdata_tn); + } else { + dbg_readinode("kill new mdata with ver %d (older than existing %d\n", + tn->version, rii->mdata_tn->version); + jffs2_kill_tn(c, tn); + return 0; + } } rii->mdata_tn = tn; dbg_readinode("keep new mdata with ver %d\n", tn->version); -- cgit v1.2.2