USB storage howto
1. Intro
It's useful to extend the storage capacity of your USB enabled Wrt router f. e. making a central file server. This can easily be done with connecting USB storage devices (like a USB stick or a external USB harddisc) to the USB port on your router.
2. Requirements
Supported router by OpenWrt with USB (f. e. the Asus WL-500G or the Asus WL-500G deluxe)
a recent OpenWrt version installed (at least White Russian RC3)
- some kind of a USB storage device (a USB stick or a external USB harddisc) supported by Linux
- a USB hub (optional) to add more USB ports (it's probably a good idea to use an active USB hub with it's own PSU)
NOTE: Devices supporting USB v2.0
3. Installation
TIP: Some routers are USB 1.1 and 2.0 compatible. To use both devices with both versions install the modules for USB 1.1 and 2.0.
3.1. Modules for USB 1.1
For USB 1.1, try installing the UHCI drivers first:
ipkg install kmod-usb-uhci insmod usbcore insmod uhci
If you see the message:
insmod: init_module: uhci: No such device
then your hardware does not have a UHCI compliant device, so you might as well remove the package:
ipkg remove kmod-usb-uhci
TIP: Most USB chips have UHCI controllers. If you received a "No such device" error, then try installing the kmod-usb-ohci package instead. The BCM4710 and BCM4712 based routers require kmod-usb-ohci:
ipkg install kmod-usb-ohci insmod usb-ohci
If you see the message:
insmod: init_module: usb-ohci: No such device
then your hardware does not have a OHCI compliant device, so you might as well remove the package:
ipkg remove kmod-usb-ohci
3.2. Modules for USB 2.0
This package includes the modules for USB 2.0.
NOTE: USB 2.0 support in White Russian is broken. There are some threads in the forum and some tickets as well if you like to read about what happens. (Im using WR 0.9 on an ASUS WL-500g Premium and USB 2.0 works just fine)
ipkg install kmod-usb2 insmod ehci-hcd
If you see messages like this:
insmod: unresolved symbol usb_calc_bus_time
try loading usbcore and then try ehci-hcd again:
insmod usbcore insmod ehci-hcd
3.3. Modules for storage
To add storage support finally install
ipkg install kmod-usb-storage insmod scsi_mod insmod sd_mod insmod usb-storage
3.4. Clean up
TIP: The max_scsi_luns=8 bit is needed for multi-card readers and should be added to the end of the scsi_mod line in the /etc/modules.d/60-usb-storage file.
OpenWrt uses /etc/modules.d directory to load the modules automatically on the next reboot. So reboot the router with
reboot
Now check if OpenWrt sees your USB device (of course inserting it into your Wrt router). If it's correct you should see similar messages as on the dmesg dump below.
dmesg
usb.c: registered new driver usbdevfs usb.c: registered new driver hub uhci.c: USB Universal Host Controller Interface driver v1.1 PCI: Enabling device 01:02.0 (0000 -> 0001) uhci.c: USB UHCI at I/O 0x100, IRQ 2 usb.c: new USB bus registered, assigned bus number 1 hub.c: USB hub found hub.c: 2 ports detected PCI: Enabling device 01:02.1 (0000 -> 0001) uhci.c: USB UHCI at I/O 0x120, IRQ 2 usb.c: new USB bus registered, assigned bus number 2 hub.c: USB hub found hub.c: 2 ports detected hub.c: new USB device 01:02.0-2, assigned address 2 usb.c: USB device 2 (vend/prod 0xd7d/0x100) is not claimed by any active driver. Initializing USB Mass Storage driver... usb.c: registered new driver usb-storage scsi0 : SCSI emulation for USB Mass Storage devices Vendor: Apacer Model: Drive Rev: 1.05 Type: Direct-Access ANSI SCSI revision: 02 Attached scsi removable disk sda at scsi0, channel 0, id 0, lun 0 SCSI device sda: 256000 512-byte hdwr sectors (131 MB) sda: Write Protect is off Partition check: /dev/scsi/host0/bus0/target0/lun0: p1 WARNING: USB Mass Storage data integrity not assured USB Mass Storage device found at 2 USB Mass Storage support registered.
4. Configuration
4.1. Usage as a storage device to extend storage
First install the kernel file system modules, for example:
ipkg install kmod-vfat
Under Kamikaze 7.07 or later, use
ipkg install kmod-fs-vfat
TIP: After installing the modules, you should either reboot the device or load the installed modules manually:
insmod fat insmod vfat
TIP: You can install support for more file systems by installing the appropriate packages.
File system |
Package name |
Comment |
VFAT/MSDOS |
kmod-vfat (kmod-fs-vfat) |
File system generally used in USB devices and older Windows |
EXT2 |
kmod-ext2 (kmod-fs-ext2) |
|
EXT3 |
kmod-ext3 (kmod-fs-ext3) |
|
Now install the fdisk package from the White Russian's backports repository. How to use the backports repository see OpenWrtDocs/Packages.
ipkg install fdisk
TIP: If you don't find fdisk in the rc6 backports repository, you can use the rc5 backports version:
ipkg install http://downloads.openwrt.org/backports/rc5/fdisk_2.12r-1_mipsel.ipk
Create the/mntdirectory for the mount point on the flash
mkdir /mnt
Check what partition you like to mount from your USB device
fdisk -l
Finally you can mount and use your USB device (with relevant modules for your file system in memory and created directory for mount):
mount /dev/scsi/host0/bus0/target0/lun0/part1 /mnt
Be happy and use your USB device like on every other GNU/Linux system or create a file server using Samba.
If you go with ext2 with journaling and install kmod-fs-ext2 , kmod-fs-ext3 and e2fsprogs you can use it like a normal unix type disk. Create the script /etc/init.d/usbdrive ( changing the mount point to match yours )
#!/bin/sh /etc/rc.common
START=99
STOP=40
start()
{
echo -n "Testing USB Partition: "
e2fsck -p /dev/scsi/host0/bus0/target0/lun0/part1 &
sleep 5
echo -n "Mounting USB drive: "
mount -t ext3 -o noatime /dev/scsi/host0/bus0/target0/lun0/part1 /usb
echo "Done."
}
stop()
{
echo -n "Umounting USB drive: "
sync
sync
umount /dev/scsi/host0/bus0/target0/lun0/part1
echo "Done."
}
restart()
{
stop
start
}
then do a ./usbdrive enable
You may need language packages to support the filenames on various file systems:
kmod-nls-base - Kernel modules for basic native language support
kmod-nls-cp437 - Kernel module for codepage 437
kmod-nls-cp850 - Kernel module for codepage 850
kmod-nls-iso8859-1 - Kernel module for iso8859-1 charset support
kmod-nls-iso8859-15 - Kernel module for iso8859-15 charset support
kmod-nls-utf8 - Kernel module for utf8 support
4.2. How do I boot from the USB device (prep)
For this to work you need the same kernel modules for USB as described above. You also need the modules for the EXT3 file system:
NOTE: IMPORTANT: There are reports that this procedure bricks routers running Kamikaze with 2.6 kernel - proceed at your own risk! (It works for some, not for others)
ipkg install kmod-ext2 kmod-ext3
After installing the modules, you should either reboot the device or load the installed modules manually:
insmod ext2 insmod jbd insmod ext3
The next step is to partition the USB device and create an EXT3 FS partition. This requires fdisk (install it as described above). You can do the partioning in OpenWrt it self or on a normal PC.
In OpenWrt do
fdisk /dev/sda -OR- fdisk /dev/scsi/host0/bus0/target0/lun0/disc
On a GNU/Linux desktop PC do
fdisk /dev/sda
IMPORTANT: Make sure you are modifying the right device. If you have any other USB drives, or a SCSI or SATA drive, your USB device might be at /dev/sdb or /dev/sdc (and so on) instead! Also, you do not want to use a partition such as /dev/sda1 (note the number at the end); you do want the base device name.
For more information about using fdisk, see http://www.tldp.org/HOWTO/Partition/fdisk_partitioning.html.
Next, "format" the newly created partition.
In OpenWrt do
For doing this in OpenWrt you first have to install the e2fsprogs package from the White Russian's backports repository. How to use the backports repository see OpenWrtDocs/Packages.
ipkg install e2fsprogs
Then "format" your partition with
mke2fs -j /dev/scsi/host0/bus0/target0/lun0/part1
mke2fs may fail on large disks (e.g. 300GB) if there is not enough memory, consider adding a swap partition, even if it is only used during mke2fs.
If you keep getting errors like:
Creating journal (4096 blocks): mke2fs: No such file or directory
while trying to create journal
then run the following command:
ln -s /proc/mounts /etc/mtab
Now, we will copy everything from the flash to the USB device (make sure the EXT3 modules are loaded):
# mount it mount -t ext3 /dev/scsi/host0/bus0/target0/lun0/part1 /mnt # now, we need to mount the root contents somewhere so we can copy # them without copying /mnt and /proc to the new usb device mkdir /tmp/root # if you're using squashfs, you want to copy the squashfs contents, # not the jffs2 symlinks, so use the command: mount -o bind /rom /tmp/root # if you're using jffs2 then use the command / mount -o bind / /tmp/root # now /tmp/root contains the root filesystem with no extra directories mounted # so we just copy this to the usb device cp /tmp/root/* /mnt -a # and now we unmount both the usb and our /tmp/root umount /tmp/root umount /mnt
Problems with booting from USB storage were reported with WhiteRussian RC4 or later, which is the version that introduced USB hotplug support. If you encounter problems as well, try disabling USB hotplug. (more info on this?)
As earlier stated on this page (to remove /etc/hotplug.d/usb/01-mount) is NOT a good idea, as this is where usbfs is mounted, so usb-storage might work fine but lsusb wohn't list your devices, and most software using USB won't be able to find devices since /proc/bus/usb will remain empty?
So either remove the file and mount usbfs somewhere else, or everything inside except the line which goes: [ -f /proc/bus/usb/devices ] || mount -t usbfs none /proc/bus/usb
4.3. Boot Configuration - (White Russian)
Next, remove /sbin/init from the JFFS2 partition (this is just a symlink to BusyBox anyway):
rm /sbin/init
And replace it with this script:
#!/bin/sh
# change this to your boot partition
boot_dev="/dev/scsi/host0/bus0/target0/lun0/part1"
# install needed modules for usb and the ext3 filesystem
# **NOTE** for usb2.0 replace "uhci" with "ehci-hcd"
# **NOTE** for ohci chipsets replace "uhci" with "usb-ohci"
for module in usbcore uhci scsi_mod sd_mod usb-storage jbd ext3; do {
insmod $module
}; done
# this may need to be higher if your disk is slow to initialize
sleep 4s
# mount the usb stick
mount "$boot_dev" /mnt
# if everything looks ok, do the pivot root
[ -x /mnt/sbin/init ] && {
mount -o move /proc /mnt/proc && \
pivot_root /mnt /mnt/mnt && {
mount -o move /mnt/dev /dev
mount -o move /mnt/tmp /tmp
mount -o move /mnt/jffs2 /jffs2 2>&-
mount -o move /mnt/sys /sys 2>&-
}
}
# finally, run the real init (from USB hopefully).
exec /bin/busybox init
Make sure your new /sbin/init is executable:
chmod a+x /sbin/init
Now just reboot, and if you did everything right it should boot from the USB device automatically.
If it could not boot from the USB device it will boot normally from the file system found on the flash as fallback.
Note that it is safest to leave the 'pivot_root' procedure as an ordinary script file, not part of the code automatically run on startup, at least until you are certain that it is operating as desired. This allows you to recover from any problems created by this script by simply rebooting the router without it.
4.4. Boot Configuration (Kamikaze)
First Create a script /etc/init.d/pivotroot
#!/bin/sh
# change this to your boot partition
boot_dev="/dev/sda1"
# install needed modules for usb and the ext3 filesystem
# **NOTE** for usb2.0 replace "uhci" with "ehci_hcd"
# **NOTE** for ohci chipsets replace "uhci" with "usb-ohci"
for module in usbcore uhci scsi_mod sd_mod usb-storage jbd kmod-fs-ext2 kmod-fs-ext3 ; do {
insmod $module
}; done
# this may need to be higher if your disk is slow to initialize
sleep 4s
# mount the usb stick
mount "$boot_dev" /mnt
# if everything looks ok, do the pivot root
[ -x /mnt/sbin/init ] && {
mount -o move /proc /mnt/proc && \
pivot_root /mnt /mnt/mnt && {
mount -o move /mnt/dev /dev
mount -o move /mnt/tmp /tmp
mount -o move /mnt/jffs2 /jffs2 2>&-
mount -o move /mnt/sys /sys 2>&-
}
}
Note: for Kamikaze 2.4 kernel that may not have hotplug2 then try using this instead. Tested with openwrt-brcm-2.4-squashfs.
#!/bin/sh
# change this to your boot partition
boot_dev="/dev/discs/disc0/part1"
# install needed modules for usb and the ext3 filesystem
# **NOTE** for usb2.0 replace "uhci" with "ehci-hcd"
# **NOTE** for ohci chipsets replace "uhci" with "usb-ohci"
for module in usbcore uhci scsi_mod sd_mod usb-storage jbd ext2 ext3 ; do {
insmod $module
}; done
# this may need to be higher if your disk is slow to initialize
sleep 4s
# mount the usb stick
mount "$boot_dev" /mnt
# if everything looks ok, do the pivot root
[ -x /mnt/sbin/init ] && {
mount -o move /proc /mnt/proc && \
pivot_root /mnt /mnt/mnt && {
mount -o move /mnt/dev /dev
mount -o move /mnt/tmp /tmp
mount -o move /mnt/jffs /jffs 2>&-
mount -o move /mnt/sys /sys 2>&-
}
}
Note: for Kazimate 2.6 kernel, add this before insmod loop.
/sbin/hotplug2 --override --persistent --max-children 1 --no-coldplug &
And kill it after the loop.
killall hotplug2
Make it executable:
chmod +x /etc/init.d/pivotroot
Then install the modules, for Kamikaze 7.07 or later (Kernel 2.6), use
ipkg install kmod-fs-ext2 kmod-fs-ext3
Test to see if pivotroot works:
/etc/init.d/pivotroot df -h
You may safely ignore errors saying "insmod: cannot insert ..." If pivotroot worked, then df will show that your USB storage is mounted on "/" (root). Now reboot.
reboot
after that edit /etc/init.d/rcS
#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
if test $2 == "boot" ; then
/etc/init.d/pivotroot
fi
{
for i in /etc/rc.d/$1*; do
$i $2 2>&1
done
} | logger -s -p 6 -t '' &
now your System should Startup nicely either from USB or from internal Flash if the USB-disk is not available.
4.5. Installing and using IPKG packages in mount point other than root
The Optware packages already make use of a similar concept, by which ipkg-opt uses a config file (/opt/etc/ipkg.conf) that points / to /opt in order to force the packages to install there. The settings to control where new packages are installed are defined by single-line entries in /etc/ipkg.conf with the original default being 'root / '. If you have external flash or hard drive, you may want to install packages there and add the corresponding directories to $PATH in /etc/profile.
NOTE: This is not tested. Please report if it's working for you.
-Works for me (MikkoKorkalo)
NOTE: PackagesOnExternalMediaHowTo contains additional important infos.
NOTE: Destination needs not to have trailing slash in order to make following script work (Nijel).
Configure ipkg for a non-root destination
echo dest usb /mnt/usb >> /etc/ipkg.conf
then install a package to a non-root destination
ipkg -dest usb install kismet-server
Copy & paste this script into /bin/ipkg-link (or somewhere in your $PATH).
#!/bin/sh
COMMAND=$1
PACKAGE=$2
setdest () {
for i in `grep dest /etc/ipkg.conf | cut -d ' ' -f 3`; do
if [ -f $i/usr/lib/ipkg/info/$PACKAGE.list ]; then
DEST=$i
fi
done
if [ "x$DEST" = "x" ]; then
echo "Can not locate $PACKAGE."
echo "Check /etc/ipkg.conf for correct dest listings";
echo "Check name of requested package: $PACKAGE"
exit 1
fi
}
addlinks () {
setdest;
cat $DEST/usr/lib/ipkg/info/$PACKAGE.list | while read LINE; do
SRC=$LINE
DST=`echo $SRC | sed "s|$DEST||"`
DSTNAME=`basename $DST`
DSTDIR=`echo $DST | sed "s|$DSTNAME\$||"`
test -f "$SRC"
if [ $? = 0 ]; then
test -e "$DST"
if [ $? = 1 ]; then
mkdir -p $DSTDIR
ln -sf $SRC $DST
else
echo "Not linking $SRC to $DST"
echo "$DST Already exists"
fi
else
test -d "$SRC"
if [ $? = 0 ]; then
test -e $DST
if [ $? = 1 ]; then
mkdir -p $DST
else
echo "directory already exists"
fi
else
echo "Source directory $SRC does not exist"
fi
fi
done
}
removelinks () {
setdest;
cat $DEST/usr/lib/ipkg/info/$PACKAGE.list | while read LINE; do
SRC=$LINE
DST=`echo $LINE | sed "s|$DEST||"`
DSTNAME=`basename $DST`
DSTDIR=`echo $DST | sed "s|$DSTNAME\$||"`
test -f $DST
if [ $? = 0 ]; then
rm -f $DST
test -d $DSTDIR && rmdir $DSTDIR 2>/dev/null
else
test -d $DST
if [ $? = 0 ]; then
rmdir $DST
else
echo "$DST does not exist"
fi
fi
done
}
mountdest () {
test -d $PACKAGE
if [ $? = 1 ]; then
echo "Mount point does not exist"
exit 1
fi
for i in $PACKAGE/usr/lib/ipkg/info/*.list; do
$0 add `basename $i .list`
done
}
umountdest () {
test -d $PACKAGE
if [ $? = 1 ]; then
echo "Mount point does not exist"
exit 1
fi
for i in $PACKAGE/usr/lib/ipkg/info/*.list; do
$0 remove `basename $i .list`
done
}
case "$COMMAND" in
add)
addlinks
;;
remove)
removelinks
;;
mount)
mountdest
;;
umount)
umountdest
;;
*)
echo "Usage: $0 <cmd> <target>"
echo " Commands: add, remove, mount, umount"
echo " Targets: <package>, <mount point>"
echo "Example: $0 add kismet-server"
echo "Example: $0 remove kismet-server"
echo "Example: $0 mount /mnt/usb"
echo "Example: $0 umount /mnt/usb"
exit 1
;;
esac
exit 0
Make sure the /bin/ipkg-link script is executable:
chmod a+x /bin/ipkg-link
Examples howto use the script:
Link a single package to root:
ipkg-link add kismet-server
Link all packages on a mount point to root:
ipkg-link mount /mnt/usb
Remove symlinks:
ipkg-link remove kismet-server
Remove all symlinks for all packages:
ipkg-link umount /mnt/usb
5. Links
Linux USB
- http://www.linux-usb.org/Linux USB device support
- http://www.linux-usb.org/devices.html