void rcl_disconnect(struct child_node* node) { assert(node); if (!node->rcl_node) return; rpc_destroy_client(node->rcl_node); node->rcl_node = NULL; }
/* * Release an RPC client */ void rpc_release_client(struct rpc_clnt *clnt) { dprintk("RPC: rpc_release_client(%p, %d)\n", clnt, atomic_read(&clnt->cl_users)); if (!atomic_dec_and_test(&clnt->cl_users)) return; wake_up(&destroy_wait); if (clnt->cl_oneshot || clnt->cl_dead) rpc_destroy_client(clnt); }
/* * 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; }
/* * Release an RPC client */ void rpc_release_client(struct rpc_clnt *clnt) { dprintk("RPC: rpc_release_client(%p, %d)\n", clnt, clnt->cl_users); if (clnt->cl_users) { if (--(clnt->cl_users) > 0) return; } else printk("rpc_release_client: %s client already free??\n", clnt->cl_protname); wake_up(&destroy_wait); if (clnt->cl_oneshot || clnt->cl_dead) rpc_destroy_client(clnt); }
/* * Properly shut down an RPC client, terminating all outstanding * requests. Note that we must be certain that cl_oneshot and * cl_dead are cleared, or else the client would be destroyed * when the last task releases it. */ int rpc_shutdown_client(struct rpc_clnt *clnt) { dprintk("RPC: shutting down %s client for %s\n", clnt->cl_protname, clnt->cl_server); while (clnt->cl_users) { #ifdef RPC_DEBUG printk("rpc_shutdown_client: client %s, tasks=%d\n", clnt->cl_protname, clnt->cl_users); #endif /* Don't let rpc_release_client destroy us */ clnt->cl_oneshot = 0; clnt->cl_dead = 0; rpc_killall_tasks(clnt); sleep_on(&destroy_wait); } return rpc_destroy_client(clnt); }