Loading drivers/usb/gadget/function/f_mass_storage.c +70 −2 Original line number Diff line number Diff line Loading @@ -251,6 +251,16 @@ static struct usb_gadget_strings *fsg_strings_array[] = { /*-------------------------------------------------------------------------*/ /* * If USB mass storage vfs operation is stuck for more than 10 sec * host will initiate the reset. Configure the timer with 9 sec to print * the error message before host is intiating the resume on it. */ #define MSC_VFS_TIMER_PERIOD_MS 9000 static int msc_vfs_timer_period_ms = MSC_VFS_TIMER_PERIOD_MS; module_param(msc_vfs_timer_period_ms, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(msc_vfs_timer_period_ms, "Set period for MSC VFS timer"); struct fsg_dev; struct fsg_common; Loading Loading @@ -316,6 +326,7 @@ struct fsg_common { /* LUN name for sysfs purpose */ char name[FSG_MAX_LUNS][LUN_NAME_LEN]; struct kref ref; struct timer_list vfs_timer; }; struct fsg_dev { Loading @@ -335,6 +346,26 @@ struct fsg_dev { struct usb_ep *bulk_out; }; static void msc_usb_vfs_timer_func(unsigned long data) { struct fsg_common *common = (struct fsg_common *) data; switch (common->data_dir) { case DATA_DIR_FROM_HOST: dev_err(&common->curlun->dev, "usb mass storage stuck in vfs_write\n"); break; case DATA_DIR_TO_HOST: dev_err(&common->curlun->dev, "usb mass storage stuck in vfs_read\n"); break; default: dev_err(&common->curlun->dev, "usb mass storage stuck in vfs_sync\n"); break; } } static inline int __fsg_is_set(struct fsg_common *common, const char *func, unsigned line) { Loading Loading @@ -635,7 +666,7 @@ static int do_read(struct fsg_common *common) loff_t file_offset, file_offset_tmp; unsigned int amount; ssize_t nread; ktime_t start, diff; /* * Get the starting Logical Block Address and check that it's * not too big. Loading Loading @@ -702,11 +733,18 @@ static int do_read(struct fsg_common *common) /* Perform the read */ file_offset_tmp = file_offset; start = ktime_get(); mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); nread = vfs_read(curlun->filp, (char __user *)bh->buf, amount, &file_offset_tmp); del_timer_sync(&common->vfs_timer); VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, (unsigned long long)file_offset, (int)nread); diff = ktime_sub(ktime_get(), start); curlun->perf.rbytes += nread; curlun->perf.rtime = ktime_add(curlun->perf.rtime, diff); if (signal_pending(current)) return -EINTR; Loading Loading @@ -767,6 +805,7 @@ static int do_write(struct fsg_common *common) unsigned int amount; ssize_t nwritten; int rc; ktime_t start, diff; if (curlun->ro) { curlun->sense_data = SS_WRITE_PROTECTED; Loading Loading @@ -895,11 +934,19 @@ static int do_write(struct fsg_common *common) /* Perform the write */ file_offset_tmp = file_offset; start = ktime_get(); mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); nwritten = vfs_write(curlun->filp, (char __user *)bh->buf, amount, &file_offset_tmp); del_timer_sync(&common->vfs_timer); VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, (unsigned long long)file_offset, (int)nwritten); diff = ktime_sub(ktime_get(), start); curlun->perf.wbytes += nwritten; curlun->perf.wtime = ktime_add(curlun->perf.wtime, diff); if (signal_pending(current)) return -EINTR; /* Interrupted! */ Loading Loading @@ -953,9 +1000,12 @@ static int do_synchronize_cache(struct fsg_common *common) /* We ignore the requested LBA and write out all file's * dirty data buffers. */ mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); rc = fsg_lun_fsync_sub(curlun); if (rc) curlun->sense_data = SS_WRITE_ERROR; del_timer_sync(&common->vfs_timer); return 0; } Loading Loading @@ -1011,7 +1061,10 @@ static int do_verify(struct fsg_common *common) file_offset = ((loff_t) lba) << curlun->blkbits; /* Write out all the dirty buffers before invalidating them */ mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); fsg_lun_fsync_sub(curlun); del_timer_sync(&common->vfs_timer); if (signal_pending(current)) return -EINTR; Loading Loading @@ -1041,9 +1094,12 @@ static int do_verify(struct fsg_common *common) /* Perform the read */ file_offset_tmp = file_offset; mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); nread = vfs_read(curlun->filp, (char __user *) bh->buf, amount, &file_offset_tmp); del_timer_sync(&common->vfs_timer); VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, (unsigned long long) file_offset, (int) nread); Loading Loading @@ -1374,8 +1430,12 @@ static int do_prevent_allow(struct fsg_common *common) return -EINVAL; } if (curlun->prevent_medium_removal && !prevent) if (!curlun->nofua && curlun->prevent_medium_removal && !prevent) { mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); fsg_lun_fsync_sub(curlun); del_timer_sync(&common->vfs_timer); } curlun->prevent_medium_removal = prevent; return 0; } Loading Loading @@ -2641,6 +2701,7 @@ static ssize_t file_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(ro); static DEVICE_ATTR_RW(nofua); static DEVICE_ATTR_RW(file); static DEVICE_ATTR(perf, 0644, fsg_show_perf, fsg_store_perf); static struct device_attribute dev_attr_ro_cdrom = __ATTR_RO(ro); static struct device_attribute dev_attr_file_nonremovable = __ATTR_RO(file); Loading Loading @@ -2785,6 +2846,7 @@ static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) */ device_remove_file(&lun->dev, &dev_attr_ro); device_remove_file(&lun->dev, &dev_attr_file); device_remove_file(&lun->dev, &dev_attr_perf); } void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) Loading Loading @@ -2918,6 +2980,10 @@ static inline int fsg_common_add_sysfs(struct fsg_common *common, if (rc) goto error; rc = device_create_file(&lun->dev, &dev_attr_perf); if (rc) pr_err("failed to create sysfs entry: %d\n", rc); return 0; error: Loading Loading @@ -3672,6 +3738,8 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi) fsg->function.free_func = fsg_free; fsg->common = common; setup_timer(&common->vfs_timer, msc_usb_vfs_timer_func, (unsigned long) common); return &fsg->function; } Loading drivers/usb/gadget/function/storage_common.c +30 −0 Original line number Diff line number Diff line Loading @@ -333,6 +333,36 @@ ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf) } EXPORT_SYMBOL_GPL(fsg_show_nofua); ssize_t fsg_show_perf(struct device *dev, struct device_attribute *attr, char *buf) { struct fsg_lun *curlun = fsg_lun_from_dev(dev); unsigned long rbytes, wbytes; int64_t rtime, wtime; rbytes = curlun->perf.rbytes; wbytes = curlun->perf.wbytes; rtime = ktime_to_us(curlun->perf.rtime); wtime = ktime_to_us(curlun->perf.wtime); return snprintf(buf, PAGE_SIZE, "Write performance :%lu bytes in %lld microseconds\n" "Read performance : %lu bytes in %lld microseconds\n", wbytes, wtime, rbytes, rtime); } ssize_t fsg_store_perf(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct fsg_lun *curlun = fsg_lun_from_dev(dev); int value; if (!kstrtoint(buf, 10, &value) && !value) memset(&curlun->perf, 0, sizeof(curlun->perf)); return count; } ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, char *buf) { Loading drivers/usb/gadget/function/storage_common.h +11 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,13 @@ struct fsg_lun { of bound block device */ unsigned int blksize; /* logical block size of bound block device */ struct device dev; struct { unsigned long rbytes; unsigned long wbytes; ktime_t rtime; ktime_t wtime; } perf; const char *name; /* "lun.name" */ const char **name_pfx; /* "function.name" */ }; Loading Loading @@ -227,5 +234,9 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count); ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, size_t count); ssize_t fsg_show_perf(struct device *dev, struct device_attribute *attr, char *buf); ssize_t fsg_store_perf(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); #endif /* USB_STORAGE_COMMON_H */ Loading
drivers/usb/gadget/function/f_mass_storage.c +70 −2 Original line number Diff line number Diff line Loading @@ -251,6 +251,16 @@ static struct usb_gadget_strings *fsg_strings_array[] = { /*-------------------------------------------------------------------------*/ /* * If USB mass storage vfs operation is stuck for more than 10 sec * host will initiate the reset. Configure the timer with 9 sec to print * the error message before host is intiating the resume on it. */ #define MSC_VFS_TIMER_PERIOD_MS 9000 static int msc_vfs_timer_period_ms = MSC_VFS_TIMER_PERIOD_MS; module_param(msc_vfs_timer_period_ms, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(msc_vfs_timer_period_ms, "Set period for MSC VFS timer"); struct fsg_dev; struct fsg_common; Loading Loading @@ -316,6 +326,7 @@ struct fsg_common { /* LUN name for sysfs purpose */ char name[FSG_MAX_LUNS][LUN_NAME_LEN]; struct kref ref; struct timer_list vfs_timer; }; struct fsg_dev { Loading @@ -335,6 +346,26 @@ struct fsg_dev { struct usb_ep *bulk_out; }; static void msc_usb_vfs_timer_func(unsigned long data) { struct fsg_common *common = (struct fsg_common *) data; switch (common->data_dir) { case DATA_DIR_FROM_HOST: dev_err(&common->curlun->dev, "usb mass storage stuck in vfs_write\n"); break; case DATA_DIR_TO_HOST: dev_err(&common->curlun->dev, "usb mass storage stuck in vfs_read\n"); break; default: dev_err(&common->curlun->dev, "usb mass storage stuck in vfs_sync\n"); break; } } static inline int __fsg_is_set(struct fsg_common *common, const char *func, unsigned line) { Loading Loading @@ -635,7 +666,7 @@ static int do_read(struct fsg_common *common) loff_t file_offset, file_offset_tmp; unsigned int amount; ssize_t nread; ktime_t start, diff; /* * Get the starting Logical Block Address and check that it's * not too big. Loading Loading @@ -702,11 +733,18 @@ static int do_read(struct fsg_common *common) /* Perform the read */ file_offset_tmp = file_offset; start = ktime_get(); mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); nread = vfs_read(curlun->filp, (char __user *)bh->buf, amount, &file_offset_tmp); del_timer_sync(&common->vfs_timer); VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, (unsigned long long)file_offset, (int)nread); diff = ktime_sub(ktime_get(), start); curlun->perf.rbytes += nread; curlun->perf.rtime = ktime_add(curlun->perf.rtime, diff); if (signal_pending(current)) return -EINTR; Loading Loading @@ -767,6 +805,7 @@ static int do_write(struct fsg_common *common) unsigned int amount; ssize_t nwritten; int rc; ktime_t start, diff; if (curlun->ro) { curlun->sense_data = SS_WRITE_PROTECTED; Loading Loading @@ -895,11 +934,19 @@ static int do_write(struct fsg_common *common) /* Perform the write */ file_offset_tmp = file_offset; start = ktime_get(); mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); nwritten = vfs_write(curlun->filp, (char __user *)bh->buf, amount, &file_offset_tmp); del_timer_sync(&common->vfs_timer); VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, (unsigned long long)file_offset, (int)nwritten); diff = ktime_sub(ktime_get(), start); curlun->perf.wbytes += nwritten; curlun->perf.wtime = ktime_add(curlun->perf.wtime, diff); if (signal_pending(current)) return -EINTR; /* Interrupted! */ Loading Loading @@ -953,9 +1000,12 @@ static int do_synchronize_cache(struct fsg_common *common) /* We ignore the requested LBA and write out all file's * dirty data buffers. */ mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); rc = fsg_lun_fsync_sub(curlun); if (rc) curlun->sense_data = SS_WRITE_ERROR; del_timer_sync(&common->vfs_timer); return 0; } Loading Loading @@ -1011,7 +1061,10 @@ static int do_verify(struct fsg_common *common) file_offset = ((loff_t) lba) << curlun->blkbits; /* Write out all the dirty buffers before invalidating them */ mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); fsg_lun_fsync_sub(curlun); del_timer_sync(&common->vfs_timer); if (signal_pending(current)) return -EINTR; Loading Loading @@ -1041,9 +1094,12 @@ static int do_verify(struct fsg_common *common) /* Perform the read */ file_offset_tmp = file_offset; mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); nread = vfs_read(curlun->filp, (char __user *) bh->buf, amount, &file_offset_tmp); del_timer_sync(&common->vfs_timer); VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, (unsigned long long) file_offset, (int) nread); Loading Loading @@ -1374,8 +1430,12 @@ static int do_prevent_allow(struct fsg_common *common) return -EINVAL; } if (curlun->prevent_medium_removal && !prevent) if (!curlun->nofua && curlun->prevent_medium_removal && !prevent) { mod_timer(&common->vfs_timer, jiffies + msecs_to_jiffies(msc_vfs_timer_period_ms)); fsg_lun_fsync_sub(curlun); del_timer_sync(&common->vfs_timer); } curlun->prevent_medium_removal = prevent; return 0; } Loading Loading @@ -2641,6 +2701,7 @@ static ssize_t file_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(ro); static DEVICE_ATTR_RW(nofua); static DEVICE_ATTR_RW(file); static DEVICE_ATTR(perf, 0644, fsg_show_perf, fsg_store_perf); static struct device_attribute dev_attr_ro_cdrom = __ATTR_RO(ro); static struct device_attribute dev_attr_file_nonremovable = __ATTR_RO(file); Loading Loading @@ -2785,6 +2846,7 @@ static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) */ device_remove_file(&lun->dev, &dev_attr_ro); device_remove_file(&lun->dev, &dev_attr_file); device_remove_file(&lun->dev, &dev_attr_perf); } void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) Loading Loading @@ -2918,6 +2980,10 @@ static inline int fsg_common_add_sysfs(struct fsg_common *common, if (rc) goto error; rc = device_create_file(&lun->dev, &dev_attr_perf); if (rc) pr_err("failed to create sysfs entry: %d\n", rc); return 0; error: Loading Loading @@ -3672,6 +3738,8 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi) fsg->function.free_func = fsg_free; fsg->common = common; setup_timer(&common->vfs_timer, msc_usb_vfs_timer_func, (unsigned long) common); return &fsg->function; } Loading
drivers/usb/gadget/function/storage_common.c +30 −0 Original line number Diff line number Diff line Loading @@ -333,6 +333,36 @@ ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf) } EXPORT_SYMBOL_GPL(fsg_show_nofua); ssize_t fsg_show_perf(struct device *dev, struct device_attribute *attr, char *buf) { struct fsg_lun *curlun = fsg_lun_from_dev(dev); unsigned long rbytes, wbytes; int64_t rtime, wtime; rbytes = curlun->perf.rbytes; wbytes = curlun->perf.wbytes; rtime = ktime_to_us(curlun->perf.rtime); wtime = ktime_to_us(curlun->perf.wtime); return snprintf(buf, PAGE_SIZE, "Write performance :%lu bytes in %lld microseconds\n" "Read performance : %lu bytes in %lld microseconds\n", wbytes, wtime, rbytes, rtime); } ssize_t fsg_store_perf(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct fsg_lun *curlun = fsg_lun_from_dev(dev); int value; if (!kstrtoint(buf, 10, &value) && !value) memset(&curlun->perf, 0, sizeof(curlun->perf)); return count; } ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, char *buf) { Loading
drivers/usb/gadget/function/storage_common.h +11 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,13 @@ struct fsg_lun { of bound block device */ unsigned int blksize; /* logical block size of bound block device */ struct device dev; struct { unsigned long rbytes; unsigned long wbytes; ktime_t rtime; ktime_t wtime; } perf; const char *name; /* "lun.name" */ const char **name_pfx; /* "function.name" */ }; Loading Loading @@ -227,5 +234,9 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count); ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, size_t count); ssize_t fsg_show_perf(struct device *dev, struct device_attribute *attr, char *buf); ssize_t fsg_store_perf(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); #endif /* USB_STORAGE_COMMON_H */