X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..d9a64523371fa019c4575bb400cbbc3a50ac9903:/bsd/miscfs/devfs/devfs_tree.c diff --git a/bsd/miscfs/devfs/devfs_tree.c b/bsd/miscfs/devfs/devfs_tree.c index 45d529e8d..6358c5c6b 100644 --- a/bsd/miscfs/devfs/devfs_tree.c +++ b/bsd/miscfs/devfs/devfs_tree.c @@ -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++;