Page MenuHomeFreeBSD

D25579.id74541.diff
No OneTemporary

D25579.id74541.diff

Index: sys/ufs/ffs/ffs_vfsops.c
===================================================================
--- sys/ufs/ffs/ffs_vfsops.c
+++ sys/ufs/ffs/ffs_vfsops.c
@@ -84,6 +84,7 @@
#include <ddb/ddb.h>
static uma_zone_t uma_inode, uma_ufs1, uma_ufs2;
+VFS_SMR_DECLARE;
static int ffs_mountfs(struct vnode *, struct mount *, struct thread *);
static void ffs_oldfscompat_read(struct fs *, struct ufsmount *,
@@ -393,6 +394,7 @@
uma_ufs2 = uma_zcreate("FFS2 dinode",
sizeof(struct ufs2_dinode), NULL, NULL, NULL, NULL,
UMA_ALIGN_PTR, 0);
+ VFS_SMR_ZONE_SET(uma_inode);
}
vfs_deleteopt(mp->mnt_optnew, "groupquota");
@@ -455,6 +457,7 @@
}
MNT_ILOCK(mp);
+ mp->mnt_kern_flag &= ~MNTK_FPLOOKUP;
mp->mnt_flag |= mntorflags;
MNT_IUNLOCK(mp);
/*
@@ -795,6 +798,17 @@
}
}
}
+
+ MNT_ILOCK(mp);
+ /*
+ * This is racy versus lookup, see ufs_fplookup_vexec for details.
+ */
+ if ((mp->mnt_kern_flag & MNTK_FPLOOKUP) != 0)
+ panic("MNTK_FPLOOKUP set on mount %p when it should not be", mp);
+ if ((mp->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0)
+ mp->mnt_kern_flag |= MNTK_FPLOOKUP;
+ MNT_IUNLOCK(mp);
+
vfs_mountedfrom(mp, fspec);
return (0);
}
@@ -1968,14 +1982,14 @@
ump = VFSTOUFS(mp);
fs = ump->um_fs;
- ip = uma_zalloc(uma_inode, M_WAITOK | M_ZERO);
+ ip = uma_zalloc_smr(uma_inode, M_WAITOK | M_ZERO);
/* Allocate a new vnode/inode. */
error = getnewvnode("ufs", mp, fs->fs_magic == FS_UFS1_MAGIC ?
&ffs_vnodeops1 : &ffs_vnodeops2, &vp);
if (error) {
*vpp = NULL;
- uma_zfree(uma_inode, ip);
+ uma_zfree_smr(uma_inode, ip);
return (error);
}
/*
@@ -2004,7 +2018,7 @@
vp->v_vflag |= VV_FORCEINSMQ;
error = insmntque(vp, mp);
if (error != 0) {
- uma_zfree(uma_inode, ip);
+ uma_zfree_smr(uma_inode, ip);
*vpp = NULL;
return (error);
}
@@ -2327,7 +2341,7 @@
uma_zfree(uma_ufs1, ip->i_din1);
else if (ip->i_din2 != NULL)
uma_zfree(uma_ufs2, ip->i_din2);
- uma_zfree(uma_inode, ip);
+ uma_zfree_smr(uma_inode, ip);
}
static int dobkgrdwrite = 1;
Index: sys/ufs/ffs/ffs_vnops.c
===================================================================
--- sys/ufs/ffs/ffs_vnops.c
+++ sys/ufs/ffs/ffs_vnops.c
@@ -735,6 +735,7 @@
ssize_t resid;
int seqcount;
int blkoffset, error, flags, ioflag, size, xfersize;
+ bool want_seqc_end;
vp = ap->a_vp;
uio = ap->a_uio;
@@ -785,6 +786,12 @@
if (vn_rlimit_fsize(vp, uio, uio->uio_td))
return (EFBIG);
+ want_seqc_end = false;
+ if ((ip->i_mode & (ISUID | ISGID))) {
+ vn_seqc_write_begin(vp);
+ want_seqc_end = true;
+ }
+
resid = uio->uio_resid;
osize = ip->i_size;
if (seqcount > BA_SEQMAX)
@@ -903,7 +910,7 @@
if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid &&
ap->a_cred) {
if (priv_check_cred(ap->a_cred, PRIV_VFS_RETAINSUGID)) {
- ip->i_mode &= ~(ISUID | ISGID);
+ UFS_INODE_SET_MODE(ip, ip->i_mode & ~(ISUID | ISGID));
DIP_SET(ip, i_mode, ip->i_mode);
}
}
@@ -919,6 +926,8 @@
if (ffs_fsfail_cleanup(VFSTOUFS(vp->v_mount), error))
error = ENXIO;
}
+ if (want_seqc_end)
+ vn_seqc_write_end(vp);
return (error);
}
@@ -1056,6 +1065,7 @@
off_t osize;
ssize_t resid;
int blkoffset, error, flags, size, xfersize;
+ bool want_seqc_end;
ip = VTOI(vp);
fs = ITOFS(ip);
@@ -1074,6 +1084,12 @@
UFS_NXADDR * fs->fs_bsize)
return (EFBIG);
+ want_seqc_end = false;
+ if ((ip->i_mode & (ISUID | ISGID))) {
+ vn_seqc_write_begin(vp);
+ want_seqc_end = true;
+ }
+
resid = uio->uio_resid;
osize = dp->di_extsize;
flags = IO_EXT;
@@ -1148,9 +1164,10 @@
* we clear the setuid and setgid bits as a precaution against
* tampering.
*/
- if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && ucred) {
- if (priv_check_cred(ucred, PRIV_VFS_RETAINSUGID)) {
- ip->i_mode &= ~(ISUID | ISGID);
+ if ((ip->i_mode & (ISUID | ISGID))) {
+ if (resid > uio->uio_resid && ucred &&
+ priv_check_cred(ucred, PRIV_VFS_RETAINSUGID)) {
+ UFS_INODE_SET_MODE(ip, ip->i_mode & ~(ISUID | ISGID));
dp->di_mode = ip->i_mode;
}
}
@@ -1163,6 +1180,8 @@
}
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
error = ffs_update(vp, 1);
+ if (want_seqc_end)
+ vn_seqc_write_end(vp);
return (error);
}
Index: sys/ufs/ufs/inode.h
===================================================================
--- sys/ufs/ufs/inode.h
+++ sys/ufs/ufs/inode.h
@@ -43,6 +43,7 @@
#include <sys/lock.h>
#include <sys/queue.h>
#include <ufs/ufs/dinode.h>
+#include <sys/seqc.h>
/*
* This must agree with the definition in <ufs/ufs/dir.h>.
@@ -149,6 +150,14 @@
#define UFS_INODE_FLAG_LAZY_MASK_ASSERTABLE \
(UFS_INODE_FLAG_LAZY_MASK & ~(IN_LAZYMOD | IN_LAZYACCESS))
+#define UFS_INODE_SET_MODE(ip, mode) do { \
+ struct inode *_ip = (ip); \
+ int _mode = (mode); \
+ \
+ ASSERT_VOP_IN_SEQC(ITOV(_ip)); \
+ atomic_store_short(&(_ip)->i_mode, _mode); \
+} while (0)
+
#define UFS_INODE_SET_FLAG(ip, flags) do { \
struct inode *_ip = (ip); \
struct vnode *_vp = ITOV(_ip); \
@@ -229,6 +238,7 @@
/* Convert between inode pointers and vnode pointers. */
#define VTOI(vp) ((struct inode *)(vp)->v_data)
+#define VTOI_SMR(vp) ((struct inode *)vn_load_v_data_smr(vp))
#define ITOV(ip) ((ip)->i_vnode)
/* Determine if soft dependencies are being done */
Index: sys/ufs/ufs/ufs_acl.c
===================================================================
--- sys/ufs/ufs/ufs_acl.c
+++ sys/ufs/ufs/ufs_acl.c
@@ -139,9 +139,11 @@
void
ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip)
{
+ int newmode;
- ip->i_mode &= ACL_PRESERVE_MASK;
- ip->i_mode |= acl_posix1e_acl_to_mode(acl);
+ newmode = ip->i_mode & ACL_PRESERVE_MASK;
+ newmode |= acl_posix1e_acl_to_mode(acl);
+ UFS_INODE_SET_MODE(ip, newmode);
DIP_SET(ip, i_mode, ip->i_mode);
}
@@ -381,7 +383,7 @@
ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td)
{
int error;
- mode_t mode;
+ mode_t mode, newmode;
struct inode *ip = VTOI(vp);
KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0,
@@ -418,8 +420,9 @@
acl_nfs4_sync_mode_from_acl(&mode, aclp);
- ip->i_mode &= ACL_PRESERVE_MASK;
- ip->i_mode |= mode;
+ newmode = ip->i_mode & ACL_PRESERVE_MASK;
+ newmode |= mode;
+ UFS_INODE_SET_MODE(ip, newmode);
DIP_SET(ip, i_mode, ip->i_mode);
UFS_INODE_SET_FLAG(ip, IN_CHANGE);
Index: sys/ufs/ufs/ufs_vnops.c
===================================================================
--- sys/ufs/ufs/ufs_vnops.c
+++ sys/ufs/ufs/ufs_vnops.c
@@ -63,6 +63,7 @@
#include <sys/lockf.h>
#include <sys/conf.h>
#include <sys/acl.h>
+#include <sys/smr.h>
#include <security/mac/mac_framework.h>
@@ -96,10 +97,12 @@
"Give all new files in directory the same ownership as the directory");
#endif
+VFS_SMR_DECLARE;
#include <ufs/ffs/ffs_extern.h>
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 vop_close_t ufs_close;
@@ -422,6 +425,48 @@
return (error);
}
+/*
+ * VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see
+ * the comment above cache_fplookup for details.
+ */
+static int
+ufs_fplookup_vexec(ap)
+ struct vop_fplookup_vexec_args /* {
+ struct vnode *a_vp;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap;
+{
+ struct vnode *vp;
+ struct inode *ip;
+ struct ucred *cred;
+ mode_t all_x, mode;
+
+ vp = ap->a_vp;
+ ip = VTOI_SMR(vp);
+ if (__predict_false(ip == NULL))
+ return (EAGAIN);
+
+ /*
+ * XXX ACL race
+ *
+ * ACLs are not supported and UFS clears/sets the flag on mount
+ * and remount. However, we may still be racing with seeing them
+ * and there are no provisions to make sure they got accounted for.
+ *
+ * This happens to match the behavior of the locked case as well,
+ * since in it the lookup is also racy -- mount takes no measures
+ * to block anyone from progressing.
+ */
+ all_x = S_IXUSR | S_IXGRP | S_IXOTH;
+ mode = atomic_load_short(&ip->i_mode);
+ if (__predict_true((mode & all_x) == all_x))
+ return (0);
+
+ cred = ap->a_cred;
+ return (vaccess_vexec_smr(mode, ip->i_uid, ip->i_gid, cred));
+}
+
/* ARGSUSED */
static int
ufs_getattr(ap)
@@ -711,7 +756,7 @@
struct thread *td;
{
struct inode *ip = VTOI(vp);
- int error;
+ int newmode, error;
/*
* To modify the permissions on a file, must possess VADMIN
@@ -744,8 +789,9 @@
return (error);
}
- ip->i_mode &= ~ALLPERMS;
- ip->i_mode |= (mode & ALLPERMS);
+ newmode = ip->i_mode & ~ALLPERMS;
+ newmode |= (mode & ALLPERMS);
+ UFS_INODE_SET_MODE(ip, newmode);
DIP_SET(ip, i_mode, ip->i_mode);
UFS_INODE_SET_FLAG(ip, IN_CHANGE);
#ifdef UFS_ACL
@@ -869,7 +915,7 @@
UFS_INODE_SET_FLAG(ip, IN_CHANGE);
if ((ip->i_mode & (ISUID | ISGID)) && (ouid != uid || ogid != gid)) {
if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) {
- ip->i_mode &= ~(ISUID | ISGID);
+ UFS_INODE_SET_MODE(ip, ip->i_mode & ~(ISUID | ISGID));
DIP_SET(ip, i_mode, ip->i_mode);
}
}
@@ -1111,6 +1157,9 @@
int error = 0;
struct mount *mp;
ino_t ino;
+ bool want_seqc_end;
+
+ want_seqc_end = false;
#ifdef INVARIANTS
if ((tcnp->cn_flags & HASBUF) == 0 ||
@@ -1315,6 +1364,13 @@
tdp->i_effnlink == 0)
panic("Bad effnlink fip %p, fdp %p, tdp %p", fip, fdp, tdp);
+ if (tvp != NULL)
+ vn_seqc_write_begin(tvp);
+ vn_seqc_write_begin(tdvp);
+ vn_seqc_write_begin(fvp);
+ vn_seqc_write_begin(fdvp);
+ want_seqc_end = true;
+
/*
* 1) Bump link count while we're moving stuff
* around. If we crash somewhere before
@@ -1513,6 +1569,14 @@
cache_purge_negative(tdvp);
unlockout:
+ if (want_seqc_end) {
+ if (tvp != NULL)
+ vn_seqc_write_end(tvp);
+ vn_seqc_write_end(tdvp);
+ vn_seqc_write_end(fvp);
+ vn_seqc_write_end(fdvp);
+ }
+
vput(fdvp);
vput(fvp);
if (tvp)
@@ -1556,6 +1620,14 @@
goto unlockout;
releout:
+ if (want_seqc_end) {
+ if (tvp != NULL)
+ vn_seqc_write_begin(tvp);
+ vn_seqc_write_begin(tdvp);
+ vn_seqc_write_begin(fvp);
+ vn_seqc_write_begin(fdvp);
+ }
+
vrele(fdvp);
vrele(fvp);
vrele(tdvp);
@@ -1590,7 +1662,7 @@
*/
if (acl->acl_cnt != 0) {
dmode = acl_posix1e_newfilemode(dmode, acl);
- ip->i_mode = dmode;
+ UFS_INODE_SET_MODE(ip, dmode);
DIP_SET(ip, i_mode, dmode);
*dacl = *acl;
ufs_sync_acl_from_inode(ip, acl);
@@ -1602,7 +1674,7 @@
/*
* Just use the mode as-is.
*/
- ip->i_mode = dmode;
+ UFS_INODE_SET_MODE(ip, dmode);
DIP_SET(ip, i_mode, dmode);
error = 0;
goto out;
@@ -1673,7 +1745,7 @@
* the it's not defined case.
*/
mode = acl_posix1e_newfilemode(mode, acl);
- ip->i_mode = mode;
+ UFS_INODE_SET_MODE(ip, mode);
DIP_SET(ip, i_mode, mode);
ufs_sync_acl_from_inode(ip, acl);
break;
@@ -1684,7 +1756,7 @@
/*
* Just use the mode as-is.
*/
- ip->i_mode = mode;
+ UFS_INODE_SET_MODE(ip, mode);
DIP_SET(ip, i_mode, mode);
error = 0;
goto out;
@@ -1796,6 +1868,7 @@
error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
if (error)
goto out;
+ vn_seqc_write_begin(tvp);
ip = VTOI(tvp);
ip->i_gid = dp->i_gid;
DIP_SET(ip, i_gid, dp->i_gid);
@@ -1846,6 +1919,7 @@
if (DOINGSOFTDEP(tvp))
softdep_revert_link(dp, ip);
UFS_VFREE(tvp, ip->i_number, dmode);
+ vn_seqc_write_end(tvp);
vgone(tvp);
vput(tvp);
return (error);
@@ -1861,6 +1935,7 @@
if (DOINGSOFTDEP(tvp))
softdep_revert_link(dp, ip);
UFS_VFREE(tvp, ip->i_number, dmode);
+ vn_seqc_write_end(tvp);
vgone(tvp);
vput(tvp);
return (error);
@@ -1868,7 +1943,7 @@
#endif
#endif /* !SUIDDIR */
UFS_INODE_SET_FLAG(ip, IN_ACCESS | IN_CHANGE | IN_UPDATE);
- ip->i_mode = dmode;
+ UFS_INODE_SET_MODE(ip, dmode);
DIP_SET(ip, i_mode, dmode);
tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
ip->i_effnlink = 2;
@@ -1974,6 +2049,7 @@
bad:
if (error == 0) {
*ap->a_vpp = tvp;
+ vn_seqc_write_end(tvp);
} else {
dp->i_effnlink--;
dp->i_nlink--;
@@ -1989,6 +2065,7 @@
UFS_INODE_SET_FLAG(ip, IN_CHANGE);
if (DOINGSOFTDEP(tvp))
softdep_revert_mkdir(dp, ip);
+ vn_seqc_write_end(tvp);
vgone(tvp);
vput(tvp);
}
@@ -2637,8 +2714,9 @@
}
#endif
#endif /* !SUIDDIR */
+ vn_seqc_write_begin(tvp); /* Mostly to cover asserts */
UFS_INODE_SET_FLAG(ip, IN_ACCESS | IN_CHANGE | IN_UPDATE);
- ip->i_mode = mode;
+ UFS_INODE_SET_MODE(ip, mode);
DIP_SET(ip, i_mode, mode);
tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
ip->i_effnlink = 1;
@@ -2648,7 +2726,7 @@
softdep_setup_create(VTOI(dvp), ip);
if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
priv_check_cred(cnp->cn_cred, PRIV_VFS_SETGID)) {
- ip->i_mode &= ~ISGID;
+ UFS_INODE_SET_MODE(ip, ip->i_mode & ~ISGID);
DIP_SET(ip, i_mode, ip->i_mode);
}
@@ -2688,6 +2766,7 @@
error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL, 0);
if (error)
goto bad;
+ vn_seqc_write_end(tvp);
*vpp = tvp;
return (0);
@@ -2702,6 +2781,7 @@
UFS_INODE_SET_FLAG(ip, IN_CHANGE);
if (DOINGSOFTDEP(tvp))
softdep_revert_create(VTOI(dvp), ip);
+ vn_seqc_write_end(tvp);
vgone(tvp);
vput(tvp);
return (error);
@@ -2740,6 +2820,7 @@
.vop_write = VOP_PANIC,
.vop_accessx = ufs_accessx,
.vop_bmap = ufs_bmap,
+ .vop_fplookup_vexec = ufs_fplookup_vexec,
.vop_cachedlookup = ufs_lookup,
.vop_close = ufs_close,
.vop_create = ufs_create,

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 15, 1:28 AM (15 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29681242
Default Alt Text
D25579.id74541.diff (13 KB)

Event Timeline