* Move a negative entry to the hot list if it matches the lookup. * * We have to take locks, but they may be contended and in the worst * case we may need to go off CPU. We don't want to spin within the * smr section and we can't block with it. Exiting the section means * the found entry could have been evicted. We are going to look it * up again. */
| 1182 | * up again. |
| 1183 | */ |
| 1184 | static bool |
| 1185 | cache_neg_promote_cond(struct vnode *dvp, struct componentname *cnp, |
| 1186 | struct namecache *oncp, uint32_t hash) |
| 1187 | { |
| 1188 | struct namecache *ncp; |
| 1189 | struct neglist *nl; |
| 1190 | u_char nc_flag; |
| 1191 | |
| 1192 | nl = NCP2NEGLIST(oncp); |
| 1193 | |
| 1194 | mtx_lock(&nl->nl_lock); |
| 1195 | /* |
| 1196 | * For hash iteration. |
| 1197 | */ |
| 1198 | vfs_smr_enter(); |
| 1199 | |
| 1200 | /* |
| 1201 | * Avoid all surprises by only succeeding if we got the same entry and |
| 1202 | * bailing completely otherwise. |
| 1203 | * XXX There are no provisions to keep the vnode around, meaning we may |
| 1204 | * end up promoting a negative entry for a *new* vnode and returning |
| 1205 | * ENOENT on its account. This is the error we want to return anyway |
| 1206 | * and promotion is harmless. |
| 1207 | * |
| 1208 | * In particular at this point there can be a new ncp which matches the |
| 1209 | * search but hashes to a different neglist. |
| 1210 | */ |
| 1211 | CK_SLIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { |
| 1212 | if (ncp == oncp) |
| 1213 | break; |
| 1214 | } |
| 1215 | |
| 1216 | /* |
| 1217 | * No match to begin with. |
| 1218 | */ |
| 1219 | if (__predict_false(ncp == NULL)) { |
| 1220 | goto out_abort; |
| 1221 | } |
| 1222 | |
| 1223 | /* |
| 1224 | * The newly found entry may be something different... |
| 1225 | */ |
| 1226 | if (!(ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen && |
| 1227 | !bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen))) { |
| 1228 | goto out_abort; |
| 1229 | } |
| 1230 | |
| 1231 | /* |
| 1232 | * ... and not even negative. |
| 1233 | */ |
| 1234 | nc_flag = atomic_load_char(&ncp->nc_flag); |
| 1235 | if ((nc_flag & NCF_NEGATIVE) == 0) { |
| 1236 | goto out_abort; |
| 1237 | } |
| 1238 | |
| 1239 | if (!cache_ncp_canuse(ncp)) { |
| 1240 | goto out_abort; |
| 1241 | } |
no test coverage detected