Re: [Hampshire] Safely unmounting a server's external hard d…

Top Page

Reply to this message
Author: John Cooper
Date:  
To: Hampshire LUG Discussion List
Subject: Re: [Hampshire] Safely unmounting a server's external hard drive
Chris Dennis wrote:
> John Cooper wrote:
>> Chris Dennis wrote:
>>> Hello folks
>>>
>>> I'm planning to use one or more external USB hard drives to backup a
>>> headless server running Debian. I'll probably use rsnapshot, with a
>>> script that detects for the presence of the right drive.
>>>
>>> But how can the server tell the user when it is safe to unplug the
>>> drive? Or maybe the user should somehow tell the server "I want to
>>> unplug the drive -- stop using it and unmount it".
>>>
>>> The user's only way of communicating with the server is by email or
>>> possibly via Webmin.
>>>
>>> Has anyone come up with a cunning plan to deal with this?
>>>
>>> cheers
>>>
>>> Chris
>
> Thanks for the various replies.
>
> The simple "unmount after backup" idea won't work for me because I'm
> planning to run rsnapshot via cron every hour while the drive is plugged
> in, but allow the drive to be taken off-site at weekends or whenever.
>
> In fact I think Webmin (for all its faults) will allow the user to
> unmount the drive and/or see whether it is currently mounted. They can
> then remove the drive knowing that it will not be used again until the
> appointed cron time -- 15 minutes past the hour for example.
>
> > Have a look at this USB suspend script:-
> >
> http://elliotli.blogspot.com/2009/01/safely-remove-usb-hard-drive-in-linux.html
>
> That all looks very elaborate. Is it really necessary? Does this mean
> that good old 'umount' hasn't been working for USB drives all this time?
>
> cheers
>
> Chris
>


Updated the script to check if hdparm works with the device and fixed
some other errors.

Example run on a USB stick with 2 partitions,/dev/sdc1 and /dev/sdc2
(see mount output after inserting USB device) :-

sudo ./usbsuspend /dev/sdc     ( or su -c './usbsuspend /dev/sdc' )


Unmount device partitions (1 to 9)
Found device /devices/pci0000:00/0000:00:02.1/usb1/1-4 associated to
/dev/sdc; USB bus id is 1-4
flush all buffers: sync
Syncing device /dev/sdc
drive state is: unknown
Drive does not support sleep mode, skipping hdparm
Unbinding device 1-4
Checking whether /devices/pci0000:00/0000:00:02.1/usb1/1-4 can be suspended
Suspending /devices/pci0000:00/0000:00:02.1/usb1/1-4 by writing to
/sys/devices/pci0000:00/0000:00:02.1/usb1/1-4/power/level
Completed



Script, cut and paste into file called usbsuspend :-

---- CUT START -----
#!/bin/bash
#
# usbsuspend
#

usage()
{
    cat<<EOF
usbsuspend


This script is designed to properly put an USB device into suspend
mode that can then be unplugged safely. It sends a SYNCHRONIZE CACHE
command followed by a START-STOP command (if the device supports it),
unbinds the device from the driver and then suspends the USB
port. After that you can disconnect your USB device safely.

usage:
$0 [options] dev

Example:
$0 /dev/sdc

options:
  -l     show the device and USB bus ID only
  -h     print this usage


EOF
}

set -e -u

SHOW_DEVICE_ONLY=0
while getopts "vlh" opt; do
    case "$opt" in
        h)
            usage
            exit 2
            ;;
        l)
            SHOW_DEVICE_ONLY=1
            ;;
        ?)
            echo
            usage
            exit 2
            ;;
    esac
done
DEV_NAME=${!OPTIND:-}


if [ -z ${DEV_NAME} ]; then
    usage
    exit 2
fi


echo "Unmount device partitions (1 to 9)"
umount ${DEV_NAME}[1-9]

if mount | grep "^${DEV_NAME}[[:digit:]]* "; then
    1>&2 echo
    1>&2 echo "the above disk or partition is still mounted, can't
suspend device"
    1>&2 echo "unmount it first using umount (may need to be root)"
    exit 1
fi


DEVICE=$(udevadm info --query=path --name=${DEV_NAME} --attribute-walk \
| egrep "looking at parent device" | head -1 | sed -e "s/.*looking at \

parent device '\(\/devices\/.*\)\/.*\/host.*/\1/g")

if [ -z $DEVICE ]; then
    1>&2 echo "cannot find appropriate parent USB/Firewire device, "
    1>&2 echo "perhaps ${DEV_NAME} is not an USB/Firewire device?"
    exit 1
fi


DEV_BUS_ID=${DEVICE##*/}

echo "Found device $DEVICE associated to $DEV_NAME; USB bus id is
$DEV_BUS_ID"

if [ ${SHOW_DEVICE_ONLY} -eq 1 ]; then
    echo Device: ${DEVICE}
    echo Bus ID: ${DEV_BUS_ID}
    exit 0
fi


echo "flush all buffers: sync"
sync
sync

# root check
if [ `id -u` -ne 0 ]
then
        echo "NOT root, required for hdparm to put drive into sleep and
unbind"
        exit
fi


echo "Syncing device $DEV_NAME"

hdparm -C "$DEV_NAME" 2> /dev/null | grep "drive state is:  unknown"
if [ $? -eq 0 ]
then
        echo "Drive does not support sleep mode, skipping hdparm"
 else
    hdparm -f "$DEV_NAME" >/dev/null || true
    hdparm -Y "$DEV_NAME" >/dev/null
fi


echo "Unbinding device $DEV_BUS_ID"
if [[ "${DEV_BUS_ID}" == fw* ]]
then
    echo -n "${DEV_BUS_ID}" > /sys/bus/firewire/drivers/sbp2/unbind
else
    echo -n "${DEV_BUS_ID}" > /sys/bus/usb/drivers/usb/unbind


    echo "Checking whether $DEVICE can be suspended"
    POWER_LEVEL_FILE=/sys${DEVICE}/power/level
    if [ ! -f "$POWER_LEVEL_FILE" ]; then
        1>&2 cat<<EOF
It's safe to remove the USB device now but better can be done. The
power level control file $POWER_LEVEL_FILE
doesn't exist on the system so I have no way to put the USB device
into suspend mode, perhaps you don't have CONFIG_USB_SUSPEND enabled
in your running kernel.


EOF
        exit 3
    fi


    echo "Suspending $DEVICE by writing to $POWER_LEVEL_FILE"
    echo 'suspend' > "$POWER_LEVEL_FILE"
fi
echo "Completed"
---- CUT END -----



--
--------------------------------------------------------------
Discover Linux - Open Source Solutions to Business and Schools
http://discoverlinux.co.uk
--------------------------------------------------------------