I've been using Linux for a while, but only since I started using "recent" distros (ie.: anything non-Debian) I have started having I/O problems with most of my USB devices. Basically when trying to write any nontrivial amount of data into them the lose connection and or reboot themselves. In the system log I observe these kinds of messages:
kernel: usb 1-7: reset high speed USB device using ehci_hcd and address 2
kernel: usb 2-1: device descriptor read/64, error -71
kernel: usb 2-4: new high speed USB device using ehci_hcd and address 13
This happens with both "pendrives" and USB-connected hard drives. I can not find any useful pattern to detecting which devices will bork and which won't except perhaps size - I've never had 1 or 2 GB pendrives bork with these messages (but then again, no one sells those anymore).
When those errors happen, pending reads to drive get locked, also locking whatever program was doing the work until I physically unplug the drive. Of course, after I reconnect the drive, I find files or partitions corrupted, thus losing me a lot of work and forcing me to some other work.
Researching around I've found links in places such as the ArchWiki or the SUSE Forums or even this very community indicating that the culprit is the default value of the USB tree attribute max_sectors
which specifies how much can be read or written to a USB drive in one go. Any more than what the drive supports and the device resets or crashes. I've found mentions that the value is too high in Linux (240
) compared to old kernels or Windows installs (128
or even 64
) which of course don't face this problem.
Since I value data integrity more than "blinding" speed (and I hope most people do!) I'd like to somehow change the max_sectors
value for "any" USB storage device where the meaning of "any" could be ample enough that I can avoid having to write custom commands or rules for the most part. Unfortunately, look where I try I haven't been able to find any configuration line or kernel boot option that can change this value (unlike, say, USB autosuspend).
What have I missed or what can I do next? I know that I can write something like the following in a more or less automatic using the udev
system, something like this:
SUBSYSTEMS=="usb", DRIVERS=="usb-storage", ATTRS{manufacturer}=="Some Company", ATTRS{serial}=="xxxxxxxxxx", ATTRS{max_sectors}=="240", ATTRS{max_sectors}="128"
And then reload or reboot the service, but I have not been able to find a generic enough udev
rule that would fit as many devices as possible (so long as they are connected via a USB plug). I have the understanding that I can write more specific rules for devices whose max_sectors
I want to restore or preserve, but here I'm only interested in a sort of wildcard.
I have tried wildcard in some attributes, such as ATTRS{manufacturer}=="*
"
to no avail.
What is a generic udev
rule that can match me as many USB-plugged devices as possible? Is this even the "correct" way of handling this issue via software? (unloading USB 2.0 modules -as eg.: Ubuntu Forums suggest- seems to be not an option, as at least Fedora seems to have them integrated to the kernel).
EDIT: As suggested by frostschutz, I'm using RUN+=
to set up the attribute, which actually works (unlike using ATTR=
). That's half a solution. I've been able to create a udev rule that matches pretty much everything, but I fear it matches too much.
SUBSYSTEMS=="usb", DRIVERS=="usb-storage", \
RUN+="/bin/sh -c 'echo 64 > /sys/block/%k/device/max_sectors'"
The problem with this rule is that it'll set max_sectors
for everything, including devices that have a lower value than 64. I've tried to make it more specific:
SUBSYSTEMS=="usb", DRIVERS=="usb-storage", ATTRS{max_sectors}=="240", \
RUN+="/bin/sh -c 'echo 64 > /sys/block/%k/device/max_sectors'"
But this doesn't work. I think I'm using the correct scope for udev rules (use attributes from one part of the tree and from one parent). What am I doing wrong?
EDIT2: Accepted the answer below. As it turns out, RUN+=
does the trick, whereas using ATTRS{…}=
for some reason doesn't. Also, the reason why I couldn't get to make a generic rule work was because I had misunderstood from the udev manpage. A rule must have at most attribute from one parent - that means if I want to use two sections, the second one must be the actual dvice. These two work mostly perfectly:
SUBSYSTEM=="scsi", ATTRS{max_sectors}=="240", \
RUN+="/bin/sh -c 'echo 64 > /sys/block/%k/device/max_sectors'"
(note the singular for the attribute, first attribute is from the actual USB device and second one from a singular ancestor at the device tree)
SUBSYSTEMS=="usb", DRIVERS=="usb-storage", ATTRS{max_sectors}=="240", \
RUN+="/bin/sh -c 'echo 64 > /sys/block/%k/device/max_sectors'"
(this one uses two attributes from the same ancestor at the device tree)
Also You can do the following: (use == to check, and = to assign):
SUBSYSTEM=="scsi", ATTRS{max_sectors}=="240", ATTRS{max_sectors}="64"
On my system (Mageia 4, 3.14.24 core i7) I had to do the opposite due terribly slow write speeds (2MB/sec) on Kingston DT101 G2 16GB: vi /usr/lib/udev/rules.d/81-udisks_maxsect.rules and add:
SUBSYSTEMS=="scsi", ATTR{max_sectors}=="240", ATTR{max_sectors}="32678"
And the dd write speed went up 3x times :-) mc cp probably 10-20x up (after I had started first partition @8192'th sector and reformatted with 64k aligned clusters): mkfs.vfat /dev/sdh1 -n KINGSTON16G -s 128 -R 4592 and use fsck.vfat -v /dev/sdh1 to check alignment Default mas_sectors (240) seem to cause high write amplification on some of the cheap new drives. But be very careful with such high setting, the similar effect is achieved at 2048 sectors:
SUBSYSTEMS=="scsi", ATTR{max_sectors}=="240", ATTR{max_sectors}="2048"
Test all yours old USB devices, that they still work well. Use vendor/model attributes in the rules files to be more specific.
max_sectors
manually for every device I plug does help a lot hence I'm trying to genericize the solution. Also yes, live CDs do work wonders! – Luis Machuca Mar 13 '13 at 00:41