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;
 }
        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
 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;
 }
 
 
 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,
 };
 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,
 
        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)
 
 static inline void destroy_super(struct super_block *s)
 {
        security_sb_free(s);
+       kfree(s->s_subtype);
        kfree(s);
 }
 
 
 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)
 {
        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;
 }
 
 /* public flags for file_system_type */
 #define FS_REQUIRES_DEV 1 
 #define FS_BINARY_MOUNTDATA 2
+#define FS_HAS_SUBTYPE 4
 #define FS_REVAL_DOT   16384   /* Check the paths ".", ".." for staleness */
 #define FS_RENAME_DOES_D_MOVE  32768   /* FS will handle d_move()
                                         * during rename() internally.
        /* Granularity of c/m/atime in ns.
           Cannot be worse than a second */
        u32                s_time_gran;
+
+       /*
+        * Filesystem subtype.  If non-empty the filesystem type field
+        * in /proc/mounts will be "type.subtype"
+        */
+       char *s_subtype;
 };
 
 extern struct timespec current_fs_time(struct super_block *sb);