ManyThings-HOWTO


Nail (nail -at- itapac --dot-- net) || 20 February 2006

0.1 The Hardware

VIA EPIA M6000E (600 Mhz Fanless EDEN Processor)
A 200W ATX DC-DC converter fanless
A 230->12V 60W AC-DC adaptor, fanless
Some lego for a cheap case
256 MB of DDR RAM
A 2.5" 20GB disk with adaptor

A 64 MB USB1.1 PEN
A 160GB external USB2 HDD
A Samsung ML1210 printer

0.2 Installing the OS

we have been using Linux for about 8 years, then i moved to *BSD derivatives, mostly by curiosity. After some try with NetBSD on the 600 Mhz box, i considered the compilations time and some hardware-specific issues and i decided to go for a Debian/Etch Linux with 2.6.15.4 kernel.

Installation has been simple: i momentanously attached a CDROM driver, installed the base system and log out. Next, i did all my work via SSH.

The box doesn't run any X server so my kernel configuration may miss something specific, but the remaining hardware works fine: integrated ethernet, USB2.0 and 1.1 at full speed, audio, VGA, serial port and firewire.

The only exception are the LM sensors, as the driver (vt1211) has never been officially ported to 2.6 kernels. Some brave folks made a port but the 2.6.15 versions simply doesn't work. You can download my .config for a vanilla 2.6.15.4 kernel by clicking here

1.0 USB hot-swapping filesystems

Because the machine will be headless and i want to have to access it the less i can, i have asked myself how to set up USB auto-mounting. The first, very simple, option is to use an hotplug plugin. You can put a script in hotplug directories that handle any USB-storage event but this would mean mounting volumes blindly: a new volume is in, mount it somewhere. Also, there are a lot of vendor codes for USB-storage objects, and the lack of documentation pushed me to think about the next solution.

My goal was to put in a USB device and to have it mounted in a device-specific directory. That is, the 64mb pen would have been mounted always in /usb/pen0 and the 160gb disk in /usb/disk0, or similar. To differentiate and identify modules i decided to use the Serial ID which comes with about every usb-storage device.

Using USB entries in the proc filesystem you can read such information in /proc/scsi/usb-storage/<scsi_id>, where the scsi_id is incrementally assigned every time you plug in a new USB device.

So the idea is: watch the kernel logs for the device id and the scsi id assigned by the scsi layer, check the device serial and mount it somewhere. Unlisted serials should be mounted with names like disk0,disk1,etc..  The kernel logs i are interested in are:

usb 2-2: new full speed USB device using uhci_hcd and address 2
scsi0 : SCSI emulation for USB Mass Storage devices
usb-storage: device found at 2
usb-storage: waiting for device to settle before scanning
  Vendor: 128MB     Model: HardDrive         Rev: 1.11
  Type:   Direct-Access                      ANSI SCSI revision: 02
SCSI device sda: 258048 512-byte hdwr sectors (132 MB)
sda: assuming drive cache: write through
SCSI device sda: 258048 512-byte hdwr sectors (132 MB)
sda: assuming drive cache: write through
 sda: sda1
sd 0:0:0:0: Attached scsi disk sda
sd 0:0:0:0: Attached scsi generic sg0 type 0
usb-storage: device scan complete

Especially, the line saying "device found at 2" notifies us that the device is a USB one , while the line saying "sd x:0:0:0: Attached scsi disk sdy" tells us the scsi host id (that is, the one having an entry in /proc/)) and the scsi disk id. It's worth noting that the log syntax has changed as of kernel 2.6.15, but the code you will find later is able to work with earlier kernels (at least, i tried with debian/etch default one).

So, our /proc/scsi/usb-storage/0 contains:

   Host scsi0: usb-storage
       Vendor: USB
      Product: Solid state disk
Serial Number: 23076000000
     Protocol: Transparent SCSI
    Transport: Bulk
       Quirks:

