summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/filesystems.c21
-rw-r--r--fs/fuse/inode.c2
-rw-r--r--fs/namespace.c4
-rw-r--r--fs/super.c27
-rw-r--r--include/linux/fs.h7
5 files changed, 55 insertions, 6 deletions
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 7a4f61aa05f8..f37f87262837 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 d8003be56e05..1397018ff476 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 be5e56bfb73e..c5b88100d914 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)
diff --git a/fs/super.c b/fs/super.c
index 8341e4e1d738..5260d620c555 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -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;
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 986b5d5d369f..527a09a82297 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -92,6 +92,7 @@ extern int dir_notify_enable;
/* 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.
@@ -961,6 +962,12 @@ struct super_block {
/* 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);