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);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to