Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F149526922
D30401.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D30401.diff
View Options
diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c
--- a/sys/fs/nullfs/null_vfsops.c
+++ b/sys/fs/nullfs/null_vfsops.c
@@ -163,7 +163,12 @@
* Save pointer to underlying FS and the reference to the
* lower root vnode.
*/
- xmp->nullm_vfs = lowerrootvp->v_mount;
+ xmp->nullm_vfs = vfs_pin_from_vp(lowerrootvp);
+ if (xmp->nullm_vfs == NULL) {
+ vput(lowerrootvp);
+ free(xmp, M_NULLFSMNT);
+ return (ENOENT);
+ }
vref(lowerrootvp);
xmp->nullm_lowerrootvp = lowerrootvp;
mp->mnt_data = xmp;
@@ -173,6 +178,7 @@
*/
error = null_nodeget(mp, lowerrootvp, &nullm_rootvp);
if (error != 0) {
+ vfs_unpin(xmp->nullm_vfs);
vrele(lowerrootvp);
free(xmp, M_NULLFSMNT);
return (error);
@@ -263,6 +269,7 @@
TAILQ_REMOVE(&ump->mnt_uppers, mp, mnt_upper_link);
MNT_IUNLOCK(ump);
}
+ vfs_unpin(ump);
vrele(mntdata->nullm_lowerrootvp);
mp->mnt_data = NULL;
free(mntdata, M_NULLFSMNT);
diff --git a/sys/fs/unionfs/union_vfsops.c b/sys/fs/unionfs/union_vfsops.c
--- a/sys/fs/unionfs/union_vfsops.c
+++ b/sys/fs/unionfs/union_vfsops.c
@@ -75,6 +75,7 @@
unionfs_domount(struct mount *mp)
{
int error;
+ struct mount *lowermp, *uppermp;
struct vnode *lowerrootvp;
struct vnode *upperrootvp;
struct unionfs_mount *ump;
@@ -285,15 +286,28 @@
error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp,
NULLVP, &(ump->um_rootvp), NULL, td);
vrele(upperrootvp);
- if (error) {
+ if (error != 0) {
free(ump, M_UNIONFSMNT);
mp->mnt_data = NULL;
return (error);
}
+ lowermp = vfs_pin_from_vp(ump->um_lowervp);
+ uppermp = vfs_pin_from_vp(ump->um_uppervp);
+
+ if (lowermp == NULL || uppermp == NULL) {
+ if (lowermp != NULL)
+ vfs_unpin(lowermp);
+ if (uppermp != NULL)
+ vfs_unpin(uppermp);
+ free(ump, M_UNIONFSMNT);
+ mp->mnt_data = NULL;
+ return (ENOENT);
+ }
+
MNT_ILOCK(mp);
- if ((ump->um_lowervp->v_mount->mnt_flag & MNT_LOCAL) &&
- (ump->um_uppervp->v_mount->mnt_flag & MNT_LOCAL))
+ if ((lowermp->mnt_flag & MNT_LOCAL) != 0 &&
+ (uppermp->mnt_flag & MNT_LOCAL) != 0)
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_kern_flag |= MNTK_NOMSYNC | MNTK_UNIONFS;
MNT_IUNLOCK(mp);
@@ -343,6 +357,8 @@
if (error)
return (error);
+ vfs_unpin(ump->um_lowervp->v_mount);
+ vfs_unpin(ump->um_uppervp->v_mount);
free(ump, M_UNIONFSMNT);
mp->mnt_data = NULL;
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -49,6 +49,7 @@
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/libkern.h>
+#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/mutex.h>
@@ -504,6 +505,39 @@
MNT_IUNLOCK(mp);
}
+struct mount *
+vfs_pin_from_vp(struct vnode *vp)
+{
+ struct mount *mp;
+
+ mp = atomic_load_ptr(&vp->v_mount);
+ if (mp == NULL)
+ return (NULL);
+ MNT_ILOCK(mp);
+ if (mp != vp->v_mount || (mp->mnt_kern_flag & MNTK_UNMOUNT) != 0) {
+ MNT_IUNLOCK(mp);
+ return (NULL);
+ }
+ MNT_REF(mp);
+ KASSERT(mp->mnt_pinned_count < INT_MAX,
+ ("mount pinned count overflow"));
+ ++mp->mnt_pinned_count;
+ MNT_IUNLOCK(mp);
+ return (mp);
+}
+
+void
+vfs_unpin(struct mount *mp)
+{
+ MNT_ILOCK(mp);
+ KASSERT(mp->mnt_pinned_count > 0, ("mount pinned count underflow"));
+ KASSERT((mp->mnt_kern_flag & MNTK_UNMOUNT) == 0,
+ ("mount pinned with pending unmount"));
+ --mp->mnt_pinned_count;
+ MNT_REL(mp);
+ MNT_IUNLOCK(mp);
+}
+
void
vfs_rel(struct mount *mp)
{
@@ -567,6 +601,7 @@
#endif
arc4rand(&mp->mnt_hashseed, sizeof mp->mnt_hashseed, 0);
TAILQ_INIT(&mp->mnt_uppers);
+ mp->mnt_pinned_count = 0;
return (mp);
}
@@ -605,6 +640,8 @@
vn_printf(vp, "dangling vnode ");
panic("unmount: dangling vnode");
}
+ KASSERT(mp->mnt_pinned_count == 0,
+ ("mnt_pinned_count = %d", mp->mnt_pinned_count));
KASSERT(TAILQ_EMPTY(&mp->mnt_uppers), ("mnt_uppers"));
if (mp->mnt_nvnodelistsize != 0)
panic("vfs_mount_destroy: nonzero nvnodelistsize");
@@ -1811,7 +1848,7 @@
MNT_ILOCK(mp);
if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 ||
(mp->mnt_flag & MNT_UPDATE) != 0 ||
- !TAILQ_EMPTY(&mp->mnt_uppers)) {
+ mp->mnt_pinned_count != 0) {
dounmount_cleanup(mp, coveredvp, 0);
return (EBUSY);
}
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -831,6 +831,9 @@
* valid.
*/
while (mp->mnt_kern_flag & MNTK_UNMOUNT) {
+ KASSERT(mp->mnt_pinned_count == 0,
+ ("%s: non-zero pinned count %d with pending unmount",
+ __func__, mp->mnt_pinned_count));
if (flags & MBF_NOWAIT || mp->mnt_kern_flag & MNTK_REFEXPIRE) {
MNT_REL(mp);
MNT_IUNLOCK(mp);
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -242,6 +242,7 @@
struct mtx mnt_listmtx;
struct vnodelst mnt_lazyvnodelist; /* (l) list of lazy vnodes */
int mnt_lazyvnodelistsize; /* (l) # of lazy vnodes */
+ int mnt_pinned_count; /* (i) unmount prevented */
struct lock mnt_explock; /* vfs_export walkers lock */
TAILQ_ENTRY(mount) mnt_upper_link; /* (i*) we in the all uppers */
TAILQ_HEAD(, mount) mnt_uppers; /* (i) upper mounts over us */
@@ -1011,6 +1012,8 @@
int vfs_suser(struct mount *, struct thread *);
void vfs_unbusy(struct mount *);
void vfs_unmountall(void);
+struct mount *vfs_pin_from_vp(struct vnode *);
+void vfs_unpin(struct mount *);
extern TAILQ_HEAD(mntlist, mount) mountlist; /* mounted filesystem list */
extern struct mtx_padalign mountlist_mtx;
extern struct nfs_public nfs_pub;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 26, 1:00 AM (4 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30356450
Default Alt Text
D30401.diff (5 KB)
Attached To
Mode
D30401: Add a generic mechanism for preventing forced unmount
Attached
Detach File
Event Timeline
Log In to Comment