Home
Tuesday, October 21, 2014
2:41:13 PM
Users online: 0   You are here >> Home > Open Source OS

Forums | Open Source OS Forums search
Forum FAQ
   
  1  
Guide: Using Udev Rules to achieve static mount points for Removable Drives under Linux
bnew 
6/2/08 3:23:30 PM
Guru

Using Udev Rules to achieve static mount points for Removable Drives under Linux

*Disclaimers:

-I certainly don’t consider myself a linux expert
-There may be other/better ways to achieve what I’ve done here- I’m just a lowly sys admin that does what works ;)
-The below glosses over quite a lot of details in some ways, and only scratches the surface in regard to what you can do with udev and related concepts. Check out the further reading links or do your own research if interested
-If something bad happens due to you following any of the examples / suggestions below, don’t come crying to me. I wanted to document what worked for me for my own personal records, I just thought I’d share it with Atomic in case it helps someone else. Your mileage may vary.
-If you have any suggestions / comments / corrections, please let me know and I’ll update the first post when I’m able.

*Aims:

-Ensure proper mounting and unmounting of drive occurs
-Ensure that said mounting / unmounting occurs automatically when drive is added / removed.
-Ensure that drive is always mounted to a fixed mount point, for the purposes of scripting etc.

*Introduction:

Typically, Linux assigns mount points in /dev automatically, in a somewhat ‘first some first served’ approach. This is usually fine for devices that are static, such as system drives in a server, but it can play havoc in other circumstances. By using Udev and appropriate Fstab entries, it is possible to ensure that removable drives under linux are consistently mounted to the same mount points (or have consistent symbolic mount points that amount to the same thing). This can apply to a wide range of devices such as digital cameras, USB hard drives, hot swappable SATA drives and so on.

There are many applications for having predictable mount points for these kind of devices. In my particular case, I have two servers that I want to backup, and then be able to take the backup home (to provide offsite redundancy). One server has a hot-swappable SATA caddy with a 500GB drive installed, and the other has a 100GB Maxtor One-Touch USB drive. Using Rsnapshot ( http://www.rsnapshot.org/) I need to be able to refer to a specific mount points in the configuration files so that the backups I have scheduled will complete.

The following details how the two servers were set up to achieve this. Note- both servers in question are running SuSe 10.2 with a 2.6.x.x kernel:

*Server 1- Hot swappable SATA drive

Step 1: Use Udev to gather information about the drive that can be used when writing Udev rules

-Look in /dev (ls /dev) before and after you plug in the drive, to see what mount point linux assigns to it. On my system, it is assigned to sda (I’ll continue to use this for the rest of the examples)
-Run the Udev info command to gather the required information:
 
udevinfo -a -p $(udevinfo -q path -n /dev/sda)

-Save the resulting output somewhere for later use

Step 2: Create the Udev rules

- Create a new rules file in your Udev folder:
 
vim /etc/udev/rules.d/10-local.rules

- Refer to the output saved from step one. You want to create two rules: one for the adding of the drive and one for the drive removal. A few things of note with the Udev rules:

-The aim with the Udev rule is to identify the device you want the rule to apply to using unique information about that device (gathered from the udevinfo command), and then specifying what action you want taken with the device
-A carriage return (new line) is read as the start of a new rule, so don’t manually begin a new line unless you want to finish the rule you have written and start writing another one
-You many have noticed that the output from running the udevinfo command is in distinct ‘chunks’. For example:

 
looking at parent device'/devices/pci0000:00/0000:00:1d.7/usb5/5-5/5-5:1.0/host20/target20:0:0':
KERNELS=="target20:0:0"
SUBSYSTEMS==""
DRIVERS==""

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb5/5-5/5-5:1.0/host20':
KERNELS=="host20"
SUBSYSTEMS==""
DRIVERS==""

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb5/5-5/5-5:1.0':
KERNELS=="5-5:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="usb-storage"
ATTRS{modalias}=="usb:v0D49p7110d0203dc00dsc00dp00ic08isc06ip50"
ATTRS{bInterfaceProtocol}=="50"
ATTRS{bInterfaceSubClass}=="06"
ATTRS{bInterfaceClass}=="08"
ATTRS{bNumEndpoints}=="03"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceNumber}=="00"



