void dec_nsm_client_ref_locked(state_nsm_client_t *pclient) { bool_t remove = FALSE; char str[HASHTABLE_DISPLAY_STRLEN]; if(isFullDebug(COMPONENT_STATE)) display_nsm_client(pclient, str); if(pclient->ssc_refcount > 1) { pclient->ssc_refcount--; LogFullDebug(COMPONENT_STATE, "Decrement refcount NSM Client {%s}", str); } else remove = TRUE; V(pclient->ssc_mutex); if(remove) { hash_buffer_t buffkey, old_key, old_value; buffkey.pdata = (caddr_t) pclient; buffkey.len = sizeof(*pclient); switch(HashTable_DelRef(ht_nsm_client, &buffkey, &old_key, &old_value, Hash_dec_nsm_client_ref)) { case HASHTABLE_SUCCESS: LogFullDebug(COMPONENT_STATE, "Free NSM Client {%s} size %llx", str, (unsigned long long) old_value.len); nsm_unmonitor((state_nsm_client_t *) old_value.pdata); free_nsm_client((state_nsm_client_t *) old_key.pdata); free_nsm_client((state_nsm_client_t *) old_value.pdata); break; case HASHTABLE_NOT_DELETED: /* ref count didn't end up at 0, don't free. */ LogDebug(COMPONENT_STATE, "HashTable_DelRef didn't reduce refcount to 0 for NSM Client {%s}", str); break; default: /* some problem occurred */ LogDebug(COMPONENT_STATE, "HashTable_DelRef failed for NSM Client {%s}", str); break; } } }
/* * Garbage collect any unused NLM hosts. * This GC combines reference counting for async operations with * mark & sweep for resources held by remote clients. */ static void nlm_gc_hosts(void) { struct nlm_host **q, *host; struct rpc_clnt *clnt; int i; dprintk("lockd: host garbage collection\n"); for (i = 0; i < NLM_HOST_NRHASH; i++) { for (host = nlm_hosts[i]; host; host = host->h_next) host->h_inuse = 0; } /* Mark all hosts that hold locks, blocks or shares */ nlmsvc_mark_resources(); for (i = 0; i < NLM_HOST_NRHASH; i++) { q = &nlm_hosts[i]; while ((host = *q) != NULL) { if (atomic_read(&host->h_count) || host->h_inuse || time_before(jiffies, host->h_expires)) { dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n", host->h_name, atomic_read(&host->h_count), host->h_inuse, host->h_expires); q = &host->h_next; continue; } dprintk("lockd: delete host %s\n", host->h_name); *q = host->h_next; /* Don't unmonitor hosts that have been invalidated */ if (host->h_monitored && !host->h_killed) nsm_unmonitor(host); if ((clnt = host->h_rpcclnt) != NULL) { if (atomic_read(&clnt->cl_users)) { printk(KERN_WARNING "lockd: active RPC handle\n"); clnt->cl_dead = 1; } else { rpc_destroy_client(host->h_rpcclnt); } } BUG_ON(!list_empty(&host->h_lockowners)); kfree(host); nrhosts--; } } next_gc = jiffies + NLM_HOST_COLLECT; }
void dec_nsm_client_ref(state_nsm_client_t *pclient) { char str[HASHTABLE_DISPLAY_STRLEN]; struct hash_latch latch; hash_error_t rc; hash_buffer_t buffkey; hash_buffer_t old_value; hash_buffer_t old_key; int32_t refcount; if(isDebug(COMPONENT_STATE)) display_nsm_client(pclient, str); refcount = atomic_dec_int32_t(&pclient->ssc_refcount); if(refcount > 0) { LogFullDebug(COMPONENT_STATE, "Decrement refcount now=%"PRId32" {%s}", refcount, str); return; } LogFullDebug(COMPONENT_STATE, "Try to remove {%s}", str); buffkey.pdata = pclient; buffkey.len = sizeof(*pclient); /* Get the hash table entry and hold latch */ rc = HashTable_GetLatch(ht_nsm_client, &buffkey, &old_value, TRUE, &latch); if(rc != HASHTABLE_SUCCESS) { if(rc == HASHTABLE_ERROR_NO_SUCH_KEY) HashTable_ReleaseLatched(ht_nsm_client, &latch); display_nsm_client(pclient, str); LogCrit(COMPONENT_STATE, "Error %s, could not find {%s}", hash_table_err_to_str(rc), str); return; } refcount = atomic_fetch_int32_t(&pclient->ssc_refcount); if(refcount > 0) { LogDebug(COMPONENT_STATE, "Did not release refcount now=%"PRId32" {%s}", refcount, str); HashTable_ReleaseLatched(ht_nsm_client, &latch); return; } /* use the key to delete the entry */ rc = HashTable_DeleteLatched(ht_nsm_client, &buffkey, &latch, &old_key, &old_value); if(rc != HASHTABLE_SUCCESS) { if(rc == HASHTABLE_ERROR_NO_SUCH_KEY) HashTable_ReleaseLatched(ht_nsm_client, &latch); display_nsm_client(pclient, str); LogCrit(COMPONENT_STATE, "Error %s, could not remove {%s}", hash_table_err_to_str(rc), str); return; } LogFullDebug(COMPONENT_STATE, "Free {%s}", str); nsm_unmonitor(old_value.pdata); free_nsm_client(old_value.pdata); }
/** * @brief Relinquish a reference on an NSM client * * @param[in] client The client to release */ void dec_nsm_client_ref(state_nsm_client_t *client) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; bool str_valid = false; struct hash_latch latch; hash_error_t rc; struct gsh_buffdesc buffkey; struct gsh_buffdesc old_value; struct gsh_buffdesc old_key; int32_t refcount; if (isDebug(COMPONENT_STATE)) { display_nsm_client(&dspbuf, client); str_valid = true; } refcount = atomic_dec_int32_t(&client->ssc_refcount); if (refcount > 0) { if (str_valid) LogFullDebug(COMPONENT_STATE, "Decrement refcount now=%" PRId32 " {%s}", refcount, str); return; } if (str_valid) LogFullDebug(COMPONENT_STATE, "Try to remove {%s}", str); buffkey.addr = client; buffkey.len = sizeof(*client); /* Get the hash table entry and hold latch */ rc = hashtable_getlatch(ht_nsm_client, &buffkey, &old_value, true, &latch); if (rc != HASHTABLE_SUCCESS) { if (rc == HASHTABLE_ERROR_NO_SUCH_KEY) hashtable_releaselatched(ht_nsm_client, &latch); if (!str_valid) display_nsm_client(&dspbuf, client); LogCrit(COMPONENT_STATE, "Error %s, could not find {%s}", hash_table_err_to_str(rc), str); return; } refcount = atomic_fetch_int32_t(&client->ssc_refcount); if (refcount > 0) { if (str_valid) LogDebug(COMPONENT_STATE, "Did not release refcount now=%"PRId32" {%s}", refcount, str); hashtable_releaselatched(ht_nsm_client, &latch); return; } /* use the key to delete the entry */ rc = hashtable_deletelatched(ht_nsm_client, &buffkey, &latch, &old_key, &old_value); if (rc != HASHTABLE_SUCCESS) { if (rc == HASHTABLE_ERROR_NO_SUCH_KEY) hashtable_releaselatched(ht_nsm_client, &latch); if (!str_valid) display_nsm_client(&dspbuf, client); LogCrit(COMPONENT_STATE, "Error %s, could not remove {%s}", hash_table_err_to_str(rc), str); return; } LogFullDebug(COMPONENT_STATE, "Free {%s}", str); nsm_unmonitor(old_value.addr); free_nsm_client(old_value.addr); }