Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 3 Dec 2016 21:23:44 +0000 (UTC)
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r309515 - stable/11/sys/kern
Message-ID:  <201612032123.uB3LNiCI026145@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trasz
Date: Sat Dec  3 21:23:43 2016
New Revision: 309515
URL: https://svnweb.freebsd.org/changeset/base/309515

Log:
  MFC r308209:
  
  Fix getfsstat(2) with MNT_WAIT to not skip filesystems that are in the
  process of being unmounted.  Previously it would skip them, even if the
  unmount eventually failed eg due to the filesystem being busy.
  
  This behaviour broke autounmountd(8) - if you tried to manually unmount
  a mounted filesystem, using 'automount -u', and the autounmountd attempted
  to refresh the filesystem list in that very moment, it would conclude that
  the filesystem got unmounted and not try to unmount it afterwards.

Modified:
  stable/11/sys/kern/vfs_syscalls.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/kern/vfs_syscalls.c
==============================================================================
--- stable/11/sys/kern/vfs_syscalls.c	Sat Dec  3 21:19:45 2016	(r309514)
+++ stable/11/sys/kern/vfs_syscalls.c	Sat Dec  3 21:23:43 2016	(r309515)
@@ -446,16 +446,19 @@ kern_getfsstat(struct thread *td, struct
     size_t *countp, enum uio_seg bufseg, int flags)
 {
 	struct mount *mp, *nmp;
-	struct statfs *sfsp, *sp, sb;
+	struct statfs *sfsp, *sp, sb, *tofree;
 	size_t count, maxcount;
 	int error;
 
+restart:
 	maxcount = bufsize / sizeof(struct statfs);
-	if (bufsize == 0)
+	if (bufsize == 0) {
 		sfsp = NULL;
-	else if (bufseg == UIO_USERSPACE)
+		tofree = NULL;
+	} else if (bufseg == UIO_USERSPACE) {
 		sfsp = *buf;
-	else /* if (bufseg == UIO_SYSSPACE) */ {
+		tofree = NULL;
+	} else /* if (bufseg == UIO_SYSSPACE) */ {
 		count = 0;
 		mtx_lock(&mountlist_mtx);
 		TAILQ_FOREACH(mp, &mountlist, mnt_list) {
@@ -464,8 +467,8 @@ kern_getfsstat(struct thread *td, struct
 		mtx_unlock(&mountlist_mtx);
 		if (maxcount > count)
 			maxcount = count;
-		sfsp = *buf = malloc(maxcount * sizeof(struct statfs), M_TEMP,
-		    M_WAITOK);
+		tofree = sfsp = *buf = malloc(maxcount * sizeof(struct statfs),
+		    M_TEMP, M_WAITOK);
 	}
 	count = 0;
 	mtx_lock(&mountlist_mtx);
@@ -480,9 +483,24 @@ kern_getfsstat(struct thread *td, struct
 			continue;
 		}
 #endif
-		if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK)) {
-			nmp = TAILQ_NEXT(mp, mnt_list);
-			continue;
+		if (flags == MNT_WAIT) {
+			if (vfs_busy(mp, MBF_MNTLSTLOCK) != 0) {
+				/*
+				 * If vfs_busy() failed, and MBF_NOWAIT
+				 * wasn't passed, then the mp is gone.
+				 * Furthermore, because of MBF_MNTLSTLOCK,
+				 * the mountlist_mtx was dropped.  We have
+				 * no other choice than to start over.
+				 */
+				mtx_unlock(&mountlist_mtx);
+				free(tofree, M_TEMP);
+				goto restart;
+			}
+		} else {
+			if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK) != 0) {
+				nmp = TAILQ_NEXT(mp, mnt_list);
+				continue;
+			}
 		}
 		if (sfsp && count < maxcount) {
 			sp = &mp->mnt_stat;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612032123.uB3LNiCI026145>