[SCM] Samba Shared Repository - branch v3-3-test updated - release-3-2-0pre2-4344-g00bbd9d

Jeff Layton jlayton at samba.org
Thu Nov 6 20:15:09 GMT 2008


The branch, v3-3-test has been updated
       via  00bbd9dc6598acb9ef8adab4308ada6bb1818f1f (commit)
      from  7cbbcc75a834179d1c48411666670d7cb7d41726 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-3-test


- Log -----------------------------------------------------------------
commit 00bbd9dc6598acb9ef8adab4308ada6bb1818f1f
Author: Jeff Layton <jlayton at redhat.com>
Date:   Thu Nov 6 15:13:48 2008 -0500

    mount.cifs: use lock/unlock_mtab scheme from util-linux-ng mount prog
    
    The util-linux-ng sources have a good, but rather complex scheme for
    locking the mtab before updating it. Mount helpers need to follow the
    same scheme. Advisory locking only works if everyone is using the same
    locking scheme.
    
    Copy the routines we need from util-linux-ng into a separate source file
    and then have mount.cifs and umount.cifs link in this object.
    
    The long term goal is to have these routines in a separate helper
    library (libmount). Mount helpers can then dynamically link in that lib.
    Until that happens, this should serve as a suitable stopgap solution.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

-----------------------------------------------------------------------

Summary of changes:
 source/Makefile.in          |    4 +-
 source/client/mount.cifs.c  |   97 ++++++++++----------
 source/client/mount.h       |   38 ++++++++
 source/client/mtab.c        |  219 +++++++++++++++++++++++++++++++++++++++++++
 source/client/umount.cifs.c |   22 +----
 5 files changed, 311 insertions(+), 69 deletions(-)
 create mode 100644 source/client/mount.h
 create mode 100644 source/client/mtab.c


Changeset truncated at 500 lines:

diff --git a/source/Makefile.in b/source/Makefile.in
index db1a10f..448a413 100644
--- a/source/Makefile.in
+++ b/source/Makefile.in
@@ -883,9 +883,9 @@ CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) \
 	  $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \
 	  $(LIBNDR_GEN_OBJ0)
 
-CIFS_MOUNT_OBJ = client/mount.cifs.o
+CIFS_MOUNT_OBJ = client/mount.cifs.o client/mtab.o
 
-CIFS_UMOUNT_OBJ = client/umount.cifs.o
+CIFS_UMOUNT_OBJ = client/umount.cifs.o client/mtab.o
 
 CIFS_UPCALL_OBJ = client/cifs.upcall.o
 
diff --git a/source/client/mount.cifs.c b/source/client/mount.cifs.c
index 2a9c2b7..da2f98b 100644
--- a/source/client/mount.cifs.c
+++ b/source/client/mount.cifs.c
@@ -39,9 +39,10 @@
 #include <mntent.h>
 #include <fcntl.h>
 #include <limits.h>
+#include "mount.h"
 
 #define MOUNT_CIFS_VERSION_MAJOR "1"
-#define MOUNT_CIFS_VERSION_MINOR "11"
+#define MOUNT_CIFS_VERSION_MINOR "12"
 
 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
  #ifdef _SAMBA_BUILD_
@@ -79,15 +80,6 @@
 #define MOUNT_PASSWD_SIZE 64
 #define DOMAIN_SIZE 64
 
-/* exit status - bits below are ORed */
-#define EX_USAGE        1       /* incorrect invocation or permission */
-#define EX_SYSERR       2       /* out of memory, cannot fork, ... */
-#define EX_SOFTWARE     4       /* internal mount bug or wrong version */
-#define EX_USER         8       /* user interrupt */
-#define EX_FILEIO      16       /* problems writing, locking, ... mtab/fstab */
-#define EX_FAIL        32       /* mount failure */
-#define EX_SOMEOK      64       /* some mount succeeded */
-
 const char *thisprogram;
 int verboseflag = 0;
 static int got_password = 0;
