Print this page
Backport fix from 
 Make NFS4.x dbe related ops lockless with atomic
Evan's review

*** 825,851 **** bp = &buckets[i]; do { found = FALSE; rw_enter(bp->dbk_lock, RW_READER); for (l = bp->dbk_head; l; l = l->next) { entry = l->entry; /* * Examine an entry. Ref count of 1 means * that the only reference is for the hash * table reference. */ if (entry->dbe_refcnt != 1) continue; mutex_enter(entry->dbe_lock); if ((entry->dbe_refcnt == 1) && (table->dbt_reaper_shutdown || table->dbt_expiry == NULL || (*table->dbt_expiry)(entry->dbe_data))) { ! entry->dbe_refcnt--; count++; found = TRUE; } mutex_exit(entry->dbe_lock); } if (found) { if (!rw_tryupgrade(bp->dbk_lock)) { rw_exit(bp->dbk_lock); --- 825,865 ---- bp = &buckets[i]; do { found = FALSE; rw_enter(bp->dbk_lock, RW_READER); for (l = bp->dbk_head; l; l = l->next) { + uint32_t refcnt; + entry = l->entry; /* * Examine an entry. Ref count of 1 means * that the only reference is for the hash * table reference. */ if (entry->dbe_refcnt != 1) continue; mutex_enter(entry->dbe_lock); + /* + * Recheck the ref. count with the lock, + * and if non-zero, leave things alone. + */ if ((entry->dbe_refcnt == 1) && (table->dbt_reaper_shutdown || table->dbt_expiry == NULL || (*table->dbt_expiry)(entry->dbe_data))) { ! refcnt = atomic_dec_32_nv(&entry->dbe_refcnt); ! if (refcnt == 0) { count++; found = TRUE; + } else { + /* + * Lost race w/ incr. + * Leave it as it was + */ + atomic_inc_32(&entry->dbe_refcnt); } + } mutex_exit(entry->dbe_lock); } if (found) { if (!rw_tryupgrade(bp->dbk_lock)) { rw_exit(bp->dbk_lock);