summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2002-03-17 15:38:00 +0000
committerDavid Woodhouse <dwmw2@infradead.org>2002-03-17 15:38:00 +0000
commit5bb3575c7c93e3315df4123a2911ada821e757c2 (patch)
tree3153d4eacba3cb97e5ef01084e38fa5d417f2323
parent0b2e8f296ddf468918463779974ef88f5f9d42d7 (diff)
Remove jffs2_sb from struct super_block union.
Remove FS_REQUIRES_DEV from JFFS2. We never really used the block device anyway.
-rw-r--r--fs/jffs2/os-linux.h6
-rw-r--r--fs/jffs2/super.c202
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/jffs2_fs_sb.h5
4 files changed, 180 insertions, 35 deletions
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 4b3fae61ff08..cad48eb13278 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: os-linux.h,v 1.15 2002/03/08 11:31:48 dwmw2 Exp $
+ * $Id: os-linux.h,v 1.16 2002/03/17 10:18:42 dwmw2 Exp $
*
*/
@@ -42,8 +42,8 @@
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
#define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode)
-#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb)
-#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
+#define JFFS2_SB_INFO(sb) (sb->u.generic_sbp)
+#define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv)
#elif defined(JFFS2_OUT_OF_KERNEL)
#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 0603521256e5..48f0cf4b7283 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: super.c,v 1.62 2002/03/12 16:23:41 dwmw2 Exp $
+ * $Id: super.c,v 1.64 2002/03/17 10:18:42 dwmw2 Exp $
*
*/
@@ -47,6 +47,7 @@
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
+#include <linux/ctype.h>
#include "nodelist.h"
void jffs2_put_super (struct super_block *);
@@ -91,46 +92,194 @@ static struct super_operations jffs2_super_operations =
clear_inode: jffs2_clear_inode
};
+static int jffs2_sb_compare(struct super_block *sb, void *data)
+{
+ struct mtd_info *mtd = 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 == mtd) {
+ D1(printk(KERN_DEBUG "jffs2_sb_compare: match on device %d (\"%s\")\n", mtd->index, 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, mtd->index, mtd->name));
+ return 0;
+ }
+}
-static int jffs2_blk_fill_super(struct super_block *sb, void *data, int silent)
+static int jffs2_sb_set(struct super_block *sb, void *data)
{
+ struct mtd_info *mtd = 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_dev = mk_kdev(MTD_BLOCK_MAJOR, mtd->index);
+
+ return 0;
+}
+
+static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
+ int flags, char *dev_name,
+ void *data, struct mtd_info *mtd)
+{
+ struct super_block *sb;
struct jffs2_sb_info *c;
int ret;
- D1(printk(KERN_DEBUG "jffs2: blk_read_super for device %s\n", sb->s_id));
+ sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, mtd);
- if (major(sb->s_dev) != MTD_BLOCK_MAJOR) {
- if (!silent)
- printk(KERN_NOTICE "jffs2: attempt to mount non-MTD device %s\n",
- sb->s_id);
- return -EINVAL;
+ if (IS_ERR(sb))
+ goto out_put;
+
+ 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));
+ goto out_put;
}
- c = JFFS2_SB_INFO(sb);
- memset(c, 0, sizeof(*c));
-
+ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n",
+ mtd->index, mtd->name));
+
+ c = kmalloc(sizeof(*c), GFP_KERNEL);
+ if (!c) {
+ sb = ERR_PTR(-ENOMEM);
+ goto out_put;
+ }
+
+ sb->u.generic_sbp = c;
sb->s_op = &jffs2_super_operations;
- c->mtd = get_mtd_device(NULL, minor(sb->s_dev));
- if (!c->mtd) {
- D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", minor(sb->s_dev)));
- return -EINVAL;
+ memset(c, 0, sizeof(*c));
+ c->os_priv = sb;
+ c->mtd = mtd;
+
+ ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0);
+
+ if (ret) {
+ /* Failure case... */
+ up_write(&sb->s_umount);
+ deactivate_super(sb);
+ sb = ERR_PTR(ret);
+ goto out_put;
}
- ret = jffs2_do_fill_super(sb, data, silent);
- if (ret)
- put_mtd_device(c->mtd);
+ sb->s_flags |= MS_ACTIVE;
+ return sb;
- return ret;
+ out_put:
+ put_mtd_device(mtd);
+
+ return sb;
}
+static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
+ int flags, char *dev_name,
+ void *data, int mtdnr)
+{
+ struct mtd_info *mtd;
+
+ mtd = get_mtd_device(NULL, mtdnr);
+ if (!mtd) {
+ D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr));
+ return ERR_PTR(-EINVAL);
+ }
+
+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
+}
+
+static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
+ int flags, char *dev_name, void *data)
+{
+ int err;
+ struct nameidata nd;
+ int mtdnr;
+ kdev_t dev;
+
+ if (!dev_name)
+ return ERR_PTR(-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 (mtd) {
+ if (!strcmp(mtd->name, dev_name+4))
+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
+ 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);
+ }
+ }
+ }
+
+ /* 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_PTR(err);
+
+ if (!S_ISBLK(nd.dentry->d_inode->i_mode)) {
+ path_release(&nd);
+ return ERR_PTR(-EINVAL);
+ }
+ if (nd.mnt->mnt_flags & MNT_NODEV) {
+ path_release(&nd);
+ return ERR_PTR(-EACCES);
+ }
+
+ dev = nd.dentry->d_inode->i_rdev;
+ path_release(&nd);
+
+ if (major(dev) != MTD_BLOCK_MAJOR) {
+ if (!(flags & MS_VERBOSE)) /* Yes I mean this. Strangely */
+ printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n",
+ dev_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, minor(dev));
+}
+
+
void jffs2_put_super (struct super_block *sb)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
-
if (!(sb->s_flags & MS_RDONLY))
jffs2_stop_garbage_collect_thread(c);
jffs2_flush_wbuf(c, 1);
@@ -140,22 +289,17 @@ void jffs2_put_super (struct super_block *sb)
if (c->mtd->sync)
c->mtd->sync(c->mtd);
put_mtd_device(c->mtd);
-
- D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
-}
-static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
-{
- return get_sb_bdev(fs_type, flags, dev_name, data, jffs2_blk_fill_super);
+ kfree(c);
+
+ D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
}
static struct file_system_type jffs2_fs_type = {
owner: THIS_MODULE,
name: "jffs2",
get_sb: jffs2_get_sb,
- kill_sb: kill_block_super,
- fs_flags: FS_REQUIRES_DEV,
+ kill_sb: generic_shutdown_super
};
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f9f89afcb51e..d05052fa4461 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -658,7 +658,6 @@ struct quota_mount_options
#include <linux/reiserfs_fs_sb.h>
#include <linux/bfs_fs_sb.h>
#include <linux/udf_fs_sb.h>
-#include <linux/jffs2_fs_sb.h>
extern struct list_head super_blocks;
extern spinlock_t sb_lock;
@@ -708,7 +707,6 @@ struct super_block {
struct reiserfs_sb_info reiserfs_sb;
struct bfs_sb_info bfs_sb;
struct udf_sb_info udf_sb;
- struct jffs2_sb_info jffs2_sb;
void *generic_sbp;
} u;
/*
diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h
index c424eb13103c..129a4c31dee1 100644
--- a/include/linux/jffs2_fs_sb.h
+++ b/include/linux/jffs2_fs_sb.h
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.25 2002/03/08 15:11:24 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.26 2002/03/17 10:18:42 dwmw2 Exp $ */
#ifndef _JFFS2_FS_SB
#define _JFFS2_FS_SB
@@ -81,6 +81,9 @@ struct jffs2_sb_info {
uint32_t wbuf_ofs;
uint32_t wbuf_len;
uint32_t wbuf_pagesize;
+
+ /* OS-private pointer for getting back to master superblock info */
+ void *os_priv;
};
#endif /* _JFFS2_FB_SB */