Don't drop the idr lock before verifying that the newly-inserted element

is present in the tree. Otherwise there exists a window during which the
element could be removed by another thread, triggering an incorrect
assertion failure.

Reviewed by:	jeff
MFC after:	1 week
Sponsored by:	EMC / Isilon Storage Division
This commit is contained in:
Mark Johnston 2015-05-02 00:26:38 +00:00
parent b4a0618c44
commit 86d4dbf1cb

View File

@ -185,27 +185,37 @@ idr_replace(struct idr *idr, void *ptr, int id)
return (res);
}
void *
idr_find(struct idr *idr, int id)
static inline void *
idr_find_locked(struct idr *idr, int id)
{
struct idr_layer *il;
void *res;
int layer;
res = NULL;
mtx_assert(&idr->lock, MA_OWNED);
id &= MAX_ID_MASK;
mtx_lock(&idr->lock);
res = NULL;
il = idr->top;
layer = idr->layers - 1;
if (il == NULL || id > idr_max(idr))
goto out;
return (NULL);
while (layer && il) {
il = il->ary[idr_pos(id, layer)];
layer--;
}
if (il != NULL)
res = il->ary[id & IDR_MASK];
out:
return (res);
}
void *
idr_find(struct idr *idr, int id)
{
void *res;
mtx_lock(&idr->lock);
res = idr_find_locked(idr, id);
mtx_unlock(&idr->lock);
return (res);
}
@ -331,13 +341,13 @@ idr_get_new(struct idr *idr, void *ptr, int *idp)
}
error = 0;
out:
mtx_unlock(&idr->lock);
#ifdef INVARIANTS
if (error == 0 && idr_find(idr, id) != ptr) {
if (error == 0 && idr_find_locked(idr, id) != ptr) {
panic("idr_get_new: Failed for idr %p, id %d, ptr %p\n",
idr, id, ptr);
}
#endif
mtx_unlock(&idr->lock);
return (error);
}
@ -438,12 +448,12 @@ idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp)
}
error = 0;
out:
mtx_unlock(&idr->lock);
#ifdef INVARIANTS
if (error == 0 && idr_find(idr, id) != ptr) {
if (error == 0 && idr_find_locked(idr, id) != ptr) {
panic("idr_get_new_above: Failed for idr %p, id %d, ptr %p\n",
idr, id, ptr);
}
#endif
mtx_unlock(&idr->lock);
return (error);
}