Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Miklos Szeredi and committed by
Linus Torvalds
79c0b2df 880afc4d

+55 -6
+15 -6
fs/filesystems.c
··· 41 41 module_put(fs->owner); 42 42 } 43 43 44 - static struct file_system_type **find_filesystem(const char *name) 44 + static struct file_system_type **find_filesystem(const char *name, unsigned len) 45 45 { 46 46 struct file_system_type **p; 47 47 for (p=&file_systems; *p; p=&(*p)->next) 48 - if (strcmp((*p)->name,name) == 0) 48 + if (strlen((*p)->name) == len && 49 + strncmp((*p)->name, name, len) == 0) 49 50 break; 50 51 return p; 51 52 } ··· 69 68 int res = 0; 70 69 struct file_system_type ** p; 71 70 71 + BUG_ON(strchr(fs->name, '.')); 72 72 if (fs->next) 73 73 return -EBUSY; 74 74 INIT_LIST_HEAD(&fs->fs_supers); 75 75 write_lock(&file_systems_lock); 76 - p = find_filesystem(fs->name); 76 + p = find_filesystem(fs->name, strlen(fs->name)); 77 77 if (*p) 78 78 res = -EBUSY; 79 79 else ··· 217 215 struct file_system_type *get_fs_type(const char *name) 218 216 { 219 217 struct file_system_type *fs; 218 + const char *dot = strchr(name, '.'); 219 + unsigned len = dot ? dot - name : strlen(name); 220 220 221 221 read_lock(&file_systems_lock); 222 - fs = *(find_filesystem(name)); 222 + fs = *(find_filesystem(name, len)); 223 223 if (fs && !try_module_get(fs->owner)) 224 224 fs = NULL; 225 225 read_unlock(&file_systems_lock); 226 - if (!fs && (request_module("%s", name) == 0)) { 226 + if (!fs && (request_module("%.*s", len, name) == 0)) { 227 227 read_lock(&file_systems_lock); 228 - fs = *(find_filesystem(name)); 228 + fs = *(find_filesystem(name, len)); 229 229 if (fs && !try_module_get(fs->owner)) 230 230 fs = NULL; 231 231 read_unlock(&file_systems_lock); 232 + } 233 + 234 + if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) { 235 + put_filesystem(fs); 236 + fs = NULL; 232 237 } 233 238 return fs; 234 239 }
+2
fs/fuse/inode.c
··· 636 636 static struct file_system_type fuse_fs_type = { 637 637 .owner = THIS_MODULE, 638 638 .name = "fuse", 639 + .fs_flags = FS_HAS_SUBTYPE, 639 640 .get_sb = fuse_get_sb, 640 641 .kill_sb = kill_anon_super, 641 642 }; ··· 653 652 static struct file_system_type fuseblk_fs_type = { 654 653 .owner = THIS_MODULE, 655 654 .name = "fuseblk", 655 + .fs_flags = FS_HAS_SUBTYPE, 656 656 .get_sb = fuse_get_sb_blk, 657 657 .kill_sb = kill_block_super, 658 658 .fs_flags = FS_REQUIRES_DEV,
+4
fs/namespace.c
··· 377 377 seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); 378 378 seq_putc(m, ' '); 379 379 mangle(m, mnt->mnt_sb->s_type->name); 380 + if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) { 381 + seq_putc(m, '.'); 382 + mangle(m, mnt->mnt_sb->s_subtype); 383 + } 380 384 seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw"); 381 385 for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { 382 386 if (mnt->mnt_sb->s_flags & fs_infop->flag)
+27
fs/super.c
··· 107 107 static inline void destroy_super(struct super_block *s) 108 108 { 109 109 security_sb_free(s); 110 + kfree(s->s_subtype); 110 111 kfree(s); 111 112 } 112 113 ··· 908 907 909 908 EXPORT_SYMBOL_GPL(vfs_kern_mount); 910 909 910 + static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) 911 + { 912 + int err; 913 + const char *subtype = strchr(fstype, '.'); 914 + if (subtype) { 915 + subtype++; 916 + err = -EINVAL; 917 + if (!subtype[0]) 918 + goto err; 919 + } else 920 + subtype = ""; 921 + 922 + mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL); 923 + err = -ENOMEM; 924 + if (!mnt->mnt_sb->s_subtype) 925 + goto err; 926 + return mnt; 927 + 928 + err: 929 + mntput(mnt); 930 + return ERR_PTR(err); 931 + } 932 + 911 933 struct vfsmount * 912 934 do_kern_mount(const char *fstype, int flags, const char *name, void *data) 913 935 { ··· 939 915 if (!type) 940 916 return ERR_PTR(-ENODEV); 941 917 mnt = vfs_kern_mount(type, flags, name, data); 918 + if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && 919 + !mnt->mnt_sb->s_subtype) 920 + mnt = fs_set_subtype(mnt, fstype); 942 921 put_filesystem(type); 943 922 return mnt; 944 923 }
+7
include/linux/fs.h
··· 92 92 /* public flags for file_system_type */ 93 93 #define FS_REQUIRES_DEV 1 94 94 #define FS_BINARY_MOUNTDATA 2 95 + #define FS_HAS_SUBTYPE 4 95 96 #define FS_REVAL_DOT 16384 /* Check the paths ".", ".." for staleness */ 96 97 #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() 97 98 * during rename() internally. ··· 962 961 /* Granularity of c/m/atime in ns. 963 962 Cannot be worse than a second */ 964 963 u32 s_time_gran; 964 + 965 + /* 966 + * Filesystem subtype. If non-empty the filesystem type field 967 + * in /proc/mounts will be "type.subtype" 968 + */ 969 + char *s_subtype; 965 970 }; 966 971 967 972 extern struct timespec current_fs_time(struct super_block *sb);