Automatically mounting and unmounting Samba/Windows shares with CIFS

by Sander Marechal

Last updated on 2007-12-03@23:55. At my work the employees are in the fortunate position that they are free to choose whatever OS they want to work with. At the moment the default is still Windows XP but you are free to wipe the drive and install whatever you feel—as long as you can do your job properly. And there is work underway to roll our own distribution for internal use. You're even free to bring in your Mac (but we won't supply you with one). The only thing that's banned (unofficially) so far is Windows Vista. Server-side we run a mixture of Linux and Windows, and the thend is to replace broken Windows machines by Linux machines if possible. In such a heterogeneous environment it makes sense to share our files through Samba. It's one of the few protocols that any OS can speak.

If you're running Windows Server 2003 then you can't use the smbfs driver that most Linux distributions ship by default. Sorry, no "Places » Connect to server" for you GNOME folk. You'll need to use the CIFS filesystem driver and you'll need to edit /etc/fstab. Adding the required fstab entries is actually quite easy as I will show below, but on Debian and it's derivative distributions you get a nasty error when you subsequently try to reboot or shutdown your machine, which hangs for about 30 seconds waiting for a timeout:

  1. CIFS VFS: No Response for Cmd <number> mid <number>

It took me quite a bit of time to properly solve that one, but in the end it turned out to be quite simple. I will show you later in the article, but let's start mounting first.

Mounting Samba shares with CIFS

Editing your /etc/fstab file is the easiest way to automatically mount your Samba shares, even if you use a laptop and travel around from network to network. Here is how your fstab entry should look (other filesystems excluded):

  1. # /etc/fstab: static file system information.
  2. #
  3. # <file system> <mount point> <type> <options> <dump> <pass>
  4. //<server>/<share> <mount point> cifs rw,_netdev,user=<username>,password=<password>,uid=<uid>,gid=<gid> 0 0

Most of the options are pretty straightforward. If you are mounting shares from a Windows server, make sure that you specify the username as DOMAIN/username, where DOMAIN is your Windows domain/workgroup. For <uid> and <gid> you should specify the userid/groupid that the share should be mounted as. You can lookup the numeric IDs in /etc/passwd and /etc/group.

Also notice that I have specified the _netdev option. CIFS doesn't know about this option and will throw a warning about it, but you should leave it in. This option ensures that the drives won't get mounted if you have no network or if you are on the wrong network. It also makes sure your shares get mounted/unmounted when you switch networks. That's because Debian's if* scripts are triggered when your network configuration changes, and they watch all the filesystems with the _netdev option and do the right thing automagically.

Getting rid of the “CIFS VFS: No Response” errors

If you have your Samba shares mounted through fstab like described above, you have probably come across this error when you reboot or shutdown, accompanied by a 30 second pause, waiting for a timeout:

  1. CIFS VFS: Server not responding
  2. CIFS VFS: No response for cmd &lt;number&gt; mid &lt;number&gt;

This problem has been bugging me for quite a while before I dug into it. As it turns out, cifs runs via a separate daemon process called cifsd. By the time that the shutdown/reboot init scripts start unmounting network filesystems, the daemon has already been killed by the system. And in there is a nice catch-22: All processes must be killed before you start unmounting volumes and with CIFS, you need to unmount first, then kill the process. And there was no way that I could create an exception in the "Shutting down all processes..." phase for the processes required by CIFS.

To solve it I wrote a little script cobbled together from bits and pieces of the umountnfs.sh and sendsigs init scripts. Basically it makes a list of all your mounted CIFS filesystems, shuts down and subsequently kills all processes that are still using those filesystems, and finally unmounts the CIFS filesystems. Save it to /etc/init.d/umountcifs and make it executable. Then symlink to it from /etc/rc0.d and /etc/rc6.d. You should ensure that umountcifs runs before the K20* init scripts fire. If it runs at K20 or later, you will still get the error. Personally I symlinked from /etc/rc(0|6).d/K19umountcifs.

Updated on 2007-12-03@23:55. Neill Hogarth adds that for (K)ubuntu 7.10 the script should be symlinked as K12umountcifs. K19 seems to work on (K)ubuntu 7.04 and lower, and on Debian Etch.