Above is a cut-down extract from the udevinfo output, showing 3 distinct ‘chunks’ of device information. The important thing to remember when choosing what information to use when identifying the device is that you must only use data from one chunk. For example:
 
SUBSYSTEMS=="usb"
DRIVERS=="usb-storage
ATTRS{bInterfaceProtocol}=="50"

The above three bits of information are all from the third ‘chunk’ and thus could be used in a rule (note- you would usually aim to use information that is more likely to be unique, such as the device model or serial number). Whereas:
 
DRIVERS=="usb-storage”
ATTRS{bInterfaceProtocol}=="50"
KERNELS=="host20"

The above contains some information from the third chunk, and some information (KERNELS=="host20") from the first chunk- thus it isn’t a valid rule.

-The following is the contents of my 10-local.rules file. It contains two rules- one for when the drive is connected, and one for when it is disconnected:
 
SUBSYSTEMS=="pci", DRIVERS=="pcieport-driver", SYMLINK+="bakhdd", ACTION=="add", RUN+="/etc/udev/scripts/mount_hdd.sh"
SUBSYSTEMS=="pci", DRIVERS=="pcieport-driver", ACTION=="remove", RUN+="/etc/udev/scripts/unmount_hdd.sh"

-In the first line (rule 1):

-SUBSYSTEMS=="pci", DRIVERS=="pcieport-driver" - these are two fields from a chunk of the output I got after running udevinfo, and are used to uniquely identify the SATA hot-swap drive (as previously noted, you would usually aim to use something like the device serial number to identify the drive, but in my case udevinfo didn’t find one, so I had to look for other ways- no other drive on the system uses the driver listed, so that was the best option for me)
- SYMLINK+="bakhdd" - tells udev to assign this drive a symbolic link (or symbolic mount point) with the name specified (‘bakhdd’). In other words, it doesn’t matter what linux assigns to the drive, there will always be a “bakhdd’ entry in /dev that can be referred to
-ACTION=="add", RUN+="/etc/udev/scripts/mount_hdd.sh" - tells udev that when it detects the drive is added, run the specified script (more on this later).

-In the second line (rule 2):

-SUBSYSTEMS=="pci", DRIVERS=="pcieport-driver" - as with rule 1, specifies the drive in question using fields from a chunk of the udevinfo output
- ACTION=="remove", RUN+="/etc/udev/scripts/unmount_hdd.sh" - tells udev that when it detects the drive is removed, run the specified script

Step 3: Create the scripts to be run by udev

As you will have noticed from Step 2, the udev rules refer to two scripts. One is run when the device is connected (ACTION==”add”) and one is run when the device is disconnected (ACTION==”remove”). In my case, these are ultra simple, one line bash scripts that just run the ‘mount’ and ‘umount’ commands respectively. Create the /scripts folder, and create two files like so (make sure they are set to executable, of course):

mount_hdd.sh
 
#!/bin/sh
# Mount drive on udev 'ACTION==add'
mount /dev/bakhdd /backups

unmount_hdd.sh
 
#!/bin/sh
# Unmount drive on udev 'ACTION==remove'
umount /backups

As you can see, the scripts simply do the same thing as would happen if you were to manually mount/unmount the drive, except that it happens automatically when the drive is connected / disconnected. You could easily have scripts that do other things though.

Step 4: Add the fstab entry

In some ways, this step may or may not be redundant, depending on your exact configuration. With my tested-and-working-fine set up, I have added entries to the fstab. If anyone can shed some more light on this area, it would be appreciated.

-Edit the /etc/fstab file and add the following line:
 
