| 5120 | } |
| 5121 | |
| 5122 | static int __noinline |
| 5123 | cache_fplookup_cross_mount(struct cache_fpl *fpl) |
| 5124 | { |
| 5125 | struct mount *mp; |
| 5126 | struct mount_pcpu *mpcpu; |
| 5127 | struct vnode *vp; |
| 5128 | seqc_t vp_seqc; |
| 5129 | |
| 5130 | vp = fpl->tvp; |
| 5131 | vp_seqc = fpl->tvp_seqc; |
| 5132 | |
| 5133 | VNPASS(vp->v_type == VDIR || vp->v_type == VBAD, vp); |
| 5134 | mp = atomic_load_ptr(&vp->v_mountedhere); |
| 5135 | if (__predict_false(mp == NULL)) { |
| 5136 | return (0); |
| 5137 | } |
| 5138 | |
| 5139 | if (!vfs_op_thread_enter_crit(mp, mpcpu)) { |
| 5140 | return (cache_fpl_partial(fpl)); |
| 5141 | } |
| 5142 | if (!vn_seqc_consistent(vp, vp_seqc)) { |
| 5143 | vfs_op_thread_exit_crit(mp, mpcpu); |
| 5144 | return (cache_fpl_partial(fpl)); |
| 5145 | } |
| 5146 | if (!cache_fplookup_mp_supported(mp)) { |
| 5147 | vfs_op_thread_exit_crit(mp, mpcpu); |
| 5148 | return (cache_fpl_partial(fpl)); |
| 5149 | } |
| 5150 | vp = atomic_load_ptr(&mp->mnt_rootvnode); |
| 5151 | if (__predict_false(vp == NULL)) { |
| 5152 | vfs_op_thread_exit_crit(mp, mpcpu); |
| 5153 | return (cache_fpl_partial(fpl)); |
| 5154 | } |
| 5155 | vp_seqc = vn_seqc_read_any(vp); |
| 5156 | vfs_op_thread_exit_crit(mp, mpcpu); |
| 5157 | if (seqc_in_modify(vp_seqc)) { |
| 5158 | return (cache_fpl_partial(fpl)); |
| 5159 | } |
| 5160 | mp = atomic_load_ptr(&vp->v_mountedhere); |
| 5161 | if (__predict_false(mp != NULL)) { |
| 5162 | /* |
| 5163 | * There are possibly more mount points on top. |
| 5164 | * Normally this does not happen so for simplicity just start |
| 5165 | * over. |
| 5166 | */ |
| 5167 | return (cache_fplookup_climb_mount(fpl)); |
| 5168 | } |
| 5169 | |
| 5170 | fpl->tvp = vp; |
| 5171 | fpl->tvp_seqc = vp_seqc; |
| 5172 | return (0); |
| 5173 | } |
| 5174 | |
| 5175 | /* |
| 5176 | * Check if a vnode is mounted on. |
no test coverage detected