diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c --- a/sys/fs/unionfs/union_subr.c +++ b/sys/fs/unionfs/union_subr.c @@ -760,7 +760,7 @@ struct vnode *uvp; struct vattr va; struct vattr lva; - struct componentname cn; + struct nameidata nd; struct mount *mp; struct ucred *cred; struct ucred *credbk; @@ -787,12 +787,14 @@ uifree(rootinfo); cnp->cn_cred = cred; - memset(&cn, 0, sizeof(cn)); + memset(&nd.ni_cnd, 0, sizeof(struct componentname)); + NDPREINIT(&nd); if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred))) goto unionfs_mkshadowdir_abort; - if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, td, cnp->cn_nameptr, cnp->cn_namelen, CREATE))) + if ((error = unionfs_relookup(udvp, &uvp, cnp, &nd.ni_cnd, td, + cnp->cn_nameptr, cnp->cn_namelen, CREATE))) goto unionfs_mkshadowdir_abort; if (uvp != NULLVP) { if (udvp == uvp) @@ -808,7 +810,7 @@ goto unionfs_mkshadowdir_free_out; unionfs_create_uppervattr_core(ump, &lva, &va, td); - error = VOP_MKDIR(udvp, &uvp, &cn, &va); + error = VOP_MKDIR(udvp, &uvp, &nd.ni_cnd, &va); if (!error) { unionfs_node_update(unp, uvp, td); @@ -818,14 +820,14 @@ * Ignore errors. */ va.va_type = VNON; - VOP_SETATTR(uvp, &va, cn.cn_cred); + VOP_SETATTR(uvp, &va, nd.ni_cnd.cn_cred); } vn_finished_write(mp); unionfs_mkshadowdir_free_out: - if (cn.cn_flags & HASBUF) { - uma_zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~HASBUF; + if (nd.ni_cnd.cn_flags & HASBUF) { + uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; } unionfs_mkshadowdir_abort: @@ -847,19 +849,21 @@ { int error; struct vnode *wvp; - struct componentname cn; + struct nameidata nd; struct mount *mp; if (path == NULL) path = cnp->cn_nameptr; wvp = NULLVP; - if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, td, path, strlen(path), CREATE))) + NDPREINIT(&nd); + if ((error = unionfs_relookup(dvp, &wvp, cnp, &nd.ni_cnd, td, path, + strlen(path), CREATE))) return (error); if (wvp != NULLVP) { - if (cn.cn_flags & HASBUF) { - uma_zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~HASBUF; + if (nd.ni_cnd.cn_flags & HASBUF) { + uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; } if (dvp == wvp) vrele(wvp); @@ -871,14 +875,14 @@ if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH))) goto unionfs_mkwhiteout_free_out; - error = VOP_WHITEOUT(dvp, &cn, CREATE); + error = VOP_WHITEOUT(dvp, &nd.ni_cnd, CREATE); vn_finished_write(mp); unionfs_mkwhiteout_free_out: - if (cn.cn_flags & HASBUF) { - uma_zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~HASBUF; + if (nd.ni_cnd.cn_flags & HASBUF) { + uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; } return (error); @@ -904,7 +908,7 @@ struct vattr lva; int fmode; int error; - struct componentname cn; + struct nameidata nd; ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount); vp = NULLVP; @@ -920,18 +924,20 @@ if (unp->un_path == NULL) panic("unionfs: un_path is null"); - cn.cn_namelen = strlen(unp->un_path); - cn.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); - bcopy(unp->un_path, cn.cn_pnbuf, cn.cn_namelen + 1); - cn.cn_nameiop = CREATE; - cn.cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN); - cn.cn_lkflags = LK_EXCLUSIVE; - cn.cn_thread = td; - cn.cn_cred = cred; - cn.cn_nameptr = cn.cn_pnbuf; + nd.ni_cnd.cn_namelen = strlen(unp->un_path); + nd.ni_cnd.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); + bcopy(unp->un_path, nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_namelen + 1); + nd.ni_cnd.cn_nameiop = CREATE; + nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | + ISLASTCN; + nd.ni_cnd.cn_lkflags = LK_EXCLUSIVE; + nd.ni_cnd.cn_thread = td; + nd.ni_cnd.cn_cred = cred; + nd.ni_cnd.cn_nameptr = nd.ni_cnd.cn_pnbuf; + NDPREINIT(&nd); vref(udvp); - if ((error = relookup(udvp, &vp, &cn)) != 0) + if ((error = relookup(udvp, &vp, &nd.ni_cnd)) != 0) goto unionfs_vn_create_on_upper_free_out2; vrele(udvp); @@ -944,7 +950,7 @@ goto unionfs_vn_create_on_upper_free_out1; } - if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0) + if ((error = VOP_CREATE(udvp, &vp, &nd.ni_cnd, uvap)) != 0) goto unionfs_vn_create_on_upper_free_out1; if ((error = VOP_OPEN(vp, fmode, cred, td, NULL)) != 0) { @@ -964,9 +970,9 @@ VOP_UNLOCK(udvp); unionfs_vn_create_on_upper_free_out2: - if (cn.cn_flags & HASBUF) { - uma_zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~HASBUF; + if (nd.ni_cnd.cn_flags & HASBUF) { + uma_zfree(namei_zone, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; } return (error); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1328,6 +1328,7 @@ } if (error != 0) return (error); + NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1 | @@ -1436,6 +1437,7 @@ int error; AUDIT_ARG_MODE(mode); + NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1 | @@ -1566,6 +1568,7 @@ struct nameidata nd; int error; + NDPREINIT(&nd); do { bwillwrite(); NDINIT_ATRIGHTS(&nd, LOOKUP, AUDITVNODE1 | at2cnpflags(flag, @@ -1714,6 +1717,7 @@ syspath = tmppath; } AUDIT_ARG_TEXT(syspath); + NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1 | @@ -1778,6 +1782,7 @@ struct nameidata nd; int error; + NDPREINIT(&nd); restart: bwillwrite(); NDINIT(&nd, DELETE, LOCKPARENT | DOWHITEOUT | AUDITVNODE1, @@ -1891,6 +1896,7 @@ return (error); } + NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | @@ -3422,6 +3428,7 @@ if (length < 0) return (EINVAL); + NDPREINIT(&nd); retry: NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, td); if ((error = namei(&nd)) != 0) @@ -3789,6 +3796,7 @@ int error; AUDIT_ARG_MODE(mode); + NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1 | @@ -3859,6 +3867,7 @@ return (error); } + NDPREINIT(&nd); restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | diff --git a/sys/sys/namei.h b/sys/sys/namei.h --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -38,6 +38,7 @@ #include #include #include +#include #include enum nameiop { LOOKUP, CREATE, DELETE, RENAME }; @@ -111,6 +112,12 @@ */ struct componentname ni_cnd; struct nameicap_tracker_head ni_cap_tracker; + /* + * Private helper data for UFS, must be at the end. See + * NDINIT_PREFILL(). + */ + seqc_t ni_dvp_seqc; + seqc_t ni_vp_seqc; }; #ifdef _KERNEL @@ -224,7 +231,8 @@ * Note the constant pattern may *hide* bugs. */ #ifdef INVARIANTS -#define NDINIT_PREFILL(arg) memset(arg, 0xff, sizeof(*arg)) +#define NDINIT_PREFILL(arg) memset(arg, 0xff, offsetof(struct nameidata, \ + ni_dvp_seqc)) #define NDINIT_DBG(arg) { (arg)->ni_debugflags = NAMEI_DBG_INITED; } #define NDREINIT_DBG(arg) { \ if (((arg)->ni_debugflags & NAMEI_DBG_INITED) == 0) \ @@ -265,6 +273,11 @@ _ndp->ni_startdir = NULL; \ } while (0) +#define NDPREINIT(ndp) do { \ + (ndp)->ni_dvp_seqc = SEQC_MOD; \ + (ndp)->ni_vp_seqc = SEQC_MOD; \ +} while (0) + #define NDF_NO_DVP_RELE 0x00000001 #define NDF_NO_DVP_UNLOCK 0x00000002 #define NDF_NO_DVP_PUT 0x00000003 diff --git a/sys/sys/seqc.h b/sys/sys/seqc.h --- a/sys/sys/seqc.h +++ b/sys/sys/seqc.h @@ -45,13 +45,15 @@ #include +#define SEQC_MOD 1 + /* * Predicts from inline functions are not honored by clang. */ #define seqc_in_modify(seqc) ({ \ seqc_t __seqc = (seqc); \ \ - __predict_false(__seqc & 1); \ + __predict_false(__seqc & SEQC_MOD); \ }) static __inline void @@ -60,7 +62,7 @@ critical_enter(); MPASS(!seqc_in_modify(*seqcp)); - *seqcp += 1; + *seqcp += SEQC_MOD; atomic_thread_fence_rel(); } @@ -69,7 +71,7 @@ { atomic_thread_fence_rel(); - *seqcp += 1; + *seqcp += SEQC_MOD; MPASS(!seqc_in_modify(*seqcp)); critical_exit(); } @@ -85,7 +87,7 @@ seqc_read_notmodify(const seqc_t *seqcp) { - return (atomic_load_acq_int(__DECONST(seqc_t *, seqcp)) & ~1); + return (atomic_load_acq_int(__DECONST(seqc_t *, seqcp)) & ~SEQC_MOD); } static __inline seqc_t @@ -126,7 +128,7 @@ { MPASS(!seqc_in_modify(*seqcp)); - *seqcp += 1; + *seqcp += SEQC_MOD; atomic_thread_fence_rel(); } @@ -135,7 +137,7 @@ { atomic_thread_fence_rel(); - *seqcp += 1; + *seqcp += SEQC_MOD; MPASS(!seqc_in_modify(*seqcp)); } diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -517,6 +517,7 @@ } */ *ap; { struct ufsmount *ump; + int error; /* * We used to skip reallocating the blocks of a file into a @@ -546,9 +547,11 @@ if (DOINGSUJ(ap->a_vp)) if (softdep_prealloc(ap->a_vp, MNT_NOWAIT) != 0) return (ENOSPC); - if (ump->um_fstype == UFS1) - return (ffs_reallocblks_ufs1(ap)); - return (ffs_reallocblks_ufs2(ap)); + vn_seqc_write_begin(ap->a_vp); + error = ump->um_fstype == UFS1 ? ffs_reallocblks_ufs1(ap) : + ffs_reallocblks_ufs2(ap); + vn_seqc_write_end(ap->a_vp); + return (error); } static int diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c --- a/sys/ufs/ffs/ffs_balloc.c +++ b/sys/ufs/ffs/ffs_balloc.c @@ -128,6 +128,8 @@ return (EFBIG); gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; + vn_seqc_write_begin(vp); + /* * If the next write will extend the file into a new block, * and the file is currently composed of a fragment @@ -144,7 +146,7 @@ &dp->di_db[0]), osize, (int)fs->fs_bsize, flags, cred, &bp); if (error) - return (error); + goto done; if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, nb, dbtofsb(fs, bp->b_blkno), dp->di_db[nb], @@ -174,17 +176,20 @@ error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); if (error != 0) - return (error); + goto done; } else { bp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); - if (bp == NULL) - return (EIO); + if (bp == NULL) { + error = EIO; + goto done; + } vfs_bio_clrbuf(bp); } bp->b_blkno = fsbtodb(fs, nb); *bpp = bp; - return (0); + error = 0; + goto done; } if (nb != 0) { /* @@ -194,9 +199,8 @@ nsize = fragroundup(fs, size); if (nsize <= osize) { error = bread(vp, lbn, osize, NOCRED, &bp); - if (error) { - return (error); - } + if (error) + goto done; bp->b_blkno = fsbtodb(fs, nb); } else { UFS_LOCK(ump); @@ -205,7 +209,7 @@ &dp->di_db[0]), osize, nsize, flags, cred, &bp); if (error) - return (error); + goto done; if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, lbn, dbtofsb(fs, bp->b_blkno), nb, @@ -221,7 +225,7 @@ ffs_blkpref_ufs1(ip, lbn, (int)lbn, &dp->di_db[0]), nsize, flags, cred, &newb); if (error) - return (error); + goto done; bp = getblk(vp, lbn, nsize, 0, 0, gbflags); bp->b_blkno = fsbtodb(fs, newb); if (flags & BA_CLRBUF) @@ -233,14 +237,15 @@ dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE | IN_IBLKDATA); *bpp = bp; - return (0); + error = 0; + goto done; } /* * Determine the number of levels of indirection. */ pref = 0; if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) - return(error); + goto done; #ifdef INVARIANTS if (num < 1) panic ("ffs_balloc_ufs1: ufs_getlbns returned indirect block"); @@ -261,7 +266,7 @@ if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags, cred, &newb)) != 0) { curthread_pflags_restore(saved_inbdflush); - return (error); + goto done; } pref = newb + fs->fs_frag; nb = newb; @@ -387,7 +392,8 @@ if (flags & BA_METAONLY) { curthread_pflags_restore(saved_inbdflush); *bpp = bp; - return (0); + error = 0; + goto done; } /* * Get the data block, allocating if necessary. @@ -453,7 +459,8 @@ } curthread_pflags_restore(saved_inbdflush); *bpp = nbp; - return (0); + error = 0; + goto done; } brelse(bp); if (flags & BA_CLRBUF) { @@ -478,7 +485,8 @@ } curthread_pflags_restore(saved_inbdflush); *bpp = nbp; - return (0); + error = 0; + goto done; fail: curthread_pflags_restore(saved_inbdflush); /* @@ -486,7 +494,7 @@ * This is the usual case and avoids the need to fsync the file. */ if (allocblk == allociblk && allocib == NULL && unwindidx == -1) - return (error); + goto done; /* * If we have failed part way through block allocation, we * have to deallocate any indirect blocks that we have allocated. @@ -574,6 +582,8 @@ ffs_blkfree(ump, fs, ump->um_devvp, *blkp, fs->fs_bsize, ip->i_number, vp->v_type, NULL, SINGLETON_KEY); } +done: + vn_seqc_write_end(vp); return (error); } @@ -619,12 +629,17 @@ return (EFBIG); gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; + vn_seqc_write_begin(vp); + /* * Check for allocating external data. */ if (flags & IO_EXT) { - if (lbn >= UFS_NXADDR) - return (EFBIG); + if (lbn >= UFS_NXADDR) { + error = EFBIG; + goto done; + } + /* * If the next write will extend the data into a new block, * and the data is currently composed of a fragment @@ -642,7 +657,7 @@ &dp->di_extb[0]), osize, (int)fs->fs_bsize, flags, cred, &bp); if (error) - return (error); + goto done; if (DOINGSOFTDEP(vp)) softdep_setup_allocext(ip, nb, dbtofsb(fs, bp->b_blkno), @@ -668,13 +683,12 @@ if (nb != 0 && dp->di_extsize >= smalllblktosize(fs, lbn + 1)) { error = bread_gb(vp, -1 - lbn, fs->fs_bsize, NOCRED, gbflags, &bp); - if (error) { - return (error); - } + if (error) + goto done; bp->b_blkno = fsbtodb(fs, nb); bp->b_xflags |= BX_ALTDATA; *bpp = bp; - return (0); + goto done; } if (nb != 0) { /* @@ -685,9 +699,8 @@ if (nsize <= osize) { error = bread_gb(vp, -1 - lbn, osize, NOCRED, gbflags, &bp); - if (error) { - return (error); - } + if (error) + goto done; bp->b_blkno = fsbtodb(fs, nb); bp->b_xflags |= BX_ALTDATA; } else { @@ -698,7 +711,7 @@ &dp->di_extb[0]), osize, nsize, flags, cred, &bp); if (error) - return (error); + goto done; bp->b_xflags |= BX_ALTDATA; if (DOINGSOFTDEP(vp)) softdep_setup_allocext(ip, lbn, @@ -715,7 +728,7 @@ ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]), nsize, flags, cred, &newb); if (error) - return (error); + goto done; bp = getblk(vp, -1 - lbn, nsize, 0, 0, gbflags); bp->b_blkno = fsbtodb(fs, newb); bp->b_xflags |= BX_ALTDATA; @@ -728,7 +741,8 @@ dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno); UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_IBLKDATA); *bpp = bp; - return (0); + error = 0; + goto done; } /* * If the next write will extend the file into a new block, @@ -746,7 +760,7 @@ &dp->di_db[0]), osize, (int)fs->fs_bsize, flags, cred, &bp); if (error) - return (error); + goto done; if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, nb, dbtofsb(fs, bp->b_blkno), @@ -775,17 +789,20 @@ error = bread_gb(vp, lbn, fs->fs_bsize, NOCRED, gbflags, &bp); if (error != 0) - return (error); + goto done; } else { bp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); - if (bp == NULL) - return (EIO); + if (bp == NULL) { + error = EIO; + goto done; + } vfs_bio_clrbuf(bp); } bp->b_blkno = fsbtodb(fs, nb); *bpp = bp; - return (0); + error = 0; + goto done; } if (nb != 0) { /* @@ -796,9 +813,8 @@ if (nsize <= osize) { error = bread_gb(vp, lbn, osize, NOCRED, gbflags, &bp); - if (error) { - return (error); - } + if (error) + goto done; bp->b_blkno = fsbtodb(fs, nb); } else { UFS_LOCK(ump); @@ -807,7 +823,7 @@ &dp->di_db[0]), osize, nsize, flags, cred, &bp); if (error) - return (error); + goto done; if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, lbn, dbtofsb(fs, bp->b_blkno), nb, @@ -823,7 +839,7 @@ ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_db[0]), nsize, flags, cred, &newb); if (error) - return (error); + goto done; bp = getblk(vp, lbn, nsize, 0, 0, gbflags); bp->b_blkno = fsbtodb(fs, newb); if (flags & BA_CLRBUF) @@ -835,14 +851,15 @@ dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE | IN_IBLKDATA); *bpp = bp; - return (0); + error = 0; + goto done; } /* * Determine the number of levels of indirection. */ pref = 0; if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) - return(error); + goto done; #ifdef INVARIANTS if (num < 1) panic ("ffs_balloc_ufs2: ufs_getlbns returned indirect block"); @@ -863,7 +880,7 @@ if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags, cred, &newb)) != 0) { curthread_pflags_restore(saved_inbdflush); - return (error); + goto done; } pref = newb + fs->fs_frag; nb = newb; @@ -991,7 +1008,8 @@ if (flags & BA_METAONLY) { curthread_pflags_restore(saved_inbdflush); *bpp = bp; - return (0); + error = 0; + goto done; } /* * Get the data block, allocating if necessary. @@ -1057,7 +1075,8 @@ } curthread_pflags_restore(saved_inbdflush); *bpp = nbp; - return (0); + error = 0; + goto done; } brelse(bp); /* @@ -1088,7 +1107,8 @@ } curthread_pflags_restore(saved_inbdflush); *bpp = nbp; - return (0); + error = 0; + goto done; fail: curthread_pflags_restore(saved_inbdflush); /* @@ -1096,7 +1116,7 @@ * This is the usual case and avoids the need to fsync the file. */ if (allocblk == allociblk && allocib == NULL && unwindidx == -1) - return (error); + goto done; /* * If we have failed part way through block allocation, we * have to deallocate any indirect blocks that we have allocated. @@ -1184,5 +1204,7 @@ ffs_blkfree(ump, fs, ump->um_devvp, *blkp, fs->fs_bsize, ip->i_number, vp->v_type, NULL, SINGLETON_KEY); } +done: + vn_seqc_write_end(vp); return (error); } diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -181,7 +181,8 @@ struct ucred *, int); int softdep_prerename(struct vnode *, struct vnode *, struct vnode *, struct vnode *); -int softdep_prelink(struct vnode *, struct vnode *); +int softdep_prelink(struct vnode *, struct vnode *, + struct componentname *); void softdep_setup_freeblocks(struct inode *, off_t, int); void softdep_setup_inomapdep(struct buf *, struct inode *, ino_t, int); void softdep_setup_blkmapdep(struct buf *, struct mount *, ufs2_daddr_t, diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -621,9 +621,10 @@ } int -softdep_prelink(dvp, vp) +softdep_prelink(dvp, vp, cnp) struct vnode *dvp; struct vnode *vp; + struct componentname *cnp; { panic("softdep_prelink called"); @@ -3221,6 +3222,26 @@ return (0); } +static void +journal_check_space(ump) + struct ufsmount *ump; +{ + struct mount *mp; + + LOCK_OWNED(ump); + + if (journal_space(ump, 0) == 0) { + softdep_speedup(ump); + mp = UFSTOVFS(ump); + FREE_LOCK(ump); + VFS_SYNC(mp, MNT_NOWAIT); + ffs_sbupdate(ump, MNT_WAIT, 0); + ACQUIRE_LOCK(ump); + if (journal_space(ump, 1) == 0) + journal_suspend(ump); + } +} + /* * Called before any allocation function to be certain that there is * sufficient space in the journal prior to creating any new records. @@ -3271,11 +3292,7 @@ ACQUIRE_LOCK(ump); process_removes(vp); process_truncates(vp); - if (journal_space(ump, 0) == 0) { - softdep_speedup(ump); - if (journal_space(ump, 1) == 0) - journal_suspend(ump); - } + journal_check_space(ump); FREE_LOCK(ump); return (0); @@ -3362,11 +3379,7 @@ ACQUIRE_LOCK(ump); softdep_speedup(ump); process_worklist_item(UFSTOVFS(ump), 2, LK_NOWAIT); - if (journal_space(ump, 0) == 0) { - softdep_speedup(ump); - if (journal_space(ump, 1) == 0) - journal_suspend(ump); - } + journal_check_space(ump); FREE_LOCK(ump); return (ERELOOKUP); } @@ -3384,11 +3397,13 @@ * syscall must be restarted at top level from the lookup. */ int -softdep_prelink(dvp, vp) +softdep_prelink(dvp, vp, cnp) struct vnode *dvp; struct vnode *vp; + struct componentname *cnp; { struct ufsmount *ump; + struct nameidata *ndp; ASSERT_VOP_ELOCKED(dvp, "prelink dvp"); if (vp != NULL) @@ -3404,37 +3419,50 @@ if (journal_space(ump, 0) || (vp != NULL && IS_SNAPSHOT(VTOI(vp)))) return (0); + /* + * Check if the journal space consumption can in theory be + * accounted on dvp and vp. If the vnodes metadata was not + * changed comparing with the previous round-trip into + * softdep_prelink(), as indicated by the seqc generation + * recorded in the nameidata, then there is no point in + * starting the sync. + */ + ndp = __containerof(cnp, struct nameidata, ni_cnd); + if (!seqc_in_modify(ndp->ni_dvp_seqc) && + vn_seqc_consistent(dvp, ndp->ni_dvp_seqc) && + (vp == NULL || (!seqc_in_modify(ndp->ni_vp_seqc) && + vn_seqc_consistent(vp, ndp->ni_vp_seqc)))) + return (0); + stat_journal_low++; if (vp != NULL) { VOP_UNLOCK(dvp); ffs_syncvnode(vp, MNT_NOWAIT, 0); vn_lock_pair(dvp, false, vp, true); if (dvp->v_data == NULL) - return (ERELOOKUP); + goto out; } if (vp != NULL) VOP_UNLOCK(vp); ffs_syncvnode(dvp, MNT_WAIT, 0); - VOP_UNLOCK(dvp); - /* Process vp before dvp as it may create .. removes. */ if (vp != NULL) { + VOP_UNLOCK(dvp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (vp->v_data == NULL) { vn_lock_pair(dvp, false, vp, true); - return (ERELOOKUP); + goto out; } ACQUIRE_LOCK(ump); process_removes(vp); process_truncates(vp); FREE_LOCK(ump); VOP_UNLOCK(vp); - } - - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - if (dvp->v_data == NULL) { - vn_lock_pair(dvp, true, vp, false); - return (ERELOOKUP); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + if (dvp->v_data == NULL) { + vn_lock_pair(dvp, true, vp, false); + goto out; + } } ACQUIRE_LOCK(ump); @@ -3444,14 +3472,14 @@ softdep_speedup(ump); process_worklist_item(UFSTOVFS(ump), 2, LK_NOWAIT); - if (journal_space(ump, 0) == 0) { - softdep_speedup(ump); - if (journal_space(ump, 1) == 0) - journal_suspend(ump); - } + journal_check_space(ump); FREE_LOCK(ump); vn_lock_pair(dvp, false, vp, false); +out: + ndp->ni_dvp_seqc = vn_seqc_read_any(dvp); + if (vp != NULL) + ndp->ni_vp_seqc = vn_seqc_read_any(vp); return (ERELOOKUP); } diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -105,14 +105,16 @@ static vop_accessx_t ufs_accessx; static vop_fplookup_vexec_t ufs_fplookup_vexec; static int ufs_chmod(struct vnode *, int, struct ucred *, struct thread *); -static int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct thread *); +static int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *, + struct thread *); static vop_close_t ufs_close; static vop_create_t ufs_create; static vop_stat_t ufs_stat; static vop_getattr_t ufs_getattr; static vop_ioctl_t ufs_ioctl; static vop_link_t ufs_link; -static int ufs_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *, const char *); +static int ufs_makeinode(int mode, struct vnode *, struct vnode **, + struct componentname *, const char *); static vop_mmapped_t ufs_mmapped; static vop_mkdir_t ufs_mkdir; static vop_mknod_t ufs_mknod; @@ -1008,7 +1010,7 @@ (VTOI(dvp)->i_flags & APPEND)) return (EPERM); if (DOINGSUJ(dvp)) { - error = softdep_prelink(dvp, vp); + error = softdep_prelink(dvp, vp, ap->a_cnp); if (error != 0) { MPASS(error == ERELOOKUP); return (error); @@ -1073,7 +1075,7 @@ #endif if (DOINGSUJ(tdvp)) { - error = softdep_prelink(tdvp, vp); + error = softdep_prelink(tdvp, vp, cnp); if (error != 0) { MPASS(error == ERELOOKUP); return (error); @@ -1145,7 +1147,7 @@ if (DOINGSUJ(dvp) && (ap->a_flags == CREATE || ap->a_flags == DELETE)) { - error = softdep_prelink(dvp, NULL); + error = softdep_prelink(dvp, NULL, cnp); if (error != 0) { MPASS(error == ERELOOKUP); return (error); @@ -1246,6 +1248,7 @@ int error = 0; struct mount *mp; ino_t ino; + seqc_t fdvp_s, fvp_s, tdvp_s, tvp_s; bool want_seqc_end; want_seqc_end = false; @@ -1269,6 +1272,8 @@ mp = NULL; goto releout; } + + fdvp_s = fvp_s = tdvp_s = tvp_s = SEQC_MOD; relock: /* * We need to acquire 2 to 4 locks depending on whether tvp is NULL @@ -1362,10 +1367,20 @@ } } - if (DOINGSOFTDEP(fdvp)) { + if (DOINGSUJ(fdvp) && + (seqc_in_modify(fdvp_s) || !vn_seqc_consistent(fdvp, fdvp_s) || + seqc_in_modify(fvp_s) || !vn_seqc_consistent(fvp, fvp_s) || + seqc_in_modify(tdvp_s) || !vn_seqc_consistent(tdvp, tdvp_s) || + (tvp != NULL && (seqc_in_modify(tvp_s) || + !vn_seqc_consistent(tvp, tvp_s))))) { error = softdep_prerename(fdvp, fvp, tdvp, tvp); if (error != 0) { if (error == ERELOOKUP) { + fdvp_s = vn_seqc_read_any(fdvp); + fvp_s = vn_seqc_read_any(fvp); + tdvp_s = vn_seqc_read_any(tdvp); + if (tvp != NULL) + tvp_s = vn_seqc_read_any(tvp); atomic_add_int(&rename_restarts, 1); goto relock; } @@ -1947,7 +1962,7 @@ } if (DOINGSUJ(dvp)) { - error = softdep_prelink(dvp, NULL); + error = softdep_prelink(dvp, NULL, cnp); if (error != 0) { MPASS(error == ERELOOKUP); return (error); @@ -2211,7 +2226,7 @@ goto out; } if (DOINGSUJ(dvp)) { - error = softdep_prelink(dvp, vp); + error = softdep_prelink(dvp, vp, cnp); if (error != 0) { MPASS(error == ERELOOKUP); return (error); @@ -2736,7 +2751,7 @@ return (EINVAL); } if (DOINGSUJ(dvp)) { - error = softdep_prelink(dvp, NULL); + error = softdep_prelink(dvp, NULL, cnp); if (error != 0) { MPASS(error == ERELOOKUP); return (error);