svn commit: r331616 - in head: sbin/mount sys/kern

Andriy Gapon avg at FreeBSD.org
Tue Mar 27 14:31:43 UTC 2018


Author: avg
Date: Tue Mar 27 14:31:42 2018
New Revision: 331616
URL: https://svnweb.freebsd.org/changeset/base/331616

Log:
  vfs_donmount: in certain cases try r/o mount if r/w mount fails
  
  If the operation is not an update, if neither r/w nor r/o mode is
  explicitly requested, if the error code hints at the possibility of the
  media being read-only, and if the fallback is allowed, then we can try
  to automatically downgrade to the readonly mode.
  
  This is especially useful for auto-mounting of removable media that
  sometimes can happen to be write-protected.
  
  The fallback to r/o is not enabled by default.  It can be requested on a
  per-mount basis with a new mount option, 'autoro'.  Or it can be
  globally allowed by setting vfs.default_autoro.
  
  Reviewed by:	cem, kib
  MFC after:	3 weeks
  Relnotes:	yes
  Differential Revision: https://reviews.freebsd.org/D13361

Modified:
  head/sbin/mount/mount.8
  head/sys/kern/vfs_mount.c

Modified: head/sbin/mount/mount.8
==============================================================================
--- head/sbin/mount/mount.8	Tue Mar 27 13:59:57 2018	(r331615)
+++ head/sbin/mount/mount.8	Tue Mar 27 14:31:42 2018	(r331616)
@@ -155,6 +155,10 @@ This flag indicates that the file system was mounted b
 .Xr automountd 8 .
 Automounted file systems are automatically unmounted by
 .Xr autounmountd 8 .
+.It Cm autoro
+Mount the file system read-write.
+If that fails with an error that suggests that the media could be read-only,
+then automatically try to mount the file system read-only.
 .It Cm current
 When used with the
 .Fl u

Modified: head/sys/kern/vfs_mount.c
==============================================================================
--- head/sys/kern/vfs_mount.c	Tue Mar 27 13:59:57 2018	(r331615)
+++ head/sys/kern/vfs_mount.c	Tue Mar 27 14:31:42 2018	(r331616)
@@ -81,6 +81,10 @@ static int	usermount = 0;
 SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0,
     "Unprivileged users may mount and unmount file systems");
 
+static bool	default_autoro = false;
+SYSCTL_BOOL(_vfs, OID_AUTO, default_autoro, CTLFLAG_RW, &default_autoro, 0,
+    "Retry failed r/w mount as r/o if no explicit ro/rw option is specified");
+
 MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure");
 MALLOC_DEFINE(M_STATFS, "statfs", "statfs structure");
 static uma_zone_t mount_zone;
@@ -546,6 +550,31 @@ vfs_mount_destroy(struct mount *mp)
 	uma_zfree(mount_zone, mp);
 }
 
+static bool
+vfs_should_downgrade_to_ro_mount(uint64_t fsflags, int error)
+{
+	/* This is an upgrade of an exisiting mount. */
+	if ((fsflags & MNT_UPDATE) != 0)
+		return (false);
+	/* This is already an R/O mount. */
+	if ((fsflags & MNT_RDONLY) != 0)
+		return (false);
+
+	switch (error) {
+	case ENODEV:	/* generic, geom, ... */
+	case EACCES:	/* cam/scsi, ... */
+	case EROFS:	/* md, mmcsd, ... */
+		/*
+		 * These errors can be returned by the storage layer to signal
+		 * that the media is read-only.  No harm in the R/O mount
+		 * attempt if the error was returned for some other reason.
+		 */
+		return (true);
+	default:
+		return (false);
+	}
+}
+
 int
 vfs_donmount(struct thread *td, uint64_t fsflags, struct uio *fsoptions)
 {
@@ -553,10 +582,12 @@ vfs_donmount(struct thread *td, uint64_t fsflags, stru
 	struct vfsopt *opt, *tmp_opt;
 	char *fstype, *fspath, *errmsg;
 	int error, fstypelen, fspathlen, errmsg_len, errmsg_pos;
+	bool autoro;
 
 	errmsg = fspath = NULL;
 	errmsg_len = fspathlen = 0;
 	errmsg_pos = -1;
+	autoro = default_autoro;
 
 	error = vfs_buildopts(fsoptions, &optlist);
 	if (error)
@@ -648,17 +679,28 @@ vfs_donmount(struct thread *td, uint64_t fsflags, stru
 			free(opt->name, M_MOUNT);
 			opt->name = strdup("nonosymfollow", M_MOUNT);
 		}
-		else if (strcmp(opt->name, "noro") == 0)
+		else if (strcmp(opt->name, "noro") == 0) {
 			fsflags &= ~MNT_RDONLY;
-		else if (strcmp(opt->name, "rw") == 0)
+			autoro = false;
+		}
+		else if (strcmp(opt->name, "rw") == 0) {
 			fsflags &= ~MNT_RDONLY;
-		else if (strcmp(opt->name, "ro") == 0)
+			autoro = false;
+		}
+		else if (strcmp(opt->name, "ro") == 0) {
 			fsflags |= MNT_RDONLY;
+			autoro = false;
+		}
 		else if (strcmp(opt->name, "rdonly") == 0) {
 			free(opt->name, M_MOUNT);
 			opt->name = strdup("ro", M_MOUNT);
 			fsflags |= MNT_RDONLY;
+			autoro = false;
 		}
+		else if (strcmp(opt->name, "autoro") == 0) {
+			vfs_freeopt(optlist, opt);
+			autoro = true;
+		}
 		else if (strcmp(opt->name, "suiddir") == 0)
 			fsflags |= MNT_SUIDDIR;
 		else if (strcmp(opt->name, "sync") == 0)
@@ -682,6 +724,19 @@ vfs_donmount(struct thread *td, uint64_t fsflags, stru
 	}
 
 	error = vfs_domount(td, fstype, fspath, fsflags, &optlist);
+
+	/*
+	 * See if we can mount in the read-only mode if the error code suggests
+	 * that it could be possible and the mount options allow for that.
+	 * Never try it if "[no]{ro|rw}" has been explicitly requested and not
+	 * overridden by "autoro".
+	 */
+	if (autoro && vfs_should_downgrade_to_ro_mount(fsflags, error)) {
+		printf("%s: R/W mount failed, possibly R/O media,"
+		    " trying R/O mount\n", __func__);
+		fsflags |= MNT_RDONLY;
+		error = vfs_domount(td, fstype, fspath, fsflags, &optlist);
+	}
 bail:
 	/* copyout the errmsg */
 	if (errmsg_pos != -1 && ((2 * errmsg_pos + 1) < fsoptions->uio_iovcnt)


More information about the svn-src-all mailing list