To conclude, here is the script I built (or download it here):

  1. #! /bin/sh
  2. ### BEGIN INIT INFO
  3. # Provides:          umountcifs
  4. # Required-Start:
  5. # Required-Stop:     umountcifs
  6. # Should-Stop:
  7. # Default-Start:
  8. # Default-Stop:      0 6
  9. # Short-Description: Unmount all cifs filesystems and terminate all processes using them
  10. # Description:
  11. ### END INIT INFO
  12.  
  13. PATH=/sbin:/usr/sbin:/bin:/usr/bin
  14. KERNEL="$(uname -s)"
  15. RELEASE="$(uname -r)"
  16. . /lib/init/vars.sh
  17.  
  18. . /lib/lsb/init-functions
  19.  
  20. case "${KERNEL}:${RELEASE}" in
  21.   Linux:[01].*|Linux:2.[01].*)
  22.         FLAGS=""
  23.         ;;
  24.   Linux:2.[23].*|Linux:2.4.?|Linux:2.4.?-*|Linux:2.4.10|Linux:2.4.10-*)
  25.         FLAGS="-f"
  26.         ;;
  27.   *)
  28.         FLAGS="-f -l"
  29.         ;;
  30. esac
  31.  
  32. do_stop () {
  33.         #
  34.         # Make list of points to unmount in reverse order of their creation
  35.         #
  36.  
  37.         exec 9<&0 </etc/mtab
  38.  
  39.         DIRS=""
  40.         while read DEV MTPT FSTYPE OPTS REST
  41.         do
  42.                 case "$MTPT" in
  43.                   /|/proc|/dev|/dev/pts|/dev/shm|/proc/*|/sys|/lib/init/rw)
  44.                         continue
  45.                         ;;
  46.                   /var/run)
  47.                         if [ yes = "$RAMRUN" ] ; then
  48.                                 continue
  49.                         fi
  50.                         ;;
  51.                   /var/lock)
  52.                         if [ yes = "$RAMLOCK" ] ; then
  53.                                 continue
  54.                         fi
  55.                         ;;
  56.                 esac
  57.                 case "$FSTYPE" in
  58.                   cifs)
  59.                         DIRS="$MTPT $DIRS"
  60.                         ;;
  61.                 esac
  62.         done
  63.  
  64.         exec 0<&9 9<&-
  65.  
  66.         if [ "$DIRS" ]
  67.         then
  68.                 # Kill all processes using the cifs volumes
  69.                 PROCESSES=""
  70.                 for DIR in $DIRS; do
  71.                         PROCESS=`fuser -m $DIR`
  72.                         if [ "$PROCESS" ]; then
  73.                                 PROCESSES="$PROCESS $PROCESSES"
  74.                         fi
  75.                 done
  76.  
  77.                 if [ "$PROCESSES" ]
  78.                 then
  79.                         log_action_begin_msg "Asking all processes using cifs filesystems to terminate"
  80.                         echo "kill -15 $PROCESSES"
  81.                         log_action_end_msg 0
  82.  
  83.                         for seq in 1 2 3 4 5 ; do
  84.                                 # use SIGCONT/signal 18 to check if there are
  85.                                 # processes left.  No need to check the exit code
  86.                                 # value, because either killall5 work and it make
  87.                                 # sense to wait for processes to die, or it fail and
  88.                                 # there is nothing to wait for.
  89.                                 echo "kill -18 $PROCESSES > /dev/null 2>&1" || break
  90.  
  91.                                 sleep 1
  92.                         done
  93.                         log_action_begin_msg "Killing all remaining processes using cifs filesystems"
  94.                         echo "kill -9 $PROCESSES > /dev/null 2>&1" # SIGKILL
  95.                         log_action_end_msg 0
  96.                 fi
  97.                 # Unmount all cifs filesystems
  98.                 [ "$VERBOSE" = no ] || log_action_begin_msg "Unmounting remote and non-toplevel cifs filesystems"
  99.                 umount $FLAGS $DIRS
  100.                 ES=$?
  101.                 [ "$VERBOSE" = no ] || log_action_end_msg $ES
  102.         fi
  103. }
  104.  
  105. case "$1" in
  106.   start)
  107.         # No-op
  108.         ;;
  109.   restart|reload|force-reload)
  110.         echo "Error: argument '$1' not supported" >&2
  111.         exit 3
  112.         ;;
  113.   stop|"")
  114.         do_stop
  115.         ;;
  116.   *)
  117.         echo "Usage: umountcifs [start|stop]" >&2
  118.         exit 3
  119.         ;;
  120. esac
  121.  
  122. :
Creative Commons Attribution-ShareAlike

Comments

#1 rodd ahrenstorff (http://ahrenstorff.us)

I run numerous W2k3 (including SP1 & SP2) servers and have no problem connecting to them using Ubuntu 7.04 with Gnome and 'Places > Connect to Server'. Strange you cannot...

#2 Sander Marechal (http://www.jejik.com)

Neill Hogarth wrote (via e-mail):
I get exactly the message that you describe on unmounting. I understand the theory of your solution for mounting but am confused by:
"and then symlink to it from /etc/rc0.d and /etc/rc6.d. You should ensure that umountcifs runs before the K20* init scripts fire. If it runs at K20 or later, you will still get the error. personally I symlinked from /etc/rc(0|6).d/K19umountcifs"

Could I possibly ask for a slightly easier explanation of that part. I understand that your description is probably as clear as can be for a Linux Guru but I am not yet at that stage.


There's quite a long thread on the Ubuntu forums that deals with this.
My solution is in there, alongside someone else's solution:

http://ubuntuforums.org/showthread.php?t=293513

To explain the bit about the piece you quoted, you need to understand
runlevels first. Google for it. There are plenty of good resources on
it. The bit that matters is this: When you shut down your system, all
the scripts in /etc/rc0.d are run. First all the scripts named Sxx
numbers (ascending), then all the scripts with Kxx (also in ascending
order). When you reboot, all the scripts in /etc/rc6.d instead of
/etc/rc0.d are run. Those scripts together form the shutdown and reboor
sequence of your machine.

What you need to do is put my script in those sequences. There best way
is to put my script in /etc/init.d and then create links to it from the
rc0.d and rc6.d directories. You do that with:

ln -s /etc/init.d/umountcifs /etc/rc0.d/K19umountcifs
ln -s /etc/init.d/umountcifs /etc/rc6.d/K19umountcifs


This means that the script will be executed after K18xxx and before
K20xxx, which is the right location for Debian Etch and Ubuntu Feisty.
From the comments in the Ubuntu forum I understand that the shutdown and
reboot sequence changed a bit for Gutsy, so if you use Gutsy then the
script needs to run sooner. For example, at K12 instead of K19.

Just experiment. Create the links and shutdown/reboot. If you still get
the error, the script needs to run sooner. So remove the links (with
"rm") and recreate them with a lower K number. Then try again.

Hope this helps!

#3 Anibal (http://www.anibalnet.nl)

Thaks for the solution, i wonder why ubuntu dont fix this problem by default ? is anoying & is a ubuntu related bug.. on my other linux boxes running slackware, mandriva, centos & red hat this doesnt happend. when i read on the forum seems to be this exist since ubuntu 7.x

Cheers
Anibal

#4 Sander Marechal (http://www.jejik.com)

@Anibal: The bug actually originates in Debian. See Debian Bug 431966. Short story is that the maintainers of init-scripts blame smbfs and vice versa, so nobody does anything. I suggest you add more comments to that thread.

#5 Anonymous Coward

Newbie here

I am a bit thick, I have tried all permutations of the cifs smbfs to try and mount a windows shared folder. The folder contains video I want to stream to my linux m/c's.

Here are the lines I have added to /etc/fstab:
//192.168.2.5/Public /media/public smbfs guest 0 0
This mounts my NAS drive no problem.

so I tried similar to mount my windows shared drive called 'videos', domain is workgroup, pc is called 'apwdesktoppc', my windows user name is 'Anthony Ward'

//192.168.2.2/Videos /media/videos cifs rw,WORKGROUP,APWDESKTOPPC=Anthony Ward,password=********

I get an error message:
mount error 22 = Invalid argument
Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)

Any suggestions as to what I am doing wrong, please?

#6 Sander Marechal (http://www.jejik.com)

I think it's choking on the space in your username. Try wrapping your username in double quotes or escaping the space, e.g. one of these:

//192.168.2.2/Videos /media/videos cifs rw,WORKGROUP,APWDESKTOPPC="Anthony Ward",password=********
//192.168.2.2/Videos /media/videos cifs rw,WORKGROUP,"APWDESKTOPPC=Anthony Ward",password=********
//192.168.2.2/Videos /media/videos cifs rw,WORKGROUP,APWDESKTOPPC=Anthony\ Ward,password=********

#7 Randy Klein

thanks for this fix, that hang up was really bothering me. BTW, it worked on Jaunty just fine.

#8 Oliver Doepner (http://doepner.net/)

You can set the symlinks for runlevel 0 and 6 like this (include the "."):

sudo update-rc.d umountcifs stop 19 0 6 .

Adding system startup for /etc/init.d/umountcifs ...
/etc/rc0.d/K19umountcifs -> ../init.d/umountcifs
/etc/rc6.d/K19umountcifs -> ../init.d/umountcifs

#9 Sander Marechal (http://www.jejik.com)

Thanks Oliver. By the way, note that the manpage for update-rc.d states that it is a tool for packagers and not for system administrators. They recommend against using update-rc.d directly but to use tools like 'sysv-rc-conf' or 'bum' instead.

#10 Oliver Doepner (http://doepner.net/)

I want to thank you for making the script available. It solved the problem for me on Debian Lenny.

But I had to set the numeric priority to 12 (i.e. K12umountcifs) so that it runs before K14network-manager.

#11 j1nn (http://jinn.mine.nu)

thanks a lot! it simply _works_ =]

#12 Anonymous Coward

another area where ubuntu clearly sucks. this should be a check box somewhere in networking.

#13 JT

This thread looks long dead but what the heck. I'm usings CIFS to mount a Win share in RHEL 4. I have the same fstab entry you show, mounting the share is fine I have no issues there. My problem is that the RHEL box is up 24/7 but the Win box is shut down and rebooted frequently. When the Win box is rebooted the mount is lost and does not reconnect automatically. To fix this I made a script to re-mount the share and I run it out of inittab. This causes CIFS VFS error messages to show on the main console whenever the Win box is down, I've have the script and the inittab entry setup to redirect stdout and stderr output to /dev/null but I'm still getting errors on the console screen.

Comments have been retired for this article.