svn commit: r188407 - head/sys/fs/udf
John Baldwin
jhb at FreeBSD.org
Mon Feb 9 12:50:24 PST 2009
Author: jhb
Date: Mon Feb 9 20:50:23 2009
New Revision: 188407
URL: http://svn.freebsd.org/changeset/base/188407
Log:
Mark udf(4) MPSAFE and add support for shared vnode locks during pathname
lookups:
- Honor the caller's locking flags in udf_root() and udf_vget().
- Set VV_ROOT for the root vnode in udf_vget() instead of only doing it in
udf_root().
- Honor the requested locking flags during pathname lookups in udf_lookup().
- Release the buffer holding the directory data before looking up the vnode
for a given file to avoid a LOR between the "udf" vnode locks and
"bufwait".
- Use vn_vget_ino() to handle ".." lookups.
- Special case "." lookups instead of calling udf_vget(). We have to do
extra checking for the vnode lock for "." lookups.
Modified:
head/sys/fs/udf/udf_vfsops.c
head/sys/fs/udf/udf_vnops.c
Modified: head/sys/fs/udf/udf_vfsops.c
==============================================================================
--- head/sys/fs/udf/udf_vfsops.c Mon Feb 9 20:42:51 2009 (r188406)
+++ head/sys/fs/udf/udf_vfsops.c Mon Feb 9 20:50:23 2009 (r188407)
@@ -344,6 +344,7 @@ udf_mountfs(struct vnode *devvp, struct
mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
MNT_ILOCK(mp);
mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED;
MNT_IUNLOCK(mp);
udfmp->im_mountp = mp;
udfmp->im_dev = devvp->v_rdev;
@@ -546,22 +547,13 @@ static int
udf_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td)
{
struct udf_mnt *udfmp;
- struct vnode *vp;
ino_t id;
- int error;
udfmp = VFSTOUDFFS(mp);
id = udf_getid(&udfmp->root_icb);
- error = udf_vget(mp, id, LK_EXCLUSIVE, vpp);
- if (error)
- return error;
-
- vp = *vpp;
- vp->v_vflag |= VV_ROOT;
-
- return (0);
+ return (udf_vget(mp, id, flags, vpp));
}
static int
@@ -597,6 +589,22 @@ udf_vget(struct mount *mp, ino_t ino, in
if (error || *vpp != NULL)
return (error);
+ /*
+ * We must promote to an exclusive lock for vnode creation. This
+ * can happen if lookup is passed LOCKSHARED.
+ */
+ if ((flags & LK_TYPE_MASK) == LK_SHARED) {
+ flags &= ~LK_TYPE_MASK;
+ flags |= LK_EXCLUSIVE;
+ }
+
+ /*
+ * We do not lock vnode creation as it is believed to be too
+ * expensive for such rare case as simultaneous creation of vnode
+ * for same ino by different processes. We just allow them to race
+ * and check later to decide who wins. Let the race begin!
+ */
+
td = curthread;
udfmp = VFSTOUDFFS(mp);
@@ -689,6 +697,13 @@ udf_vget(struct mount *mp, ino_t ino, in
vp->v_type = VLNK;
break;
}
+
+ if (vp->v_type != VFIFO)
+ VN_LOCK_ASHARE(vp);
+
+ if (ino == udf_getid(&udfmp->root_icb))
+ vp->v_vflag |= VV_ROOT;
+
*vpp = vp;
return (0);
Modified: head/sys/fs/udf/udf_vnops.c
==============================================================================
--- head/sys/fs/udf/udf_vnops.c Mon Feb 9 20:42:51 2009 (r188406)
+++ head/sys/fs/udf/udf_vnops.c Mon Feb 9 20:50:23 2009 (r188407)
@@ -1068,13 +1068,14 @@ udf_lookup(struct vop_cachedlookup_args
long namelen;
ino_t id = 0;
int offset, error = 0;
- int numdirpasses, fsize;
+ int fsize, lkflags, ltype, numdirpasses;
dvp = a->a_dvp;
node = VTON(dvp);
udfmp = node->udfmp;
nameiop = a->a_cnp->cn_nameiop;
flags = a->a_cnp->cn_flags;
+ lkflags = a->a_cnp->cn_lkflags;
nameptr = a->a_cnp->cn_nameptr;
namelen = a->a_cnp->cn_namelen;
fsize = le64toh(node->fentry->inf_len);
@@ -1135,20 +1136,35 @@ lookloop:
/* Did we have a match? */
if (id) {
- if (flags & ISDOTDOT)
- VOP_UNLOCK(dvp, 0);
- error = udf_vget(udfmp->im_mountp, id, LK_EXCLUSIVE, &tdp);
- if (flags & ISDOTDOT)
- vn_lock(dvp, LK_EXCLUSIVE|LK_RETRY);
- if (!error) {
+ /*
+ * Remember where this entry was if it's the final
+ * component.
+ */
+ if ((flags & ISLASTCN) && nameiop == LOOKUP)
+ node->diroff = ds->offset + ds->off;
+ if (numdirpasses == 2)
+ nchstats.ncs_pass2++;
+ udf_closedir(ds);
+
+ if (flags & ISDOTDOT) {
+ error = vn_vget_ino(dvp, id, lkflags, &tdp);
+ } else if (node->hash_id == id) {
+ VREF(dvp); /* we want ourself, ie "." */
/*
- * Remember where this entry was if it's the final
- * component.
+ * When we lookup "." we still can be asked to lock it
+ * differently.
*/
- if ((flags & ISLASTCN) && nameiop == LOOKUP)
- node->diroff = ds->offset + ds->off;
- if (numdirpasses == 2)
- nchstats.ncs_pass2++;
+ ltype = lkflags & LK_TYPE_MASK;
+ if (ltype != VOP_ISLOCKED(dvp)) {
+ if (ltype == LK_EXCLUSIVE)
+ vn_lock(dvp, LK_UPGRADE | LK_RETRY);
+ else /* if (ltype == LK_SHARED) */
+ vn_lock(dvp, LK_DOWNGRADE | LK_RETRY);
+ }
+ tdp = dvp;
+ } else
+ error = udf_vget(udfmp->im_mountp, id, lkflags, &tdp);
+ if (!error) {
*vpp = tdp;
/* Put this entry in the cache */
if (flags & MAKEENTRY)
@@ -1162,6 +1178,7 @@ lookloop:
udf_closedir(ds);
goto lookloop;
}
+ udf_closedir(ds);
/* Enter name into cache as non-existant */
if (flags & MAKEENTRY)
@@ -1175,7 +1192,6 @@ lookloop:
}
}
- udf_closedir(ds);
return (error);
}
More information about the svn-src-all
mailing list