fuse: Call vfs_get_tree() for submounts
[linux-2.6-microblaze.git] / fs / fuse / inode.c
index a0a8228..c7aee88 100644 (file)
@@ -1353,8 +1353,44 @@ int fuse_fill_super_submount(struct super_block *sb,
        return 0;
 }
 
+/* Filesystem context private data holds the FUSE inode of the mount point */
 static int fuse_get_tree_submount(struct fs_context *fsc)
 {
+       struct fuse_mount *fm;
+       struct fuse_inode *mp_fi = fsc->fs_private;
+       struct fuse_conn *fc = get_fuse_conn(&mp_fi->inode);
+       struct super_block *sb;
+       int err;
+
+       fm = kzalloc(sizeof(struct fuse_mount), GFP_KERNEL);
+       if (!fm)
+               return -ENOMEM;
+
+       fsc->s_fs_info = fm;
+       sb = sget_fc(fsc, NULL, set_anon_super_fc);
+       if (IS_ERR(sb)) {
+               kfree(fm);
+               return PTR_ERR(sb);
+       }
+       fm->fc = fuse_conn_get(fc);
+
+       /* Initialize superblock, making @mp_fi its root */
+       err = fuse_fill_super_submount(sb, mp_fi);
+       if (err) {
+               fuse_conn_put(fc);
+               kfree(fm);
+               sb->s_fs_info = NULL;
+               deactivate_locked_super(sb);
+               return err;
+       }
+
+       down_write(&fc->killsb);
+       list_add_tail(&fm->fc_entry, &fc->mounts);
+       up_write(&fc->killsb);
+
+       sb->s_flags |= SB_ACTIVE;
+       fsc->root = dget(sb->s_root);
+
        return 0;
 }