/dev/bakhdd /backups auto rw,user,noauto,sync 0 0

For a good guide on all things fstab, have a look here:

http://www.tuxfiles.org/linuxhelp/fstab.html

As mentioned, I’m still not 100% sure on the relevance/significance to what I’m dong with the udev stuff. It does work though.

Step 5: Testing

With most recent kernels, you should be able to make udev rule changes and have those changes update on the fly. If you have problems with not seeing the results of changing the rules, you might want to try running ‘udevtrigger’ and ‘udevcontrol reload_rules’

That’s pretty much it. Do some testing to ensure that the drive properly mounts/unmounts, and write /read some files to it.

*Server 2- Maxtor Onetouch USB drive

The process for this drive is exactly the same as described in the steps for server 1, other than the fields used in the udev rules. I’ll just briefly go through the steps again:

First, get the udev data for the drive:
 
looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb5/5-5':
KERNELS=="5-5"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{configuration}==""
ATTRS{serial}=="B248W1YH "
ATTRS{product}=="OneTouch II"
ATTRS{manufacturer}=="Maxtor"
ATTRS{maxchild}=="0"
ATTRS{version}==" 2.00"
ATTRS{devnum}=="20"
ATTRS{speed}=="480"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{bNumConfigurations}=="1"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceClass}=="00"
ATTRS{bcdDevice}=="0203"
ATTRS{idProduct}=="7110"
ATTRS{idVendor}=="0d49"
ATTRS{bMaxPower}==" 0mA"
ATTRS{bmAttributes}=="c0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bNumInterfaces}==" 1"

The above is just one ‘chunk’ from the udevinfo output, but as you can see we have struck gold- udev finds both a serial number and product name. Excellent candidates for the udev rules.

Next, create the rules. As this is on a separate server, the rule file needs to be created again:
 
SUBSYSTEMS=="usb", ATTRS{serial}==" B248W1YH", ATTRS{product}=="OneTouch II", SYMLINK+="bakhdd", ACTION=="add", RUN+="/etc/udev/scripts/mount_hdd.sh"
SUBSYSTEMS=="pci", DRIVERS=="ehci_hcd", ATTRS{class}=="0x0c0320", ATTRS{subsystem_device}=="0x0162", ACTION=="remove", RUN+="/etc/udev/scripts/unmount_hdd.sh"

Note with the above: Initially, I tried to write the rules exactly the same as I had for the SATA drive- using the same fields for both the ‘add’ rule and the ‘remove’ rule. However, this didn’t seem to work for the Maxtor- the ‘add’ rule worked perfectly but the remove rule didn’t seem to work. After a bit of playing around, I found that using fields from a different chunk of udevinfo output solved the problem. So, if you have issues, try using different fields.

Creating the mount / unmount scripts- exactly the same as before

Add the fstab entry- again, same as before.

Now test away, and you’re done.

*Results:

Both removable drives now function well. On either server, I can plug in the removable drive and it will mount to the /backups folder, using the bakhdd symlink. In my backup scripts, I can refer to /backups knowing that, as long as the drive in question is plugged in and turned on, the backup will happen properly. Once done, I can remove the drive in question, and the /backups folder and related /dev entries are removed cleanly.

So that’s it. Hope that’s of some use to some other people out there in linuxland.

*References / further reading:

http://www.linuxquestions.org/questions/linux-general-1/make-removable-usb-hdd-mount-at-fixed-mou
http://reactivated.net/writing_udev_rules.html
http://linux.die.net/man/8/udev
http://www.tuxfiles.org/linuxhelp/fstab.html



Edited by bnew: 6/2/2008 3:26:49 PM


Edited by bnew: 6/2/2008 5:13:20 PM


Edited by bnew: 6/2/2008 5:16:35 PM

-----

bnew 
13/2/08 9:26:52 AM
Guru

lol, I guess no-one has much to say about this. Ah well, let me know if it does prove useful for anyone.

-----

  1  
Forums | Open Source OS