diff options
author | jhb <jhb@FreeBSD.org> | 2009-02-09 20:50:23 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2009-02-09 20:50:23 +0000 |
commit | 48ea2cb2ca9b5c828fc829924277900c2a269471 (patch) | |
tree | 7875828c5ce171cb0127f73d765d184133bfd384 /sys/fs/udf/udf_vnops.c | |
parent | cf9ddd99b24e2dc96a1c93ff5ce6baaca7cb8ea5 (diff) | |
download | FreeBSD-src-48ea2cb2ca9b5c828fc829924277900c2a269471.zip FreeBSD-src-48ea2cb2ca9b5c828fc829924277900c2a269471.tar.gz |
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.
Diffstat (limited to 'sys/fs/udf/udf_vnops.c')
-rw-r--r-- | sys/fs/udf/udf_vnops.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c index a80c3ce..05481bc 100644 --- a/sys/fs/udf/udf_vnops.c +++ b/sys/fs/udf/udf_vnops.c @@ -1068,13 +1068,14 @@ udf_lookup(struct vop_cachedlookup_args *a) 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); } |