diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2007-05-08 00:25:43 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 11:15:01 -0700 |
commit | 79c0b2df79eb56fc71e54c75cd7fb3acf84370f9 (patch) | |
tree | f19be816fef3565b7f9cc746786e29fee0ac62e6 /fs | |
parent | 880afc4d76af452267174b5989943f081c1db2c0 (diff) | |
download | op-kernel-dev-79c0b2df79eb56fc71e54c75cd7fb3acf84370f9.zip op-kernel-dev-79c0b2df79eb56fc71e54c75cd7fb3acf84370f9.tar.gz |
add filesystem subtype support
There's a slight problem with filesystem type representation in fuse
based filesystems.
From the kernel's view, there are just two filesystem types: fuse and
fuseblk. From the user's view there are lots of different filesystem
types. The user is not even much concerned if the filesystem is fuse based
or not. So there's a conflict of interest in how this should be
represented in fstab, mtab and /proc/mounts.
The current scheme is to encode the real filesystem type in the mount
source. So an sshfs mount looks like this:
sshfs#user@server:/ /mnt/server fuse rw,nosuid,nodev,...
This url-ish syntax works OK for sshfs and similar filesystems. However
for block device based filesystems (ntfs-3g, zfs) it doesn't work, since
the kernel expects the mount source to be a real device name.
A possibly better scheme would be to encode the real type in the type
field as "type.subtype". So fuse mounts would look like this:
/dev/hda1 /mnt/windows fuseblk.ntfs-3g rw,...
user@server:/ /mnt/server fuse.sshfs rw,nosuid,nodev,...
This patch adds the necessary code to the kernel so that this can be
correctly displayed in /proc/mounts.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/filesystems.c | 21 | ||||
-rw-r--r-- | fs/fuse/inode.c | 2 | ||||
-rw-r--r-- | fs/namespace.c | 4 | ||||
-rw-r--r-- | fs/super.c | 27 |
4 files changed, 48 insertions, 6 deletions
diff --git a/fs/filesystems.c b/fs/filesystems.c index 7a4f61a..f37f872 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -41,11 +41,12 @@ void put_filesystem(struct file_system_type *fs) module_put(fs->owner); } -static struct file_system_type **find_filesystem(const char *name) +static struct file_system_type **find_filesystem(const char *name, unsigned len) { struct file_system_type **p; for (p=&file_systems; *p; p=&(*p)->next) - if (strcmp((*p)->name,name) == 0) + if (strlen((*p)->name) == len && + strncmp((*p)->name, name, len) == 0) break; return p; } @@ -68,11 +69,12 @@ int register_filesystem(struct file_system_type * fs) int res = 0; struct file_system_type ** p; + BUG_ON(strchr(fs->name, '.')); if (fs->next) return -EBUSY; INIT_LIST_HEAD(&fs->fs_supers); write_lock(&file_systems_lock); - p = find_filesystem(fs->name); + p = find_filesystem(fs->name, strlen(fs->name)); if (*p) res = -EBUSY; else @@ -215,19 +217,26 @@ int get_filesystem_list(char * buf) struct file_system_type *get_fs_type(const char *name) { struct file_system_type *fs; + const char *dot = strchr(name, '.'); + unsigned len = dot ? dot - name : strlen(name); read_lock(&file_systems_lock); - fs = *(find_filesystem(name)); + fs = *(find_filesystem(name, len)); if (fs && !try_module_get(fs->owner)) fs = NULL; read_unlock(&file_systems_lock); - if (!fs && (request_module("%s", name) == 0)) { + if (!fs && (request_module("%.*s", len, name) == 0)) { read_lock(&file_systems_lock); - fs = *(find_filesystem(name)); + fs = *(find_filesystem(name, len)); if (fs && !try_module_get(fs->owner)) fs = NULL; read_unlock(&file_systems_lock); } + + if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) { + put_filesystem(fs); + fs = NULL; + } return fs; } diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index d8003be..1397018 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -636,6 +636,7 @@ static int fuse_get_sb(struct file_system_type *fs_type, static struct file_system_type fuse_fs_type = { .owner = THIS_MODULE, .name = "fuse", + .fs_flags = FS_HAS_SUBTYPE, .get_sb = fuse_get_sb, .kill_sb = kill_anon_super, }; @@ -652,6 +653,7 @@ static int fuse_get_sb_blk(struct file_system_type *fs_type, static struct file_system_type fuseblk_fs_type = { .owner = THIS_MODULE, .name = "fuseblk", + .fs_flags = FS_HAS_SUBTYPE, .get_sb = fuse_get_sb_blk, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, diff --git a/fs/namespace.c b/fs/namespace.c index be5e56b..c5b8810 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -377,6 +377,10 @@ static int show_vfsmnt(struct seq_file *m, void *v) seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); seq_putc(m, ' '); mangle(m, mnt->mnt_sb->s_type->name); + if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) { + seq_putc(m, '.'); + mangle(m, mnt->mnt_sb->s_subtype); + } seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw"); for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { if (mnt->mnt_sb->s_flags & fs_infop->flag) @@ -107,6 +107,7 @@ out: static inline void destroy_super(struct super_block *s) { security_sb_free(s); + kfree(s->s_subtype); kfree(s); } @@ -907,6 +908,29 @@ out: EXPORT_SYMBOL_GPL(vfs_kern_mount); +static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) +{ + int err; + const char *subtype = strchr(fstype, '.'); + if (subtype) { + subtype++; + err = -EINVAL; + if (!subtype[0]) + goto err; + } else + subtype = ""; + + mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL); + err = -ENOMEM; + if (!mnt->mnt_sb->s_subtype) + goto err; + return mnt; + + err: + mntput(mnt); + return ERR_PTR(err); +} + struct vfsmount * do_kern_mount(const char *fstype, int flags, const char *name, void *data) { @@ -915,6 +939,9 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data) if (!type) return ERR_PTR(-ENODEV); mnt = vfs_kern_mount(type, flags, name, data); + if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && + !mnt->mnt_sb->s_subtype) + mnt = fs_set_subtype(mnt, fstype); put_filesystem(type); return mnt; } |