]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/miscfs/devfs/devfs_tree.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / miscfs / devfs / devfs_tree.c
index 45d529e8d2c001dbd1b098cd8d5d069fac08484d..6358c5c6b1d61fdadd9b18bb6ce76a4d00cc5573 100644 (file)
@@ -328,7 +328,7 @@ dev_finddir(const char * path,
            while (*scan != '/' && *scan)
                scan++;
 
-           strlcpy(component, start, scan - start);
+           strlcpy(component, start, (scan - start) + 1);
            if (*scan == '/')
                scan++;
 
@@ -967,7 +967,7 @@ static int
 dev_dup_entry(devnode_t * parent, devdirent_t * back, devdirent_t * *dnm_pp,
              struct devfsmount *dvm)
 {
-       devdirent_t *   entry_p;
+       devdirent_t *   entry_p = NULL;
        devdirent_t *   newback;
        devdirent_t *   newfront;
        int     error;
@@ -978,10 +978,14 @@ dev_dup_entry(devnode_t * parent, devdirent_t * back, devdirent_t * *dnm_pp,
         * go get the node made (if we need to)
         * use the back one as a prototype
         */
-       if ((error = dev_add_entry(back->de_name, parent, type,
-                               NULL, dnp,
-                               parent?parent->dn_dvm:dvm, &entry_p)) != 0) {
+    error = dev_add_entry(back->de_name, parent, type, NULL, dnp,
+                          parent?parent->dn_dvm:dvm, &entry_p);
+    if (!error && (entry_p == NULL)) {
+        error = ENOMEM; /* Really can't happen, but make static analyzer happy */
+    }
+       if (error != 0) {
                printf("duplicating %s failed\n",back->de_name);
+        goto out;
        }
 
        /*
@@ -1009,6 +1013,7 @@ dev_dup_entry(devnode_t * parent, devdirent_t * back, devdirent_t * *dnm_pp,
                        }
                }
        }
+out:
        *dnm_pp = entry_p;
        return error;
 }
@@ -1156,7 +1161,16 @@ retry:
 
                DEVFS_UNLOCK();
 
-               error = vnode_getwithvid(vn_p, vid);
+               /*
+                * We want to use the drainok variant of vnode_getwithvid
+                * because we _don't_ want to get an iocount if the vnode is
+                * is blocked in vnode_drain as it can cause infinite
+                * loops in vn_open_auth. While in use vnodes are typically
+                * only reclaimed on forced unmounts, In use devfs tty vnodes
+                * can  be quite frequently reclaimed by revoke(2) or by the
+                * exit of a controlling process.
+                */
+               error = vnode_getwithvid_drainok(vn_p, vid);
 
                DEVFS_LOCK();
 
@@ -1180,22 +1194,25 @@ retry:
                         * vnode.  Therefore, ENOENT is a valid result.
                         */
                        error = ENOENT;
+               } else if (error == ENODEV) {
+                       /*
+                        * The Filesystem is getting unmounted.
+                        */
+                       error = ENOENT;
                } else if (error && (nretries < DEV_MAX_VNODE_RETRY)) {
                        /*
                         * If we got an error from vnode_getwithvid, it means
                         * we raced with a recycle and lost i.e. we asked for
-                        * an iocount only after vnode_drain had completed on
-                        * the vnode and returned with an error only after
-                        * devfs_reclaim was called on the vnode. While
-                        * devfs_reclaim sets dn_vn to NULL but while we were
-                        * waiting to reacquire DEVFS_LOCK, another vnode might
-                        * have gotten associated with the dnp. In either case,
-                        * we need to retry otherwise we will end up returning
-                        * an ENOENT for this lookup but the next lookup will
-                        * succeed because it creates a new vnode (or a racing
-                        * lookup created a new vnode already).
-                        *
-                        * We cap the number of retries at 8.
+                        * an iocount only after vnode_drain had been entered
+                        * for the vnode and returned with an error only after
+                        * devfs_reclaim was called on the vnode.  devfs_reclaim
+                        * sets dn_vn to NULL but while we were waiting to
+                        * reacquire DEVFS_LOCK, another vnode might have gotten
+                        * associated with the dnp. In either case, we need to
+                        * retry otherwise we will end up returning an ENOENT
+                        * for this lookup but the next lookup will  succeed
+                        * because it creates a new vnode (or a racing  lookup
+                        * created a new vnode already).
                         */
                        error = 0;
                        nretries++;