summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_mount.c
diff options
context:
space:
mode:
authorjh <jh@FreeBSD.org>2011-02-19 14:27:14 +0000
committerjh <jh@FreeBSD.org>2011-02-19 14:27:14 +0000
commitd4c0c6675e49cad63379c70ad9009fee79ac872c (patch)
treeaf7858df90f4fb3d18aff663be028bffedb2f87e /sys/kern/vfs_mount.c
parent63238d2066e987f2a713b979494a8475f82d24ff (diff)
downloadFreeBSD-src-d4c0c6675e49cad63379c70ad9009fee79ac872c.zip
FreeBSD-src-d4c0c6675e49cad63379c70ad9009fee79ac872c.tar.gz
Don't restore old mount options and flags if VFS_MOUNT(9) succeeds but
vfs_export() fails. Restoring old options and flags after successful VFS_MOUNT(9) call may cause the file system internal state to become inconsistent with mount options and flags. Specifically the FFS super block fs_ronly field and the MNT_RDONLY flag may get out of sync. PR: kern/133614 Discussed on: freebsd-hackers
Diffstat (limited to 'sys/kern/vfs_mount.c')
-rw-r--r--sys/kern/vfs_mount.c55
1 files changed, 29 insertions, 26 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index cc8321a..afb4109 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -70,7 +70,7 @@ __FBSDID("$FreeBSD$");
#define VFS_MOUNTARG_SIZE_MAX (1024 * 64)
static int vfs_domount(struct thread *td, const char *fstype,
- char *fspath, int fsflags, void *fsdata);
+ char *fspath, int fsflags, struct vfsoptlist **optlist);
static void free_mntarg(struct mntarg *ma);
static int usermount = 0;
@@ -667,7 +667,7 @@ vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions)
goto bail;
}
- error = vfs_domount(td, fstype, fspath, fsflags, optlist);
+ error = vfs_domount(td, fstype, fspath, fsflags, &optlist);
bail:
/* copyout the errmsg */
if (errmsg_pos != -1 && ((2 * errmsg_pos + 1) < fsoptions->uio_iovcnt)
@@ -683,7 +683,7 @@ bail:
}
}
- if (error != 0)
+ if (optlist != NULL)
vfs_freeopts(optlist);
return (error);
}
@@ -762,12 +762,12 @@ mount(td, uap)
*/
static int
vfs_domount_first(
- struct thread *td, /* Calling thread. */
- struct vfsconf *vfsp, /* File system type. */
- char *fspath, /* Mount path. */
- struct vnode *vp, /* Vnode to be covered. */
- int fsflags, /* Flags common to all filesystems. */
- void *fsdata /* Options local to the filesystem. */
+ struct thread *td, /* Calling thread. */
+ struct vfsconf *vfsp, /* File system type. */
+ char *fspath, /* Mount path. */
+ struct vnode *vp, /* Vnode to be covered. */
+ int fsflags, /* Flags common to all filesystems. */
+ struct vfsoptlist **optlist /* Options local to the filesystem. */
)
{
struct vattr va;
@@ -807,7 +807,7 @@ vfs_domount_first(
/* Allocate and initialize the filesystem. */
mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred);
/* XXXMAC: pass to vfs_mount_alloc? */
- mp->mnt_optnew = fsdata;
+ mp->mnt_optnew = *optlist;
/* Set the mount level flags. */
mp->mnt_flag = (fsflags & (MNT_UPDATEMASK | MNT_ROOTFS | MNT_RDONLY));
@@ -830,6 +830,7 @@ vfs_domount_first(
if (mp->mnt_opt != NULL)
vfs_freeopts(mp->mnt_opt);
mp->mnt_opt = mp->mnt_optnew;
+ *optlist = NULL;
(void)VFS_STATFS(mp, &mp->mnt_stat);
/*
@@ -872,16 +873,16 @@ vfs_domount_first(
*/
static int
vfs_domount_update(
- struct thread *td, /* Calling thread. */
- struct vnode *vp, /* Mount point vnode. */
- int fsflags, /* Flags common to all filesystems. */
- void *fsdata /* Options local to the filesystem. */
+ struct thread *td, /* Calling thread. */
+ struct vnode *vp, /* Mount point vnode. */
+ int fsflags, /* Flags common to all filesystems. */
+ struct vfsoptlist **optlist /* Options local to the filesystem. */
)
{
struct oexport_args oexport;
struct export_args export;
struct mount *mp;
- int error, flag;
+ int error, export_error, flag;
mtx_assert(&Giant, MA_OWNED);
ASSERT_VOP_ELOCKED(vp, __func__);
@@ -932,7 +933,7 @@ vfs_domount_update(
if ((mp->mnt_flag & MNT_ASYNC) == 0)
mp->mnt_kern_flag &= ~MNTK_ASYNC;
MNT_IUNLOCK(mp);
- mp->mnt_optnew = fsdata;
+ mp->mnt_optnew = *optlist;
vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt);
/*
@@ -942,11 +943,12 @@ vfs_domount_update(
*/
error = VFS_MOUNT(mp);
+ export_error = 0;
if (error == 0) {
/* Process the export option. */
if (vfs_copyopt(mp->mnt_optnew, "export", &export,
sizeof(export)) == 0) {
- error = vfs_export(mp, &export);
+ export_error = vfs_export(mp, &export);
} else if (vfs_copyopt(mp->mnt_optnew, "export", &oexport,
sizeof(oexport)) == 0) {
export.ex_flags = oexport.ex_flags;
@@ -958,7 +960,7 @@ vfs_domount_update(
export.ex_masklen = oexport.ex_masklen;
export.ex_indexfile = oexport.ex_indexfile;
export.ex_numsecflavors = 0;
- error = vfs_export(mp, &export);
+ export_error = vfs_export(mp, &export);
}
}
@@ -988,6 +990,7 @@ vfs_domount_update(
if (mp->mnt_opt != NULL)
vfs_freeopts(mp->mnt_opt);
mp->mnt_opt = mp->mnt_optnew;
+ *optlist = NULL;
(void)VFS_STATFS(mp, &mp->mnt_stat);
/*
* Prevent external consumers of mount options from reading
@@ -1005,7 +1008,7 @@ end:
vp->v_iflag &= ~VI_MOUNT;
VI_UNLOCK(vp);
vrele(vp);
- return (error);
+ return (error != 0 ? error : export_error);
}
/*
@@ -1013,11 +1016,11 @@ end:
*/
static int
vfs_domount(
- struct thread *td, /* Calling thread. */
- const char *fstype, /* Filesystem type. */
- char *fspath, /* Mount path. */
- int fsflags, /* Flags common to all filesystems. */
- void *fsdata /* Options local to the filesystem. */
+ struct thread *td, /* Calling thread. */
+ const char *fstype, /* Filesystem type. */
+ char *fspath, /* Mount path. */
+ int fsflags, /* Flags common to all filesystems. */
+ struct vfsoptlist **optlist /* Options local to the filesystem. */
)
{
struct vfsconf *vfsp;
@@ -1087,9 +1090,9 @@ vfs_domount(
vp = nd.ni_vp;
if ((fsflags & MNT_UPDATE) == 0) {
error = vfs_domount_first(td, vfsp, fspath, vp, fsflags,
- fsdata);
+ optlist);
} else {
- error = vfs_domount_update(td, vp, fsflags, fsdata);
+ error = vfs_domount_update(td, vp, fsflags, optlist);
}
mtx_unlock(&Giant);
OpenPOWER on IntegriCloud