From: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx> When configfs is in place, the things related to intialization of struct fsg_common will be split over a number of places. This patch adds several functions which together cover the former intialization routine fsg_common_init. As a consequence, issuing of some debug messages needs to be adjusted. Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> --- drivers/usb/gadget/f_mass_storage.c | 400 +++++++++++++++++++++++++++++++++-- drivers/usb/gadget/f_mass_storage.h | 31 +++ drivers/usb/gadget/storage_common.c | 24 +-- 3 files changed, 430 insertions(+), 25 deletions(-) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 8d0b451..fc3b5ff 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -299,6 +299,7 @@ struct fsg_common { unsigned int short_packet_received:1; unsigned int bad_lun_okay:1; unsigned int running:1; + unsigned int sysfs:1; int thread_wakeup_needed; struct completion thread_notifier; @@ -2604,6 +2605,374 @@ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) return -EINVAL; } +static struct fsg_common *fsg_common_setup(struct fsg_common *common, bool zero) +{ + if (!common) { + common = kzalloc(sizeof *common, GFP_KERNEL); + if (!common) + return ERR_PTR(-ENOMEM); + common->free_storage_on_release = 1; + } else { + if (zero) + memset(common, 0, sizeof *common); + common->free_storage_on_release = 0; + } + init_rwsem(&common->filesem); + spin_lock_init(&common->lock); + kref_init(&common->ref); + init_completion(&common->thread_notifier); + init_waitqueue_head(&common->fsg_wait); + common->state = FSG_STATE_TERMINATED; + + return common; +} + +void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs) +{ + common->sysfs = sysfs; +} + +int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n) +{ + struct fsg_buffhd *bh, *new_buffhds; + int i, rc; + + rc = fsg_num_buffers_validate(n); + if (rc != 0) + return rc; + + new_buffhds = kcalloc(n, sizeof *(new_buffhds), GFP_KERNEL); + if (!new_buffhds) + return -ENOMEM; + + /* Data buffers cyclic list */ + bh = new_buffhds; + i = n; + goto buffhds_first_it; + do { + bh->next = bh + 1; + ++bh; +buffhds_first_it: + bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); + if (unlikely(!bh->buf)) + goto error_release; + } while (--i); + bh->next = new_buffhds; + + common->fsg_num_buffers = n; + kfree(common->buffhds); + common->buffhds = new_buffhds; + + return 0; + +error_release: + bh = new_buffhds; + i = n - i; + while (i--) { + kfree(bh->buf); + bh++; + }; + + kfree(new_buffhds); + + return -ENOMEM; +} + +void fsg_common_free_buffers(struct fsg_common *common) +{ + struct fsg_buffhd *bh; + int i; + + bh = common->buffhds; + i = common->fsg_num_buffers; + while (i--) { + kfree(bh->buf); + bh++; + }; + + kfree(common->buffhds); + common->buffhds = NULL; +} + +int fsg_common_set_nluns(struct fsg_common *common, int nluns) +{ + struct fsg_lun **curlun; + + /* Find out how many LUNs there should be */ + if (nluns < 1 || nluns > FSG_MAX_LUNS) { + ERROR(common, "invalid number of LUNs: %u\n", nluns); + return -EINVAL; + } + + curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); + if (unlikely(!curlun)) + return -ENOMEM; + + common->luns = curlun; + common->nluns = nluns; + + pr_info("Number of LUNs=%d\n", common->nluns); + + return 0; +} + +void fsg_common_free_luns(struct fsg_common *common) +{ + kfree(common->luns); + common->luns = NULL; +} + +void fsg_common_set_ops(struct fsg_common *common, const struct fsg_operations *ops) +{ + common->ops = ops; +} + +void fsg_common_set_private_data(struct fsg_common *common, void *priv) +{ + common->private_data = priv; +} + +int fsg_common_set_cdev(struct fsg_common *common, + struct usb_composite_dev *cdev, bool can_stall) +{ + struct usb_string *us; + int rc; + + common->gadget = cdev->gadget; + common->ep0 = cdev->gadget->ep0; + common->ep0req = cdev->req; + common->cdev = cdev; + + us = usb_gstrings_attach(cdev, fsg_strings_array, + ARRAY_SIZE(fsg_strings)); + if (IS_ERR(us)) { + rc = PTR_ERR(us); + return rc; + } + fsg_intf_desc.iInterface = us[FSG_STRING_INTERFACE].id; + + /* + * Some peripheral controllers are known not to be able to + * halt bulk endpoints correctly. If one of them is present, + * disable stalls. + */ + common->can_stall = can_stall && !(gadget_is_at91(common->gadget)); + + return 0; +} + +static inline int fsg_common_add_sysfs(struct fsg_common *common, + struct fsg_lun *lun) +{ + int rc; + + rc = device_register(&lun->dev); + if (rc) { + put_device(&lun->dev); + return rc; + } + + rc = device_create_file(&lun->dev, + lun->cdrom + ? &dev_attr_ro_cdrom + : &dev_attr_ro); + if (rc) + goto error_cdrom; + rc = device_create_file(&lun->dev, + lun->removable + ? &dev_attr_file + : &dev_attr_file_nonremovable); + if (rc) + goto error_removable; + rc = device_create_file(&lun->dev, &dev_attr_nofua); + if (rc) + goto error_nofua; + + return 0; + +error_nofua: + device_remove_file(&lun->dev, + lun->removable + ? &dev_attr_file + : &dev_attr_file_nonremovable); +error_removable: + device_remove_file(&lun->dev, + lun->cdrom + ? &dev_attr_ro_cdrom + : &dev_attr_ro); +error_cdrom: + device_unregister(&lun->dev); + return rc; +} + +void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) +{ + if (sysfs) { + device_remove_file(&lun->dev, &dev_attr_nofua); + device_remove_file(&lun->dev, + lun->cdrom + ? &dev_attr_ro_cdrom + : &dev_attr_ro); + device_remove_file(&lun->dev, + lun->removable + ? &dev_attr_file + : &dev_attr_file_nonremovable); + device_unregister(&lun->dev); + } + fsg_lun_close(lun); + kfree(lun); +} + +void fsg_common_remove_luns(struct fsg_common *common) +{ + int i; + + for (i = 0; i < common->nluns; ++i) + fsg_common_remove_lun(common->luns[i], common->sysfs); +} + +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, + unsigned int id) +{ + struct fsg_lun *lun; + char *pathbuf; + int rc; + + if (!common->nluns || !common->luns) + return -ENODEV; + + if (common->luns[id]) + return -EBUSY; + + lun = kzalloc(sizeof(*lun), GFP_KERNEL); + if (!lun) + return -ENOMEM; + + lun->cdrom = !!cfg->cdrom; + lun->ro = cfg->cdrom || cfg->ro; + lun->initially_ro = lun->ro; + lun->removable = cfg->removable; + + common->luns[id] = lun; + + if (common->sysfs) { + lun->dev.release = fsg_lun_release; + lun->dev.parent = &common->gadget->dev; + dev_set_drvdata(&lun->dev, &common->filesem); + dev_set_name(&lun->dev, "lun%d", id); + + rc = fsg_common_add_sysfs(common, lun); + if (rc) { + pr_info("failed to register LUN%d: %d\n", id, rc); + goto error_sysfs; + } + } + + if (cfg->filename) { + rc = fsg_lun_open(lun, cfg->filename); + if (rc) + goto error_lun; + } else if (!lun->removable) { + pr_err("no file given for LUN%d\n", id); + rc = -EINVAL; + goto error_lun; + } + + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); + { + char *p = "(no medium)"; + if (fsg_lun_is_open(lun)) { + p = "(error)"; + if (pathbuf) { + p = d_path(&lun->filp->f_path, + pathbuf, PATH_MAX); + if (IS_ERR(p)) + p = "(error)"; + } + } + pr_info("LUN: %s%s%sfile: %s\n", + lun->removable ? "removable " : "", + lun->ro ? "read only " : "", + lun->cdrom ? "CD-ROM " : "", + p); + } + kfree(pathbuf); + + return 0; + +error_lun: + if (common->sysfs) { + device_remove_file(&lun->dev, &dev_attr_nofua); + device_remove_file(&lun->dev, + lun->cdrom + ? &dev_attr_ro_cdrom + : &dev_attr_ro); + device_remove_file(&lun->dev, + lun->removable + ? &dev_attr_file + : &dev_attr_file_nonremovable); + device_unregister(&lun->dev); + } + fsg_lun_close(lun); +error_sysfs: + kfree(lun); + return rc; +} + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg) +{ + int i, rc; + + for (i = 0; i < common->nluns; ++i) { + rc = fsg_common_create_lun(common, &cfg->luns[i], i); + if (rc) + goto fail; + } + + pr_info("Number of LUNs=%d\n", common->nluns); + + return 0; + +fail: + while (--i >= 0) + fsg_common_remove_lun(common->luns[i], true); + return rc; +} + +void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, + const char *pn) +{ + int i; + + /* Prepare inquiryString */ + i = get_default_bcdDevice(); + snprintf(common->inquiry_string, sizeof common->inquiry_string, + "%-8s%-16s%04x", vn ?: "Linux", + /* Assume product name dependent on the first LUN */ + pn ?: ((*common->luns)->cdrom + ? "File-CD Gadget" + : "File-Stor Gadget"), + i); +} + +int fsg_common_run_thread(struct fsg_common *common) +{ + common->state = FSG_STATE_IDLE; + /* Tell the thread to start working */ + common->thread_task = + kthread_create(fsg_main_thread, common, "file-storage"); + if (IS_ERR(common->thread_task)) { + common->state = FSG_STATE_TERMINATED; + return PTR_ERR(common->thread_task); + } + + DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); + + wake_up_process(common->thread_task); + + return 0; +} + struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) @@ -2637,6 +3006,8 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, memset(common, 0, sizeof *common); common->free_storage_on_release = 0; } + common->sysfs = true; + common->state = FSG_STATE_IDLE; common->fsg_num_buffers = cfg->fsg_num_buffers; common->buffhds = kcalloc(common->fsg_num_buffers, @@ -2818,6 +3189,15 @@ error_release: return ERR_PTR(rc); } +static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) +{ + device_remove_file(&lun->dev, &dev_attr_nofua); + device_remove_file(&lun->dev, lun->cdrom + ? &dev_attr_ro_cdrom : &dev_attr_ro); + device_remove_file(&lun->dev, lun->removable + ? &dev_attr_file : &dev_attr_file_nonremovable); +} + static void fsg_common_release(struct kref *ref) { struct fsg_common *common = container_of(ref, struct fsg_common, ref); @@ -2836,32 +3216,26 @@ static void fsg_common_release(struct kref *ref) for (; i; --i, ++lun) { if (!*lun) continue; - device_remove_file(&(*lun)->dev, &dev_attr_nofua); - device_remove_file(&(*lun)->dev, - (*lun)->cdrom - ? &dev_attr_ro_cdrom - : &dev_attr_ro); - device_remove_file(&(*lun)->dev, - (*lun)->removable - ? &dev_attr_file - : &dev_attr_file_nonremovable); + if (common->sysfs) + fsg_common_remove_sysfs(*lun); fsg_lun_close(*lun); - device_unregister(&(*lun)->dev); + if (common->sysfs) + device_unregister(&(*lun)->dev); kfree(*lun); } kfree(common->luns); } - { + if (likely(common->buffhds)){ struct fsg_buffhd *bh = common->buffhds; unsigned i = common->fsg_num_buffers; do { kfree(bh->buf); } while (++bh, --i); - } - kfree(common->buffhds); + kfree(common->buffhds); + } if (common->free_storage_on_release) kfree(common); } diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index b64761d..46e6863 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -102,6 +102,37 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg); +void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs); + +int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n); + +void fsg_common_free_buffers(struct fsg_common *common); + +int fsg_common_set_nluns(struct fsg_common *common, int nluns); + +void fsg_common_free_luns(struct fsg_common *common); + +void fsg_common_set_ops(struct fsg_common *common, const struct fsg_operations *ops); + +void fsg_common_set_private_data(struct fsg_common *common, void *priv); + +int fsg_common_set_cdev(struct fsg_common *common, + struct usb_composite_dev *cdev, bool can_stall); + +void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs); + +void fsg_common_remove_luns(struct fsg_common *common); + +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, + unsigned int id); + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); + +void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, + const char *pn); + +int fsg_common_run_thread(struct fsg_common *common); + void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 942324c..a70a5d3 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -179,7 +179,7 @@ EXPORT_SYMBOL(fsg_ss_function); void fsg_lun_close(struct fsg_lun *curlun) { if (curlun->filp) { - LDBG(curlun, "close backing file\n"); + pr_debug("close backing file\n"); fput(curlun->filp); curlun->filp = NULL; } @@ -208,7 +208,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename) if (ro) filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0); if (IS_ERR(filp)) { - LINFO(curlun, "unable to open backing file: %s\n", filename); + pr_info("unable to open backing file: %s\n", filename); return PTR_ERR(filp); } @@ -217,7 +217,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename) inode = file_inode(filp); if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) { - LINFO(curlun, "invalid file type: %s\n", filename); + pr_info("invalid file type: %s\n", filename); goto out; } @@ -226,7 +226,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename) * If we can't write the file, use it read-only. */ if (!(filp->f_op->read || filp->f_op->aio_read)) { - LINFO(curlun, "file not readable: %s\n", filename); + pr_info("file not readable: %s\n", filename); goto out; } if (!(filp->f_op->write || filp->f_op->aio_write)) @@ -234,7 +234,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename) size = i_size_read(inode->i_mapping->host); if (size < 0) { - LINFO(curlun, "unable to find file size: %s\n", filename); + pr_info("unable to find file size: %s\n", filename); rc = (int) size; goto out; } @@ -256,13 +256,13 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename) min_sectors = 300; /* Smallest track is 300 frames */ if (num_sectors >= 256*60*75) { num_sectors = 256*60*75 - 1; - LINFO(curlun, "file too big: %s\n", filename); - LINFO(curlun, "using only first %d blocks\n", + pr_info("file too big: %s\n", filename); + pr_info("using only first %d blocks\n", (int) num_sectors); } } if (num_sectors < min_sectors) { - LINFO(curlun, "file too small: %s\n", filename); + pr_info("file too small: %s\n", filename); rc = -ETOOSMALL; goto out; } @@ -276,7 +276,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename) curlun->filp = filp; curlun->file_length = size; curlun->num_sectors = num_sectors; - LDBG(curlun, "open backing file: %s\n", filename); + pr_debug("open backing file: %s\n", filename); return 0; out: @@ -391,12 +391,12 @@ ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, */ down_read(filesem); if (fsg_lun_is_open(curlun)) { - LDBG(curlun, "read-only status change prevented\n"); + pr_debug("read-only status change prevented\n"); rc = -EBUSY; } else { curlun->ro = ro; curlun->initially_ro = ro; - LDBG(curlun, "read-only status set to %d\n", curlun->ro); + pr_debug("read-only status set to %d\n", curlun->ro); rc = count; } up_read(filesem); @@ -434,7 +434,7 @@ ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, int rc = 0; if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { - LDBG(curlun, "eject attempt prevented\n"); + pr_debug("eject attempt prevented\n"); return -EBUSY; /* "Door is locked" */ } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html