diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 3cdd8359efda..6b6c7f1b773f 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -274,7 +274,7 @@ struct fsg_common { unsigned int nluns; unsigned int lun; - struct fsg_lun *luns; + struct fsg_lun **luns; struct fsg_lun *curlun; unsigned int bulk_out_maxpacket; @@ -2151,7 +2151,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) common->data_dir = DATA_DIR_NONE; common->lun = cbw->Lun; if (common->lun < common->nluns) - common->curlun = &common->luns[common->lun]; + common->curlun = common->luns[common->lun]; else common->curlun = NULL; common->tag = cbw->Tag; @@ -2299,7 +2299,9 @@ reset: common->running = 1; for (i = 0; i < common->nluns; ++i) - common->luns[i].unit_attention_data = SS_RESET_OCCURRED; + if (common->luns[i]) + common->luns[i]->unit_attention_data = + SS_RESET_OCCURRED; return rc; } @@ -2399,7 +2401,9 @@ static void handle_exception(struct fsg_common *common) common->state = FSG_STATE_STATUS_PHASE; else { for (i = 0; i < common->nluns; ++i) { - curlun = &common->luns[i]; + curlun = common->luns[i]; + if (!curlun) + continue; curlun->prevent_medium_removal = 0; curlun->sense_data = SS_NO_SENSE; curlun->unit_attention_data = SS_NO_SENSE; @@ -2441,8 +2445,9 @@ static void handle_exception(struct fsg_common *common) * CONFIG_CHANGE cases. */ /* for (i = 0; i < common->nluns; ++i) */ - /* common->luns[i].unit_attention_data = */ - /* SS_RESET_OCCURRED; */ + /* if (common->luns[i]) */ + /* common->luns[i]->unit_attention_data = */ + /* SS_RESET_OCCURRED; */ break; case FSG_STATE_CONFIG_CHANGE: @@ -2538,12 +2543,13 @@ static int fsg_main_thread(void *common_) if (!common->ops || !common->ops->thread_exits || common->ops->thread_exits(common) < 0) { - struct fsg_lun *curlun = common->luns; + struct fsg_lun **curlun_it = common->luns; unsigned i = common->nluns; down_write(&common->filesem); - for (; i--; ++curlun) { - if (!fsg_lun_is_open(curlun)) + for (; i--; ++curlun_it) { + struct fsg_lun *curlun = *curlun_it; + if (!curlun || !fsg_lun_is_open(curlun)) continue; fsg_lun_close(curlun); @@ -2637,7 +2643,7 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, { struct usb_gadget *gadget = cdev->gadget; struct fsg_buffhd *bh; - struct fsg_lun *curlun; + struct fsg_lun **curlun_it; struct fsg_lun_config *lcfg; int nluns, i, rc; char *pathbuf; @@ -2694,16 +2700,26 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, * Create the LUNs, open their backing files, and register the * LUN devices in sysfs. */ - curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); - if (unlikely(!curlun)) { + curlun_it = kcalloc(nluns, sizeof(*curlun_it), GFP_KERNEL); + if (unlikely(!curlun_it)) { rc = -ENOMEM; goto error_release; } - common->luns = curlun; + common->luns = curlun_it; init_rwsem(&common->filesem); - for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) { + for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun_it, ++lcfg) { + struct fsg_lun *curlun; + + curlun = kzalloc(sizeof(*curlun), GFP_KERNEL); + if (!curlun) { + rc = -ENOMEM; + common->nluns = i; + goto error_release; + } + *curlun_it = curlun; + curlun->cdrom = !!lcfg->cdrom; curlun->ro = lcfg->cdrom || lcfg->ro; curlun->initially_ro = curlun->ro; @@ -2719,6 +2735,7 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, INFO(common, "failed to register LUN%d: %d\n", i, rc); common->nluns = i; put_device(&curlun->dev); + kfree(curlun); goto error_release; } @@ -2771,7 +2788,7 @@ buffhds_first_it: snprintf(common->inquiry_string, sizeof common->inquiry_string, "%-8s%-16s%04x", cfg->vendor_name ?: "Linux", /* Assume product name dependent on the first LUN */ - cfg->product_name ?: (common->luns->cdrom + cfg->product_name ?: ((*common->luns)->cdrom ? "File-CD Gadget" : "File-Stor Gadget"), i); @@ -2802,9 +2819,10 @@ buffhds_first_it: INFO(common, "Number of LUNs=%d\n", common->nluns); pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); - for (i = 0, nluns = common->nluns, curlun = common->luns; + for (i = 0, nluns = common->nluns, curlun_it = common->luns; i < nluns; - ++curlun, ++i) { + ++curlun_it, ++i) { + struct fsg_lun *curlun = *curlun_it; char *p = "(no medium)"; if (fsg_lun_is_open(curlun)) { p = "(error)"; @@ -2849,11 +2867,14 @@ static void fsg_common_release(struct kref *ref) } if (likely(common->luns)) { - struct fsg_lun *lun = common->luns; + struct fsg_lun **lun_it = common->luns; unsigned i = common->nluns; /* In error recovery common->nluns may be zero. */ - for (; i; --i, ++lun) { + for (; i; --i, ++lun_it) { + struct fsg_lun *lun = *lun_it; + if (!lun) + continue; device_remove_file(&lun->dev, &dev_attr_nofua); device_remove_file(&lun->dev, lun->cdrom @@ -2865,6 +2886,7 @@ static void fsg_common_release(struct kref *ref) : &dev_attr_file_nonremovable); fsg_lun_close(lun); device_unregister(&lun->dev); + kfree(lun); } kfree(common->luns);