@@ -1424,48 +1416,57 @@ mount_retry:
 		printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
 		rc = EX_FAIL;
 	} else {
+		atexit(unlock_mtab);
+		rc = lock_mtab();
+		if (rc) {
+			printf("cannot lock mtab");
+			goto mount_exit;
+		}
 		pmntfile = setmntent(MOUNTED, "a+");
-		if(pmntfile) {
-			mountent.mnt_fsname = dev_name;
-			mountent.mnt_dir = mountpoint;
-			mountent.mnt_type = CONST_DISCARD(char *,"cifs");
-			mountent.mnt_opts = (char *)malloc(220);
-			if(mountent.mnt_opts) {
-				char * mount_user = getusername();
-				memset(mountent.mnt_opts,0,200);
-				if(flags & MS_RDONLY)
-					strlcat(mountent.mnt_opts,"ro",220);
-				else
-					strlcat(mountent.mnt_opts,"rw",220);
-				if(flags & MS_MANDLOCK)
-					strlcat(mountent.mnt_opts,",mand",220);
-				if(flags & MS_NOEXEC)
-					strlcat(mountent.mnt_opts,",noexec",220);
-				if(flags & MS_NOSUID)
-					strlcat(mountent.mnt_opts,",nosuid",220);
-				if(flags & MS_NODEV)
-					strlcat(mountent.mnt_opts,",nodev",220);
-				if(flags & MS_SYNCHRONOUS)
-					strlcat(mountent.mnt_opts,",synch",220);
-				if(mount_user) {
-					if(getuid() != 0) {
-						strlcat(mountent.mnt_opts,",user=",220);
-						strlcat(mountent.mnt_opts,mount_user,220);
-					}
-					/* free(mount_user); do not free static mem */
-				}
-			}
-			mountent.mnt_freq = 0;
-			mountent.mnt_passno = 0;
-			rc = addmntent(pmntfile,&mountent);
-			endmntent(pmntfile);
-			SAFE_FREE(mountent.mnt_opts);
-			if (rc)
-				rc = EX_FILEIO;
-		} else {
+		if (!pmntfile) {
 			printf("could not update mount table\n");
+			unlock_mtab();
 			rc = EX_FILEIO;
+			goto mount_exit;
 		}
+		mountent.mnt_fsname = dev_name;
+		mountent.mnt_dir = mountpoint;
+		mountent.mnt_type = CONST_DISCARD(char *,"cifs");
+		mountent.mnt_opts = (char *)malloc(220);
+		if(mountent.mnt_opts) {
+			char * mount_user = getusername();
+			memset(mountent.mnt_opts,0,200);
+			if(flags & MS_RDONLY)
+				strlcat(mountent.mnt_opts,"ro",220);
+			else
+				strlcat(mountent.mnt_opts,"rw",220);
+			if(flags & MS_MANDLOCK)
+				strlcat(mountent.mnt_opts,",mand",220);
+			if(flags & MS_NOEXEC)
+				strlcat(mountent.mnt_opts,",noexec",220);
+			if(flags & MS_NOSUID)
+				strlcat(mountent.mnt_opts,",nosuid",220);
+			if(flags & MS_NODEV)
+				strlcat(mountent.mnt_opts,",nodev",220);
+			if(flags & MS_SYNCHRONOUS)
+				strlcat(mountent.mnt_opts,",sync",220);
+			if(mount_user) {
+				if(getuid() != 0) {
+					strlcat(mountent.mnt_opts,
+						",user=", 220);
+					strlcat(mountent.mnt_opts,
+						mount_user, 220);
+				}
+			}
+		}
+		mountent.mnt_freq = 0;
+		mountent.mnt_passno = 0;
+		rc = addmntent(pmntfile,&mountent);
+		endmntent(pmntfile);
+		unlock_mtab();
+		SAFE_FREE(mountent.mnt_opts);
+		if (rc)
+			rc = EX_FILEIO;
 	}
 mount_exit:
 	if(mountpassword) {
diff --git a/source/client/mount.h b/source/client/mount.h
new file mode 100644
index 0000000..23ea4f0
--- /dev/null
+++ b/source/client/mount.h
@@ -0,0 +1,38 @@
+/* 
+ * Copyright (C) 2008 Jeff Layton (jlayton at samba.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* most of this info was taken from the util-linux-ng sources */
+
+#ifndef _MOUNT_H_
+#define _MOUNT_H_
+
+/* exit status - bits below are ORed */
+#define EX_USAGE	1	/* incorrect invocation or permission */
+#define EX_SYSERR	2	/* out of memory, cannot fork, ... */
+#define EX_SOFTWARE	4	/* internal mount bug or wrong version */
+#define EX_USER		8	/* user interrupt */
+#define EX_FILEIO      16	/* problems writing, locking, ... mtab/fstab */
+#define EX_FAIL	       32	/* mount failure */
+#define EX_SOMEOK      64	/* some mount succeeded */
+
+#define _PATH_MOUNTED_LOCK	_PATH_MOUNTED "~"
+#define _PATH_MOUNTED_TMP	_PATH_MOUNTED ".tmp"
+
+extern int lock_mtab(void);
+extern void unlock_mtab(void);
+
+#endif /* ! _MOUNT_H_ */
diff --git a/source/client/mtab.c b/source/client/mtab.c
new file mode 100644
index 0000000..93fbd11
--- /dev/null
+++ b/source/client/mtab.c
@@ -0,0 +1,219 @@
+/*
+ * mtab locking routines for use with mount.cifs and umount.cifs
+ * Copyright (C) 2008 Jeff Layton (jlayton at samba.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This code was copied from the util-linux-ng sources and modified:
+ *
+ * git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git
+ *
+ * ...specifically from mount/fstab.c. That file has no explicit license. The
+ * "default" license for anything in that tree is apparently GPLv2+, so I
+ * believe we're OK to copy it here.
+ *
+ * Jeff Layton <jlayton at samba.org> 
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <stdlib.h>
+#include <signal.h>
+#include "mount.h"
+
+
+/* Updating mtab ----------------------------------------------*/
+
+/* Flag for already existing lock file. */
+static int we_created_lockfile = 0;
+static int lockfile_fd = -1;
+
+/* Flag to indicate that signals have been set up. */
+static int signals_have_been_setup = 0;
+
+static void
+handler (int sig) {
+     exit(EX_USER);
+}
+
+static void
+setlkw_timeout (int sig) {
+     /* nothing, fcntl will fail anyway */
+}
+
+/* Remove lock file.  */
+void
+unlock_mtab (void) {
+	if (we_created_lockfile) {
+		close(lockfile_fd);
+		lockfile_fd = -1;
+		unlink (_PATH_MOUNTED_LOCK);
+		we_created_lockfile = 0;
+	}
+}
+
+/* Create the lock file.
+   The lock file will be removed if we catch a signal or when we exit. */
+/* The old code here used flock on a lock file /etc/mtab~ and deleted
+   this lock file afterwards. However, as rgooch remarks, that has a
+   race: a second mount may be waiting on the lock and proceed as
+   soon as the lock file is deleted by the first mount, and immediately
+   afterwards a third mount comes, creates a new /etc/mtab~, applies
+   flock to that, and also proceeds, so that the second and third mount
+   now both are scribbling in /etc/mtab.
+   The new code uses a link() instead of a creat(), where we proceed
+   only if it was us that created the lock, and hence we always have
+   to delete the lock afterwards. Now the use of flock() is in principle
+   superfluous, but avoids an arbitrary sleep(). */
+
+/* Where does the link point to? Obvious choices are mtab and mtab~~.
+   HJLu points out that the latter leads to races. Right now we use
+   mtab~.<pid> instead. Use 20 as upper bound for the length of %d. */
+#define MOUNTLOCK_LINKTARGET		_PATH_MOUNTED_LOCK "%d"
+#define MOUNTLOCK_LINKTARGET_LTH	(sizeof(_PATH_MOUNTED_LOCK)+20)
+
+/*
+ * The original mount locking code has used sleep(1) between attempts and
+ * maximal number of attemps has been 5.
+ *
+ * There was very small number of attempts and extremely long waiting (1s)
+ * that is useless on machines with large number of concurret mount processes.
+ *
+ * Now we wait few thousand microseconds between attempts and we have global
+ * time limit (30s) rather than limit for number of attempts. The advantage
+ * is that this method also counts time which we spend in fcntl(F_SETLKW) and
+ * number of attempts is not so much restricted.
+ *
+ * -- kzak at redhat.com [2007-Mar-2007]
+ */
+
+/* maximum seconds between first and last attempt */
+#define MOUNTLOCK_MAXTIME		30
+
+/* sleep time (in microseconds, max=999999) between attempts */
+#define MOUNTLOCK_WAITTIME		5000
+
+int
+lock_mtab (void) {
+	int i;
+	struct timespec waittime;
+	struct timeval maxtime;
+	char linktargetfile[MOUNTLOCK_LINKTARGET_LTH];
+
+	if (!signals_have_been_setup) {
+		int sig = 0;
+		struct sigaction sa;
+
+		sa.sa_handler = handler;
+		sa.sa_flags = 0;
+		sigfillset (&sa.sa_mask);
+
+		while (sigismember (&sa.sa_mask, ++sig) != -1
+		       && sig != SIGCHLD) {
+			if (sig == SIGALRM)
+				sa.sa_handler = setlkw_timeout;
+			else
+				sa.sa_handler = handler;
+			sigaction (sig, &sa, (struct sigaction *) 0);
+		}
+		signals_have_been_setup = 1;
+	}
+
+	sprintf(linktargetfile, MOUNTLOCK_LINKTARGET, getpid ());
+
+	i = open (linktargetfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
+	if (i < 0) {
+		/* linktargetfile does not exist (as a file)
+		   and we cannot create it. Read-only filesystem?
+		   Too many files open in the system?
+		   Filesystem full? */
+		return EX_FILEIO;
+	}
+	close(i);
+
+	gettimeofday(&maxtime, NULL);
+	maxtime.tv_sec += MOUNTLOCK_MAXTIME;
+
+	waittime.tv_sec = 0;
+	waittime.tv_nsec = (1000 * MOUNTLOCK_WAITTIME);
+
+	/* Repeat until it was us who made the link */
+	while (!we_created_lockfile) {
+		struct timeval now;
+		struct flock flock;
+		int errsv, j;
+
+		j = link(linktargetfile, _PATH_MOUNTED_LOCK);
+		errsv = errno;
+
+		if (j == 0)
+			we_created_lockfile = 1;
+
+		if (j < 0 && errsv != EEXIST) {
+			(void) unlink(linktargetfile);
+			return EX_FILEIO;
+		}
+
+		lockfile_fd = open (_PATH_MOUNTED_LOCK, O_WRONLY);
+
+		if (lockfile_fd < 0) {
+			/* Strange... Maybe the file was just deleted? */
+			gettimeofday(&now, NULL);
+			if (errno == ENOENT && now.tv_sec < maxtime.tv_sec) {
+				we_created_lockfile = 0;
+				continue;
+			}
+			(void) unlink(linktargetfile);
+			return EX_FILEIO;
+		}
+
+		flock.l_type = F_WRLCK;
+		flock.l_whence = SEEK_SET;
+		flock.l_start = 0;
+		flock.l_len = 0;
+
+		if (j == 0) {
+			/* We made the link. Now claim the lock. If we can't
+			 * get it, continue anyway
+			 */
+			fcntl (lockfile_fd, F_SETLK, &flock);
+			(void) unlink(linktargetfile);
+		} else {
+			/* Someone else made the link. Wait. */
+			gettimeofday(&now, NULL);
+			if (now.tv_sec < maxtime.tv_sec) {
+				alarm(maxtime.tv_sec - now.tv_sec);
+				if (fcntl (lockfile_fd, F_SETLKW, &flock) == -1) {
+					(void) unlink(linktargetfile);
+					return EX_FILEIO;
+				}
+				alarm(0);
+				nanosleep(&waittime, NULL);
+			} else {
+				(void) unlink(linktargetfile);
+				return EX_FILEIO;
+			}
+			close(lockfile_fd);
+		}
+	}
+	return 0;
+}
+
diff --git a/source/client/umount.cifs.c b/source/client/umount.cifs.c
index 3e2415a..aff7cea 100644
--- a/source/client/umount.cifs.c
+++ b/source/client/umount.cifs.c
@@ -33,9 +33,10 @@
 #include <errno.h>
 #include <string.h>
 #include <mntent.h>
+#include "mount.h"
 
 #define UNMOUNT_CIFS_VERSION_MAJOR "0"
-#define UNMOUNT_CIFS_VERSION_MINOR "5"
+#define UNMOUNT_CIFS_VERSION_MINOR "6"
 
 #ifndef UNMOUNT_CIFS_VENDOR_SUFFIX
  #ifdef _SAMBA_BUILD_
@@ -137,24 +138,6 @@ static int umount_check_perm(char * dir)
 	return rc;
 }
 
-static int lock_mtab(void)
-{
-	int rc;
-	
-	rc = mknod(MOUNTED_LOCK , 0600, 0);
-	if(rc == -1)
-		printf("\ngetting lock file %s failed with %s\n",MOUNTED_LOCK,
-				strerror(errno));
-		
-	return rc;	
-	
-}
-
-static void unlock_mtab(void)
-{
-	unlink(MOUNTED_LOCK);	
-}
-
 static int remove_from_mtab(char * mountpoint)
 {
 	int rc;
@@ -168,6 +151,7 @@ static int remove_from_mtab(char * mountpoint)
 
 	/* Do we first need to check if it is writable? */ 
 
+	atexit(unlock_mtab);
 	if (lock_mtab()) {
 		printf("Mount table locked\n");
 		return -EACCES;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list