Now, i can look for our serial number and decide where to mount the disk (we assume that external disks have only one partition. The work can be done using this python script (storage-automount)

The script is a standalone deamon that reads the kernel logs from a FIFO and get input a configuration file telling it where to mount the varioius serial ID.However, it does more. Read next section to understand what storage-automount does at all.

1.1 NFS Exporting hot-plugged filesystems

Remembering our goal, i wanted hot plugged filesystems to be shared to a FreeBSD or Linux system. There are a lot of network filesystems in the linux kernel, but only one isn natively supported on FreeBSD too: NFS (v3,for simplicity).

Sharing a mounted filesystem i want to appear as it is mounted and disappear when unmounted via NFS is pretty a pain in the you_understood_where. We don't talk about basic NFS deamon setup, as the NFS howto can do this; instead, i suppose NFS just works.

The first problem is: mounted filesystems in NFS exported subdirectories aren't exported by default. This issue can be solved by adding the nohide,no_subtree_check options to your export. However, as the man page says, nohide works only on a per-host export, thus, if you want to export it for an entire subnet you need one export entry per host. No extra way.

Second: if you mount a filesystem and you want to share it, you must put an explicit export entry for the mounted directory. So, each time you plug in a device, you have to mount and then export it. These exports do not need nohide, so you can put a classwide share.

Third: external disks are likely to be VFAT filesystem and shared in a closed enviroment (your house). To let any user from any host write and read files without permission problems, you can add all_squash,anonuid=XXXX,anongid=YYYY to the export entry, to ignore remote user info and use a single user. This will help us with samba too.

Fourth: depending on your client configuration, a common problem with BSD derivatives such as FreeBSD and MacOSX is a "poor write performance" over NFS. This is mainly due to the share exported with the sync default behaviour. You can put async to achieve higher speeds, however this can lead to (rare) data corruption, as writes are acknowledge before being effectively processed. The choice is yours.

Fifth: let's suppose to generally export /nfs/ and to have /nfs/DISK0/ containing our pendrive contents. To unmount it, you have to unexport it before. This involves changing the NFS entries, and it is bad. Especially, you cannot put a new export entry with the same name, as this will stale the NFS entry and force the remote system to remount the root share. To solve this, you have to use one-time shares, by generating a new univoke directory and share name each time i mount a disk. A choice for the name may be the disk id, however, to cut the problem, i decided to use system time.

storage-automount (see above) does this for us. Also, it makes a link with the original disk name syntax (e.g. DISK0) to the new one-time share. The next section contains how to configure it.

1.5 Setting up storage-automount

The script is, at the moment, a bit rustic. That is, no big configurations options or standard formats. Not being a python guru, i just did all by hand.

At first, you must create the FIFO storage-automount uses to read kernel logs. Create the pipe by running mkfifo /var/log/kern_fifo and then add the following line to your syslog.conf:

kern.debug;kern.info    |/var/log/kern_fifo

killHUP syslogd and you are ok. Next, you have to write a storage-automount configuration file. The syntax is very simple. It is a line-wise text file where comment lines begin with # and all the others are considered configuration entries.

Each line, except the default one, contain three items, separated by a tab. The first entry is a prefix that the device serial number must match. That is, you can write the serial number itself or just put the initial digit if you are lazy.
The second entry is the disk mounted name. Please avoid using DISKx because it is reserved for unnamed entries. You can put any alphanumeric string here, and it will appear in the NFS share as the link pointing to the one-time share. You can also put a dash (-) to let storage-automount autonaming.
The third entry is a filesystem type indication. Possible entries are "auto" or "vfat" or any known filesystem type. You can also put a "NONE" (uppercase) to forbid the share mounting.
If you want to put a catch-all entry getting all unlisted serials, you can use "*". Please remember that the file is read in the writing order so a misplaced catch-all may create inconsistent behaviours.
This is an example file:

# An example file
030001EC9F30   PASTA vfat
1	ONE	auto
*       -

To let the shares properly work, create two directories: /usb/ and /nfs/ (you can change their name in the script, if you don't like them). Then open your /etc/exports file and share the /nfs directory using at least the nohide,no_subtree_check options writing a share per host. Remember to use exportfs to make the changes effective.

Here it is an example:

/nfs    172.19.15.1(rw,all_squash,anonuid=1002,anongid=1002,async,nohide,insecure,no_subtree_check)
/nfs    172.19.15.2(rw,all_squash,anonuid=1002,anongid=1002,async,nohide,insecure,no_subtree_check)
/nfs    172.19.15.3(rw,all_squash,anonuid=1002,anongid=1002,async,nohide,insecure,no_subtree_check)

The last step consists in editing the script itself. Locate the lines signed with a CHANGE IT and follow the script instructions.
You can now run the deamon as root when the host boots up. The command line syntax is storage-automount <kernel_fifo> <disk configuration path>. So:

/usr/local/sbin/storage-automount /var/log/kern_fifo /etc/automount.conf

If nothing has gone wrong, by adding the USB disk we called "PASTA" before, you will find: an export entry for the directory (use showmount -e), a directory with a numeric name in /nfs/disks/, linked by /nfs/PASTA, and a directory in /usb/ named PASTA. The latter directory should contain the filesystem contents and the /nfs/PASTA/ directory contents should be visibile from a NFS mounting host.

1.6 Unmounting storage

Another simple python script is storage-umount