The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=aaaa4fb54e5c427b7a8d305c3562fe5dde4ec8ec

commit aaaa4fb54e5c427b7a8d305c3562fe5dde4ec8ec
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2022-01-06 01:47:31 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2022-01-08 04:21:58 +0000

    msdosfs: use mntfs vnode for pm_devvp
    
    to prevent races with devfs VCHR vnode reclamation, same as it was
    done for UFS.
    
    Reported by:    pho
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D33721
---
 sys/fs/msdosfs/msdosfs_vfsops.c | 42 ++++++++++++++++++++++++++++++-----------
 sys/fs/msdosfs/msdosfsmount.h   |  1 +
 2 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
index 3c2606ab5a91..15f90c2e0e23 100644
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -53,6 +53,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/buf.h>
+#include <sys/bufobj.h>
 #include <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/iconv.h>
@@ -64,6 +65,7 @@
 #include <sys/namei.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
+#include <sys/rwlock.h>
 #include <sys/stat.h>
 #include <sys/taskqueue.h>
 #include <sys/vnode.h>
@@ -229,7 +231,7 @@ msdosfs_cmount(struct mntarg *ma, void *data, uint64_t 
flags)
 static int
 msdosfs_mount(struct mount *mp)
 {
-       struct vnode *devvp;      /* vnode for blk device to mount */
+       struct vnode *devvp, *odevvp;     /* vnode for blk device to mount */
        struct thread *td;
        /* msdosfs specific mount control block */
        struct msdosfsmount *pmp = NULL;
@@ -302,17 +304,17 @@ msdosfs_mount(struct mount *mp)
                         * If upgrade to read-write by non-root, then verify
                         * that user has necessary permissions on the device.
                         */
-                       devvp = pmp->pm_devvp;
-                       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
-                       error = VOP_ACCESS(devvp, VREAD | VWRITE,
+                       odevvp = pmp->pm_odevvp;
+                       vn_lock(odevvp, LK_EXCLUSIVE | LK_RETRY);
+                       error = VOP_ACCESS(odevvp, VREAD | VWRITE,
                            td->td_ucred, td);
                        if (error)
                                error = priv_check(td, PRIV_VFS_MOUNT_PERM);
                        if (error) {
-                               VOP_UNLOCK(devvp);
+                               VOP_UNLOCK(odevvp);
                                return (error);
                        }
-                       VOP_UNLOCK(devvp);
+                       VOP_UNLOCK(odevvp);
                        g_topology_lock();
                        error = g_access(pmp->pm_cp, 0, 1, 0);
                        g_topology_unlock();
@@ -385,7 +387,7 @@ msdosfs_mount(struct mount *mp)
 #endif
        } else {
                vput(devvp);
-               if (devvp != pmp->pm_devvp)
+               if (devvp != pmp->pm_odevvp)
                        return (EINVAL);        /* XXX needs translation */
        }
        if (error) {
@@ -408,11 +410,12 @@ msdosfs_mount(struct mount *mp)
 }
 
 static int
-mountmsdosfs(struct vnode *devvp, struct mount *mp)
+mountmsdosfs(struct vnode *odevvp, struct mount *mp)
 {
        struct msdosfsmount *pmp;
        struct buf *bp;
        struct cdev *dev;
+       struct vnode *devvp;
        union bootsector *bsp;
        struct byte_bpb33 *b33;
        struct byte_bpb50 *b50;
@@ -427,10 +430,13 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
        pmp = NULL;
        ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
 
+       devvp = mntfs_allocvp(mp, odevvp);
+       VOP_UNLOCK(odevvp);
+       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
        dev = devvp->v_rdev;
        if (atomic_cmpset_acq_ptr((uintptr_t *)&dev->si_mountpt, 0,
            (uintptr_t)mp) == 0) {
-               VOP_UNLOCK(devvp);
+               mntfs_freevp(devvp);
                return (EBUSY);
        }
        g_topology_lock();
@@ -438,11 +444,14 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
        g_topology_unlock();
        if (error != 0) {
                atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0);
-               VOP_UNLOCK(devvp);
+               mntfs_freevp(devvp);
                return (error);
        }
        dev_ref(dev);
        bo = &devvp->v_bufobj;
+       BO_LOCK(&odevvp->v_bufobj);
+       odevvp->v_bufobj.bo_flag |= BO_NOBUFS;
+       BO_UNLOCK(&odevvp->v_bufobj);
        VOP_UNLOCK(devvp);
        if (dev->si_iosize_max != 0)
                mp->mnt_iosize_max = dev->si_iosize_max;
@@ -709,6 +718,7 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
         * fillinusemap() needs pm_devvp.
         */
        pmp->pm_devvp = devvp;
+       pmp->pm_odevvp = odevvp;
        pmp->pm_dev = dev;
 
        /*
@@ -764,7 +774,12 @@ error_exit:
                free(pmp, M_MSDOSFSMNT);
                mp->mnt_data = NULL;
        }
+       BO_LOCK(&odevvp->v_bufobj);
+       odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS;
+       BO_UNLOCK(&odevvp->v_bufobj);
        atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0);
+       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
+       mntfs_freevp(devvp);
        dev_rel(dev);
        return (error);
 }
@@ -841,11 +856,16 @@ msdosfs_unmount(struct mount *mp, int mntflags)
        if (susp)
                vfs_write_resume(mp, VR_START_WRITE);
 
+       vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
        g_topology_lock();
        g_vfs_close(pmp->pm_cp);
        g_topology_unlock();
+       BO_LOCK(&pmp->pm_odevvp->v_bufobj);
+       pmp->pm_odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS;
+       BO_UNLOCK(&pmp->pm_odevvp->v_bufobj);
        atomic_store_rel_ptr((uintptr_t *)&pmp->pm_dev->si_mountpt, 0);
-       vrele(pmp->pm_devvp);
+       mntfs_freevp(pmp->pm_devvp);
+       vrele(pmp->pm_odevvp);
        dev_rel(pmp->pm_dev);
        free(pmp->pm_inusemap, M_MSDOSFSFAT);
        lockdestroy(&pmp->pm_fatlock);
diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h
index 6a0ba896dff5..5caa40f2b648 100644
--- a/sys/fs/msdosfs/msdosfsmount.h
+++ b/sys/fs/msdosfs/msdosfsmount.h
@@ -83,6 +83,7 @@ struct msdosfsmount {
        mode_t pm_dirmask;      /* mask to and with file protection bits
                                   for directories */
        struct vnode *pm_devvp; /* vnode for character device mounted */
+       struct vnode *pm_odevvp;/* real devfs vnode */
        struct cdev *pm_dev;    /* character device mounted */
        struct bpb50 pm_bpb;    /* BIOS parameter blk for this fs */
        u_long pm_BlkPerSec;    /* How many DEV_BSIZE blocks fit inside a 
physical sector */

Reply via email to