* Lock part of the cache affected by the insertion. * * This means vnodelocks for dvp, vp and the relevant bucketlock. * However, insertion can result in removal of an old entry. In this * case we have an additional vnode and bucketlock pair to lock. * * That is, in the worst case we have to lock 3 vnodes and 2 bucketlocks, while * preserving the locking order (smaller address first). */
| 2159 | * preserving the locking order (smaller address first). |
| 2160 | */ |
| 2161 | static void |
| 2162 | cache_enter_lock(struct celockstate *cel, struct vnode *dvp, struct vnode *vp, |
| 2163 | uint32_t hash) |
| 2164 | { |
| 2165 | struct namecache *ncp; |
| 2166 | struct mtx *blps[2]; |
| 2167 | u_char nc_flag; |
| 2168 | |
| 2169 | blps[0] = HASH2BUCKETLOCK(hash); |
| 2170 | for (;;) { |
| 2171 | blps[1] = NULL; |
| 2172 | cache_lock_vnodes_cel(cel, dvp, vp); |
| 2173 | if (vp == NULL || vp->v_type != VDIR) |
| 2174 | break; |
| 2175 | ncp = atomic_load_consume_ptr(&vp->v_cache_dd); |
| 2176 | if (ncp == NULL) |
| 2177 | break; |
| 2178 | nc_flag = atomic_load_char(&ncp->nc_flag); |
| 2179 | if ((nc_flag & NCF_ISDOTDOT) == 0) |
| 2180 | break; |
| 2181 | MPASS(ncp->nc_dvp == vp); |
| 2182 | blps[1] = NCP2BUCKETLOCK(ncp); |
| 2183 | if ((nc_flag & NCF_NEGATIVE) != 0) |
| 2184 | break; |
| 2185 | if (cache_lock_vnodes_cel_3(cel, ncp->nc_vp)) |
| 2186 | break; |
| 2187 | /* |
| 2188 | * All vnodes got re-locked. Re-validate the state and if |
| 2189 | * nothing changed we are done. Otherwise restart. |
| 2190 | */ |
| 2191 | if (ncp == vp->v_cache_dd && |
| 2192 | (ncp->nc_flag & NCF_ISDOTDOT) != 0 && |
| 2193 | blps[1] == NCP2BUCKETLOCK(ncp) && |
| 2194 | VP2VNODELOCK(ncp->nc_vp) == cel->vlp[2]) |
| 2195 | break; |
| 2196 | cache_unlock_vnodes_cel(cel); |
| 2197 | cel->vlp[0] = NULL; |
| 2198 | cel->vlp[1] = NULL; |
| 2199 | cel->vlp[2] = NULL; |
| 2200 | } |
| 2201 | cache_lock_buckets_cel(cel, blps[0], blps[1]); |
| 2202 | } |
| 2203 | |
| 2204 | static void |
| 2205 | cache_enter_lock_dd(struct celockstate *cel, struct vnode *dvp, struct vnode *vp, |
no test coverage detected