2

I'm trying to build a simple "appliance"-type device running a minimal Linux and some custom code. Part of the functionality I am offering is that the user can attach a USB flash drive or hard drive to a specific USB port and the device can write data to a filesystem on that device.

This question has two parts:


#1: How can I determine the actual block device file for the USB mass storage device which has been attached to one specific hardware USB port?

Simply assuming that the USB storage device will always be at /dev/sdb seems a bit risky, because suppose a user connects a hub to the port, or suppose you get a device with multiple endpoints (e.g. a card reader). Also, suppose the device reboots or starts up with a USB device in the USB port and for whatever reason the system decides to make the USB device /dev/sda and the internal storage /dev/sdb. (It is conceivable that the boot medium for this device will be USB as well, so that makes this quite likely.)

So what I basically want to be able to do is say "Give me the device file (like /dev/sdb) for the USB mass storage device at this specific USB port." If multiple block devices are found on one port, I would like an "array", or a list of all of the endpoints specific to that single device.

For the instance that someone attaches a hub to the port and connects multiple flash drives to that hub, I'd be ok with either 1) nothing showing up at all (and telling users that hubs are not allowed and they should only simply directly attach), or 2) getting a list of all block devices connected to the hub (similar to a multi-endpoint device).

Also obviously if someone attaches a non-storage device to that port, whatever method I come up should not give a storage device node.


#2: What is the best practice to mount a filesystem such so that it can be safely removed without first unmounting it as long as no writes are occurring?

Obviously users will be told to never remove the device while its light is flashing, etc. However, requiring a user to go through a manual unmount process could be a bad UX for this appliance. (It will have a very minimal UI, so implementing a safely-remove-hardware option that is easy to access and use would be challenging.) Basically, the user should be able to pull their drive out as soon as it is visually obvious that no more writing is occurring.

Obviously, most devices connected will be vfat. I'd like to also support ntfs (via ntfs-3g) and exfat (via exfat-fuse).

I could simply issue syncs whenever I write data in my own code, but one use case is an external app which streams data to the USB device in chunks. Think data logger. A file is created and data is streamed to it in chunks, but between each chunk it should be acceptable for the user to pull the drive when it is between writes, have the system detect it and cleanly stop data logging, and have the drive structure be safe.

Also once the device is pulled, I need to be aware of it quickly so my code can remove the mount and stop any operations that might be expecting to see the drive.


I know I'm asking a lot to allow users to just pull drives at will, and obviously if a user pulls a drive during a write this will be a problem, but I do want to allow at the very least the closest to this holy grail that I can.

Ideas?

  • Does this device have a screen and keyboard for you to ask the user for a device file? Can't you simply have a single USB port on your device? If you're building the machine, can't you put a button to act as an eject button? – Julie Pelletier Dec 31 '16 at 22:39
  • BTW: You really ought to only ask one question at a time; it's quite possible someone only has an answer to one or the other, and would be hesitant to answer. It's fine to ask two questions and link the two together (ask one, ask the second with a link to the first, edit the first to link to the second). – derobert Jan 1 '17 at 0:05
3

For (1), I'd suggest looking at udisks—they've solved a lot of this for you already. Including such things as "what happens if the user plugs in two storage devices?" (remember: USB hubs, and of course some devices present themselves as multiple). udisks lets you easily find the available devices, be notified when one becomes available (or is removed), check various device attributes, etc. It'll also handle mounting for you—including supporting a wide variety of filesystems.

For (2), if possible I'd unmount the device between writes. If not, you could mount it sync and/or dirsync mode, that should help—that should keep the filesystem in a consistent state between writes. Also, if you write to pre-allocated space, that'll often involve no (or at least minimal, mtime only) filesystem metadata changes. (When you create the log, write 10MB of zero's; then seek back to the beginning and stream your data to it. When you hit 10MB, create another log. Only the infrequent create operation really risks filesystem corruption.)

As Julie Pelletier noted, though, some sort of eject button would be preferable.

Also, as a side note, if you can have the external app write its data to a pipe (including a named one created with mkfifo) then your code can read from the pipe and handle the actual write to USB. The same applies if you have the external app write to a temporary file on a tmpfs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.