Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb-storage: Optimize scan delay more precisely

Current storage scan delay is reduced by the following old commit.

a4a47bc03fe5 ("Lower USB storage settling delay to something more reasonable")

It means that delay is at least 'one second', or zero with delay_use=0.
'one second' is still long delay especially for embedded system but
when delay_use is set to 0 (no delay), still error observed on some USB drives.

So delay_use should not be set to 0 but 'one second' is quite long.
Especially for embedded system, it's important for end user
how quickly access to USB drive when it's connected.
That's why we have a chance to minimize such a constant long delay.

This patch optimizes scan delay more precisely
to minimize delay time but not to have any problems on USB drives
by extending module parameter 'delay_use' in milliseconds internally.
The parameter 'delay_use' optionally supports in milliseconds
if it ends with 'ms'.
It makes the range of value to 1 / 1000 in internal 32-bit value
but it's still enough to set the delay time.
By default, delay time is 'one second' for backward compatibility.

For example, it seems to be good by changing delay_use=100ms,
that is 100 millisecond delay without issues for most USB pen drives.

Signed-off-by: Norihiko Hama <Norihiko.Hama@alpsalpine.com>
Link: https://lore.kernel.org/r/20240515004339.29892-1-Norihiko.Hama@alpsalpine.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Norihiko Hama and committed by
Greg Kroah-Hartman
804da867 0a01aec2

+100 -4
+3
Documentation/admin-guide/kernel-parameters.txt
··· 7099 7099 usb-storage.delay_use= 7100 7100 [UMS] The delay in seconds before a new device is 7101 7101 scanned for Logical Units (default 1). 7102 + Optionally the delay in milliseconds if the value has 7103 + suffix with "ms". 7104 + Example: delay_use=2567ms 7102 7105 7103 7106 usb-storage.quirks= 7104 7107 [UMS] A list of quirks entries to supplement or
+97 -4
drivers/usb/storage/usb.c
··· 68 68 MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); 69 69 MODULE_LICENSE("GPL"); 70 70 71 - static unsigned int delay_use = 1; 72 - module_param(delay_use, uint, S_IRUGO | S_IWUSR); 73 - MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); 71 + static unsigned int delay_use = 1 * MSEC_PER_SEC; 72 + 73 + /** 74 + * parse_delay_str - parse an unsigned decimal integer delay 75 + * @str: String to parse. 76 + * @ndecimals: Number of decimal to scale up. 77 + * @suffix: Suffix string to parse. 78 + * @val: Where to store the parsed value. 79 + * 80 + * Parse an unsigned decimal value in @str, optionally end with @suffix. 81 + * Stores the parsed value in @val just as it is if @str ends with @suffix. 82 + * Otherwise store the value scale up by 10^(@ndecimal). 83 + * 84 + * Returns 0 on success, a negative error code otherwise. 85 + */ 86 + static int parse_delay_str(const char *str, int ndecimals, const char *suffix, 87 + unsigned int *val) 88 + { 89 + int n, n2, l; 90 + char buf[16]; 91 + 92 + l = strlen(suffix); 93 + n = strlen(str); 94 + if (n > 0 && str[n - 1] == '\n') 95 + --n; 96 + if (n >= l && !strncmp(&str[n - l], suffix, l)) { 97 + n -= l; 98 + n2 = 0; 99 + } else 100 + n2 = ndecimals; 101 + 102 + if (n + n2 > sizeof(buf) - 1) 103 + return -EINVAL; 104 + 105 + memcpy(buf, str, n); 106 + while (n2-- > 0) 107 + buf[n++] = '0'; 108 + buf[n] = 0; 109 + 110 + return kstrtouint(buf, 10, val); 111 + } 112 + 113 + /** 114 + * format_delay_ms - format an integer value into a delay string 115 + * @val: The integer value to format, scaled by 10^(@ndecimals). 116 + * @ndecimals: Number of decimal to scale down. 117 + * @suffix: Suffix string to format. 118 + * @str: Where to store the formatted string. 119 + * @size: The size of buffer for @str. 120 + * 121 + * Format an integer value in @val scale down by 10^(@ndecimals) without @suffix 122 + * if @val is divisible by 10^(@ndecimals). 123 + * Otherwise format a value in @val just as it is with @suffix 124 + * 125 + * Returns the number of characters written into @str. 126 + */ 127 + static int format_delay_ms(unsigned int val, int ndecimals, const char *suffix, 128 + char *str, int size) 129 + { 130 + u64 delay_ms = val; 131 + unsigned int rem = do_div(delay_ms, int_pow(10, ndecimals)); 132 + int ret; 133 + 134 + if (rem) 135 + ret = scnprintf(str, size, "%u%s\n", val, suffix); 136 + else 137 + ret = scnprintf(str, size, "%u\n", (unsigned int)delay_ms); 138 + return ret; 139 + } 140 + 141 + static int delay_use_set(const char *s, const struct kernel_param *kp) 142 + { 143 + unsigned int delay_ms; 144 + int ret; 145 + 146 + ret = parse_delay_str(skip_spaces(s), 3, "ms", &delay_ms); 147 + if (ret < 0) 148 + return ret; 149 + 150 + *((unsigned int *)kp->arg) = delay_ms; 151 + return 0; 152 + } 153 + 154 + static int delay_use_get(char *s, const struct kernel_param *kp) 155 + { 156 + unsigned int delay_ms = *((unsigned int *)kp->arg); 157 + 158 + return format_delay_ms(delay_ms, 3, "ms", s, PAGE_SIZE); 159 + } 160 + 161 + static const struct kernel_param_ops delay_use_ops = { 162 + .set = delay_use_set, 163 + .get = delay_use_get, 164 + }; 165 + module_param_cb(delay_use, &delay_use_ops, &delay_use, 0644); 166 + MODULE_PARM_DESC(delay_use, "time to delay before using a new device"); 74 167 75 168 static char quirks[128]; 76 169 module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR); ··· 1157 1064 if (delay_use > 0) 1158 1065 dev_dbg(dev, "waiting for device to settle before scanning\n"); 1159 1066 queue_delayed_work(system_freezable_wq, &us->scan_dwork, 1160 - delay_use * HZ); 1067 + msecs_to_jiffies(delay_use)); 1161 1068 return 0; 1162 1069 1163 1070 /* We come here if there are any problems */