Merge tag 'asoc-fix-v5.14-rc2' of https://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / usb / gadget / function / f_fs.c
index d4844af..9c0c393 100644 (file)
@@ -250,8 +250,8 @@ EXPORT_SYMBOL_GPL(ffs_lock);
 static struct ffs_dev *_ffs_find_dev(const char *name);
 static struct ffs_dev *_ffs_alloc_dev(void);
 static void _ffs_free_dev(struct ffs_dev *dev);
-static void *ffs_acquire_dev(const char *dev_name);
-static void ffs_release_dev(struct ffs_data *ffs_data);
+static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);
+static void ffs_release_dev(struct ffs_dev *ffs_dev);
 static int ffs_ready(struct ffs_data *ffs);
 static void ffs_closed(struct ffs_data *ffs);
 
@@ -1554,8 +1554,8 @@ unmapped_value:
 static int ffs_fs_get_tree(struct fs_context *fc)
 {
        struct ffs_sb_fill_data *ctx = fc->fs_private;
-       void *ffs_dev;
        struct ffs_data *ffs;
+       int ret;
 
        ENTER();
 
@@ -1574,13 +1574,12 @@ static int ffs_fs_get_tree(struct fs_context *fc)
                return -ENOMEM;
        }
 
-       ffs_dev = ffs_acquire_dev(ffs->dev_name);
-       if (IS_ERR(ffs_dev)) {
+       ret = ffs_acquire_dev(ffs->dev_name, ffs);
+       if (ret) {
                ffs_data_put(ffs);
-               return PTR_ERR(ffs_dev);
+               return ret;
        }
 
-       ffs->private_data = ffs_dev;
        ctx->ffs_data = ffs;
        return get_tree_nodev(fc, ffs_sb_fill);
 }
@@ -1591,7 +1590,6 @@ static void ffs_fs_free_fc(struct fs_context *fc)
 
        if (ctx) {
                if (ctx->ffs_data) {
-                       ffs_release_dev(ctx->ffs_data);
                        ffs_data_put(ctx->ffs_data);
                }
 
@@ -1630,10 +1628,8 @@ ffs_fs_kill_sb(struct super_block *sb)
        ENTER();
 
        kill_litter_super(sb);
-       if (sb->s_fs_info) {
-               ffs_release_dev(sb->s_fs_info);
+       if (sb->s_fs_info)
                ffs_data_closed(sb->s_fs_info);
-       }
 }
 
 static struct file_system_type ffs_fs_type = {
@@ -1703,6 +1699,7 @@ static void ffs_data_put(struct ffs_data *ffs)
        if (refcount_dec_and_test(&ffs->ref)) {
                pr_info("%s(): freeing\n", __func__);
                ffs_data_clear(ffs);
+               ffs_release_dev(ffs->private_data);
                BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
                       swait_active(&ffs->ep0req_completion.wait) ||
                       waitqueue_active(&ffs->wait));
@@ -3032,6 +3029,7 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
        struct ffs_function *func = ffs_func_from_usb(f);
        struct f_fs_opts *ffs_opts =
                container_of(f->fi, struct f_fs_opts, func_inst);
+       struct ffs_data *ffs_data;
        int ret;
 
        ENTER();
@@ -3046,12 +3044,13 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
        if (!ffs_opts->no_configfs)
                ffs_dev_lock();
        ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
-       func->ffs = ffs_opts->dev->ffs_data;
+       ffs_data = ffs_opts->dev->ffs_data;
        if (!ffs_opts->no_configfs)
                ffs_dev_unlock();
        if (ret)
                return ERR_PTR(ret);
 
+       func->ffs = ffs_data;
        func->conf = c;
        func->gadget = c->cdev->gadget;
 
@@ -3506,6 +3505,7 @@ static void ffs_free_inst(struct usb_function_instance *f)
        struct f_fs_opts *opts;
 
        opts = to_f_fs_opts(f);
+       ffs_release_dev(opts->dev);
        ffs_dev_lock();
        _ffs_free_dev(opts->dev);
        ffs_dev_unlock();
@@ -3693,47 +3693,48 @@ static void _ffs_free_dev(struct ffs_dev *dev)
 {
        list_del(&dev->entry);
 
-       /* Clear the private_data pointer to stop incorrect dev access */
-       if (dev->ffs_data)
-               dev->ffs_data->private_data = NULL;
-
        kfree(dev);
        if (list_empty(&ffs_devices))
                functionfs_cleanup();
 }
 
-static void *ffs_acquire_dev(const char *dev_name)
+static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
 {
+       int ret = 0;
        struct ffs_dev *ffs_dev;
 
        ENTER();
        ffs_dev_lock();
 
        ffs_dev = _ffs_find_dev(dev_name);
-       if (!ffs_dev)
-               ffs_dev = ERR_PTR(-ENOENT);
-       else if (ffs_dev->mounted)
-               ffs_dev = ERR_PTR(-EBUSY);
-       else if (ffs_dev->ffs_acquire_dev_callback &&
-           ffs_dev->ffs_acquire_dev_callback(ffs_dev))
-               ffs_dev = ERR_PTR(-ENOENT);
-       else
+       if (!ffs_dev) {
+               ret = -ENOENT;
+       } else if (ffs_dev->mounted) {
+               ret = -EBUSY;
+       else if (ffs_dev->ffs_acquire_dev_callback &&
+                  ffs_dev->ffs_acquire_dev_callback(ffs_dev)) {
+               ret = -ENOENT;
+       } else {
                ffs_dev->mounted = true;
+               ffs_dev->ffs_data = ffs_data;
+               ffs_data->private_data = ffs_dev;
+       }
 
        ffs_dev_unlock();
-       return ffs_dev;
+       return ret;
 }
 
-static void ffs_release_dev(struct ffs_data *ffs_data)
+static void ffs_release_dev(struct ffs_dev *ffs_dev)
 {
-       struct ffs_dev *ffs_dev;
-
        ENTER();
        ffs_dev_lock();
 
-       ffs_dev = ffs_data->private_data;
-       if (ffs_dev) {
+       if (ffs_dev && ffs_dev->mounted) {
                ffs_dev->mounted = false;
+               if (ffs_dev->ffs_data) {
+                       ffs_dev->ffs_data->private_data = NULL;
+                       ffs_dev->ffs_data = NULL;
+               }
 
                if (ffs_dev->ffs_release_dev_callback)
                        ffs_dev->ffs_release_dev_callback(ffs_dev);
@@ -3761,7 +3762,6 @@ static int ffs_ready(struct ffs_data *ffs)
        }
 
        ffs_obj->desc_ready = true;
-       ffs_obj->ffs_data = ffs;
 
        if (ffs_obj->ffs_ready_callback) {
                ret = ffs_obj->ffs_ready_callback(ffs);
@@ -3789,7 +3789,6 @@ static void ffs_closed(struct ffs_data *ffs)
                goto done;
 
        ffs_obj->desc_ready = false;
-       ffs_obj->ffs_data = NULL;
 
        if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
            ffs_obj->ffs_closed_callback)