* Handle trailing slashes (e.g., "foo/"). * * If a trailing slash is found the terminal vnode must be a directory. * Regular lookup shortens the path by nulifying the first trailing slash and * sets the TRAILINGSLASH flag to denote this took place. There are several * checks on it performed later. * * Similarly to spurious slashes, lockless lookup handles this in a speculative * manner rel
| 5392 | * Only plain lookups are supported for now to restrict corner cases to handle. |
| 5393 | */ |
| 5394 | static int __noinline |
| 5395 | cache_fplookup_trailingslash(struct cache_fpl *fpl) |
| 5396 | { |
| 5397 | #ifdef INVARIANTS |
| 5398 | size_t ni_pathlen; |
| 5399 | #endif |
| 5400 | struct nameidata *ndp; |
| 5401 | struct componentname *cnp; |
| 5402 | struct namecache *ncp; |
| 5403 | struct vnode *tvp; |
| 5404 | char *cn_nameptr_orig, *cn_nameptr_slash; |
| 5405 | seqc_t tvp_seqc; |
| 5406 | u_char nc_flag; |
| 5407 | |
| 5408 | ndp = fpl->ndp; |
| 5409 | cnp = fpl->cnp; |
| 5410 | tvp = fpl->tvp; |
| 5411 | tvp_seqc = fpl->tvp_seqc; |
| 5412 | |
| 5413 | MPASS(fpl->dvp == fpl->tvp); |
| 5414 | KASSERT(cache_fpl_istrailingslash(fpl), |
| 5415 | ("%s: expected trailing slash at %p; string [%s]\n", __func__, fpl->nulchar - 1, |
| 5416 | cnp->cn_pnbuf)); |
| 5417 | KASSERT(cnp->cn_nameptr[0] == '\0', |
| 5418 | ("%s: expected nul char at %p; string [%s]\n", __func__, &cnp->cn_nameptr[0], |
| 5419 | cnp->cn_pnbuf)); |
| 5420 | KASSERT(cnp->cn_namelen == 0, |
| 5421 | ("%s: namelen 0 but got %ld; string [%s]\n", __func__, cnp->cn_namelen, |
| 5422 | cnp->cn_pnbuf)); |
| 5423 | MPASS(cnp->cn_nameptr > cnp->cn_pnbuf); |
| 5424 | |
| 5425 | if (cnp->cn_nameiop != LOOKUP) { |
| 5426 | return (cache_fpl_aborted(fpl)); |
| 5427 | } |
| 5428 | |
| 5429 | if (__predict_false(tvp->v_type != VDIR)) { |
| 5430 | if (!vn_seqc_consistent(tvp, tvp_seqc)) { |
| 5431 | return (cache_fpl_aborted(fpl)); |
| 5432 | } |
| 5433 | cache_fpl_smr_exit(fpl); |
| 5434 | return (cache_fpl_handled_error(fpl, ENOTDIR)); |
| 5435 | } |
| 5436 | |
| 5437 | /* |
| 5438 | * Denote the last component. |
| 5439 | */ |
| 5440 | ndp->ni_next = &cnp->cn_nameptr[0]; |
| 5441 | MPASS(cache_fpl_islastcn(ndp)); |
| 5442 | |
| 5443 | /* |
| 5444 | * Unwind trailing slashes. |
| 5445 | */ |
| 5446 | cn_nameptr_orig = cnp->cn_nameptr; |
| 5447 | while (cnp->cn_nameptr >= cnp->cn_pnbuf) { |
| 5448 | cnp->cn_nameptr--; |
| 5449 | if (cnp->cn_nameptr[0] != '/') { |
| 5450 | break; |
| 5451 | } |
no test coverage detected