2

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.

4
  • In Fedora, using largeish pendrives (up to 16GiB) and a 350GiB hard disk in an enclosure have never given me such problems. Check that the hardware (pendrives, USB port) are OK (might as well use a "non-recent", i.e., Debian ;-) LiveCD.
    – vonbrand
    Commented Mar 12, 2013 at 23:47
  • Does the max_sectors actually help? No point finding a way to automate this setting if it does not actually resolve the issue. Commented Mar 13, 2013 at 0:25
  • Changing 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! Commented Mar 13, 2013 at 0:41
  • 1
    Regarding the recent edit adding the section starting "Also You can do the following:" - it looks at this should be an answer - could you please add that as an answer and edit it out of the question again? (But I'm not sure it can be easily separated, because there were partly answering edits before - maybe it's hard to separate - in this case, an answer with a short summary of the edits refering there for details would be good) Commented Feb 4, 2015 at 18:37

1 Answer 1

0

Sounds like a hardware issue you should go and fix. Powered USB Hub (if it's a power supply related issue), different USB cables, no front panel, a different USB controller (addon card), ...

If it stays unreliable, an option would be using the sync mount option for USB media. That way no caching is done whatsoever, but you will see a big impact on performance as a result. Also (for flash drives) a possibility of extra writes (like if you create a file and immediately delete it, with async it would never be written in the first place, whereas sync always writes everything immediately).

6
  • Changing the hardware is not really an option, at least for the laptops I use, and what's more I sometimes use these systems on the field due to work, so eg.: no external power sources. Hence why I'm looking for a software solution. Generically adding a sync option to the automounts seems a sensible option, aI don't really bother about speed loss; but then again how do I write a generic rule that does that? Commented Mar 13, 2013 at 0:38
  • External power source could be as simple as another battery pack. The ones usually used for charging phones or MP3 players on the go. Also, Y-USB-Cable to use an extra USB port for power. On the off chance that a single port doesn't give enough juice. Commented Mar 13, 2013 at 5:13
  • 1
    For the udev rule, if all else fails you can use BUS=="scsi", RUN+="/bin/bash -c 'echo 64 > /sys/block/%k/device/max_sectors'" or something. Attributes would be alot nicer of course, if that works at all. For automounting, no idea, not using that anywhere, good old mount-it-yourself for me... sorry. Search/Make a separate question about it? Commented Mar 13, 2013 at 5:17
  • Using RUN+= instead of ATTR works wonders as the value is actually written to the tree. Thanks. Now I've fell into the problem of writing an overgeneric rule, see updated edit. Commented Mar 13, 2013 at 13:54
  • It's possible that you can see some attributes only for a scsi subsystem rule. But if you're going to do a run anyway, you can just as well outsource your checks to there [ $(<max_size) == "240" ] && echo .... (Somehow this question turned into chaos xD) Commented Mar 13, 2013 at 17:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .