vfs: add support for WANTPARENT and LOCKPARENT to lockless lookup
This makes the realpath syscall operational with the new lookup. Note that the walk to obtain the full path name still takes locks. Tested by: pho Differential Revision: https://reviews.freebsd.org/D23917
This commit is contained in:
parent
8230d29357
commit
404927357d
@ -3011,8 +3011,8 @@ cache_fpl_handled_impl(struct cache_fpl *fpl, int error, int line)
|
||||
#define cache_fpl_handled(x, e) cache_fpl_handled_impl((x), (e), __LINE__)
|
||||
|
||||
#define CACHE_FPL_SUPPORTED_CN_FLAGS \
|
||||
(LOCKLEAF | FOLLOW | LOCKSHARED | SAVENAME | ISOPEN | NOMACCHECK | \
|
||||
AUDITVNODE1 | AUDITVNODE2)
|
||||
(LOCKLEAF | LOCKPARENT | WANTPARENT | FOLLOW | LOCKSHARED | SAVENAME | \
|
||||
ISOPEN | NOMACCHECK | AUDITVNODE1 | AUDITVNODE2)
|
||||
|
||||
static bool
|
||||
cache_can_fplookup(struct cache_fpl *fpl)
|
||||
@ -3208,35 +3208,17 @@ cache_fplookup_partial_setup(struct cache_fpl *fpl)
|
||||
}
|
||||
|
||||
static int
|
||||
cache_fplookup_final(struct cache_fpl *fpl)
|
||||
cache_fplookup_final_child(struct cache_fpl *fpl, enum vgetstate tvs)
|
||||
{
|
||||
struct componentname *cnp;
|
||||
enum vgetstate tvs;
|
||||
struct vnode *dvp, *tvp;
|
||||
seqc_t dvp_seqc, tvp_seqc;
|
||||
struct vnode *tvp;
|
||||
seqc_t tvp_seqc;
|
||||
int error;
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
cache_fpl_smr_exit(fpl);
|
||||
|
||||
if ((cnp->cn_flags & LOCKLEAF) != 0) {
|
||||
error = vget_finish(tvp, cnp->cn_lkflags, tvs);
|
||||
if (error != 0) {
|
||||
@ -3257,6 +3239,107 @@ cache_fplookup_final(struct cache_fpl *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;
|
||||
seqc_t dvp_seqc, tvp_seqc;
|
||||
int error;
|
||||
|
||||
cnp = fpl->cnp;
|
||||
dvp = fpl->dvp;
|
||||
dvp_seqc = fpl->dvp_seqc;
|
||||
tvp = fpl->tvp;
|
||||
tvp_seqc = fpl->tvp_seqc;
|
||||
|
||||
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);
|
||||
if (tvs == VGET_NONE) {
|
||||
cache_fpl_smr_exit(fpl);
|
||||
vget_abort(dvp, dvs);
|
||||
return (cache_fpl_aborted(fpl));
|
||||
}
|
||||
|
||||
cache_fpl_smr_exit(fpl);
|
||||
|
||||
if ((cnp->cn_flags & LOCKPARENT) != 0) {
|
||||
error = vget_finish(dvp, LK_EXCLUSIVE, dvs);
|
||||
if (error != 0) {
|
||||
vget_abort(tvp, tvs);
|
||||
return (cache_fpl_aborted(fpl));
|
||||
}
|
||||
} else {
|
||||
vget_finish_ref(dvp, dvs);
|
||||
}
|
||||
|
||||
if (!vn_seqc_consistent(dvp, dvp_seqc)) {
|
||||
vget_abort(tvp, tvs);
|
||||
if ((cnp->cn_flags & LOCKPARENT) != 0)
|
||||
vput(dvp);
|
||||
else
|
||||
vrele(dvp);
|
||||
cache_fpl_aborted(fpl);
|
||||
return (error);
|
||||
}
|
||||
|
||||
error = cache_fplookup_final_child(fpl, tvs);
|
||||
if (error != 0) {
|
||||
MPASS(fpl->status == CACHE_FPL_STATUS_ABORTED);
|
||||
if ((cnp->cn_flags & LOCKPARENT) != 0)
|
||||
vput(dvp);
|
||||
else
|
||||
vrele(dvp);
|
||||
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));
|
||||
}
|
||||
|
||||
cache_fpl_smr_exit(fpl);
|
||||
return (cache_fplookup_final_child(fpl, tvs));
|
||||
}
|
||||
|
||||
static int
|
||||
cache_fplookup_next(struct cache_fpl *fpl)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user