| 4744 | } |
| 4745 | |
| 4746 | static int __noinline |
| 4747 | cache_fplookup_dotdot(struct cache_fpl *fpl) |
| 4748 | { |
| 4749 | struct nameidata *ndp; |
| 4750 | struct componentname *cnp; |
| 4751 | struct namecache *ncp; |
| 4752 | struct vnode *dvp; |
| 4753 | struct prison *pr; |
| 4754 | u_char nc_flag; |
| 4755 | |
| 4756 | ndp = fpl->ndp; |
| 4757 | cnp = fpl->cnp; |
| 4758 | dvp = fpl->dvp; |
| 4759 | |
| 4760 | MPASS(cache_fpl_isdotdot(cnp)); |
| 4761 | |
| 4762 | /* |
| 4763 | * XXX this is racy the same way regular lookup is |
| 4764 | */ |
| 4765 | for (pr = cnp->cn_cred->cr_prison; pr != NULL; |
| 4766 | pr = pr->pr_parent) |
| 4767 | if (dvp == pr->pr_root) |
| 4768 | break; |
| 4769 | |
| 4770 | if (dvp == ndp->ni_rootdir || |
| 4771 | dvp == ndp->ni_topdir || |
| 4772 | dvp == rootvnode || |
| 4773 | pr != NULL) { |
| 4774 | fpl->tvp = dvp; |
| 4775 | fpl->tvp_seqc = vn_seqc_read_any(dvp); |
| 4776 | if (seqc_in_modify(fpl->tvp_seqc)) { |
| 4777 | return (cache_fpl_aborted(fpl)); |
| 4778 | } |
| 4779 | return (0); |
| 4780 | } |
| 4781 | |
| 4782 | if ((dvp->v_vflag & VV_ROOT) != 0) { |
| 4783 | /* |
| 4784 | * TODO |
| 4785 | * The opposite of climb mount is needed here. |
| 4786 | */ |
| 4787 | return (cache_fpl_partial(fpl)); |
| 4788 | } |
| 4789 | |
| 4790 | ncp = atomic_load_consume_ptr(&dvp->v_cache_dd); |
| 4791 | if (ncp == NULL) { |
| 4792 | return (cache_fpl_aborted(fpl)); |
| 4793 | } |
| 4794 | |
| 4795 | nc_flag = atomic_load_char(&ncp->nc_flag); |
| 4796 | if ((nc_flag & NCF_ISDOTDOT) != 0) { |
| 4797 | if ((nc_flag & NCF_NEGATIVE) != 0) |
| 4798 | return (cache_fpl_aborted(fpl)); |
| 4799 | fpl->tvp = ncp->nc_vp; |
| 4800 | } else { |
| 4801 | fpl->tvp = ncp->nc_dvp; |
| 4802 | } |
| 4803 |
no test coverage detected