Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-1-4]: src/sys/kern This commit approved in advance by rel-eng



details:   https://anonhg.NetBSD.org/src/rev/65accd6740f5
branches:  netbsd-1-4
changeset: 469200:65accd6740f5
user:      sommerfeld <sommerfeld%NetBSD.org@localhost>
date:      Sun Jul 11 10:24:09 1999 +0000

description:
This commit approved in advance by rel-eng

Pullup of -current version of getcwd implementation, with
clone(2)-specific changes backed out (which required a manual merge).

Fixes:
7944: getcwd permission checking overly strict.
7761: getcwd with large buffer fails spuriously.
7373: recursive lock deadlock for adosfs (correct, non-stopgap fix;
changed to not use LOCKPARENT).
Also, significant code cleanup to error paths which may fix the problems
reported in 7881.

diffstat:

 sys/kern/vfs_getcwd.c |  445 +++++++++++++++++++++----------------------------
 1 files changed, 188 insertions(+), 257 deletions(-)

diffs (truncated from 681 to 300 lines):

diff -r 6c2f9e1706ff -r 65accd6740f5 sys/kern/vfs_getcwd.c
--- a/sys/kern/vfs_getcwd.c     Fri Jul 09 15:04:18 1999 +0000
+++ b/sys/kern/vfs_getcwd.c     Sun Jul 11 10:24:09 1999 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: vfs_getcwd.c,v 1.3.2.2 1999/04/28 18:43:44 perry Exp $ */
+/* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -54,7 +54,7 @@
 #include <sys/syscallargs.h>
 
 static int
-getcwd_scandir __P((struct vnode *, struct vnode **,
+getcwd_scandir __P((struct vnode **, struct vnode **,
     char **, char *, struct proc *));
 static int
 getcwd_getcache __P((struct vnode **, struct vnode **,
@@ -68,22 +68,44 @@
 #define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4)
 
 /*
+ * Vnode variable naming conventions in this file:
+ *
+ * rvp: the current root we're aiming towards.
+ * lvp, *lvpp: the "lower" vnode
+ * uvp, *uvpp: the "upper" vnode.
+ *
+ * Since all the vnodes we're dealing with are directories, and the
+ * lookups are going *up* in the filesystem rather than *down*, the
+ * usual "pvp" (parent) or "dvp" (directory) naming conventions are
+ * too confusing.
+ */
+
+/*
  * XXX Will infinite loop in certain cases if a directory read reliably
  *     returns EINVAL on last block.
  * XXX is EINVAL the right thing to return if a directory is malformed?
  */
 
 /*
- * Find parent vnode of cvp, return in *pvpp
- * Scan it looking for name of directory entry pointing at cvp.
+ * XXX Untested vs. mount -o union; probably does the wrong thing.
+ */
+
+/*
+ * Find parent vnode of *lvpp, return in *uvpp
+ *
+ * If we care about the name, scan it looking for name of directory
+ * entry pointing at lvp.
  *
  * Place the name in the buffer which starts at bufp, immediately
  * before *bpp, and move bpp backwards to point at the start of it.
+ *
+ * On entry, *lvpp is a locked vnode reference; on exit, it is vput and NULL'ed
+ * On exit, *uvpp is either NULL or is a locked vnode reference.
  */
 static int
-getcwd_scandir(cvp, pvpp, bpp, bufp, p)
-       struct vnode *cvp;
-       struct vnode **pvpp;
+getcwd_scandir(lvpp, uvpp, bpp, bufp, p)
+       struct vnode **lvpp;
+       struct vnode **uvpp;
        char **bpp;
        char *bufp;
        struct proc *p;
@@ -98,17 +120,32 @@
        int     dirbuflen;
        ino_t   fileno;
        struct vattr va;
-       struct vnode *pvp = NULL;
+       struct vnode *uvp = NULL;
+       struct vnode *lvp = *lvpp;      
        struct componentname cn;
        int len, reclen;
        tries = 0;
 
        /*
+        * If we want the filename, get some info we need while the
+        * current directory is still locked.
+        */
+       if (bufp != NULL) {
+               error = VOP_GETATTR(lvp, &va, p->p_ucred, p);
+               if (error) {
+                       vput(lvp);
+                       *lvpp = NULL;
+                       *uvpp = NULL;
+                       return error;
+               }
+       }
+
+       /*
         * Ok, we have to do it the hard way..
-        * First, get parent vnode using lookup of ..
+        * Next, get parent vnode using lookup of ..
         */
        cn.cn_nameiop = LOOKUP;
-       cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY | LOCKPARENT;
+       cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY;
        cn.cn_proc = p;
        cn.cn_cred = p->p_ucred;
        cn.cn_pnbuf = NULL;
@@ -116,28 +153,28 @@
        cn.cn_namelen = 2;
        cn.cn_hash = 0;
        cn.cn_consume = 0;
-
+       
        /*
-        * At this point, cvp is locked, and will be locked
-        * on return in all cases.
-        * On successful return, *pvpp will also be locked
+        * At this point, lvp is locked and will be unlocked by the lookup.
+        * On successful return, *uvpp will be locked
         */
-       error = VOP_LOOKUP(cvp, pvpp, &cn);
+       error = VOP_LOOKUP(lvp, uvpp, &cn);
        if (error) {
-               *pvpp = NULL;
+               vput(lvp);
+               *lvpp = NULL;
+               *uvpp = NULL;
                return error;
        }
-       pvp = *pvpp;
+       uvp = *uvpp;
 
        /* If we don't care about the pathname, we're done */
-       if (bufp == NULL)
+       if (bufp == NULL) {
+               vrele(lvp);
+               *lvpp = NULL;
                return 0;
+       }
        
