| 4915 | } |
| 4916 | |
| 4917 | static int __noinline |
| 4918 | cache_fplookup_symlink(struct cache_fpl *fpl) |
| 4919 | { |
| 4920 | struct mount *mp; |
| 4921 | struct nameidata *ndp; |
| 4922 | struct componentname *cnp; |
| 4923 | struct vnode *dvp, *tvp; |
| 4924 | int error; |
| 4925 | |
| 4926 | ndp = fpl->ndp; |
| 4927 | cnp = fpl->cnp; |
| 4928 | dvp = fpl->dvp; |
| 4929 | tvp = fpl->tvp; |
| 4930 | |
| 4931 | if (cache_fpl_islastcn(ndp)) { |
| 4932 | if ((cnp->cn_flags & FOLLOW) == 0) { |
| 4933 | return (cache_fplookup_final(fpl)); |
| 4934 | } |
| 4935 | } |
| 4936 | |
| 4937 | mp = atomic_load_ptr(&dvp->v_mount); |
| 4938 | if (__predict_false(mp == NULL)) { |
| 4939 | return (cache_fpl_aborted(fpl)); |
| 4940 | } |
| 4941 | |
| 4942 | /* |
| 4943 | * Note this check races against setting the flag just like regular |
| 4944 | * lookup. |
| 4945 | */ |
| 4946 | if (__predict_false((mp->mnt_flag & MNT_NOSYMFOLLOW) != 0)) { |
| 4947 | cache_fpl_smr_exit(fpl); |
| 4948 | return (cache_fpl_handled_error(fpl, EACCES)); |
| 4949 | } |
| 4950 | |
| 4951 | error = VOP_FPLOOKUP_SYMLINK(tvp, fpl); |
| 4952 | if (__predict_false(error != 0)) { |
| 4953 | switch (error) { |
| 4954 | case EAGAIN: |
| 4955 | return (cache_fpl_partial(fpl)); |
| 4956 | case ENOENT: |
| 4957 | case ENAMETOOLONG: |
| 4958 | case ELOOP: |
| 4959 | cache_fpl_smr_exit(fpl); |
| 4960 | return (cache_fpl_handled_error(fpl, error)); |
| 4961 | default: |
| 4962 | return (cache_fpl_aborted(fpl)); |
| 4963 | } |
| 4964 | } |
| 4965 | |
| 4966 | if (*(cnp->cn_nameptr) == '/') { |
| 4967 | fpl->dvp = cache_fpl_handle_root(fpl); |
| 4968 | fpl->dvp_seqc = vn_seqc_read_any(fpl->dvp); |
| 4969 | if (seqc_in_modify(fpl->dvp_seqc)) { |
| 4970 | return (cache_fpl_aborted(fpl)); |
| 4971 | } |
| 4972 | } |
| 4973 | return (0); |
| 4974 | } |
no test coverage detected