summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2006-01-09 20:42:19 +0000
committertegge <tegge@FreeBSD.org>2006-01-09 20:42:19 +0000
commitd344c1186100b5323aefd8a08d585a95db5aa73c (patch)
tree63c09ce208013c75e9755db86cfe31120c538d27 /sys/kern
parent4d88aab3ea1d28d6617480348f596c37389d6434 (diff)
downloadFreeBSD-src-d344c1186100b5323aefd8a08d585a95db5aa73c.zip
FreeBSD-src-d344c1186100b5323aefd8a08d585a95db5aa73c.tar.gz
Add marker vnodes to ensure that all vnodes associated with the mount point are
iterated over when using MNT_VNODE_FOREACH. Reviewed by: truckman
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_default.c8
-rw-r--r--sys/kern/vfs_mount.c122
-rw-r--r--sys/kern/vfs_subr.c39
3 files changed, 132 insertions, 37 deletions
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index d8adf7c..be8c931 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -545,7 +545,7 @@ vfs_stdsync(mp, waitfor, td)
int waitfor;
struct thread *td;
{
- struct vnode *vp, *nvp;
+ struct vnode *vp, *mvp;
int error, lockreq, allerror = 0;
lockreq = LK_EXCLUSIVE | LK_INTERLOCK;
@@ -556,7 +556,7 @@ vfs_stdsync(mp, waitfor, td)
*/
MNT_ILOCK(mp);
loop:
- MNT_VNODE_FOREACH(vp, mp, nvp) {
+ MNT_VNODE_FOREACH(vp, mp, mvp) {
VI_LOCK(vp);
if (vp->v_bufobj.bo_dirty.bv_cnt == 0) {
@@ -567,8 +567,10 @@ loop:
if ((error = vget(vp, lockreq, td)) != 0) {
MNT_ILOCK(mp);
- if (error == ENOENT)
+ if (error == ENOENT) {
+ MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp);
goto loop;
+ }
continue;
}
error = VOP_FSYNC(vp, waitfor, td);
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index ee8c1dc..b7b31a8 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -90,6 +90,7 @@ SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0,
"Unprivileged users may mount and unmount file systems");
MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure");
+MALLOC_DEFINE(M_VNODE_MARKER, "vnodemarker", "vnode marker");
/* List of mounted filesystems. */
struct mntlist mountlist = TAILQ_HEAD_INITIALIZER(mountlist);
@@ -445,6 +446,28 @@ static void
vfs_mount_destroy(struct mount *mp, struct thread *td)
{
+ MNT_ILOCK(mp);
+ if (mp->mnt_holdcnt != 0) {
+ printf("Waiting for mount point to be unheld\n");
+ while (mp->mnt_holdcnt != 0) {
+ mp->mnt_holdcntwaiters++;
+ msleep(&mp->mnt_holdcnt, MNT_MTX(mp),
+ PZERO, "mntdestroy", 0);
+ mp->mnt_holdcntwaiters--;
+ }
+ printf("mount point unheld\n");
+ }
+ if (mp->mnt_writeopcount > 0) {
+ printf("Waiting for mount point write ops\n");
+ while (mp->mnt_writeopcount > 0) {
+ mp->mnt_kern_flag |= MNTK_SUSPEND;
+ msleep(&mp->mnt_writeopcount,
+ MNT_MTX(mp),
+ PZERO, "mntdestroy2", 0);
+ }
+ printf("mount point write ops completed\n");
+ }
+ MNT_IUNLOCK(mp);
mp->mnt_vfc->vfc_refcount--;
if (!TAILQ_EMPTY(&mp->mnt_nvnodelist))
panic("unmount: dangling vnode");
@@ -453,6 +476,12 @@ vfs_mount_destroy(struct mount *mp, struct thread *td)
MNT_ILOCK(mp);
if (mp->mnt_kern_flag & MNTK_MWAIT)
wakeup(mp);
+ if (mp->mnt_writeopcount != 0)
+ panic("vfs_mount_destroy: nonzero writeopcount");
+ if (mp->mnt_nvnodelistsize != 0)
+ panic("vfs_mount_destroy: nonzero nvnodelistsize");
+ mp->mnt_writeopcount = -1000;
+ mp->mnt_nvnodelistsize = -1000;
MNT_IUNLOCK(mp);
mtx_destroy(&mp->mnt_mtx);
#ifdef MAC
@@ -1658,27 +1687,96 @@ vfs_copyopt(opts, name, dest, len)
*/
struct vnode *
-__mnt_vnode_next(struct vnode **nvp, struct mount *mp)
+__mnt_vnode_next(struct vnode **mvp, struct mount *mp)
{
struct vnode *vp;
- mtx_assert(&mp->mnt_mtx, MA_OWNED);
+ mtx_assert(MNT_MTX(mp), MA_OWNED);
- vp = *nvp;
+ KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch"));
+ vp = TAILQ_NEXT(*mvp, v_nmntvnodes);
+ while (vp != NULL && vp->v_type == VMARKER)
+ vp = TAILQ_NEXT(vp, v_nmntvnodes);
+
/* Check if we are done */
- if (vp == NULL)
+ if (vp == NULL) {
+ __mnt_vnode_markerfree(mvp, mp);
return (NULL);
- /* If our next vnode is no longer ours, start over */
- if (vp->v_mount != mp)
- vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
- /* Save pointer to next vnode in list */
- if (vp != NULL)
- *nvp = TAILQ_NEXT(vp, v_nmntvnodes);
- else
- *nvp = NULL;
+ }
+ TAILQ_REMOVE(&mp->mnt_nvnodelist, *mvp, v_nmntvnodes);
+ TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, *mvp, v_nmntvnodes);
return (vp);
}
+struct vnode *
+__mnt_vnode_first(struct vnode **mvp, struct mount *mp)
+{
+ struct vnode *vp;
+
+ mtx_assert(MNT_MTX(mp), MA_OWNED);
+
+ vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
+ while (vp != NULL && vp->v_type == VMARKER)
+ vp = TAILQ_NEXT(vp, v_nmntvnodes);
+
+ /* Check if we are done */
+ if (vp == NULL) {
+ *mvp = NULL;
+ return (NULL);
+ }
+ mp->mnt_holdcnt++;
+ MNT_IUNLOCK(mp);
+ *mvp = (struct vnode *) malloc(sizeof(struct vnode),
+ M_VNODE_MARKER,
+ M_WAITOK | M_ZERO);
+ MNT_ILOCK(mp);
+ (*mvp)->v_type = VMARKER;
+
+ vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
+ while (vp != NULL && vp->v_type == VMARKER)
+ vp = TAILQ_NEXT(vp, v_nmntvnodes);
+
+ /* Check if we are done */
+ if (vp == NULL) {
+ MNT_IUNLOCK(mp);
+ free(*mvp, M_VNODE_MARKER);
+ MNT_ILOCK(mp);
+ *mvp = NULL;
+ mp->mnt_holdcnt--;
+ if (mp->mnt_holdcnt == 0 && mp->mnt_holdcntwaiters != 0)
+ wakeup(&mp->mnt_holdcnt);
+ return (NULL);
+ }
+ mp->mnt_markercnt++;
+ (*mvp)->v_mount = mp;
+ TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, *mvp, v_nmntvnodes);
+ return (vp);
+}
+
+
+void
+__mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp)
+{
+
+ if (*mvp == NULL)
+ return;
+
+ mtx_assert(MNT_MTX(mp), MA_OWNED);
+
+ KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch"));
+ TAILQ_REMOVE(&mp->mnt_nvnodelist, *mvp, v_nmntvnodes);
+ MNT_IUNLOCK(mp);
+ free(*mvp, M_VNODE_MARKER);
+ MNT_ILOCK(mp);
+ *mvp = NULL;
+
+ mp->mnt_markercnt--;
+ mp->mnt_holdcnt--;
+ if (mp->mnt_holdcnt == 0 && mp->mnt_holdcntwaiters != 0)
+ wakeup(&mp->mnt_holdcnt);
+}
+
+
int
__vfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
{
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index a57b2ba..629e22d 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -134,9 +134,9 @@ enum vtype iftovt_tab[16] = {
VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
};
-int vttoif_tab[9] = {
+int vttoif_tab[10] = {
0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,
- S_IFSOCK, S_IFIFO, S_IFMT,
+ S_IFSOCK, S_IFIFO, S_IFMT, S_IFMT
};
/*
@@ -566,7 +566,12 @@ vlrureclaim(struct mount *mp)
vn_start_write(NULL, &mp, V_WAIT);
MNT_ILOCK(mp);
count = mp->mnt_nvnodelistsize / 10 + 1;
- while (count && (vp = TAILQ_FIRST(&mp->mnt_nvnodelist)) != NULL) {
+ while (count != 0) {
+ vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
+ while (vp != NULL && vp->v_type == VMARKER)
+ vp = TAILQ_NEXT(vp, v_nmntvnodes);
+ if (vp == NULL)
+ break;
TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
--count;
@@ -968,6 +973,8 @@ insmntque(struct vnode *vp, struct mount *mp)
VNASSERT(mp != NULL, vp, ("Don't call insmntque(foo, NULL)"));
MNT_ILOCK(vp->v_mount);
TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
+ VNASSERT(mp->mnt_nvnodelistsize >= 0, vp,
+ ("neg mount point vnode list size"));
mp->mnt_nvnodelistsize++;
MNT_IUNLOCK(vp->v_mount);
}
@@ -2241,7 +2248,7 @@ vflush(mp, rootrefs, flags, td)
int flags;
struct thread *td;
{
- struct vnode *vp, *nvp, *rootvp = NULL;
+ struct vnode *vp, *mvp, *rootvp = NULL;
struct vattr vattr;
int busy = 0, error;
@@ -2260,7 +2267,7 @@ vflush(mp, rootrefs, flags, td)
}
MNT_ILOCK(mp);
loop:
- MNT_VNODE_FOREACH(vp, mp, nvp) {
+ MNT_VNODE_FOREACH(vp, mp, mvp) {
VI_LOCK(vp);
vholdl(vp);
@@ -2269,6 +2276,7 @@ loop:
if (error) {
vdrop(vp);
MNT_ILOCK(mp);
+ MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp);
goto loop;
}
/*
@@ -2489,7 +2497,8 @@ count_dev(dev)
* Print out a description of a vnode.
*/
static char *typename[] =
-{"VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD"};
+{"VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD",
+ "VMARKER"};
void
vn_printf(struct vnode *vp, const char *fmt, ...)
@@ -2818,20 +2827,11 @@ vfs_unmountall()
void
vfs_msync(struct mount *mp, int flags)
{
- struct vnode *vp, *nvp;
+ struct vnode *vp, *mvp;
struct vm_object *obj;
- int tries;
- tries = 5;
MNT_ILOCK(mp);
-loop:
- TAILQ_FOREACH_SAFE(vp, &mp->mnt_nvnodelist, v_nmntvnodes, nvp) {
- if (vp->v_mount != mp) {
- if (--tries > 0)
- goto loop;
- break;
- }
-
+ MNT_VNODE_FOREACH(vp, mp, mvp) {
VI_LOCK(vp);
if ((vp->v_iflag & VI_OBJDIRTY) &&
(flags == MNT_WAIT || VOP_ISLOCKED(vp, NULL) == 0)) {
@@ -2856,11 +2856,6 @@ loop:
vput(vp);
}
MNT_ILOCK(mp);
- if (TAILQ_NEXT(vp, v_nmntvnodes) != nvp) {
- if (--tries > 0)
- goto loop;
- break;
- }
} else
VI_UNLOCK(vp);
}
OpenPOWER on IntegriCloud