Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_lookup.c
Show First 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | |||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
static void NDVALIDATE_impl(struct nameidata *, int); | static void NDVALIDATE_impl(struct nameidata *, int); | ||||
#define NDVALIDATE(ndp) NDVALIDATE_impl(ndp, __LINE__) | #define NDVALIDATE(ndp) NDVALIDATE_impl(ndp, __LINE__) | ||||
#else | #else | ||||
#define NDVALIDATE(ndp) | #define NDVALIDATE(ndp) | ||||
#endif | #endif | ||||
#define NDRESTART(ndp) do { \ | |||||
NDREINIT_DBG(ndp); \ | |||||
ndp->ni_resflags = 0; \ | |||||
ndp->ni_cnd.cn_flags &= ~NAMEI_INTERNAL_FLAGS; \ | |||||
ndp->ni_cnd.cn_flags |= ISRESTARTED; \ | |||||
} while (0) | |||||
SDT_PROVIDER_DEFINE(vfs); | SDT_PROVIDER_DEFINE(vfs); | ||||
SDT_PROBE_DEFINE4(vfs, namei, lookup, entry, "struct vnode *", "char *", | SDT_PROBE_DEFINE4(vfs, namei, lookup, entry, "struct vnode *", "char *", | ||||
"unsigned long", "bool"); | "unsigned long", "bool"); | ||||
SDT_PROBE_DEFINE4(vfs, namei, lookup, return, "int", "struct vnode *", "bool", | SDT_PROBE_DEFINE4(vfs, namei, lookup, return, "int", "struct vnode *", "bool", | ||||
"struct nameidata"); | "struct nameidata"); | ||||
/* Allocation zone for namei. */ | /* Allocation zone for namei. */ | ||||
uma_zone_t namei_zone; | uma_zone_t namei_zone; | ||||
▲ Show 20 Lines • Show All 236 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Get starting point for the translation. | * Get starting point for the translation. | ||||
*/ | */ | ||||
pwd = pwd_hold(td); | pwd = pwd_hold(td); | ||||
/* | /* | ||||
* The reference on ni_rootdir is acquired in the block below to avoid | * The reference on ni_rootdir is acquired in the block below to avoid | ||||
* back-to-back atomics for absolute lookups. | * back-to-back atomics for absolute lookups. | ||||
*/ | */ | ||||
ndp->ni_rootdir = pwd->pwd_rdir; | namei_setup_rootdir(ndp, cnp, rootvnode, pwd); | ||||
ndp->ni_topdir = pwd->pwd_jdir; | ndp->ni_topdir = pwd->pwd_jdir; | ||||
if (cnp->cn_pnbuf[0] == '/') { | if (cnp->cn_pnbuf[0] == '/') { | ||||
ndp->ni_resflags |= NIRES_ABS; | ndp->ni_resflags |= NIRES_ABS; | ||||
error = namei_handle_root(ndp, dpp); | error = namei_handle_root(ndp, dpp); | ||||
} else { | } else { | ||||
if (ndp->ni_startdir != NULL) { | if (ndp->ni_startdir != NULL) { | ||||
*dpp = ndp->ni_startdir; | *dpp = ndp->ni_startdir; | ||||
▲ Show 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | KASSERT((cnp->cn_flags & NAMEI_INTERNAL_FLAGS) == 0, | ||||
("namei: unexpected flags: %" PRIx64 "\n", | ("namei: unexpected flags: %" PRIx64 "\n", | ||||
cnp->cn_flags & NAMEI_INTERNAL_FLAGS)); | cnp->cn_flags & NAMEI_INTERNAL_FLAGS)); | ||||
if (cnp->cn_flags & NOCACHE) | if (cnp->cn_flags & NOCACHE) | ||||
KASSERT(cnp->cn_nameiop != LOOKUP, | KASSERT(cnp->cn_nameiop != LOOKUP, | ||||
("%s: NOCACHE passed with LOOKUP", __func__)); | ("%s: NOCACHE passed with LOOKUP", __func__)); | ||||
MPASS(ndp->ni_startdir == NULL || ndp->ni_startdir->v_type == VDIR || | MPASS(ndp->ni_startdir == NULL || ndp->ni_startdir->v_type == VDIR || | ||||
ndp->ni_startdir->v_type == VBAD); | ndp->ni_startdir->v_type == VBAD); | ||||
restart: | |||||
ndp->ni_lcf = 0; | ndp->ni_lcf = 0; | ||||
ndp->ni_loopcnt = 0; | ndp->ni_loopcnt = 0; | ||||
ndp->ni_vp = NULL; | ndp->ni_vp = NULL; | ||||
error = namei_getpath(ndp); | error = namei_getpath(ndp); | ||||
if (__predict_false(error != 0)) { | if (__predict_false(error != 0)) { | ||||
namei_cleanup_cnp(cnp); | namei_cleanup_cnp(cnp); | ||||
SDT_PROBE4(vfs, namei, lookup, return, error, NULL, | SDT_PROBE4(vfs, namei, lookup, return, error, NULL, | ||||
Show All 18 Lines | #endif | ||||
error = cache_fplookup(ndp, &status, &pwd); | error = cache_fplookup(ndp, &status, &pwd); | ||||
switch (status) { | switch (status) { | ||||
case CACHE_FPL_STATUS_UNSET: | case CACHE_FPL_STATUS_UNSET: | ||||
__assert_unreachable(); | __assert_unreachable(); | ||||
break; | break; | ||||
case CACHE_FPL_STATUS_HANDLED: | case CACHE_FPL_STATUS_HANDLED: | ||||
if (error == 0) | if (error == 0) | ||||
NDVALIDATE(ndp); | NDVALIDATE(ndp); | ||||
else if (__predict_false(pwd->pwd_adir != pwd->pwd_rdir && | |||||
(cnp->cn_flags & ISRESTARTED) == 0)) { | |||||
namei_cleanup_cnp(cnp); | |||||
NDRESTART(ndp); | |||||
goto restart; | |||||
} | |||||
return (error); | return (error); | ||||
case CACHE_FPL_STATUS_PARTIAL: | case CACHE_FPL_STATUS_PARTIAL: | ||||
TAILQ_INIT(&ndp->ni_cap_tracker); | TAILQ_INIT(&ndp->ni_cap_tracker); | ||||
dp = ndp->ni_startdir; | dp = ndp->ni_startdir; | ||||
break; | break; | ||||
case CACHE_FPL_STATUS_DESTROYED: | case CACHE_FPL_STATUS_DESTROYED: | ||||
ndp->ni_loopcnt = 0; | ndp->ni_loopcnt = 0; | ||||
error = namei_getpath(ndp); | error = namei_getpath(ndp); | ||||
Show All 24 Lines | #endif | ||||
} | } | ||||
/* | /* | ||||
* Locked lookup. | * Locked lookup. | ||||
*/ | */ | ||||
for (;;) { | for (;;) { | ||||
ndp->ni_startdir = dp; | ndp->ni_startdir = dp; | ||||
error = vfs_lookup(ndp); | error = vfs_lookup(ndp); | ||||
if (error != 0) | if (error != 0) { | ||||
kib: Should this check be more specific, e.g. only if the file was not found, instead of some other… | |||||
if (__predict_false(pwd->pwd_adir != pwd->pwd_rdir && | |||||
(cnp->cn_flags & ISRESTARTED) == 0)) { | |||||
nameicap_cleanup(ndp); | |||||
pwd_drop(pwd); | |||||
namei_cleanup_cnp(cnp); | |||||
NDRESTART(ndp); | |||||
goto restart; | |||||
} else | |||||
goto out; | goto out; | ||||
} | |||||
/* | /* | ||||
* If not a symbolic link, we're done. | * If not a symbolic link, we're done. | ||||
*/ | */ | ||||
if ((cnp->cn_flags & ISSYMLINK) == 0) { | if ((cnp->cn_flags & ISSYMLINK) == 0) { | ||||
SDT_PROBE4(vfs, namei, lookup, return, error, | SDT_PROBE4(vfs, namei, lookup, return, error, | ||||
ndp->ni_vp, false, ndp); | ndp->ni_vp, false, ndp); | ||||
nameicap_cleanup(ndp); | nameicap_cleanup(ndp); | ||||
▲ Show 20 Lines • Show All 1,001 Lines • Show Last 20 Lines |
Should this check be more specific, e.g. only if the file was not found, instead of some other errors?