diff options
author | tegge <tegge@FreeBSD.org> | 2006-09-26 04:12:49 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2006-09-26 04:12:49 +0000 |
commit | 83154f853d9ca39deb1add01e032aff1f0678514 (patch) | |
tree | ac46e0b5a80f88127d3d14dc940a5f2746573c00 /sys/ufs/ffs | |
parent | d7fe3e736512a1dd37a985037184eecf7df1f26d (diff) | |
download | FreeBSD-src-83154f853d9ca39deb1add01e032aff1f0678514.zip FreeBSD-src-83154f853d9ca39deb1add01e032aff1f0678514.tar.gz |
Use mount interlock to protect all changes to mnt_flag and mnt_kern_flag.
This eliminates a race where MNT_UPDATE flag could be lost when nmount()
raced against sync(), sync_fsync() or quotactl().
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r-- | sys/ufs/ffs/ffs_snapshot.c | 7 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 2 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 56 |
3 files changed, 51 insertions, 14 deletions
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index b183569..f23f098 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -194,7 +194,7 @@ ffs_snapshot(mp, snapfile) ufs2_daddr_t numblks, blkno, *blkp, *snapblklist; int error, cg, snaploc; int i, size, len, loc; - int flag = mp->mnt_flag; + int flag; struct timespec starttime = {0, 0}, endtime; char saved_nice = 0; long redo = 0, snaplistsize = 0; @@ -216,6 +216,9 @@ ffs_snapshot(mp, snapfile) ump = VFSTOUFS(mp); fs = ump->um_fs; sn = NULL; + MNT_ILOCK(mp); + flag = mp->mnt_flag; + MNT_IUNLOCK(mp); /* * Need to serialize access to snapshot code per filesystem. @@ -828,7 +831,9 @@ out: fs->fs_active = 0; } UFS_UNLOCK(ump); + MNT_ILOCK(mp); mp->mnt_flag = flag; + MNT_IUNLOCK(mp); if (error) (void) ffs_truncate(vp, (off_t)0, 0, NOCRED, td); (void) ffs_syncvnode(vp, MNT_WAIT); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index d2f6015..6805563 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -1423,8 +1423,10 @@ softdep_mount(devvp, mp, fs, cred) struct buf *bp; int error, cyl; + MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_ASYNC; mp->mnt_flag |= MNT_SOFTDEP; + MNT_IUNLOCK(mp); ump = VFSTOUFS(mp); LIST_INIT(&ump->softdep_workitem_pending); ump->softdep_worklist_tail = NULL; diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 0c12305..1c8c4d3 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -129,6 +129,7 @@ ffs_mount(struct mount *mp, struct thread *td) struct ufsmount *ump = 0; struct fs *fs; int error, flags; + u_int mntorflags, mntandnotflags; mode_t accessmode; struct nameidata ndp; char *fspec; @@ -151,33 +152,38 @@ ffs_mount(struct mount *mp, struct thread *td) if (error) return (error); + mntorflags = 0; + mntandnotflags = 0; if (vfs_getopt(mp->mnt_optnew, "acls", NULL, NULL) == 0) - mp->mnt_flag |= MNT_ACLS; + mntorflags |= MNT_ACLS; if (vfs_getopt(mp->mnt_optnew, "async", NULL, NULL) == 0) - mp->mnt_flag |= MNT_ASYNC; + mntorflags |= MNT_ASYNC; if (vfs_getopt(mp->mnt_optnew, "force", NULL, NULL) == 0) - mp->mnt_flag |= MNT_FORCE; + mntorflags |= MNT_FORCE; if (vfs_getopt(mp->mnt_optnew, "multilabel", NULL, NULL) == 0) - mp->mnt_flag |= MNT_MULTILABEL; + mntorflags |= MNT_MULTILABEL; if (vfs_getopt(mp->mnt_optnew, "noasync", NULL, NULL) == 0) - mp->mnt_flag &= ~MNT_ASYNC; + mntandnotflags |= MNT_ASYNC; if (vfs_getopt(mp->mnt_optnew, "noatime", NULL, NULL) == 0) - mp->mnt_flag |= MNT_NOATIME; + mntorflags |= MNT_NOATIME; if (vfs_getopt(mp->mnt_optnew, "noclusterr", NULL, NULL) == 0) - mp->mnt_flag |= MNT_NOCLUSTERR; + mntorflags |= MNT_NOCLUSTERR; if (vfs_getopt(mp->mnt_optnew, "noclusterw", NULL, NULL) == 0) - mp->mnt_flag |= MNT_NOCLUSTERW; + mntorflags |= MNT_NOCLUSTERW; if (vfs_getopt(mp->mnt_optnew, "snapshot", NULL, NULL) == 0) - mp->mnt_flag |= MNT_SNAPSHOT; + mntorflags |= MNT_SNAPSHOT; + MNT_ILOCK(mp); + mp->mnt_flag = (mp->mnt_flag | mntorflags) & ~mntandnotflags; + MNT_IUNLOCK(mp); /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. @@ -237,7 +243,9 @@ ffs_mount(struct mount *mp, struct thread *td) g_topology_unlock(); PICKUP_GIANT(); fs->fs_ronly = 1; + MNT_ILOCK(mp); mp->mnt_flag |= MNT_RDONLY; + MNT_IUNLOCK(mp); } if ((mp->mnt_flag & MNT_RELOAD) && (error = ffs_reload(mp, td)) != 0) @@ -289,7 +297,9 @@ ffs_mount(struct mount *mp, struct thread *td) if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0) return (error); fs->fs_ronly = 0; + MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_RDONLY; + MNT_IUNLOCK(mp); fs->fs_clean = 0; if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) { vn_finished_write(mp); @@ -312,13 +322,21 @@ ffs_mount(struct mount *mp, struct thread *td) * Softdep_mount() clears it in an initial mount * or ro->rw remount. */ - if (mp->mnt_flag & MNT_SOFTDEP) + if (mp->mnt_flag & MNT_SOFTDEP) { + /* XXX: Reset too late ? */ + MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_ASYNC; + MNT_IUNLOCK(mp); + } /* * Keep MNT_ACLS flag if it is stored in superblock. */ - if ((fs->fs_flags & FS_ACLS) != 0) + if ((fs->fs_flags & FS_ACLS) != 0) { + /* XXX: Set too late ? */ + MNT_ILOCK(mp); mp->mnt_flag |= MNT_ACLS; + MNT_IUNLOCK(mp); + } /* * If this is a snapshot request, take the snapshot. @@ -745,23 +763,31 @@ ffs_mountfs(devvp, mp, td) vfs_getnewfsid(mp); } mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; + MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; - if ((fs->fs_flags & FS_MULTILABEL) != 0) + MNT_IUNLOCK(mp); + if ((fs->fs_flags & FS_MULTILABEL) != 0) { #ifdef MAC + MNT_ILOCK(mp); mp->mnt_flag |= MNT_MULTILABEL; + MNT_IUNLOCK(mp); #else printf( "WARNING: %s: multilabel flag on fs but no MAC support\n", mp->mnt_stat.f_mntonname); #endif - if ((fs->fs_flags & FS_ACLS) != 0) + } + if ((fs->fs_flags & FS_ACLS) != 0) { #ifdef UFS_ACL + MNT_ILOCK(mp); mp->mnt_flag |= MNT_ACLS; + MNT_IUNLOCK(mp); #else printf( "WARNING: %s: ACLs flag on fs but no ACLs support\n", mp->mnt_stat.f_mntonname); #endif + } ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; @@ -825,7 +851,9 @@ ffs_mountfs(devvp, mp, td) */ devvp->v_bufobj.bo_flag |= BO_NEEDSGIANT; #else + MNT_ILOCK(mp); mp->mnt_kern_flag |= MNTK_MPSAFE; + MNT_IUNLOCK(mp); #endif return (0); out: @@ -1003,7 +1031,9 @@ ffs_unmount(mp, mntflags, td) free(fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; + MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_LOCAL; + MNT_IUNLOCK(mp); return (error); } |