summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2010-06-20 13:35:16 +0000
committerkib <kib@FreeBSD.org>2010-06-20 13:35:16 +0000
commite735ee5c8d1c56d4d050c3db2b30b65da1b04642 (patch)
tree99ea5fd01bccf95f5df89ea1cd7a141627c24669 /sys/ufs
parent01e81eb99e553eaf40221a7ac49c862a8b7f9d87 (diff)
downloadFreeBSD-src-e735ee5c8d1c56d4d050c3db2b30b65da1b04642.zip
FreeBSD-src-e735ee5c8d1c56d4d050c3db2b30b65da1b04642.tar.gz
Ensure that VOP_ACCESSX is called with exclusively locked vnode for
the kernel compiled with QUOTA option. ufs_accessx() upgrades the vdp vnode lock from shared to exclusive to assign the dquot structure to the vnode, and ufs_delete_denied() is called when tvp is locked. Since upgrade drops shared lock when non-blocked upgrade failed, LOR is there. Reported and tested by: Dmitry Pryanishnikov <lynx.ripe gmail com> Tested by: pho PR: kern/147890 MFC after: 1 week
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ufs/ufs_lookup.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 0030c52..c779491 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -77,6 +77,32 @@ SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, "");
/* true if old FS format...*/
#define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0)
+#ifdef QUOTA
+static int
+ufs_lookup_upgrade_lock(struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, __FUNCTION__);
+ if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
+ return (0);
+
+ error = 0;
+
+ /*
+ * Upgrade vnode lock, since getinoquota()
+ * requires exclusive lock to modify inode.
+ */
+ vhold(vp);
+ vn_lock(vp, LK_UPGRADE | LK_RETRY);
+ VI_LOCK(vp);
+ if (vp->v_iflag & VI_DOOMED)
+ error = ENOENT;
+ vdropl(vp);
+ return (error);
+}
+#endif
+
static int
ufs_delete_denied(struct vnode *vdp, struct vnode *tdp, struct ucred *cred,
struct thread *td)
@@ -232,6 +258,13 @@ ufs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp,
vnode_create_vobject(vdp, DIP(dp, i_size), cnp->cn_thread);
bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
+#ifdef QUOTA
+ if ((nameiop == DELETE || nameiop == RENAME) && (flags & ISLASTCN)) {
+ error = ufs_lookup_upgrade_lock(vdp);
+ if (error != 0)
+ return (error);
+ }
+#endif
restart:
bp = NULL;
OpenPOWER on IntegriCloud