Sun Aug 9 07:27:54 2009 UTC ()
Begin splitting lookup() into more tractable pieces too.


(dholland)
diff -r1.117 -r1.118 src/sys/kern/vfs_lookup.c

cvs diff -r1.117 -r1.118 src/sys/kern/vfs_lookup.c (expand / switch to unified diff)

--- src/sys/kern/vfs_lookup.c 2009/08/09 03:28:35 1.117
+++ src/sys/kern/vfs_lookup.c 2009/08/09 07:27:54 1.118
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 dholland Exp $ */ 1/* $NetBSD: vfs_lookup.c,v 1.118 2009/08/09 07:27:54 dholland Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1982, 1986, 1989, 1993 4 * Copyright (c) 1982, 1986, 1989, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc. 6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed 7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph 8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc. 10 * the permission of UNIX System Laboratories, Inc.
11 * 11 *
12 * Redistribution and use in source and binary forms, with or without 12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions 13 * modification, are permitted provided that the following conditions
14 * are met: 14 * are met:
@@ -27,27 +27,27 @@ @@ -27,27 +27,27 @@
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE. 34 * SUCH DAMAGE.
35 * 35 *
36 * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95 36 * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95
37 */ 37 */
38 38
39#include <sys/cdefs.h> 39#include <sys/cdefs.h>
40__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 dholland Exp $"); 40__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.118 2009/08/09 07:27:54 dholland Exp $");
41 41
42#include "opt_magiclinks.h" 42#include "opt_magiclinks.h"
43 43
44#include <sys/param.h> 44#include <sys/param.h>
45#include <sys/systm.h> 45#include <sys/systm.h>
46#include <sys/kernel.h> 46#include <sys/kernel.h>
47#include <sys/syslimits.h> 47#include <sys/syslimits.h>
48#include <sys/time.h> 48#include <sys/time.h>
49#include <sys/namei.h> 49#include <sys/namei.h>
50#include <sys/vnode.h> 50#include <sys/vnode.h>
51#include <sys/mount.h> 51#include <sys/mount.h>
52#include <sys/errno.h> 52#include <sys/errno.h>
53#include <sys/filedesc.h> 53#include <sys/filedesc.h>
@@ -214,51 +214,71 @@ symlink_magic(struct proc *p, char *cp,  @@ -214,51 +214,71 @@ symlink_magic(struct proc *p, char *cp,
214 * while (!done && !error) { 214 * while (!done && !error) {
215 * call lookup to search path. 215 * call lookup to search path.
216 * if symbolic link, massage name in buffer and continue 216 * if symbolic link, massage name in buffer and continue
217 * } 217 * }
218 */ 218 */
219 219
220/* 220/*
221 * Internal state for a namei operation. 221 * Internal state for a namei operation.
222 */ 222 */
223struct namei_state { 223struct namei_state {
224 struct nameidata *ndp; 224 struct nameidata *ndp;
225 struct componentname *cnp; 225 struct componentname *cnp;
226 226
 227 /* used by the pieces of namei */
 228 struct vnode *namei_startdir; /* The directory namei() starts from. */
 229
 230 /* used by the pieces of lookup */
 231 int lookup_alldone;
 232
 233 int docache; /* == 0 do not cache last component */
 234 int rdonly; /* lookup read-only flag bit */
227 struct vnode *dp; /* the directory we are searching */ 235 struct vnode *dp; /* the directory we are searching */
 236 int slashes;
228}; 237};
229 238
 239/* XXX reorder things to make this decl unnecessary */
 240static int do_lookup(struct namei_state *state);
 241
 242
230/* 243/*
231 * Initialize the namei working state. 244 * Initialize the namei working state.
232 */ 245 */
233static void 246static void
234namei_init(struct namei_state *state, struct nameidata *ndp) 247namei_init(struct namei_state *state, struct nameidata *ndp)
235{ 248{
236 state->ndp = ndp; 249 state->ndp = ndp;
237 state->cnp = &ndp->ni_cnd; 250 state->cnp = &ndp->ni_cnd;
238 251
 252 state->namei_startdir = NULL;
 253
 254 state->lookup_alldone = 0;
 255
 256 state->docache = 0;
 257 state->rdonly = 0;
239 state->dp = NULL; 258 state->dp = NULL;
 259 state->slashes = 0;
240} 260}
241 261
242/* 262/*
243 * Clean up the working namei state, leaving things ready for return 263 * Clean up the working namei state, leaving things ready for return
244 * from namei. 264 * from namei.
245 */ 265 */
246static void 266static void
247namei_cleanup(struct namei_state *state) 267namei_cleanup(struct namei_state *state)
248{ 268{
249 KASSERT(state->cnp == &state->ndp->ni_cnd); 269 KASSERT(state->cnp == &state->ndp->ni_cnd);
250 270
251 //KASSERT(state->dp == NULL); // not yet 271 //KASSERT(state->namei_startdir == NULL); // not yet
252 272
253 /* nothing for now */ 273 /* nothing for now */
254 (void)state; 274 (void)state;
255} 275}
256 276
257////////////////////////////// 277//////////////////////////////
258 278
259/* 279/*
260 * Start up namei. Early portion. 280 * Start up namei. Early portion.
261 * 281 *
262 * This is divided from namei_start2 by the emul_retry: point. 282 * This is divided from namei_start2 by the emul_retry: point.
263 */ 283 */
264static void 284static void
@@ -311,99 +331,99 @@ namei_start2(struct namei_state *state) @@ -311,99 +331,99 @@ namei_start2(struct namei_state *state)
311 331
312 if (error) { 332 if (error) {
313 PNBUF_PUT(cnp->cn_pnbuf); 333 PNBUF_PUT(cnp->cn_pnbuf);
314 ndp->ni_vp = NULL; 334 ndp->ni_vp = NULL;
315 return (error); 335 return (error);
316 } 336 }
317 ndp->ni_loopcnt = 0; 337 ndp->ni_loopcnt = 0;
318 338
319 /* 339 /*
320 * Get root directory for the translation. 340 * Get root directory for the translation.
321 */ 341 */
322 cwdi = self->l_proc->p_cwdi; 342 cwdi = self->l_proc->p_cwdi;
323 rw_enter(&cwdi->cwdi_lock, RW_READER); 343 rw_enter(&cwdi->cwdi_lock, RW_READER);
324 state->dp = cwdi->cwdi_rdir; 344 state->namei_startdir = cwdi->cwdi_rdir;
325 if (state->dp == NULL) 345 if (state->namei_startdir == NULL)
326 state->dp = rootvnode; 346 state->namei_startdir = rootvnode;
327 ndp->ni_rootdir = state->dp; 347 ndp->ni_rootdir = state->namei_startdir;
328 348
329 /* 349 /*
330 * Check if starting from root directory or current directory. 350 * Check if starting from root directory or current directory.
331 */ 351 */
332 if (cnp->cn_pnbuf[0] == '/') { 352 if (cnp->cn_pnbuf[0] == '/') {
333 if (cnp->cn_flags & TRYEMULROOT) { 353 if (cnp->cn_flags & TRYEMULROOT) {
334 if (cnp->cn_flags & EMULROOTSET) { 354 if (cnp->cn_flags & EMULROOTSET) {
335 /* Called from (eg) emul_find_interp() */ 355 /* Called from (eg) emul_find_interp() */
336 state->dp = ndp->ni_erootdir; 356 state->namei_startdir = ndp->ni_erootdir;
337 } else { 357 } else {
338 if (cwdi->cwdi_edir == NULL 358 if (cwdi->cwdi_edir == NULL
339 || (cnp->cn_pnbuf[1] == '.'  359 || (cnp->cn_pnbuf[1] == '.'
340 && cnp->cn_pnbuf[2] == '.'  360 && cnp->cn_pnbuf[2] == '.'
341 && cnp->cn_pnbuf[3] == '/')) { 361 && cnp->cn_pnbuf[3] == '/')) {
342 ndp->ni_erootdir = NULL; 362 ndp->ni_erootdir = NULL;
343 } else { 363 } else {
344 state->dp = cwdi->cwdi_edir; 364 state->namei_startdir = cwdi->cwdi_edir;
345 ndp->ni_erootdir = state->dp; 365 ndp->ni_erootdir = state->namei_startdir;
346 } 366 }
347 } 367 }
348 } else { 368 } else {
349 ndp->ni_erootdir = NULL; 369 ndp->ni_erootdir = NULL;
350 if (cnp->cn_flags & NOCHROOT) 370 if (cnp->cn_flags & NOCHROOT)
351 state->dp = ndp->ni_rootdir = rootvnode; 371 state->namei_startdir = ndp->ni_rootdir = rootvnode;
352 } 372 }
353 } else { 373 } else {
354 state->dp = cwdi->cwdi_cdir; 374 state->namei_startdir = cwdi->cwdi_cdir;
355 ndp->ni_erootdir = NULL; 375 ndp->ni_erootdir = NULL;
356 } 376 }
357 VREF(state->dp); 377 VREF(state->namei_startdir);
358 rw_exit(&cwdi->cwdi_lock); 378 rw_exit(&cwdi->cwdi_lock);
359 379
360 /* 380 /*
361 * Ktrace it. 381 * Ktrace it.
362 */ 382 */
363 if (ktrpoint(KTR_NAMEI)) { 383 if (ktrpoint(KTR_NAMEI)) {
364 if (ndp->ni_erootdir != NULL) { 384 if (ndp->ni_erootdir != NULL) {
365 /* 385 /*
366 * To make any sense, the trace entry need to have the 386 * To make any sense, the trace entry need to have the
367 * text of the emulation path prepended. 387 * text of the emulation path prepended.
368 * Usually we can get this from the current process, 388 * Usually we can get this from the current process,
369 * but when called from emul_find_interp() it is only 389 * but when called from emul_find_interp() it is only
370 * in the exec_package - so we get it passed in ni_next 390 * in the exec_package - so we get it passed in ni_next
371 * (this is a hack). 391 * (this is a hack).
372 */ 392 */
373 const char *emul_path; 393 const char *emul_path;
374 if (cnp->cn_flags & EMULROOTSET) 394 if (cnp->cn_flags & EMULROOTSET)
375 emul_path = ndp->ni_next; 395 emul_path = ndp->ni_next;
376 else 396 else
377 emul_path = self->l_proc->p_emul->e_path; 397 emul_path = self->l_proc->p_emul->e_path;
378 ktrnamei2(emul_path, strlen(emul_path), 398 ktrnamei2(emul_path, strlen(emul_path),
379 cnp->cn_pnbuf, ndp->ni_pathlen); 399 cnp->cn_pnbuf, ndp->ni_pathlen);
380 } else 400 } else
381 ktrnamei(cnp->cn_pnbuf, ndp->ni_pathlen); 401 ktrnamei(cnp->cn_pnbuf, ndp->ni_pathlen);
382 } 402 }
383 403
384 vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY); 404 vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY);
385 405
386 return 0; 406 return 0;
387} 407}
388 408
389/* 409/*
390 * Undo namei_start: unlock and release the current lookup directory, 410 * Undo namei_start: unlock and release the current lookup directory,
391 * and discard the path buffer. 411 * and discard the path buffer.
392 */ 412 */
393static void 413static void
394namei_end(struct namei_state *state) 414namei_end(struct namei_state *state)
395{ 415{
396 vput(state->dp); 416 vput(state->namei_startdir);
397 PNBUF_PUT(state->cnp->cn_pnbuf); 417 PNBUF_PUT(state->cnp->cn_pnbuf);
398 //state->cnp->cn_pnbuf = NULL; // not yet (just in case) (XXX) 418 //state->cnp->cn_pnbuf = NULL; // not yet (just in case) (XXX)
399} 419}
400 420
401/* 421/*
402 * Check for being at a symlink. 422 * Check for being at a symlink.
403 */ 423 */
404static inline int 424static inline int
405namei_atsymlink(struct namei_state *state) 425namei_atsymlink(struct namei_state *state)
406{ 426{
407 return (state->cnp->cn_flags & ISSYMLINK) != 0; 427 return (state->cnp->cn_flags & ISSYMLINK) != 0;
408} 428}
409 429
@@ -464,43 +484,43 @@ badlink: @@ -464,43 +484,43 @@ badlink:
464 symlink_magic(self->l_proc, cp, &linklen)) || 484 symlink_magic(self->l_proc, cp, &linklen)) ||
465 (linklen + ndp->ni_pathlen >= MAXPATHLEN)) { 485 (linklen + ndp->ni_pathlen >= MAXPATHLEN)) {
466 error = ENAMETOOLONG; 486 error = ENAMETOOLONG;
467 goto badlink; 487 goto badlink;
468 } 488 }
469 if (ndp->ni_pathlen > 1) { 489 if (ndp->ni_pathlen > 1) {
470 memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen); 490 memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
471 PNBUF_PUT(cnp->cn_pnbuf); 491 PNBUF_PUT(cnp->cn_pnbuf);
472 cnp->cn_pnbuf = cp; 492 cnp->cn_pnbuf = cp;
473 } else 493 } else
474 cnp->cn_pnbuf[linklen] = '\0'; 494 cnp->cn_pnbuf[linklen] = '\0';
475 ndp->ni_pathlen += linklen; 495 ndp->ni_pathlen += linklen;
476 vput(ndp->ni_vp); 496 vput(ndp->ni_vp);
477 state->dp = ndp->ni_dvp; 497 state->namei_startdir = ndp->ni_dvp;
478 498
479 /* 499 /*
480 * Check if root directory should replace current directory. 500 * Check if root directory should replace current directory.
481 */ 501 */
482 if (cnp->cn_pnbuf[0] == '/') { 502 if (cnp->cn_pnbuf[0] == '/') {
483 vput(state->dp); 503 vput(state->namei_startdir);
484 /* Keep absolute symbolic links inside emulation root */ 504 /* Keep absolute symbolic links inside emulation root */
485 state->dp = ndp->ni_erootdir; 505 state->namei_startdir = ndp->ni_erootdir;
486 if (state->dp == NULL || (cnp->cn_pnbuf[1] == '.'  506 if (state->namei_startdir == NULL || (cnp->cn_pnbuf[1] == '.'
487 && cnp->cn_pnbuf[2] == '.' 507 && cnp->cn_pnbuf[2] == '.'
488 && cnp->cn_pnbuf[3] == '/')) { 508 && cnp->cn_pnbuf[3] == '/')) {
489 ndp->ni_erootdir = NULL; 509 ndp->ni_erootdir = NULL;
490 state->dp = ndp->ni_rootdir; 510 state->namei_startdir = ndp->ni_rootdir;
491 } 511 }
492 VREF(state->dp); 512 VREF(state->namei_startdir);
493 vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY); 513 vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY);
494 } 514 }
495 515
496 return 0; 516 return 0;
497} 517}
498 518
499////////////////////////////// 519//////////////////////////////
500 520
501static int 521static int
502do_namei(struct namei_state *state) 522do_namei(struct namei_state *state)
503{ 523{
504 int error; 524 int error;
505 525
506 struct nameidata *ndp = state->ndp; 526 struct nameidata *ndp = state->ndp;
@@ -509,33 +529,33 @@ do_namei(struct namei_state *state) @@ -509,33 +529,33 @@ do_namei(struct namei_state *state)
509 KASSERT(cnp == &ndp->ni_cnd); 529 KASSERT(cnp == &ndp->ni_cnd);
510 530
511 namei_start1(state); 531 namei_start1(state);
512 532
513 emul_retry: 533 emul_retry:
514 534
515 error = namei_start2(state); 535 error = namei_start2(state);
516 if (error) { 536 if (error) {
517 return error; 537 return error;
518 } 538 }
519 539
520 /* Loop through symbolic links */ 540 /* Loop through symbolic links */
521 for (;;) { 541 for (;;) {
522 if (!state->dp->v_mount) { 542 if (state->namei_startdir->v_mount == NULL) {
523 /* Give up if the directory is no longer mounted */ 543 /* Give up if the directory is no longer mounted */
524 namei_end(state); 544 namei_end(state);
525 return (ENOENT); 545 return (ENOENT);
526 } 546 }
527 cnp->cn_nameptr = cnp->cn_pnbuf; 547 cnp->cn_nameptr = cnp->cn_pnbuf;
528 ndp->ni_startdir = state->dp; 548 ndp->ni_startdir = state->namei_startdir;
529 error = lookup(ndp); 549 error = lookup(ndp);
530 if (error != 0) { 550 if (error != 0) {
531 /* XXX this should use namei_end() */ 551 /* XXX this should use namei_end() */
532 if (ndp->ni_dvp) { 552 if (ndp->ni_dvp) {
533 vput(ndp->ni_dvp); 553 vput(ndp->ni_dvp);
534 } 554 }
535 if (ndp->ni_erootdir != NULL) { 555 if (ndp->ni_erootdir != NULL) {
536 /* Retry the whole thing from the normal root */ 556 /* Retry the whole thing from the normal root */
537 cnp->cn_flags &= ~TRYEMULROOT; 557 cnp->cn_flags &= ~TRYEMULROOT;
538 goto emul_retry; 558 goto emul_retry;
539 } 559 }
540 PNBUF_PUT(cnp->cn_pnbuf); 560 PNBUF_PUT(cnp->cn_pnbuf);
541 return (error); 561 return (error);
@@ -650,427 +670,512 @@ namei_hash(const char *name, const char  @@ -650,427 +670,512 @@ namei_hash(const char *name, const char
650 * dirloop: 670 * dirloop:
651 * identify next component of name at ndp->ni_ptr 671 * identify next component of name at ndp->ni_ptr
652 * handle degenerate case where name is null string 672 * handle degenerate case where name is null string
653 * if .. and crossing mount points and on mounted filesys, find parent 673 * if .. and crossing mount points and on mounted filesys, find parent
654 * call VOP_LOOKUP routine for next component name 674 * call VOP_LOOKUP routine for next component name
655 * directory vnode returned in ni_dvp, locked. 675 * directory vnode returned in ni_dvp, locked.
656 * component vnode returned in ni_vp (if it exists), locked. 676 * component vnode returned in ni_vp (if it exists), locked.
657 * if result vnode is mounted on and crossing mount points, 677 * if result vnode is mounted on and crossing mount points,
658 * find mounted on vnode 678 * find mounted on vnode
659 * if more components of name, do next level at dirloop 679 * if more components of name, do next level at dirloop
660 * return the answer in ni_vp, locked if LOCKLEAF set 680 * return the answer in ni_vp, locked if LOCKLEAF set
661 * if LOCKPARENT set, return locked parent in ni_dvp 681 * if LOCKPARENT set, return locked parent in ni_dvp
662 */ 682 */
663int 683
664lookup(struct nameidata *ndp) 684/*
 685 * Begin lookup().
 686 */
 687static int
 688lookup_start(struct namei_state *state)
665{ 689{
666 const char *cp; /* pointer into pathname argument */ 690 const char *cp; /* pointer into pathname argument */
667 struct vnode *dp = 0; /* the directory we are searching */ 691
668 struct vnode *tdp; /* saved dp */ 692 struct componentname *cnp = state->cnp;
669 struct mount *mp; /* mount table entry */ 693 struct nameidata *ndp = state->ndp;
670 int docache; /* == 0 do not cache last component */ 694
671 int rdonly; /* lookup read-only flag bit */ 695 KASSERT(cnp == &ndp->ni_cnd);
672 int error = 0; 696
673 int slashes; 697 state->lookup_alldone = 0;
674 struct componentname *cnp = &ndp->ni_cnd; 698 state->dp = NULL;
675 struct lwp *l = curlwp; 
676 699
677 /* 700 /*
678 * Setup: break out flag bits into variables. 701 * Setup: break out flag bits into variables.
679 */ 702 */
680 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 703 state->docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
681 if (cnp->cn_nameiop == DELETE) 704 if (cnp->cn_nameiop == DELETE)
682 docache = 0; 705 state->docache = 0;
683 rdonly = cnp->cn_flags & RDONLY; 706 state->rdonly = cnp->cn_flags & RDONLY;
684 ndp->ni_dvp = NULL; 707 ndp->ni_dvp = NULL;
685 cnp->cn_flags &= ~ISSYMLINK; 708 cnp->cn_flags &= ~ISSYMLINK;
686 dp = ndp->ni_startdir; 709 state->dp = ndp->ni_startdir;
687 ndp->ni_startdir = NULLVP; 710 ndp->ni_startdir = NULLVP;
688 711
689 /* 712 /*
690 * If we have a leading string of slashes, remove them, and just make 713 * If we have a leading string of slashes, remove them, and just make
691 * sure the current node is a directory. 714 * sure the current node is a directory.
692 */ 715 */
693 cp = cnp->cn_nameptr; 716 cp = cnp->cn_nameptr;
694 if (*cp == '/') { 717 if (*cp == '/') {
695 do { 718 do {
696 cp++; 719 cp++;
697 } while (*cp == '/'); 720 } while (*cp == '/');
698 ndp->ni_pathlen -= cp - cnp->cn_nameptr; 721 ndp->ni_pathlen -= cp - cnp->cn_nameptr;
699 cnp->cn_nameptr = cp; 722 cnp->cn_nameptr = cp;
700 723
701 if (dp->v_type != VDIR) { 724 if (state->dp->v_type != VDIR) {
702 error = ENOTDIR; 725 vput(state->dp);
703 vput(dp); 726 return ENOTDIR;
704 goto bad; 
705 } 727 }
706 728
707 /* 729 /*
708 * If we've exhausted the path name, then just return the 730 * If we've exhausted the path name, then just return the
709 * current node. 731 * current node.
710 */ 732 */
711 if (cnp->cn_nameptr[0] == '\0') { 733 if (cnp->cn_nameptr[0] == '\0') {
712 ndp->ni_vp = dp; 734 ndp->ni_vp = state->dp;
713 cnp->cn_flags |= ISLASTCN; 735 cnp->cn_flags |= ISLASTCN;
714 goto terminal; 736
 737 /* bleh */
 738 state->lookup_alldone = 1;
 739 return 0;
715 } 740 }
716 } 741 }
717 742
718dirloop: 743 return 0;
 744}
 745
 746static int
 747lookup_parsepath(struct namei_state *state)
 748{
 749 const char *cp; /* pointer into pathname argument */
 750
 751 struct componentname *cnp = state->cnp;
 752 struct nameidata *ndp = state->ndp;
 753
 754 KASSERT(cnp == &ndp->ni_cnd);
 755
719 /* 756 /*
720 * Search a new directory. 757 * Search a new directory.
721 * 758 *
722 * The cn_hash value is for use by vfs_cache. 759 * The cn_hash value is for use by vfs_cache.
723 * The last component of the filename is left accessible via 760 * The last component of the filename is left accessible via
724 * cnp->cn_nameptr for callers that need the name. Callers needing 761 * cnp->cn_nameptr for callers that need the name. Callers needing
725 * the name set the SAVENAME flag. When done, they assume 762 * the name set the SAVENAME flag. When done, they assume
726 * responsibility for freeing the pathname buffer. 763 * responsibility for freeing the pathname buffer.
727 * 764 *
728 * At this point, our only vnode state is that "dp" is held and locked. 765 * At this point, our only vnode state is that "dp" is held and locked.
729 */ 766 */
730 cnp->cn_consume = 0; 767 cnp->cn_consume = 0;
731 cp = NULL; 768 cp = NULL;
732 cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp); 769 cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp);
733 cnp->cn_namelen = cp - cnp->cn_nameptr; 770 cnp->cn_namelen = cp - cnp->cn_nameptr;
734 if (cnp->cn_namelen > NAME_MAX) { 771 if (cnp->cn_namelen > NAME_MAX) {
735 vput(dp); 772 vput(state->dp);
736 error = ENAMETOOLONG; 
737 ndp->ni_dvp = NULL; 773 ndp->ni_dvp = NULL;
738 goto bad; 774 return ENAMETOOLONG;
739 } 775 }
740#ifdef NAMEI_DIAGNOSTIC 776#ifdef NAMEI_DIAGNOSTIC
741 { char c = *cp; 777 { char c = *cp;
742 *(char *)cp = '\0'; 778 *(char *)cp = '\0';
743 printf("{%s}: ", cnp->cn_nameptr); 779 printf("{%s}: ", cnp->cn_nameptr);
744 *(char *)cp = c; } 780 *(char *)cp = c; }
745#endif /* NAMEI_DIAGNOSTIC */ 781#endif /* NAMEI_DIAGNOSTIC */
746 ndp->ni_pathlen -= cnp->cn_namelen; 782 ndp->ni_pathlen -= cnp->cn_namelen;
747 ndp->ni_next = cp; 783 ndp->ni_next = cp;
748 /* 784 /*
749 * If this component is followed by a slash, then move the pointer to 785 * If this component is followed by a slash, then move the pointer to
750 * the next component forward, and remember that this component must be 786 * the next component forward, and remember that this component must be
751 * a directory. 787 * a directory.
752 */ 788 */
753 if (*cp == '/') { 789 if (*cp == '/') {
754 do { 790 do {
755 cp++; 791 cp++;
756 } while (*cp == '/'); 792 } while (*cp == '/');
757 slashes = cp - ndp->ni_next; 793 state->slashes = cp - ndp->ni_next;
758 ndp->ni_pathlen -= slashes; 794 ndp->ni_pathlen -= state->slashes;
759 ndp->ni_next = cp; 795 ndp->ni_next = cp;
760 cnp->cn_flags |= REQUIREDIR; 796 cnp->cn_flags |= REQUIREDIR;
761 } else { 797 } else {
762 slashes = 0; 798 state->slashes = 0;
763 cnp->cn_flags &= ~REQUIREDIR; 799 cnp->cn_flags &= ~REQUIREDIR;
764 } 800 }
765 /* 801 /*
766 * We do special processing on the last component, whether or not it's 802 * We do special processing on the last component, whether or not it's
767 * a directory. Cache all intervening lookups, but not the final one. 803 * a directory. Cache all intervening lookups, but not the final one.
768 */ 804 */
769 if (*cp == '\0') { 805 if (*cp == '\0') {
770 if (docache) 806 if (state->docache)
771 cnp->cn_flags |= MAKEENTRY; 807 cnp->cn_flags |= MAKEENTRY;
772 else 808 else
773 cnp->cn_flags &= ~MAKEENTRY; 809 cnp->cn_flags &= ~MAKEENTRY;
774 cnp->cn_flags |= ISLASTCN; 810 cnp->cn_flags |= ISLASTCN;
775 } else { 811 } else {
776 cnp->cn_flags |= MAKEENTRY; 812 cnp->cn_flags |= MAKEENTRY;
777 cnp->cn_flags &= ~ISLASTCN; 813 cnp->cn_flags &= ~ISLASTCN;
778 } 814 }
779 if (cnp->cn_namelen == 2 && 815 if (cnp->cn_namelen == 2 &&
780 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 816 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
781 cnp->cn_flags |= ISDOTDOT; 817 cnp->cn_flags |= ISDOTDOT;
782 else 818 else
783 cnp->cn_flags &= ~ISDOTDOT; 819 cnp->cn_flags &= ~ISDOTDOT;
784 820
 821 return 0;
 822}
 823
 824static int
 825lookup_once(struct namei_state *state)
 826{
 827 struct vnode *tdp; /* saved dp */
 828 struct mount *mp; /* mount table entry */
 829 struct lwp *l = curlwp;
 830 int error;
 831
 832 struct componentname *cnp = state->cnp;
 833 struct nameidata *ndp = state->ndp;
 834
 835 KASSERT(cnp == &ndp->ni_cnd);
 836
785 /* 837 /*
786 * Handle "..": two special cases. 838 * Handle "..": two special cases.
787 * 1. If at root directory (e.g. after chroot) 839 * 1. If at root directory (e.g. after chroot)
788 * or at absolute root directory 840 * or at absolute root directory
789 * then ignore it so can't get out. 841 * then ignore it so can't get out.
790 * 1a. If at the root of the emulation filesystem go to the real 842 * 1a. If at the root of the emulation filesystem go to the real
791 * root. So "/../<path>" is always absolute. 843 * root. So "/../<path>" is always absolute.
792 * 1b. If we have somehow gotten out of a jail, warn 844 * 1b. If we have somehow gotten out of a jail, warn
793 * and also ignore it so we can't get farther out. 845 * and also ignore it so we can't get farther out.
794 * 2. If this vnode is the root of a mounted 846 * 2. If this vnode is the root of a mounted
795 * filesystem, then replace it with the 847 * filesystem, then replace it with the
796 * vnode which was mounted on so we take the 848 * vnode which was mounted on so we take the
797 * .. in the other file system. 849 * .. in the other file system.
798 */ 850 */
799 if (cnp->cn_flags & ISDOTDOT) { 851 if (cnp->cn_flags & ISDOTDOT) {
800 struct proc *p = l->l_proc; 852 struct proc *p = l->l_proc;
801 853
802 for (;;) { 854 for (;;) {
803 if (dp == ndp->ni_rootdir || dp == rootvnode) { 855 if (state->dp == ndp->ni_rootdir || state->dp == rootvnode) {
804 ndp->ni_dvp = dp; 856 ndp->ni_dvp = state->dp;
805 ndp->ni_vp = dp; 857 ndp->ni_vp = state->dp;
806 VREF(dp); 858 VREF(state->dp);
807 goto nextname; 859 return 0;
808 } 860 }
809 if (ndp->ni_rootdir != rootvnode) { 861 if (ndp->ni_rootdir != rootvnode) {
810 int retval; 862 int retval;
811 863
812 VOP_UNLOCK(dp, 0); 864 VOP_UNLOCK(state->dp, 0);
813 retval = vn_isunder(dp, ndp->ni_rootdir, l); 865 retval = vn_isunder(state->dp, ndp->ni_rootdir, l);
814 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 866 vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
815 if (!retval) { 867 if (!retval) {
816 /* Oops! We got out of jail! */ 868 /* Oops! We got out of jail! */
817 log(LOG_WARNING, 869 log(LOG_WARNING,
818 "chrooted pid %d uid %d (%s) " 870 "chrooted pid %d uid %d (%s) "
819 "detected outside of its chroot\n", 871 "detected outside of its chroot\n",
820 p->p_pid, kauth_cred_geteuid(l->l_cred), 872 p->p_pid, kauth_cred_geteuid(l->l_cred),
821 p->p_comm); 873 p->p_comm);
822 /* Put us at the jail root. */ 874 /* Put us at the jail root. */
823 vput(dp); 875 vput(state->dp);
824 dp = ndp->ni_rootdir; 876 state->dp = ndp->ni_rootdir;
825 ndp->ni_dvp = dp; 877 ndp->ni_dvp = state->dp;
826 ndp->ni_vp = dp; 878 ndp->ni_vp = state->dp;
827 VREF(dp); 879 VREF(state->dp);
828 VREF(dp); 880 VREF(state->dp);
829 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 881 vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
830 goto nextname; 882 return 0;
831 } 883 }
832 } 884 }
833 if ((dp->v_vflag & VV_ROOT) == 0 || 885 if ((state->dp->v_vflag & VV_ROOT) == 0 ||
834 (cnp->cn_flags & NOCROSSMOUNT)) 886 (cnp->cn_flags & NOCROSSMOUNT))
835 break; 887 break;
836 tdp = dp; 888 tdp = state->dp;
837 dp = dp->v_mount->mnt_vnodecovered; 889 state->dp = state->dp->v_mount->mnt_vnodecovered;
838 vput(tdp); 890 vput(tdp);
839 VREF(dp); 891 VREF(state->dp);
840 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 892 vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
841 } 893 }
842 } 894 }
843 895
844 /* 896 /*
845 * We now have a segment name to search for, and a directory to search. 897 * We now have a segment name to search for, and a directory to search.
846 * Again, our only vnode state is that "dp" is held and locked. 898 * Again, our only vnode state is that "dp" is held and locked.
847 */ 899 */
848unionlookup: 900unionlookup:
849 ndp->ni_dvp = dp; 901 ndp->ni_dvp = state->dp;
850 ndp->ni_vp = NULL; 902 ndp->ni_vp = NULL;
851 error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp); 903 error = VOP_LOOKUP(state->dp, &ndp->ni_vp, cnp);
852 if (error != 0) { 904 if (error != 0) {
853#ifdef DIAGNOSTIC 905#ifdef DIAGNOSTIC
854 if (ndp->ni_vp != NULL) 906 if (ndp->ni_vp != NULL)
855 panic("leaf `%s' should be empty", cnp->cn_nameptr); 907 panic("leaf `%s' should be empty", cnp->cn_nameptr);
856#endif /* DIAGNOSTIC */ 908#endif /* DIAGNOSTIC */
857#ifdef NAMEI_DIAGNOSTIC 909#ifdef NAMEI_DIAGNOSTIC
858 printf("not found\n"); 910 printf("not found\n");
859#endif /* NAMEI_DIAGNOSTIC */ 911#endif /* NAMEI_DIAGNOSTIC */
860 if ((error == ENOENT) && 912 if ((error == ENOENT) &&
861 (dp->v_vflag & VV_ROOT) && 913 (state->dp->v_vflag & VV_ROOT) &&
862 (dp->v_mount->mnt_flag & MNT_UNION)) { 914 (state->dp->v_mount->mnt_flag & MNT_UNION)) {
863 tdp = dp; 915 tdp = state->dp;
864 dp = dp->v_mount->mnt_vnodecovered; 916 state->dp = state->dp->v_mount->mnt_vnodecovered;
865 vput(tdp); 917 vput(tdp);
866 VREF(dp); 918 VREF(state->dp);
867 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 919 vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
868 goto unionlookup; 920 goto unionlookup;
869 } 921 }
870 922
871 if (error != EJUSTRETURN) 923 if (error != EJUSTRETURN)
872 goto bad; 924 return error;
873 925
874 /* 926 /*
875 * If this was not the last component, or there were trailing 927 * If this was not the last component, or there were trailing
876 * slashes, and we are not going to create a directory, 928 * slashes, and we are not going to create a directory,
877 * then the name must exist. 929 * then the name must exist.
878 */ 930 */
879 if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) { 931 if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) {
880 error = ENOENT; 932 return ENOENT;
881 goto bad; 
882 } 933 }
883 934
884 /* 935 /*
885 * If creating and at end of pathname, then can consider 936 * If creating and at end of pathname, then can consider
886 * allowing file to be created. 937 * allowing file to be created.
887 */ 938 */
888 if (rdonly) { 939 if (state->rdonly) {
889 error = EROFS; 940 return EROFS;
890 goto bad; 
891 } 941 }
892 942
893 /* 943 /*
894 * We return with ni_vp NULL to indicate that the entry 944 * We return with ni_vp NULL to indicate that the entry
895 * doesn't currently exist, leaving a pointer to the 945 * doesn't currently exist, leaving a pointer to the
896 * (possibly locked) directory vnode in ndp->ni_dvp. 946 * (possibly locked) directory vnode in ndp->ni_dvp.
897 */ 947 */
898 if (cnp->cn_flags & SAVESTART) { 948 if (cnp->cn_flags & SAVESTART) {
899 ndp->ni_startdir = ndp->ni_dvp; 949 ndp->ni_startdir = ndp->ni_dvp;
900 VREF(ndp->ni_startdir); 950 VREF(ndp->ni_startdir);
901 } 951 }
 952 state->lookup_alldone = 1;
902 return (0); 953 return (0);
903 } 954 }
904#ifdef NAMEI_DIAGNOSTIC 955#ifdef NAMEI_DIAGNOSTIC
905 printf("found\n"); 956 printf("found\n");
906#endif /* NAMEI_DIAGNOSTIC */ 957#endif /* NAMEI_DIAGNOSTIC */
907 958
908 /* 959 /*
909 * Take into account any additional components consumed by the 960 * Take into account any additional components consumed by the
910 * underlying filesystem. This will include any trailing slashes after 961 * underlying filesystem. This will include any trailing slashes after
911 * the last component consumed. 962 * the last component consumed.
912 */ 963 */
913 if (cnp->cn_consume > 0) { 964 if (cnp->cn_consume > 0) {
914 ndp->ni_pathlen -= cnp->cn_consume - slashes; 965 ndp->ni_pathlen -= cnp->cn_consume - state->slashes;
915 ndp->ni_next += cnp->cn_consume - slashes; 966 ndp->ni_next += cnp->cn_consume - state->slashes;
916 cnp->cn_consume = 0; 967 cnp->cn_consume = 0;
917 if (ndp->ni_next[0] == '\0') 968 if (ndp->ni_next[0] == '\0')
918 cnp->cn_flags |= ISLASTCN; 969 cnp->cn_flags |= ISLASTCN;
919 } 970 }
920 971
921 dp = ndp->ni_vp; 972 state->dp = ndp->ni_vp;
922 973
923 /* 974 /*
924 * "dp" and "ndp->ni_dvp" are both locked and held, 975 * "state->dp" and "ndp->ni_dvp" are both locked and held,
925 * and may be the same vnode. 976 * and may be the same vnode.
926 */ 977 */
927 978
928 /* 979 /*
929 * Check to see if the vnode has been mounted on; 980 * Check to see if the vnode has been mounted on;
930 * if so find the root of the mounted file system. 981 * if so find the root of the mounted file system.
931 */ 982 */
932 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 983 while (state->dp->v_type == VDIR && (mp = state->dp->v_mountedhere) &&
933 (cnp->cn_flags & NOCROSSMOUNT) == 0) { 984 (cnp->cn_flags & NOCROSSMOUNT) == 0) {
934 error = vfs_busy(mp, NULL); 985 error = vfs_busy(mp, NULL);
935 if (error != 0) { 986 if (error != 0) {
936 vput(dp); 987 vput(state->dp);
937 goto bad; 988 return error;
938 } 989 }
939 KASSERT(ndp->ni_dvp != dp); 990 KASSERT(ndp->ni_dvp != state->dp);
940 VOP_UNLOCK(ndp->ni_dvp, 0); 991 VOP_UNLOCK(ndp->ni_dvp, 0);
941 vput(dp); 992 vput(state->dp);
942 error = VFS_ROOT(mp, &tdp); 993 error = VFS_ROOT(mp, &tdp);
943 vfs_unbusy(mp, false, NULL); 994 vfs_unbusy(mp, false, NULL);
944 if (error) { 995 if (error) {
945 vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY); 996 vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
946 goto bad; 997 return error;
947 } 998 }
948 VOP_UNLOCK(tdp, 0); 999 VOP_UNLOCK(tdp, 0);
949 ndp->ni_vp = dp = tdp; 1000 ndp->ni_vp = state->dp = tdp;
950 vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY); 1001 vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
951 vn_lock(ndp->ni_vp, LK_EXCLUSIVE | LK_RETRY); 1002 vn_lock(ndp->ni_vp, LK_EXCLUSIVE | LK_RETRY);
952 } 1003 }
953 1004
 1005 return 0;
 1006}
 1007
 1008static int
 1009do_lookup(struct namei_state *state)
 1010{
 1011 int error = 0;
 1012
 1013 struct componentname *cnp = state->cnp;
 1014 struct nameidata *ndp = state->ndp;
 1015
 1016 KASSERT(cnp == &ndp->ni_cnd);
 1017
 1018 error = lookup_start(state);
 1019 if (error) {
 1020 goto bad;
 1021 }
 1022 // XXX: this case should not be necessary given proper handling
 1023 // of slashes elsewhere.
 1024 if (state->lookup_alldone) {
 1025 goto terminal;
 1026 }
 1027
 1028dirloop:
 1029 error = lookup_parsepath(state);
 1030 if (error) {
 1031 goto bad;
 1032 }
 1033
 1034 error = lookup_once(state);
 1035 if (error) {
 1036 goto bad;
 1037 }
 1038 // XXX ought to be able to avoid this case too
 1039 if (state->lookup_alldone) {
 1040 /* this should NOT be "goto terminal;" */
 1041 return 0;
 1042 }
 1043
954 /* 1044 /*
955 * Check for symbolic link. Back up over any slashes that we skipped, 1045 * Check for symbolic link. Back up over any slashes that we skipped,
956 * as we will need them again. 1046 * as we will need them again.
957 */ 1047 */
958 if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) { 1048 if ((state->dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
959 ndp->ni_pathlen += slashes; 1049 ndp->ni_pathlen += state->slashes;
960 ndp->ni_next -= slashes; 1050 ndp->ni_next -= state->slashes;
961 cnp->cn_flags |= ISSYMLINK; 1051 cnp->cn_flags |= ISSYMLINK;
962 return (0); 1052 return (0);
963 } 1053 }
964 1054
965 /* 1055 /*
966 * Check for directory, if the component was followed by a series of 1056 * Check for directory, if the component was followed by a series of
967 * slashes. 1057 * slashes.
968 */ 1058 */
969 if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) { 1059 if ((state->dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
970 error = ENOTDIR; 1060 error = ENOTDIR;
971 KASSERT(dp != ndp->ni_dvp); 1061 KASSERT(state->dp != ndp->ni_dvp);
972 vput(dp); 1062 vput(state->dp);
973 goto bad; 1063 goto bad;
974 } 1064 }
975 1065
976nextname: 
977 
978 /* 1066 /*
979 * Not a symbolic link. If this was not the last component, then 1067 * Not a symbolic link. If this was not the last component, then
980 * continue at the next component, else return. 1068 * continue at the next component, else return.
981 */ 1069 */
982 if (!(cnp->cn_flags & ISLASTCN)) { 1070 if (!(cnp->cn_flags & ISLASTCN)) {
983 cnp->cn_nameptr = ndp->ni_next; 1071 cnp->cn_nameptr = ndp->ni_next;
984 if (ndp->ni_dvp == dp) { 1072 if (ndp->ni_dvp == state->dp) {
985 vrele(ndp->ni_dvp); 1073 vrele(ndp->ni_dvp);
986 } else { 1074 } else {
987 vput(ndp->ni_dvp); 1075 vput(ndp->ni_dvp);
988 } 1076 }
989 goto dirloop; 1077 goto dirloop;
990 } 1078 }
991 1079
992terminal: 1080terminal:
993 if (dp == ndp->ni_erootdir) { 1081 if (state->dp == ndp->ni_erootdir) {
994 /* 1082 /*
995 * We are about to return the emulation root. 1083 * We are about to return the emulation root.
996 * This isn't a good idea because code might repeatedly 1084 * This isn't a good idea because code might repeatedly
997 * lookup ".." until the file matches that returned 1085 * lookup ".." until the file matches that returned
998 * for "/" and loop forever. 1086 * for "/" and loop forever.
999 * So convert it to the real root. 1087 * So convert it to the real root.
1000 */ 1088 */
1001 if (ndp->ni_dvp == dp) 1089 if (ndp->ni_dvp == state->dp)
1002 vrele(dp); 1090 vrele(state->dp);
1003 else 1091 else
1004 if (ndp->ni_dvp != NULL) 1092 if (ndp->ni_dvp != NULL)
1005 vput(ndp->ni_dvp); 1093 vput(ndp->ni_dvp);
1006 ndp->ni_dvp = NULL; 1094 ndp->ni_dvp = NULL;
1007 vput(dp); 1095 vput(state->dp);
1008 dp = ndp->ni_rootdir; 1096 state->dp = ndp->ni_rootdir;
1009 VREF(dp); 1097 VREF(state->dp);
1010 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 1098 vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
1011 ndp->ni_vp = dp; 1099 ndp->ni_vp = state->dp;
1012 } 1100 }
1013 1101
1014 /* 1102 /*
1015 * If the caller requested the parent node (i.e. 1103 * If the caller requested the parent node (i.e.
1016 * it's a CREATE, DELETE, or RENAME), and we don't have one 1104 * it's a CREATE, DELETE, or RENAME), and we don't have one
1017 * (because this is the root directory), then we must fail. 1105 * (because this is the root directory), then we must fail.
1018 */ 1106 */
1019 if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) { 1107 if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) {
1020 switch (cnp->cn_nameiop) { 1108 switch (cnp->cn_nameiop) {
1021 case CREATE: 1109 case CREATE:
1022 error = EEXIST; 1110 error = EEXIST;
1023 break; 1111 break;
1024 case DELETE: 1112 case DELETE:
1025 case RENAME: 1113 case RENAME:
1026 error = EBUSY; 1114 error = EBUSY;
1027 break; 1115 break;
1028 default: 1116 default:
1029 KASSERT(0); 1117 KASSERT(0);
1030 } 1118 }
1031 vput(dp); 1119 vput(state->dp);
1032 goto bad; 1120 goto bad;
1033 } 1121 }
1034 1122
1035 /* 1123 /*
1036 * Disallow directory write attempts on read-only lookups. 1124 * Disallow directory write attempts on read-only lookups.
1037 * Prefers EEXIST over EROFS for the CREATE case. 1125 * Prefers EEXIST over EROFS for the CREATE case.
1038 */ 1126 */
1039 if (rdonly && 1127 if (state->rdonly &&
1040 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 1128 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
1041 error = EROFS; 1129 error = EROFS;
1042 if (dp != ndp->ni_dvp) { 1130 if (state->dp != ndp->ni_dvp) {
1043 vput(dp); 1131 vput(state->dp);
1044 } 1132 }
1045 goto bad; 1133 goto bad;
1046 } 1134 }
1047 if (ndp->ni_dvp != NULL) { 1135 if (ndp->ni_dvp != NULL) {
1048 if (cnp->cn_flags & SAVESTART) { 1136 if (cnp->cn_flags & SAVESTART) {
1049 ndp->ni_startdir = ndp->ni_dvp; 1137 ndp->ni_startdir = ndp->ni_dvp;
1050 VREF(ndp->ni_startdir); 1138 VREF(ndp->ni_startdir);
1051 } 1139 }
1052 } 1140 }
1053 if ((cnp->cn_flags & LOCKLEAF) == 0) { 1141 if ((cnp->cn_flags & LOCKLEAF) == 0) {
1054 VOP_UNLOCK(dp, 0); 1142 VOP_UNLOCK(state->dp, 0);
1055 } 1143 }
1056 return (0); 1144 return (0);
1057 1145
1058bad: 1146bad:
1059 ndp->ni_vp = NULL; 1147 ndp->ni_vp = NULL;
1060 return (error); 1148 return (error);
1061} 1149}
1062 1150
1063/* 1151/*
 1152 * Externally visible interface used by nfsd (bletch, yuk, XXX)
 1153 */
 1154int
 1155lookup(struct nameidata *ndp)
 1156{
 1157 struct namei_state state;
 1158 int error;
 1159
 1160 /* For now at least we don't have to frob the state */
 1161 namei_init(&state, ndp);
 1162 error = do_lookup(&state);
 1163 namei_cleanup(&state);
 1164
 1165 return error;
 1166}
 1167
 1168/*
1064 * Reacquire a path name component. 1169 * Reacquire a path name component.
1065 * dvp is locked on entry and exit. 1170 * dvp is locked on entry and exit.
1066 * *vpp is locked on exit unless it's NULL. 1171 * *vpp is locked on exit unless it's NULL.
1067 */ 1172 */
1068int 1173int
1069relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) 1174relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
1070{ 1175{
1071 int rdonly; /* lookup read-only flag bit */ 1176 int rdonly; /* lookup read-only flag bit */
1072 int error = 0; 1177 int error = 0;
1073#ifdef DEBUG 1178#ifdef DEBUG
1074 uint32_t newhash; /* DEBUG: check name hash */ 1179 uint32_t newhash; /* DEBUG: check name hash */
1075 const char *cp; /* DEBUG: check name ptr/len */ 1180 const char *cp; /* DEBUG: check name ptr/len */
1076#endif /* DEBUG */ 1181#endif /* DEBUG */