fuse: split fuse_mount off of fuse_conn
[linux-2.6-microblaze.git] / fs / fuse / virtio_fs.c
index 9c23e40..746fa1a 100644 (file)
@@ -1270,7 +1270,8 @@ static inline void virtio_fs_ctx_set_defaults(struct fuse_fs_context *ctx)
 
 static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc)
 {
-       struct fuse_conn *fc = get_fuse_conn_super(sb);
+       struct fuse_mount *fm = get_fuse_mount_super(sb);
+       struct fuse_conn *fc = fm->fc;
        struct virtio_fs *fs = fc->iq.priv;
        struct fuse_fs_context *ctx = fsc->fs_private;
        unsigned int i;
@@ -1315,7 +1316,7 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc)
 
        /* Previous unmount will stop all queues. Start these again */
        virtio_fs_start_all_queues(fs);
-       fuse_send_init(fc);
+       fuse_send_init(fm);
        mutex_unlock(&virtio_fs_mutex);
        return 0;
 
@@ -1326,21 +1327,14 @@ err:
        return err;
 }
 
-static void virtio_kill_sb(struct super_block *sb)
+static void virtio_fs_conn_destroy(struct fuse_mount *fm)
 {
-       struct fuse_conn *fc = get_fuse_conn_super(sb);
-       struct virtio_fs *vfs;
-       struct virtio_fs_vq *fsvq;
-
-       /* If mount failed, we can still be called without any fc */
-       if (!fc)
-               return fuse_kill_sb_anon(sb);
-
-       vfs = fc->iq.priv;
-       fsvq = &vfs->vqs[VQ_HIPRIO];
+       struct fuse_conn *fc = fm->fc;
+       struct virtio_fs *vfs = fc->iq.priv;
+       struct virtio_fs_vq *fsvq = &vfs->vqs[VQ_HIPRIO];
 
-       /* Stop dax worker. Soon evict_inodes() will be called which will
-        * free all memory ranges belonging to all inodes.
+       /* Stop dax worker. Soon evict_inodes() will be called which
+        * will free all memory ranges belonging to all inodes.
         */
        if (IS_ENABLED(CONFIG_FUSE_DAX))
                fuse_dax_cancel_work(fc);
@@ -1351,9 +1345,9 @@ static void virtio_kill_sb(struct super_block *sb)
        spin_unlock(&fsvq->lock);
        virtio_fs_drain_all_queues(vfs);
 
-       fuse_kill_sb_anon(sb);
+       fuse_conn_destroy(fm);
 
-       /* fuse_kill_sb_anon() must have sent destroy. Stop all queues
+       /* fuse_conn_destroy() must have sent destroy. Stop all queues
         * and drain one more time and free fuse devices. Freeing fuse
         * devices will drop their reference on fuse_conn and that in
         * turn will drop its reference on virtio_fs object.
@@ -1363,12 +1357,27 @@ static void virtio_kill_sb(struct super_block *sb)
        virtio_fs_free_devs(vfs);
 }
 
+static void virtio_kill_sb(struct super_block *sb)
+{
+       struct fuse_mount *fm = get_fuse_mount_super(sb);
+       bool last;
+
+       /* If mount failed, we can still be called without any fc */
+       if (fm) {
+               last = fuse_mount_remove(fm);
+               if (last)
+                       virtio_fs_conn_destroy(fm);
+       }
+       kill_anon_super(sb);
+}
+
 static int virtio_fs_test_super(struct super_block *sb,
                                struct fs_context *fsc)
 {
-       struct fuse_conn *fc = fsc->s_fs_info;
+       struct fuse_mount *fsc_fm = fsc->s_fs_info;
+       struct fuse_mount *sb_fm = get_fuse_mount_super(sb);
 
-       return fc->iq.priv == get_fuse_conn_super(sb)->iq.priv;
+       return fsc_fm->fc->iq.priv == sb_fm->fc->iq.priv;
 }
 
 static int virtio_fs_set_super(struct super_block *sb,
@@ -1378,7 +1387,7 @@ static int virtio_fs_set_super(struct super_block *sb,
 
        err = get_anon_bdev(&sb->s_dev);
        if (!err)
-               fuse_conn_get(fsc->s_fs_info);
+               fuse_mount_get(fsc->s_fs_info);
 
        return err;
 }
@@ -1388,6 +1397,7 @@ static int virtio_fs_get_tree(struct fs_context *fsc)
        struct virtio_fs *fs;
        struct super_block *sb;
        struct fuse_conn *fc;
+       struct fuse_mount *fm;
        int err;
 
        /* This gets a reference on virtio_fs object. This ptr gets installed
@@ -1408,14 +1418,23 @@ static int virtio_fs_get_tree(struct fs_context *fsc)
                return -ENOMEM;
        }
 
-       fuse_conn_init(fc, get_user_ns(current_user_ns()), &virtio_fs_fiq_ops,
-                      fs);
+       fm = kzalloc(sizeof(struct fuse_mount), GFP_KERNEL);
+       if (!fm) {
+               mutex_lock(&virtio_fs_mutex);
+               virtio_fs_put(fs);
+               mutex_unlock(&virtio_fs_mutex);
+               kfree(fc);
+               return -ENOMEM;
+       }
+
+       fuse_conn_init(fc, fm, get_user_ns(current_user_ns()),
+                      &virtio_fs_fiq_ops, fs);
        fc->release = fuse_free_conn;
        fc->delete_stale = true;
 
-       fsc->s_fs_info = fc;
+       fsc->s_fs_info = fm;
        sb = sget_fc(fsc, virtio_fs_test_super, virtio_fs_set_super);
-       fuse_conn_put(fc);
+       fuse_mount_put(fm);
        if (IS_ERR(sb))
                return PTR_ERR(sb);