Loading drivers/usb/gadget/function/f_fs.c +187 −74 Original line number Diff line number Diff line Loading @@ -67,18 +67,27 @@ __ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len); static int __must_check __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); static LIST_HEAD(inst_list); /* ffs instance status */ static DEFINE_MUTEX(ffs_ep_lock); static bool ffs_inst_exist; static struct f_fs_opts *g_opts; #define INST_NAME_SIZE 16 /* Free instance structures */ static void ffs_inst_clean(struct f_fs_opts *opts); static void ffs_inst_clean_delay(void); static int ffs_inst_exist_check(void); struct ffs_inst_status { char inst_name[INST_NAME_SIZE]; struct list_head list; struct mutex ffs_lock; bool inst_exist; struct f_fs_opts *opts; struct ffs_data *ffs_data; }; /* Global ffs_data pointer */ static struct ffs_data *g_ffs_data; /* Free instance structures */ static void ffs_inst_clean(struct f_fs_opts *opts, const char *inst_name); static void ffs_inst_clean_delay(const char *inst_name); static int ffs_inst_exist_check(const char *inst_name); static struct ffs_inst_status *name_to_inst_status( const char *inst_name, bool create_inst); /* The function structure ***************************************************/ Loading Loading @@ -367,7 +376,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ffs_log("enter:len %zu state %d setup_state %d flags %lu", len, ffs->state, ffs->setup_state, ffs->flags); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -557,7 +566,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, ffs_log("enter:len %zu state %d setup_state %d flags %lu", len, ffs->state, ffs->setup_state, ffs->flags); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -668,7 +677,7 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -711,7 +720,7 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading @@ -736,7 +745,7 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait) ffs_log("enter:state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -993,6 +1002,10 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ffs_log("enter: epfile name %s epfile err %d (%s)", epfile->name, atomic_read(&epfile->error), io_data->read ? "READ" : "WRITE"); ret = ffs_inst_exist_check(epfile->ffs->dev_name); if (ret < 0) return ret; /* to get updated error atomic variable value */ smp_mb__before_atomic(); if (atomic_read(&epfile->error)) Loading Loading @@ -1247,7 +1260,7 @@ ffs_epfile_open(struct inode *inode, struct file *file) ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, epfile->ffs->setup_state, epfile->ffs->flags); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(epfile->ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -1302,16 +1315,11 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) { struct ffs_io_data io_data, *p = &io_data; ssize_t res; int ret; ENTER(); ffs_log("enter"); ret = ffs_inst_exist_check(); if (ret < 0) return ret; if (!is_sync_kiocb(kiocb)) { p = kmalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) Loading Loading @@ -1348,16 +1356,11 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) { struct ffs_io_data io_data, *p = &io_data; ssize_t res; int ret; ENTER(); ffs_log("enter"); ret = ffs_inst_exist_check(); if (ret < 0) return ret; if (!is_sync_kiocb(kiocb)) { p = kmalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) Loading Loading @@ -1433,7 +1436,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, epfile->ffs->setup_state, epfile->ffs->flags); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(epfile->ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -1741,6 +1744,7 @@ ffs_fs_mount(struct file_system_type *t, int flags, int ret; void *ffs_dev; struct ffs_data *ffs; struct ffs_inst_status *inst_status; ENTER(); Loading Loading @@ -1770,6 +1774,18 @@ ffs_fs_mount(struct file_system_type *t, int flags, ffs->private_data = ffs_dev; data.ffs_data = ffs; inst_status = name_to_inst_status(ffs->dev_name, false); if (IS_ERR(inst_status)) { ffs_log("failed to find instance (%s)\n", ffs->dev_name); return ERR_PTR(-EINVAL); } /* Store ffs to global status structure */ ffs_dev_lock(); inst_status->ffs_data = ffs; ffs_dev_unlock(); rv = mount_nodev(t, flags, &data, ffs_sb_fill); if (IS_ERR(rv) && data.ffs_data) { ffs_release_dev(data.ffs_data); Loading Loading @@ -1881,6 +1897,9 @@ static void ffs_data_opened(struct ffs_data *ffs) static void ffs_data_put(struct ffs_data *ffs) { struct ffs_inst_status *inst_status; const char *dev_name; ENTER(); ffs_log("enter"); Loading @@ -1889,16 +1908,20 @@ static void ffs_data_put(struct ffs_data *ffs) smp_mb__before_atomic(); if (unlikely(atomic_dec_and_test(&ffs->ref))) { pr_info("%s(): freeing\n", __func__); /* Clear g_ffs_data */ /* Clear ffs from global structure */ inst_status = name_to_inst_status(ffs->dev_name, false); if (!IS_ERR(inst_status)) { ffs_dev_lock(); g_ffs_data = NULL; inst_status->ffs_data = NULL; ffs_dev_unlock(); } ffs_data_clear(ffs); BUG_ON(waitqueue_active(&ffs->ev.waitq) || waitqueue_active(&ffs->ep0req_completion.wait)); kfree(ffs->dev_name); dev_name = ffs->dev_name; kfree(ffs); ffs_inst_clean_delay(); ffs_inst_clean_delay(dev_name); kfree(dev_name); } ffs_log("exit"); Loading Loading @@ -1965,11 +1988,6 @@ static struct ffs_data *ffs_data_new(void) /* XXX REVISIT need to update it in some places, or do we? */ ffs->ev.can_stall = 1; /* Store ffs to g_ffs_data */ ffs_dev_lock(); g_ffs_data = ffs; ffs_dev_unlock(); ffs_log("exit"); return ffs; Loading Loading @@ -3882,79 +3900,146 @@ static struct config_item_type ffs_func_type = { /* Function registration interface ******************************************/ static int ffs_inst_exist_check(void) static struct ffs_inst_status *name_to_inst_status( const char *inst_name, bool create_inst) { mutex_lock(&ffs_ep_lock); struct ffs_inst_status *inst_status; list_for_each_entry(inst_status, &inst_list, list) { if (!strncasecmp(inst_status->inst_name, inst_name, strlen(inst_name))) return inst_status; } if (unlikely(ffs_inst_exist == false)) { mutex_unlock(&ffs_ep_lock); if (!create_inst) return ERR_PTR(-ENODEV); inst_status = kzalloc(sizeof(struct ffs_inst_status), GFP_KERNEL); if (!inst_status) return ERR_PTR(-ENOMEM); mutex_init(&inst_status->ffs_lock); snprintf(inst_status->inst_name, INST_NAME_SIZE, inst_name); list_add_tail(&inst_status->list, &inst_list); return inst_status; } static int ffs_inst_exist_check(const char *inst_name) { struct ffs_inst_status *inst_status; inst_status = name_to_inst_status(inst_name, false); if (IS_ERR(inst_status)) { pr_err_ratelimited( "%s: f_fs instance freed already.\n", __func__); "%s: failed to find instance (%s)\n", __func__, inst_name); return -ENODEV; } mutex_lock(&inst_status->ffs_lock); if (unlikely(inst_status->inst_exist == false)) { mutex_unlock(&inst_status->ffs_lock); pr_err_ratelimited( "%s: f_fs instance (%s) has been freed already.\n", __func__, inst_name); return -ENODEV; } mutex_unlock(&ffs_ep_lock); mutex_unlock(&inst_status->ffs_lock); return 0; } static void ffs_inst_clean(struct f_fs_opts *opts) static void ffs_inst_clean(struct f_fs_opts *opts, const char *inst_name) { g_opts = NULL; struct ffs_inst_status *inst_status; inst_status = name_to_inst_status(inst_name, false); if (IS_ERR(inst_status)) { pr_err_ratelimited( "%s: failed to find instance (%s)\n", __func__, inst_name); return; } inst_status->opts = NULL; ffs_dev_lock(); _ffs_free_dev(opts->dev); ffs_dev_unlock(); kfree(opts); } static void ffs_inst_clean_delay(void) static void ffs_inst_clean_delay(const char *inst_name) { mutex_lock(&ffs_ep_lock); struct ffs_inst_status *inst_status; if (unlikely(ffs_inst_exist == false)) { if (g_opts) { ffs_inst_clean(g_opts); inst_status = name_to_inst_status(inst_name, false); if (IS_ERR(inst_status)) { pr_err_ratelimited( "%s: failed to find (%s) instance\n", __func__, inst_name); return; } mutex_lock(&inst_status->ffs_lock); if (unlikely(inst_status->inst_exist == false)) { if (inst_status->opts) { ffs_inst_clean(inst_status->opts, inst_name); pr_err_ratelimited("%s: Delayed free memory\n", __func__); } mutex_unlock(&ffs_ep_lock); mutex_unlock(&inst_status->ffs_lock); return; } mutex_unlock(&ffs_ep_lock); mutex_unlock(&inst_status->ffs_lock); } static void ffs_free_inst(struct usb_function_instance *f) { struct f_fs_opts *opts; struct ffs_inst_status *inst_status; opts = to_f_fs_opts(f); mutex_lock(&ffs_ep_lock); inst_status = name_to_inst_status(opts->dev->name, false); if (IS_ERR(inst_status)) { ffs_log("failed to find (%s) instance\n", opts->dev->name); return; } mutex_lock(&inst_status->ffs_lock); if (opts->dev->ffs_data && atomic_read(&opts->dev->ffs_data->opened)) { ffs_inst_exist = false; mutex_unlock(&ffs_ep_lock); ffs_log("%s: Dev is open, free mem when dev close\n", __func__); inst_status->inst_exist = false; mutex_unlock(&inst_status->ffs_lock); ffs_log("Dev is open, free mem when dev (%s) close\n", opts->dev->name); return; } ffs_inst_clean(opts); ffs_inst_exist = false; g_opts = NULL; mutex_unlock(&ffs_ep_lock); ffs_inst_clean(opts, opts->dev->name); inst_status->inst_exist = false; mutex_unlock(&inst_status->ffs_lock); } #define MAX_INST_NAME_LEN 40 static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) { struct f_fs_opts *opts; struct f_fs_opts *opts, *opts_prev; struct ffs_data *ffs_data_tmp; char *ptr; const char *tmp; int name_len, ret; struct ffs_inst_status *inst_status; name_len = strlen(name) + 1; if (name_len > MAX_INST_NAME_LEN) Loading @@ -3964,13 +4049,22 @@ static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) if (!ptr) return -ENOMEM; mutex_lock(&ffs_ep_lock); if (g_opts) { mutex_unlock(&ffs_ep_lock); ffs_log("%s: prev inst do not freed yet\n", __func__); inst_status = name_to_inst_status(ptr, true); if (IS_ERR(inst_status)) { ffs_log("failed to create status struct for (%s) instance\n", ptr); return -EINVAL; } mutex_lock(&inst_status->ffs_lock); opts_prev = inst_status->opts; if (opts_prev) { mutex_unlock(&inst_status->ffs_lock); ffs_log("instance (%s): prev inst do not freed yet\n", inst_status->inst_name); return -EBUSY; } mutex_unlock(&ffs_ep_lock); mutex_unlock(&inst_status->ffs_lock); opts = to_f_fs_opts(fi); tmp = NULL; Loading @@ -3992,8 +4086,9 @@ static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) * ffs_private_data also need to update new allocated opts->dev * address. */ if (g_ffs_data) opts->dev->ffs_data = g_ffs_data; ffs_data_tmp = inst_status->ffs_data; if (ffs_data_tmp) opts->dev->ffs_data = ffs_data_tmp; if (opts->dev->ffs_data) opts->dev->ffs_data->private_data = opts->dev; Loading @@ -4002,10 +4097,10 @@ static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) kfree(tmp); mutex_lock(&ffs_ep_lock); ffs_inst_exist = true; g_opts = opts; mutex_unlock(&ffs_ep_lock); mutex_lock(&inst_status->ffs_lock); inst_status->inst_exist = true; inst_status->opts = opts; mutex_unlock(&inst_status->ffs_lock); return 0; } Loading Loading @@ -4410,6 +4505,24 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len, return data; } static void __exit ffs_exit(void) { struct ffs_inst_status *inst_status, *inst_status_tmp = NULL; list_for_each_entry(inst_status, &inst_list, list) { if (inst_status_tmp) { list_del(&inst_status_tmp->list); kfree(inst_status_tmp); } inst_status_tmp = inst_status; } if (inst_status_tmp) { list_del(&inst_status_tmp->list); kfree(inst_status_tmp); } } module_exit(ffs_exit); DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Nazarewicz"); Loading
drivers/usb/gadget/function/f_fs.c +187 −74 Original line number Diff line number Diff line Loading @@ -67,18 +67,27 @@ __ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len); static int __must_check __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); static LIST_HEAD(inst_list); /* ffs instance status */ static DEFINE_MUTEX(ffs_ep_lock); static bool ffs_inst_exist; static struct f_fs_opts *g_opts; #define INST_NAME_SIZE 16 /* Free instance structures */ static void ffs_inst_clean(struct f_fs_opts *opts); static void ffs_inst_clean_delay(void); static int ffs_inst_exist_check(void); struct ffs_inst_status { char inst_name[INST_NAME_SIZE]; struct list_head list; struct mutex ffs_lock; bool inst_exist; struct f_fs_opts *opts; struct ffs_data *ffs_data; }; /* Global ffs_data pointer */ static struct ffs_data *g_ffs_data; /* Free instance structures */ static void ffs_inst_clean(struct f_fs_opts *opts, const char *inst_name); static void ffs_inst_clean_delay(const char *inst_name); static int ffs_inst_exist_check(const char *inst_name); static struct ffs_inst_status *name_to_inst_status( const char *inst_name, bool create_inst); /* The function structure ***************************************************/ Loading Loading @@ -367,7 +376,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ffs_log("enter:len %zu state %d setup_state %d flags %lu", len, ffs->state, ffs->setup_state, ffs->flags); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -557,7 +566,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, ffs_log("enter:len %zu state %d setup_state %d flags %lu", len, ffs->state, ffs->setup_state, ffs->flags); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -668,7 +677,7 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -711,7 +720,7 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading @@ -736,7 +745,7 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait) ffs_log("enter:state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -993,6 +1002,10 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ffs_log("enter: epfile name %s epfile err %d (%s)", epfile->name, atomic_read(&epfile->error), io_data->read ? "READ" : "WRITE"); ret = ffs_inst_exist_check(epfile->ffs->dev_name); if (ret < 0) return ret; /* to get updated error atomic variable value */ smp_mb__before_atomic(); if (atomic_read(&epfile->error)) Loading Loading @@ -1247,7 +1260,7 @@ ffs_epfile_open(struct inode *inode, struct file *file) ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, epfile->ffs->setup_state, epfile->ffs->flags); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(epfile->ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -1302,16 +1315,11 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) { struct ffs_io_data io_data, *p = &io_data; ssize_t res; int ret; ENTER(); ffs_log("enter"); ret = ffs_inst_exist_check(); if (ret < 0) return ret; if (!is_sync_kiocb(kiocb)) { p = kmalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) Loading Loading @@ -1348,16 +1356,11 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) { struct ffs_io_data io_data, *p = &io_data; ssize_t res; int ret; ENTER(); ffs_log("enter"); ret = ffs_inst_exist_check(); if (ret < 0) return ret; if (!is_sync_kiocb(kiocb)) { p = kmalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) Loading Loading @@ -1433,7 +1436,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, epfile->ffs->setup_state, epfile->ffs->flags); ret = ffs_inst_exist_check(); ret = ffs_inst_exist_check(epfile->ffs->dev_name); if (ret < 0) return ret; Loading Loading @@ -1741,6 +1744,7 @@ ffs_fs_mount(struct file_system_type *t, int flags, int ret; void *ffs_dev; struct ffs_data *ffs; struct ffs_inst_status *inst_status; ENTER(); Loading Loading @@ -1770,6 +1774,18 @@ ffs_fs_mount(struct file_system_type *t, int flags, ffs->private_data = ffs_dev; data.ffs_data = ffs; inst_status = name_to_inst_status(ffs->dev_name, false); if (IS_ERR(inst_status)) { ffs_log("failed to find instance (%s)\n", ffs->dev_name); return ERR_PTR(-EINVAL); } /* Store ffs to global status structure */ ffs_dev_lock(); inst_status->ffs_data = ffs; ffs_dev_unlock(); rv = mount_nodev(t, flags, &data, ffs_sb_fill); if (IS_ERR(rv) && data.ffs_data) { ffs_release_dev(data.ffs_data); Loading Loading @@ -1881,6 +1897,9 @@ static void ffs_data_opened(struct ffs_data *ffs) static void ffs_data_put(struct ffs_data *ffs) { struct ffs_inst_status *inst_status; const char *dev_name; ENTER(); ffs_log("enter"); Loading @@ -1889,16 +1908,20 @@ static void ffs_data_put(struct ffs_data *ffs) smp_mb__before_atomic(); if (unlikely(atomic_dec_and_test(&ffs->ref))) { pr_info("%s(): freeing\n", __func__); /* Clear g_ffs_data */ /* Clear ffs from global structure */ inst_status = name_to_inst_status(ffs->dev_name, false); if (!IS_ERR(inst_status)) { ffs_dev_lock(); g_ffs_data = NULL; inst_status->ffs_data = NULL; ffs_dev_unlock(); } ffs_data_clear(ffs); BUG_ON(waitqueue_active(&ffs->ev.waitq) || waitqueue_active(&ffs->ep0req_completion.wait)); kfree(ffs->dev_name); dev_name = ffs->dev_name; kfree(ffs); ffs_inst_clean_delay(); ffs_inst_clean_delay(dev_name); kfree(dev_name); } ffs_log("exit"); Loading Loading @@ -1965,11 +1988,6 @@ static struct ffs_data *ffs_data_new(void) /* XXX REVISIT need to update it in some places, or do we? */ ffs->ev.can_stall = 1; /* Store ffs to g_ffs_data */ ffs_dev_lock(); g_ffs_data = ffs; ffs_dev_unlock(); ffs_log("exit"); return ffs; Loading Loading @@ -3882,79 +3900,146 @@ static struct config_item_type ffs_func_type = { /* Function registration interface ******************************************/ static int ffs_inst_exist_check(void) static struct ffs_inst_status *name_to_inst_status( const char *inst_name, bool create_inst) { mutex_lock(&ffs_ep_lock); struct ffs_inst_status *inst_status; list_for_each_entry(inst_status, &inst_list, list) { if (!strncasecmp(inst_status->inst_name, inst_name, strlen(inst_name))) return inst_status; } if (unlikely(ffs_inst_exist == false)) { mutex_unlock(&ffs_ep_lock); if (!create_inst) return ERR_PTR(-ENODEV); inst_status = kzalloc(sizeof(struct ffs_inst_status), GFP_KERNEL); if (!inst_status) return ERR_PTR(-ENOMEM); mutex_init(&inst_status->ffs_lock); snprintf(inst_status->inst_name, INST_NAME_SIZE, inst_name); list_add_tail(&inst_status->list, &inst_list); return inst_status; } static int ffs_inst_exist_check(const char *inst_name) { struct ffs_inst_status *inst_status; inst_status = name_to_inst_status(inst_name, false); if (IS_ERR(inst_status)) { pr_err_ratelimited( "%s: f_fs instance freed already.\n", __func__); "%s: failed to find instance (%s)\n", __func__, inst_name); return -ENODEV; } mutex_lock(&inst_status->ffs_lock); if (unlikely(inst_status->inst_exist == false)) { mutex_unlock(&inst_status->ffs_lock); pr_err_ratelimited( "%s: f_fs instance (%s) has been freed already.\n", __func__, inst_name); return -ENODEV; } mutex_unlock(&ffs_ep_lock); mutex_unlock(&inst_status->ffs_lock); return 0; } static void ffs_inst_clean(struct f_fs_opts *opts) static void ffs_inst_clean(struct f_fs_opts *opts, const char *inst_name) { g_opts = NULL; struct ffs_inst_status *inst_status; inst_status = name_to_inst_status(inst_name, false); if (IS_ERR(inst_status)) { pr_err_ratelimited( "%s: failed to find instance (%s)\n", __func__, inst_name); return; } inst_status->opts = NULL; ffs_dev_lock(); _ffs_free_dev(opts->dev); ffs_dev_unlock(); kfree(opts); } static void ffs_inst_clean_delay(void) static void ffs_inst_clean_delay(const char *inst_name) { mutex_lock(&ffs_ep_lock); struct ffs_inst_status *inst_status; if (unlikely(ffs_inst_exist == false)) { if (g_opts) { ffs_inst_clean(g_opts); inst_status = name_to_inst_status(inst_name, false); if (IS_ERR(inst_status)) { pr_err_ratelimited( "%s: failed to find (%s) instance\n", __func__, inst_name); return; } mutex_lock(&inst_status->ffs_lock); if (unlikely(inst_status->inst_exist == false)) { if (inst_status->opts) { ffs_inst_clean(inst_status->opts, inst_name); pr_err_ratelimited("%s: Delayed free memory\n", __func__); } mutex_unlock(&ffs_ep_lock); mutex_unlock(&inst_status->ffs_lock); return; } mutex_unlock(&ffs_ep_lock); mutex_unlock(&inst_status->ffs_lock); } static void ffs_free_inst(struct usb_function_instance *f) { struct f_fs_opts *opts; struct ffs_inst_status *inst_status; opts = to_f_fs_opts(f); mutex_lock(&ffs_ep_lock); inst_status = name_to_inst_status(opts->dev->name, false); if (IS_ERR(inst_status)) { ffs_log("failed to find (%s) instance\n", opts->dev->name); return; } mutex_lock(&inst_status->ffs_lock); if (opts->dev->ffs_data && atomic_read(&opts->dev->ffs_data->opened)) { ffs_inst_exist = false; mutex_unlock(&ffs_ep_lock); ffs_log("%s: Dev is open, free mem when dev close\n", __func__); inst_status->inst_exist = false; mutex_unlock(&inst_status->ffs_lock); ffs_log("Dev is open, free mem when dev (%s) close\n", opts->dev->name); return; } ffs_inst_clean(opts); ffs_inst_exist = false; g_opts = NULL; mutex_unlock(&ffs_ep_lock); ffs_inst_clean(opts, opts->dev->name); inst_status->inst_exist = false; mutex_unlock(&inst_status->ffs_lock); } #define MAX_INST_NAME_LEN 40 static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) { struct f_fs_opts *opts; struct f_fs_opts *opts, *opts_prev; struct ffs_data *ffs_data_tmp; char *ptr; const char *tmp; int name_len, ret; struct ffs_inst_status *inst_status; name_len = strlen(name) + 1; if (name_len > MAX_INST_NAME_LEN) Loading @@ -3964,13 +4049,22 @@ static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) if (!ptr) return -ENOMEM; mutex_lock(&ffs_ep_lock); if (g_opts) { mutex_unlock(&ffs_ep_lock); ffs_log("%s: prev inst do not freed yet\n", __func__); inst_status = name_to_inst_status(ptr, true); if (IS_ERR(inst_status)) { ffs_log("failed to create status struct for (%s) instance\n", ptr); return -EINVAL; } mutex_lock(&inst_status->ffs_lock); opts_prev = inst_status->opts; if (opts_prev) { mutex_unlock(&inst_status->ffs_lock); ffs_log("instance (%s): prev inst do not freed yet\n", inst_status->inst_name); return -EBUSY; } mutex_unlock(&ffs_ep_lock); mutex_unlock(&inst_status->ffs_lock); opts = to_f_fs_opts(fi); tmp = NULL; Loading @@ -3992,8 +4086,9 @@ static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) * ffs_private_data also need to update new allocated opts->dev * address. */ if (g_ffs_data) opts->dev->ffs_data = g_ffs_data; ffs_data_tmp = inst_status->ffs_data; if (ffs_data_tmp) opts->dev->ffs_data = ffs_data_tmp; if (opts->dev->ffs_data) opts->dev->ffs_data->private_data = opts->dev; Loading @@ -4002,10 +4097,10 @@ static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) kfree(tmp); mutex_lock(&ffs_ep_lock); ffs_inst_exist = true; g_opts = opts; mutex_unlock(&ffs_ep_lock); mutex_lock(&inst_status->ffs_lock); inst_status->inst_exist = true; inst_status->opts = opts; mutex_unlock(&inst_status->ffs_lock); return 0; } Loading Loading @@ -4410,6 +4505,24 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len, return data; } static void __exit ffs_exit(void) { struct ffs_inst_status *inst_status, *inst_status_tmp = NULL; list_for_each_entry(inst_status, &inst_list, list) { if (inst_status_tmp) { list_del(&inst_status_tmp->list); kfree(inst_status_tmp); } inst_status_tmp = inst_status; } if (inst_status_tmp) { list_del(&inst_status_tmp->list); kfree(inst_status_tmp); } } module_exit(ffs_exit); DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Nazarewicz");