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);