X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/4ba76501152d51ccb5647018f3192c6096367d48..eb6b6ca394357805f2bdba989abae309f718b4d8:/bsd/vfs/vfs_lookup.c diff --git a/bsd/vfs/vfs_lookup.c b/bsd/vfs/vfs_lookup.c index 85d47741e..9aad31d57 100644 --- a/bsd/vfs/vfs_lookup.c +++ b/bsd/vfs/vfs_lookup.c @@ -113,7 +113,7 @@ static int vfs_getrealpath(const char * path, char * realpath, size_t bufsize, v #endif static int lookup_traverse_mountpoints(struct nameidata *ndp, struct componentname *cnp, vnode_t dp, int vbusyflags, vfs_context_t ctx); -static int handle_symlink_for_namei(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx); +static int lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx); static int lookup_authorize_search(vnode_t dp, struct componentname *cnp, int dp_authorized_in_cache, vfs_context_t ctx); static void lookup_consider_update_cache(vnode_t dvp, vnode_t vp, struct componentname *cnp, int nc_generation); static int lookup_handle_found_vnode(struct nameidata *ndp, struct componentname *cnp, int rdonly, @@ -167,8 +167,6 @@ namei(struct nameidata *ndp) { struct filedesc *fdp; /* pointer to file descriptor state */ struct vnode *dp; /* the directory we are searching */ - struct vnode *rootdir_with_usecount = NULLVP; - struct vnode *startdir_with_usecount = NULLVP; struct vnode *usedvp = ndp->ni_dvp; /* store pointer to vp in case we must loop due to * heavy vnode pressure */ u_long cnpflags = ndp->ni_cnd.cn_flags; /* store in case we have to restore after loop */ @@ -185,6 +183,8 @@ namei(struct nameidata *ndp) int volfs_restarts = 0; #endif size_t bytes_copied = 0; + bool take_proc_lock = !(ndp->ni_flag & NAMEI_NOPROCLOCK); + bool proc_lock_taken = false; fdp = p->p_fd; @@ -351,29 +351,15 @@ retry_copy: /* * determine the starting point for the translation. * - * We may need to upto 2 usecounts on vnodes before starting the translation - * We need to have a usecount on the root directory for the process - * for the entire duration of the lookup. This is because symlink - * translation can restart translation at / if a symlink is encountered. - * - * For the duration of this lookup at rootdir for this lookup is the one - * we fetch now under the proc_fdlock even the if the proc rootdir changes - * once we let go of the proc_fdlock. - * - * In the future we may consider holding off a chroot till we complete - * in progress lookups. - * - * If the starting directory is not the process rootdir then we need - * a usecount on the starting directory as well for the duration of the - * lookup. - * - * Getting an addtional usecount involves first getting an iocount under - * the lock that ensures that a usecount is on the directory. Once we - * get an iocount we can release the lock and we will be free to get a - * usecount without the vnode getting recycled. Once we get the usecount - * we can release the icoount which we used to get our usecount. + * We hold the proc_dirs lock across the lookup so that the + * process rootdir and cwd are stable (i.e. the usecounts + * on them are mainatained for the duration of the lookup) */ - proc_fdlock(p); + if (take_proc_lock) { + assert(proc_lock_taken == false); + proc_dirs_lock_shared(p); + proc_lock_taken = true; + } if (!(fdp->fd_flags & FD_CHROOT)) { ndp->ni_rootdir = rootvnode; } else { @@ -382,10 +368,8 @@ retry_copy: if (!ndp->ni_rootdir) { if (!(fdp->fd_flags & FD_CHROOT)) { - proc_fdunlock(p); printf("rootvnode is not set\n"); } else { - proc_fdunlock(p); /* This should be a panic */ printf("fdp->fd_rdir is not set\n"); } @@ -393,43 +377,10 @@ retry_copy: goto error_out; } - /* - * We have the proc_fdlock here so we still have a usecount - * on ndp->ni_rootdir. - * - * However we need to get our own usecount on it in order to - * ensure that the vnode isn't recycled to something else. - * - * Note : It's fine if the vnode is force reclaimed but with - * a usecount it won't be reused until we release the reference. - * - * In order to get that usecount however, we need to first - * get non blocking iocount since we'll be doing this under - * the proc_fdlock. - */ - if (vnode_get(ndp->ni_rootdir) != 0) { - proc_fdunlock(p); - error = ENOENT; - goto error_out; - } - - proc_fdunlock(p); - - /* Now we can safely get our own ref on ni_rootdir */ - error = vnode_ref_ext(ndp->ni_rootdir, O_EVTONLY, 0); - vnode_put(ndp->ni_rootdir); - if (error) { - ndp->ni_rootdir = NULLVP; - goto error_out; - } - - rootdir_with_usecount = ndp->ni_rootdir; - cnp->cn_nameptr = cnp->cn_pnbuf; ndp->ni_usedvp = NULLVP; - bool dp_needs_put = false; if (*(cnp->cn_nameptr) == '/') { while (*(cnp->cn_nameptr) == '/') { cnp->cn_nameptr++; @@ -440,40 +391,15 @@ retry_copy: dp = ndp->ni_dvp; ndp->ni_usedvp = dp; } else { - dp = vfs_context_get_cwd(ctx); - if (dp) { - dp_needs_put = true; - } + dp = vfs_context_cwd(ctx); } if (dp == NULLVP || (dp->v_lflag & VL_DEAD)) { - if (dp_needs_put) { - vnode_put(dp); - dp_needs_put = false; - } dp = NULLVP; error = ENOENT; goto error_out; } - if (dp != rootdir_with_usecount) { - error = vnode_ref_ext(dp, O_EVTONLY, 0); - if (error) { - if (dp_needs_put) { - vnode_put(dp); - dp_needs_put = false; - } - dp = NULLVP; - goto error_out; - } - startdir_with_usecount = dp; - } - - if (dp_needs_put) { - vnode_put(dp); - dp_needs_put = false; - } - ndp->ni_dvp = NULLVP; ndp->ni_vp = NULLVP; @@ -492,7 +418,6 @@ retry_copy: goto error_out; } #endif - ndp->ni_startdir = dp; dp = NULLVP; @@ -504,46 +429,19 @@ retry_copy: * Check for symbolic link */ if ((cnp->cn_flags & ISSYMLINK) == 0) { - if (startdir_with_usecount) { - vnode_rele_ext(startdir_with_usecount, O_EVTONLY, 0); - startdir_with_usecount = NULLVP; - } - if (rootdir_with_usecount) { - vnode_rele_ext(rootdir_with_usecount, O_EVTONLY, 0); - rootdir_with_usecount = NULLVP; + if (proc_lock_taken) { + proc_dirs_unlock_shared(p); + proc_lock_taken = false; } return 0; } continue_symlink: - /* - * Gives us a new path to process, and a starting dir (with an iocount). - * The iocount is needed to take a usecount on the vnode returned - * (if it is not a vnode we already have a usecount on). - */ - error = handle_symlink_for_namei(ndp, &dp, ctx); + /* Gives us a new path to process, and a starting dir */ + error = lookup_handle_symlink(ndp, &dp, ctx); if (error != 0) { break; } - - if (dp == ndp->ni_rootdir && startdir_with_usecount) { - vnode_rele_ext(startdir_with_usecount, O_EVTONLY, 0); - startdir_with_usecount = NULLVP; - } else if (dp != startdir_with_usecount) { - if (startdir_with_usecount) { - vnode_rele_ext(startdir_with_usecount, O_EVTONLY, 0); - startdir_with_usecount = NULLVP; - } - error = vnode_ref_ext(dp, O_EVTONLY, 0); - if (error) { - vnode_put(dp); - dp = NULLVP; - goto error_out; - } - startdir_with_usecount = dp; - } - /* iocount not required on dp anymore */ - vnode_put(dp); } /* * only come here if we fail to handle a SYMLINK... @@ -559,6 +457,10 @@ out_drop: vnode_put(ndp->ni_vp); } error_out: + if (proc_lock_taken) { + proc_dirs_unlock_shared(p); + proc_lock_taken = false; + } if ((cnp->cn_flags & HASBUF)) { cnp->cn_flags &= ~HASBUF; FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); @@ -567,15 +469,6 @@ error_out: ndp->ni_vp = NULLVP; ndp->ni_dvp = NULLVP; - if (startdir_with_usecount) { - vnode_rele_ext(startdir_with_usecount, O_EVTONLY, 0); - startdir_with_usecount = NULLVP; - } - if (rootdir_with_usecount) { - vnode_rele_ext(rootdir_with_usecount, O_EVTONLY, 0); - rootdir_with_usecount = NULLVP; - } - #if CONFIG_VOLFS /* * Deal with volfs fallout. @@ -1261,13 +1154,15 @@ dirloop: tdp = dp; dp = tdp->v_mount->mnt_vnodecovered; - vnode_put(tdp); - if ((vnode_getwithref(dp))) { + vnode_put(tdp); dp = NULLVP; error = ENOENT; goto bad; } + + vnode_put(tdp); + ndp->ni_dvp = dp; dp_authorized = 0; } @@ -1670,10 +1565,10 @@ out: /* * Takes ni_vp and ni_dvp non-NULL. Returns with *new_dp set to the location - * at which to start a lookup with a resolved path and with an iocount. + * at which to start a lookup with a resolved path, and all other iocounts dropped. */ static int -handle_symlink_for_namei(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) +lookup_handle_symlink(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t ctx) { int error; char *cp; /* pointer into pathname argument */ @@ -1764,18 +1659,17 @@ handle_symlink_for_namei(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t c /* * starting point for 'relative' * symbolic link path - * - * If the starting point is not the root we have to return an iocounted - * dp to namei so we don't release the icoount here. */ dp = ndp->ni_dvp; - ndp->ni_dvp = NULLVP; /* * get rid of references returned via 'lookup' */ vnode_put(ndp->ni_vp); + vnode_put(ndp->ni_dvp); /* ALWAYS have a dvp for a symlink */ + ndp->ni_vp = NULLVP; + ndp->ni_dvp = NULLVP; /* * Check if symbolic link restarts us at the root @@ -1785,20 +1679,9 @@ handle_symlink_for_namei(struct nameidata *ndp, vnode_t *new_dp, vfs_context_t c cnp->cn_nameptr++; ndp->ni_pathlen--; } - vnode_put(dp); if ((dp = ndp->ni_rootdir) == NULLVP) { return ENOENT; } - if (vnode_get(dp) != 0) { - return ENOENT; - } - } - - if (dp == NULLVP || (dp->v_lflag & VL_DEAD)) { - if (dp) { - vnode_put(dp); - } - return ENOENT; } *new_dp = dp;