Print this page
Backport fix from 
 Make NFS4.x dbe related ops lockless with atomic
Evan's review
        
@@ -825,27 +825,41 @@
                 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))) {
-                                        entry->dbe_refcnt--;
+                                        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);