exofs_mount(): fix leaks on failure exits
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 10 Nov 2018 03:26:42 +0000 (22:26 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 17 Dec 2018 23:36:33 +0000 (18:36 -0500)
... and don't abuse mount_nodev(), while we are at it.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Reviewed-by: David Howells <dhowells@redhat.com>
fs/exofs/super.c

index 906839a..fc80c72 100644 (file)
@@ -705,21 +705,18 @@ out:
 /*
  * Read the superblock from the OSD and fill in the fields
  */
-static int exofs_fill_super(struct super_block *sb, void *data, int silent)
+static int exofs_fill_super(struct super_block *sb,
+                               struct exofs_mountopt *opts,
+                               struct exofs_sb_info *sbi,
+                               int silent)
 {
        struct inode *root;
-       struct exofs_mountopt *opts = data;
-       struct exofs_sb_info *sbi;      /*extended info                  */
        struct osd_dev *od;             /* Master device                 */
        struct exofs_fscb fscb;         /*on-disk superblock info        */
        struct ore_comp comp;
        unsigned table_count;
        int ret;
 
-       sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
-       if (!sbi)
-               return -ENOMEM;
-
        /* use mount options to fill superblock */
        if (opts->is_osdname) {
                struct osd_dev_info odi = {.systemid_len = 0};
@@ -863,7 +860,9 @@ static struct dentry *exofs_mount(struct file_system_type *type,
                          int flags, const char *dev_name,
                          void *data)
 {
+       struct super_block *s;
        struct exofs_mountopt opts;
+       struct exofs_sb_info *sbi;
        int ret;
 
        ret = parse_options(data, &opts);
@@ -872,9 +871,31 @@ static struct dentry *exofs_mount(struct file_system_type *type,
                return ERR_PTR(ret);
        }
 
+       sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+       if (!sbi) {
+               kfree(opts.dev_name);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       s = sget(type, NULL, set_anon_super, flags, NULL);
+
+       if (IS_ERR(s)) {
+               kfree(opts.dev_name);
+               kfree(sbi);
+               return ERR_CAST(s);
+       }
+
        if (!opts.dev_name)
                opts.dev_name = dev_name;
-       return mount_nodev(type, flags, &opts, exofs_fill_super);
+
+
+       ret = exofs_fill_super(s, &opts, sbi, flags & SB_SILENT ? 1 : 0);
+       if (ret) {
+               deactivate_locked_super(s);
+               return ERR_PTR(ret);
+       }
+       s->s_flags |= SB_ACTIVE;
+       return dget(s->s_root);
 }
 
 /*