| 4404 | } |
| 4405 | |
| 4406 | static int __noinline |
| 4407 | cache_fplookup_final_withparent(struct cache_fpl *fpl) |
| 4408 | { |
| 4409 | struct componentname *cnp; |
| 4410 | enum vgetstate dvs, tvs; |
| 4411 | struct vnode *dvp, *tvp; |
| 4412 | seqc_t dvp_seqc; |
| 4413 | int error; |
| 4414 | |
| 4415 | cnp = fpl->cnp; |
| 4416 | dvp = fpl->dvp; |
| 4417 | dvp_seqc = fpl->dvp_seqc; |
| 4418 | tvp = fpl->tvp; |
| 4419 | |
| 4420 | MPASS((cnp->cn_flags & (LOCKPARENT|WANTPARENT)) != 0); |
| 4421 | |
| 4422 | /* |
| 4423 | * This is less efficient than it can be for simplicity. |
| 4424 | */ |
| 4425 | dvs = vget_prep_smr(dvp); |
| 4426 | if (__predict_false(dvs == VGET_NONE)) { |
| 4427 | return (cache_fpl_aborted(fpl)); |
| 4428 | } |
| 4429 | tvs = vget_prep_smr(tvp); |
| 4430 | if (__predict_false(tvs == VGET_NONE)) { |
| 4431 | cache_fpl_smr_exit(fpl); |
| 4432 | vget_abort(dvp, dvs); |
| 4433 | return (cache_fpl_aborted(fpl)); |
| 4434 | } |
| 4435 | |
| 4436 | cache_fpl_smr_exit(fpl); |
| 4437 | |
| 4438 | if ((cnp->cn_flags & LOCKPARENT) != 0) { |
| 4439 | error = vget_finish(dvp, LK_EXCLUSIVE, dvs); |
| 4440 | if (__predict_false(error != 0)) { |
| 4441 | vget_abort(tvp, tvs); |
| 4442 | return (cache_fpl_aborted(fpl)); |
| 4443 | } |
| 4444 | } else { |
| 4445 | vget_finish_ref(dvp, dvs); |
| 4446 | } |
| 4447 | |
| 4448 | if (!vn_seqc_consistent(dvp, dvp_seqc)) { |
| 4449 | vget_abort(tvp, tvs); |
| 4450 | if ((cnp->cn_flags & LOCKPARENT) != 0) |
| 4451 | vput(dvp); |
| 4452 | else |
| 4453 | vrele(dvp); |
| 4454 | return (cache_fpl_aborted(fpl)); |
| 4455 | } |
| 4456 | |
| 4457 | error = cache_fplookup_final_child(fpl, tvs); |
| 4458 | if (__predict_false(error != 0)) { |
| 4459 | MPASS(fpl->status == CACHE_FPL_STATUS_ABORTED); |
| 4460 | if ((cnp->cn_flags & LOCKPARENT) != 0) |
| 4461 | vput(dvp); |
| 4462 | else |
| 4463 | vrele(dvp); |
no test coverage detected