-       error = VOP_GETATTR(cvp, &va, p->p_ucred, p);
-       if (error)
-               return error;
        fileno = va.va_fileid;
-       
 
        dirbuflen = DIRBLKSIZ;
        if (dirbuflen < va.va_blocksize)
@@ -163,14 +200,8 @@
 
                eofflag = 0;
 
-               /* XXX un-break adosfs */
-               VOP_UNLOCK(cvp, 0);
+               error = VOP_READDIR(uvp, &uio, p->p_ucred, &eofflag, 0, 0);
 
-               error = VOP_READDIR(pvp, &uio, p->p_ucred, &eofflag, 0, 0);
-
-               /* XXX not handling lock failures here.. */
-               (void) vn_lock(cvp, LK_EXCLUSIVE | LK_RETRY);
-               
                off = uio.uio_offset;
 
                /*
@@ -231,17 +262,17 @@
         * Deal with mount -o union, which unions only the
         * root directory of the mount.
         */
-       if ((pvp->v_flag & VROOT) &&
-           (pvp->v_mount->mnt_flag & MNT_UNION)) {
-               struct vnode *tvp = pvp;
-               pvp = pvp->v_mount->mnt_vnodecovered;
+       if ((uvp->v_flag & VROOT) &&
+           (uvp->v_mount->mnt_flag & MNT_UNION)) {
+               struct vnode *tvp = uvp;
+               uvp = uvp->v_mount->mnt_vnodecovered;
                vput(tvp);
-               VREF(pvp);
-               *pvpp = pvp;
-               error = vn_lock(pvp, LK_EXCLUSIVE | LK_RETRY);
+               VREF(uvp);
+               *uvpp = uvp;
+               error = vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY);
                if (error != 0) {
-                       vrele(pvp);
-                       *pvpp = pvp = NULL;
+                       vrele(uvp);
+                       *uvpp = uvp = NULL;
                        goto out;
                }
                goto unionread;
@@ -250,6 +281,8 @@
        error = ENOENT;
                
 out:
+       vrele(lvp);
+       *lvpp = NULL;
        free(dirbuf, M_TEMP);
        return error;
 }
@@ -258,51 +291,77 @@
  * Look in the vnode-to-name reverse cache to see if
  * we can find things the easy way.
  *
- * XXX vn_lock/vget failure paths are untested.
+ * XXX vget failure path is untested.
+ *
+ * On entry, *lvpp is a locked vnode reference.
+ * On exit, one of the following is the case:
+ *     0) Both *lvpp and *uvpp are NULL and failure is returned.
+ *     1) *uvpp is NULL, *lvpp remains locked and -1 is returned (cache miss)
+ *      2) *uvpp is a locked vnode reference, *lvpp is vput and NULL'ed
+ *        and 0 is returned (cache hit)
  */
 
 static int
-getcwd_getcache(vpp, dvpp, bpp, bufp)
-       struct vnode **vpp, **dvpp;
+getcwd_getcache(lvpp, uvpp, bpp, bufp)
+       struct vnode **lvpp, **uvpp;
        char **bpp;
        char *bufp;
 {
-       struct vnode *cvp, *pvp = NULL;
+       struct vnode *lvp, *uvp = NULL;
        int error;
-       
-       cvp = *vpp;
+       int vpid;
        
-       error = cache_revlookup(cvp, dvpp, bpp, bufp);
-       if (error)
-               return error;
-       pvp = *dvpp;
+       lvp = *lvpp;
        
        /*
-        * Do a little dance with the locks to avoid deadlocking
-        * someone going the other way.  Since we're going up, we have
-        * to release the current lock before we take the parent lock,
-        * and then re-take the current lock.  Since either lock can
-        * fail, causing us to abort, this is a little convoluted.
+        * This returns 0 on a cache hit, -1 on a clean cache miss,
+        * or an errno on other failure.
+        */
+       error = cache_revlookup(lvp, uvpp, bpp, bufp);
+       if (error) {
+               if (error != -1) {
+                       vput(lvp);
+                       *lvpp = NULL;
+                       *uvpp = NULL;
+               }
+               return error;
+       }
+       uvp = *uvpp;
+       vpid = uvp->v_id;
+
+       /*
+        * Since we're going up, we have to release the current lock
+        * before we take the parent lock.
         */
 
-       VOP_UNLOCK(cvp, 0);
-       /* cur now unlocked... */
-       error = vget(pvp, LK_EXCLUSIVE | LK_RETRY);
-       if (error != 0) {
-               vrele(cvp);
-               *vpp = NULL;
-               *dvpp = NULL;
-               return error;
+       VOP_UNLOCK(lvp, 0);
+
+       error = vget(uvp, LK_EXCLUSIVE | LK_RETRY);
+       if (error != 0)
+               *uvpp = NULL;
+       /*
+        * Verify that vget succeeded, and check that vnode capability
+        * didn't change while we were waiting for the lock.
+        */
+       if (error || (vpid != uvp->v_id)) {
+               /*
+                * Oops, we missed.  If the vget failed, or the
+                * capability changed, try to get our lock back; if
+                * that works, tell caller to try things the hard way,
+                * otherwise give up.
+                */
+               if (!error) vput(uvp);
+               *uvpp = NULL;
+               
+               error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY);
+
+               if (!error)
+                       return -1;
        }
-       /* parent is now locked */
-       error = vn_lock(cvp, LK_EXCLUSIVE | LK_RETRY);
-       if (error != 0) {
-               vrele(cvp);
-               *vpp = NULL;
-               return error;
-       }
-       /* ok, cur is now locked again.. */
-       return 0;



Home | Main Index | Thread Index | Old Index