Subject: Re: multiple mounts on same directory
To: None <tech-userlevel@NetBSD.org>
From: Alan Barrett <apb@cequrux.com>
List: tech-userlevel
Date: 07/18/2003 21:25:47
On Fri, 18 Jul 2003, Bill Studenmund wrote:
> > Is it OK to hard-code knowledge of these special cases in the duplicate
> > detection part of "mount -a"?
> 
> I'd say a switch (fstype) would be best, and have it: 1) note if the
> fromname should be looked at (kern, proc, mfs would be no), and if the
> from name needs to be different than what's in the fstab.

OK.  fstype is a string, so it's a chain of strcmp tests instead of a
switch.  I append a patch for review.

I searched the kernel sources for anything that sets f_mntfromname or
calls set_statfs_info(), so I hope I found all file systems that do
something unusual.

--apb (Alan Barrett)

Index: sbin/mount/mount.c
--- mount.c	19 Jan 2003 10:49:12 -0000	1.65
+++ mount.c	18 Jul 2003 19:22:50 -0000
@@ -349,13 +349,77 @@
 		}
 		for(i = 0; i < numfs; i++) {
 			/*
-			 * XXX can't check f_mntfromname,
-			 * thanks to mfs, union, etc.
+			 * If the mounted file system described by
+			 * sfp[i] matches the file system to be mounted,
+			 * then this would be a duplicate, so do not
+			 * mount it.
+			 *
+			 * Note that a duplicate does not always have a
+			 * matching f_mntfromname field.  For example:
+			 *
+			 * fstype	original name	f_mntfromname
+			 * ------	-------------	-------------
+			 * mfs		anything	mfs:123
+			 * kernfs	anything	kernfs
+			 * procfs	anything	procfs
+			 * union (with default UNMNT_ABOVE option)
+			 *		/some/dir	<above>:/some/dir
+			 * union (with "-b" UNMNT_BELOW option)
+			 *		/some/dir	<below>:/some/dir
+			 * union (with "-r" UNMNT_REPLACE option)
+			 *		/some/dir	/some/dir
+			 * smbfs	???		//user@host/service
+			 * coda		???		CODA
+			 *
+			 * If f_mntonname and f_fstypename match, then
+			 * we copy f_mntfromname into a local buffer
+			 * (fromname) and possibly modify the copy
+			 * before checking whether it equals the desired
+			 * name.
 			 */
-			if (strncmp(name, sfp[i].f_mntonname, MNAMELEN) == 0 &&
-			    strncmp(vfstype, sfp[i].f_fstypename,
-				MFSNAMELEN) == 0) {
-				if (verbose)
+			char fromname[MNAMELEN];
+			char *check_fromname = fromname;
+
+			if (strncmp(name, sfp[i].f_mntonname, MNAMELEN) != 0
+			    || strncmp(vfstype, sfp[i].f_fstypename,
+					MFSNAMELEN) != 0)
+				continue; /* not a duplicate */
+			strlcpy(fromname, sfp[i].f_mntfromname, MNAMELEN);
+			if (strcmp(vfstype, "mfs") == 0
+			    || strcmp(vfstype, "procfs") == 0
+			    || strcmp(vfstype, "kernfs") == 0
+			    || strcmp(vfstype, "coda") == 0
+			    || strcmp(vfstype, "fdesc") == 0) {
+				/* Ignore fromname. */
+				check_fromname = NULL;
+			} else if (strcmp(vfstype, "union") == 0) {
+				/*
+				 * Focus after the colon in
+				 * "<above>:/some/dir" or
+				 * "<below>:/some/dir".  Note that
+				 * there is no extra <foo> in the
+				 * UNMNT_REPLACE case.
+				 */
+				char *s;
+
+				if (fromname[0] == '<'
+				    && (s = strchr(fromname, ':')) != NULL)
+					check_fromname = s + 1;
+			} else if (strcmp(vfstype, "smbfs") == 0) {
+				/*
+				 * XXX: smbfs_mount() in
+				 *	sys/fs/smbfs/smbfs_vfsops.c
+				 *	creates f_mntfromname from
+				 *	several components, and I don't
+				 *	know where the components came
+				 *	from.
+				 */
+				 check_fromname = NULL;
+			}
+			if (check_fromname == NULL
+			    || strncmp(spec, check_fromname, MNAMELEN) == 0) {
+				/* It's a duplicate. */
+				if (verbose) {
 					(void)printf("%s on %s type %.*s: "
 					    "%s\n",
 					    sfp[i].f_mntfromname,
@@ -363,6 +427,7 @@
 					    MFSNAMELEN,
 					    sfp[i].f_fstypename,
 					    "already mounted");
+				}
 				return (0);
 			}
 		}