Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_cache.c
Show First 20 Lines • Show All 2,972 Lines • ▼ Show 20 Lines | cache_fpl_handled_impl(struct cache_fpl *fpl, int error, int line) | ||||
fpl->status = CACHE_FPL_STATUS_HANDLED; | fpl->status = CACHE_FPL_STATUS_HANDLED; | ||||
fpl->line = line; | fpl->line = line; | ||||
return (error); | return (error); | ||||
} | } | ||||
#define cache_fpl_handled(x, e) cache_fpl_handled_impl((x), (e), __LINE__) | #define cache_fpl_handled(x, e) cache_fpl_handled_impl((x), (e), __LINE__) | ||||
#define CACHE_FPL_SUPPORTED_CN_FLAGS \ | #define CACHE_FPL_SUPPORTED_CN_FLAGS \ | ||||
(LOCKLEAF | FOLLOW | LOCKSHARED | SAVENAME | ISOPEN | AUDITVNODE1) | (LOCKLEAF | LOCKPARENT | WANTPARENT | FOLLOW | LOCKSHARED | SAVENAME | \ | ||||
ISOPEN | AUDITVNODE1) | |||||
static bool | static bool | ||||
cache_can_fplookup(struct cache_fpl *fpl) | cache_can_fplookup(struct cache_fpl *fpl) | ||||
{ | { | ||||
struct nameidata *ndp; | struct nameidata *ndp; | ||||
struct componentname *cnp; | struct componentname *cnp; | ||||
struct thread *td; | struct thread *td; | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | if (fpl->pwd != pwd) { | ||||
return (CACHE_FPL_FAILED); | return (CACHE_FPL_FAILED); | ||||
} | } | ||||
fpl->ndp->ni_startdir = dvp; | fpl->ndp->ni_startdir = dvp; | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
cache_fplookup_final(struct cache_fpl *fpl) | cache_fplookup_final_child(struct cache_fpl *fpl, enum vgetstate tvs) | ||||
{ | { | ||||
struct componentname *cnp; | struct componentname *cnp; | ||||
enum vgetstate tvs; | struct vnode *tvp; | ||||
seqc_t tvp_seqc; | |||||
int error; | |||||
cnp = fpl->cnp; | |||||
tvp = fpl->tvp; | |||||
tvp_seqc = fpl->tvp_seqc; | |||||
if ((cnp->cn_flags & LOCKLEAF) != 0) | |||||
error = vget_finish(tvp, cnp->cn_lkflags, tvs); | |||||
else | |||||
error = vget_finish_ref(tvp, tvs); | |||||
if (error != 0) { | |||||
return (cache_fpl_partial(fpl)); | |||||
} | |||||
if (!vn_seqc_consistent(tvp, tvp_seqc)) { | |||||
if ((cnp->cn_flags & LOCKLEAF) != 0) | |||||
vput(tvp); | |||||
else | |||||
vrele(tvp); | |||||
return (cache_fpl_aborted(fpl)); | |||||
} | |||||
return (cache_fpl_handled(fpl, 0)); | |||||
} | |||||
static int __noinline | |||||
cache_fplookup_final_withparent(struct cache_fpl *fpl) | |||||
{ | |||||
enum vgetstate dvs, tvs; | |||||
struct componentname *cnp; | |||||
struct vnode *dvp, *tvp; | struct vnode *dvp, *tvp; | ||||
seqc_t dvp_seqc, tvp_seqc; | seqc_t dvp_seqc, tvp_seqc; | ||||
int error; | int error; | ||||
cnp = fpl->cnp; | cnp = fpl->cnp; | ||||
dvp = fpl->dvp; | dvp = fpl->dvp; | ||||
dvp_seqc = fpl->dvp_seqc; | dvp_seqc = fpl->dvp_seqc; | ||||
tvp = fpl->tvp; | tvp = fpl->tvp; | ||||
tvp_seqc = fpl->tvp_seqc; | tvp_seqc = fpl->tvp_seqc; | ||||
VNPASS(cache_fplookup_vnode_supported(dvp), dvp); | MPASS((cnp->cn_flags & (LOCKPARENT|WANTPARENT)) != 0); | ||||
/* | |||||
* This is less efficient than it can be for simplicity. | |||||
*/ | |||||
dvs = vget_prep_smr(dvp); | |||||
if (dvs == VGET_NONE) { | |||||
return (cache_fpl_aborted(fpl)); | |||||
} | |||||
tvs = vget_prep_smr(tvp); | tvs = vget_prep_smr(tvp); | ||||
if (tvs == VGET_NONE) { | if (tvs == VGET_NONE) { | ||||
return (cache_fpl_partial(fpl)); | |||||
} | |||||
if (!vn_seqc_consistent(dvp, dvp_seqc)) { | |||||
cache_fpl_smr_exit(fpl); | cache_fpl_smr_exit(fpl); | ||||
vget_abort(tvp, tvs); | vget_abort(dvp, dvs); | ||||
return (cache_fpl_aborted(fpl)); | return (cache_fpl_aborted(fpl)); | ||||
} | } | ||||
cache_fpl_smr_exit(fpl); | cache_fpl_smr_exit(fpl); | ||||
if ((cnp->cn_flags & LOCKLEAF) != 0) | if ((cnp->cn_flags & LOCKPARENT) != 0) | ||||
error = vget_finish(tvp, cnp->cn_lkflags, tvs); | error = vget_finish(dvp, LK_EXCLUSIVE, dvs); | ||||
else | else | ||||
error = vget_finish_ref(tvp, tvs); | error = vget_finish_ref(dvp, dvs); | ||||
if (error != 0) { | if (error != 0) { | ||||
vget_abort(tvp, tvs); | |||||
return (cache_fpl_aborted(fpl)); | return (cache_fpl_aborted(fpl)); | ||||
} | } | ||||
if (!vn_seqc_consistent(tvp, tvp_seqc)) { | if (!vn_seqc_consistent(dvp, dvp_seqc)) { | ||||
if ((cnp->cn_flags & LOCKLEAF) != 0) | vget_abort(tvp, tvs); | ||||
vput(tvp); | if ((cnp->cn_flags & LOCKPARENT) != 0) | ||||
vput(dvp); | |||||
else | else | ||||
vrele(tvp); | vrele(dvp); | ||||
cache_fpl_aborted(fpl); | |||||
return (error); | |||||
} | |||||
error = cache_fplookup_final_child(fpl, tvs); | |||||
if (error != 0) { | |||||
if ((cnp->cn_flags & LOCKPARENT) != 0) | |||||
vput(dvp); | |||||
else | |||||
vrele(dvp); | |||||
cache_fpl_aborted(fpl); | |||||
return (error); | |||||
} | |||||
MPASS(fpl->status == CACHE_FPL_STATUS_HANDLED); | |||||
return (0); | |||||
} | |||||
static int | |||||
cache_fplookup_final(struct cache_fpl *fpl) | |||||
{ | |||||
struct componentname *cnp; | |||||
enum vgetstate tvs; | |||||
struct vnode *dvp, *tvp; | |||||
seqc_t dvp_seqc, tvp_seqc; | |||||
cnp = fpl->cnp; | |||||
dvp = fpl->dvp; | |||||
dvp_seqc = fpl->dvp_seqc; | |||||
tvp = fpl->tvp; | |||||
tvp_seqc = fpl->tvp_seqc; | |||||
VNPASS(cache_fplookup_vnode_supported(dvp), dvp); | |||||
if ((cnp->cn_flags & (LOCKPARENT|WANTPARENT)) != 0) | |||||
return (cache_fplookup_final_withparent(fpl)); | |||||
tvs = vget_prep_smr(tvp); | |||||
if (tvs == VGET_NONE) { | |||||
return (cache_fpl_partial(fpl)); | |||||
} | |||||
if (!vn_seqc_consistent(dvp, dvp_seqc)) { | |||||
cache_fpl_smr_exit(fpl); | |||||
vget_abort(tvp, tvs); | |||||
return (cache_fpl_aborted(fpl)); | return (cache_fpl_aborted(fpl)); | ||||
} | } | ||||
return (cache_fpl_handled(fpl, 0)); | cache_fpl_smr_exit(fpl); | ||||
return (cache_fplookup_final_child(fpl, tvs)); | |||||
} | } | ||||
static int | static int | ||||
cache_fplookup_next(struct cache_fpl *fpl) | cache_fplookup_next(struct cache_fpl *fpl) | ||||
{ | { | ||||
struct componentname *cnp; | struct componentname *cnp; | ||||
struct namecache *ncp; | struct namecache *ncp; | ||||
struct vnode *dvp, *tvp; | struct vnode *dvp, *tvp; | ||||
▲ Show 20 Lines • Show All 529 Lines • Show Last 20 Lines |