Page MenuHomeFreeBSD

D30152.id89176.diff
No OneTemporary

D30152.id89176.diff

Index: sys/fs/unionfs/union.h
===================================================================
--- sys/fs/unionfs/union.h
+++ sys/fs/unionfs/union.h
@@ -134,6 +134,9 @@
#define UNIONFSVPTOUPPERVP(vp) (VTOUNIONFS(vp)->un_uppervp)
#endif
+struct mount *unionfs_mount_trybusy(struct vnode *);
+void unionfs_mount_unbusy(struct mount *);
+
extern struct vop_vector unionfs_vnodeops;
#ifdef MALLOC_DECLARE
Index: sys/fs/unionfs/union_subr.c
===================================================================
--- sys/fs/unionfs/union_subr.c
+++ sys/fs/unionfs/union_subr.c
@@ -55,6 +55,8 @@
#include <sys/stat.h>
#include <sys/resourcevar.h>
+#include <machine/atomic.h>
+
#include <security/mac/mac_framework.h>
#include <vm/uma.h>
@@ -1239,7 +1241,7 @@
#ifdef DIAGNOSTIC
-struct vnode *
+struct vnode *
unionfs_checkuppervp(struct vnode *vp, char *fil, int lno)
{
struct unionfs_node *unp;
@@ -1259,7 +1261,7 @@
return (unp->un_uppervp);
}
-struct vnode *
+struct vnode *
unionfs_checklowervp(struct vnode *vp, char *fil, int lno)
{
struct unionfs_node *unp;
@@ -1279,3 +1281,31 @@
return (unp->un_lowervp);
}
#endif
+
+/*
+ * Attempt to mark the underlying mount for a vnode busy so that unionfs
+ * can safely access it or issue VFS_* operations against it.
+ * Returns NULL on failure.
+ */
+struct mount *
+unionfs_mount_trybusy(struct vnode *vp)
+{
+ struct mount *mp;
+ int error;
+
+ mp = atomic_load_ptr(&vp->v_mount);
+ if (mp == NULL)
+ return (NULL);
+ error = vfs_busy(mp, MBF_NOWAIT);
+ if (error != 0)
+ return (NULL);
+
+ return (mp);
+}
+
+void
+unionfs_mount_unbusy(struct mount *mp)
+{
+ if (mp != NULL)
+ vfs_unbusy(mp);
+}
Index: sys/fs/unionfs/union_vfsops.c
===================================================================
--- sys/fs/unionfs/union_vfsops.c
+++ sys/fs/unionfs/union_vfsops.c
@@ -75,10 +75,11 @@
unionfs_domount(struct mount *mp)
{
int error;
+ struct mount *lowermp, *uppermp;
struct vnode *lowerrootvp;
struct vnode *upperrootvp;
struct unionfs_mount *ump;
- struct thread *td;
+ struct thread *td;
char *target;
char *tmp;
char *ep;
@@ -285,18 +286,27 @@
error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp,
NULLVP, &(ump->um_rootvp), NULL, td);
vrele(upperrootvp);
- if (error) {
- free(ump, M_UNIONFSMNT);
- mp->mnt_data = NULL;
- return (error);
+ if (error != 0)
+ goto unionfs_domount_cleanup;
+
+ lowermp = unionfs_mount_trybusy(ump->um_lowervp);
+ uppermp = unionfs_mount_trybusy(ump->um_uppervp);
+ if (lowermp == NULL || uppermp == NULL)
+ error = ENOENT;
+ else {
+ MNT_ILOCK(mp);
+ 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);
}
- MNT_ILOCK(mp);
- if ((ump->um_lowervp->v_mount->mnt_flag & MNT_LOCAL) &&
- (ump->um_uppervp->v_mount->mnt_flag & MNT_LOCAL))
- mp->mnt_flag |= MNT_LOCAL;
- mp->mnt_kern_flag |= MNTK_NOMSYNC | MNTK_UNIONFS;
- MNT_IUNLOCK(mp);
+ unionfs_mount_unbusy(uppermp);
+ unionfs_mount_unbusy(lowermp);
+
+ if (error != 0)
+ goto unionfs_domount_cleanup;
/*
* Get new fsid
@@ -310,6 +320,12 @@
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
return (0);
+
+unionfs_domount_cleanup:
+
+ free(ump, M_UNIONFSMNT);
+ mp->mnt_data = NULL;
+ return (error);
}
/*
@@ -371,21 +387,37 @@
}
static int
-unionfs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg)
+unionfs_quotactl(struct mount *mp, int cmds, uid_t uid, void *arg,
+ bool *mp_busy)
{
+ struct mount *uppermp;
struct unionfs_mount *ump;
+ int error;
+ bool unbusy;
+
+ unbusy = true;
ump = MOUNTTOUNIONFSMOUNT(mp);
+ uppermp = unionfs_mount_trybusy(ump->um_uppervp);
/*
* Writing is always performed to upper vnode.
*/
- return (VFS_QUOTACTL(ump->um_uppervp->v_mount, cmd, uid, arg));
+ if (uppermp == NULL)
+ error = ENOENT;
+ else
+ error = VFS_QUOTACTL(uppermp, cmds, uid, arg, &unbusy);
+
+ if (unbusy)
+ unionfs_mount_unbusy(uppermp);
+
+ return (error);
}
static int
unionfs_statfs(struct mount *mp, struct statfs *sbp)
{
+ struct mount *lowermp, *uppermp;
struct unionfs_mount *ump;
int error;
struct statfs *mstat;
@@ -398,7 +430,13 @@
mstat = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK | M_ZERO);
- error = VFS_STATFS(ump->um_lowervp->v_mount, mstat);
+ lowermp = unionfs_mount_trybusy(ump->um_lowervp);
+ if (lowermp != NULL)
+ error = VFS_STATFS(lowermp, mstat);
+ else
+ error = ENOENT;
+
+ unionfs_mount_unbusy(lowermp);
if (error) {
free(mstat, M_STATFS);
return (error);
@@ -410,7 +448,13 @@
lbsize = mstat->f_bsize;
- error = VFS_STATFS(ump->um_uppervp->v_mount, mstat);
+ uppermp = unionfs_mount_trybusy(ump->um_uppervp);
+ if (uppermp != NULL)
+ error = VFS_STATFS(uppermp, mstat);
+ else
+ error = ENOENT;
+
+ unionfs_mount_unbusy(uppermp);
if (error) {
free(mstat, M_STATFS);
return (error);
@@ -470,19 +514,32 @@
unionfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
int namespace, const char *attrname)
{
+ struct mount *cmp;
struct unionfs_mount *ump;
struct unionfs_node *unp;
+ struct vnode *vp, *mvp;
+ int error;
ump = MOUNTTOUNIONFSMOUNT(mp);
unp = VTOUNIONFS(filename_vp);
if (unp->un_uppervp != NULLVP) {
- return (VFS_EXTATTRCTL(ump->um_uppervp->v_mount, cmd,
- unp->un_uppervp, namespace, attrname));
+ vp = unp->un_uppervp;
+ mvp = ump->um_uppervp;
} else {
- return (VFS_EXTATTRCTL(ump->um_lowervp->v_mount, cmd,
- unp->un_lowervp, namespace, attrname));
+ vp = unp->un_lowervp;
+ mvp = ump->um_lowervp;
}
+ cmp = unionfs_mount_trybusy(mvp);
+
+ if (cmp == NULL)
+ error = ENOENT;
+ else
+ error = VFS_EXTATTRCTL(cmp, cmd, vp, namespace, attrname);
+
+ unionfs_mount_unbusy(cmp);
+
+ return (error);
}
static struct vfsops unionfs_vfsops = {
Index: sys/fs/unionfs/union_vnops.c
===================================================================
--- sys/fs/unionfs/union_vnops.c
+++ sys/fs/unionfs/union_vnops.c
@@ -61,6 +61,8 @@
#include <fs/unionfs/union.h>
+#include <machine/atomic.h>
+
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <vm/vm_object.h>
@@ -671,6 +673,7 @@
static int
unionfs_access(struct vop_access_args *ap)
{
+ struct mount *uppermp;
struct unionfs_mount *ump;
struct unionfs_node *unp;
struct vnode *uvp;
@@ -714,7 +717,15 @@
if (lvp != NULLVP) {
if (accmode & VWRITE) {
- if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) {
+ uppermp = atomic_load_ptr(&ump->um_uppervp->v_mount);
+ if (uppermp == NULL)
+ return (ENOENT);
+ /*
+ * struct mount* is type-stable, so we should be able
+ * to safely access uppermp->mnt_flag even if a
+ * concurrent unmount recycles the object.
+ */
+ if (uppermp->mnt_flag & MNT_RDONLY) {
switch (ap->a_vp->v_type) {
case VREG:
case VDIR:
@@ -751,13 +762,14 @@
static int
unionfs_getattr(struct vop_getattr_args *ap)
{
- int error;
+ struct mount *uppermp;
struct unionfs_node *unp;
struct unionfs_mount *ump;
struct vnode *uvp;
struct vnode *lvp;
struct thread *td;
struct vattr va;
+ int error;
UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n");
@@ -782,7 +794,15 @@
error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred);
- if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) {
+ uppermp = atomic_load_ptr(&ump->um_uppervp->v_mount);
+ if (uppermp == NULL)
+ error = ENOENT;
+ /*
+ * struct mount* is type-stable, so we should be able to safely
+ * access uppermp->mnt_flag even if a concurrent unmount recycles
+ * the object.
+ */
+ if (error == 0 && !(uppermp->mnt_flag & MNT_RDONLY)) {
/* correct the attr toward shadow file/dir. */
if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td);

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 18, 3:37 PM (16 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15870189
Default Alt Text
D30152.id89176.diff (7 KB)

Event Timeline