diff options
author | jeff <jeff@FreeBSD.org> | 2006-02-22 06:29:55 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2006-02-22 06:29:55 +0000 |
commit | 5495fe549e8aa0d8c1708e5f6ce9a5104dd0f2c2 (patch) | |
tree | a34b5cedb551c48ba1084660b4269ff00f6a8ee3 /sys | |
parent | d099befc573acb0eb5b095b7f0d22beb38abc067 (diff) | |
download | FreeBSD-src-5495fe549e8aa0d8c1708e5f6ce9a5104dd0f2c2.zip FreeBSD-src-5495fe549e8aa0d8c1708e5f6ce9a5104dd0f2c2.tar.gz |
- We can not hold a vnode lock while we do a lookup. Search for and load
modules prior to looking up the directory which we will cover to avoid
this problem in mount.
- We must hold the coveredvp locked before we can busy the mountpoint to
prevent a lock order reversal with the vfs_busy() in lookup which holds
the directory lock prior to doing a vfs_busy(). The directory lock is
required to safely clear the v_mountedhere field on the directory.
MFC After: 1 week
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/vfs_mount.c | 44 |
1 files changed, 25 insertions, 19 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 0e7aa86..d0c9f41 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -466,6 +466,7 @@ vfs_mount_destroy(struct mount *mp, struct thread *td) { int i; + vfs_unbusy(mp, td); MNT_ILOCK(mp); for (i = 0; mp->mnt_ref && i < 3; i++) msleep(mp, MNT_MTX(mp), PVFS, "mntref", hz); @@ -501,7 +502,6 @@ vfs_mount_destroy(struct mount *mp, struct thread *td) mp->mnt_vfc->vfc_refcount--; if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) panic("unmount: dangling vnode"); - vfs_unbusy(mp,td); lockdestroy(&mp->mnt_lock); MNT_ILOCK(mp); if (mp->mnt_kern_flag & MNTK_MWAIT) @@ -741,7 +741,6 @@ vfs_domount( struct nameidata nd; mtx_assert(&Giant, MA_OWNED); - /* * Be ultra-paranoid about making sure the type and fspath * variables will fit in our mp buffers, including the @@ -770,6 +769,18 @@ vfs_domount( */ if (suser(td) != 0) fsflags |= MNT_NOSUID | MNT_USER; + + /* Load KLDs before we lock the covered vnode to avoid reversals. */ + vfsp = NULL; + if ((fsflags & MNT_UPDATE) == 0) { + /* Don't try to load KLDs if we're mounting the root. */ + if (fsflags & MNT_ROOTFS) + vfsp = vfs_byname(fstype); + else + vfsp = vfs_byname_kld(fstype, td, &error); + if (vfsp == NULL) + return (ENODEV); + } /* * Get vnode to be covered */ @@ -848,19 +859,6 @@ vfs_domount( vput(vp); return (ENOTDIR); } - /* Don't try to load KLDs if we're mounting the root. */ - if (fsflags & MNT_ROOTFS) { - if ((vfsp = vfs_byname(fstype)) == NULL) { - vput(vp); - return (ENODEV); - } - } else { - vfsp = vfs_byname_kld(fstype, td, &error); - if (vfsp == NULL) { - vput(vp); - return (error); - } - } VI_LOCK(vp); if ((vp->v_iflag & VI_MOUNT) != 0 || vp->v_mountedhere != NULL) { @@ -1069,9 +1067,13 @@ dounmount(mp, flags, td) mtx_assert(&Giant, MA_OWNED); + if ((coveredvp = mp->mnt_vnodecovered) != NULL) + vn_lock(coveredvp, LK_EXCLUSIVE | LK_RETRY, td); MNT_ILOCK(mp); if (mp->mnt_kern_flag & MNTK_UNMOUNT) { MNT_IUNLOCK(mp); + if (coveredvp) + VOP_UNLOCK(coveredvp, 0, td); return (EBUSY); } mp->mnt_kern_flag |= MNTK_UNMOUNT; @@ -1086,6 +1088,8 @@ dounmount(mp, flags, td) if (mp->mnt_kern_flag & MNTK_MWAIT) wakeup(mp); MNT_IUNLOCK(mp); + if (coveredvp) + VOP_UNLOCK(coveredvp, 0, td); return (error); } vn_start_write(NULL, &mp, V_WAIT); @@ -1141,17 +1145,19 @@ dounmount(mp, flags, td) if (mp->mnt_kern_flag & MNTK_MWAIT) wakeup(mp); MNT_IUNLOCK(mp); + if (coveredvp) + VOP_UNLOCK(coveredvp, 0, td); return (error); } mtx_lock(&mountlist_mtx); TAILQ_REMOVE(&mountlist, mp, mnt_list); - if ((coveredvp = mp->mnt_vnodecovered) != NULL) - coveredvp->v_mountedhere = NULL; mtx_unlock(&mountlist_mtx); + if (coveredvp != NULL) { + coveredvp->v_mountedhere = NULL; + vput(coveredvp); + } vfs_event_signal(NULL, VQ_UNMOUNT, 0); vfs_mount_destroy(mp, td); - if (coveredvp != NULL) - vrele(coveredvp); return (0); } |