📄 host.c
字号:
* the source address. */struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, const char *hostname, const size_t hostname_len){ struct sockaddr_in sin = { .sin_family = AF_INET, }; struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6, }; struct nlm_lookup_host_info ni = { .server = 1, .sap = svc_addr(rqstp), .salen = rqstp->rq_addrlen, .protocol = rqstp->rq_prot, .version = rqstp->rq_vers, .hostname = hostname, .hostname_len = hostname_len, .src_len = rqstp->rq_addrlen, }; dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__, (int)hostname_len, hostname, rqstp->rq_vers, (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp")); switch (ni.sap->sa_family) { case AF_INET: sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr; ni.src_sap = (struct sockaddr *)&sin; break; case AF_INET6: ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6); ni.src_sap = (struct sockaddr *)&sin6; break; default: return NULL; } return nlm_lookup_host(&ni);}/* * Create the NLM RPC client for an NLM peer */struct rpc_clnt *nlm_bind_host(struct nlm_host *host){ struct rpc_clnt *clnt; dprintk("lockd: nlm_bind_host %s (%s)\n", host->h_name, host->h_addrbuf); /* Lock host handle */ mutex_lock(&host->h_mutex); /* If we've already created an RPC client, check whether * RPC rebind is required */ if ((clnt = host->h_rpcclnt) != NULL) { if (time_after_eq(jiffies, host->h_nextrebind)) { rpc_force_rebind(clnt); host->h_nextrebind = jiffies + NLM_HOST_REBIND; dprintk("lockd: next rebind in %lu jiffies\n", host->h_nextrebind - jiffies); } } else { unsigned long increment = nlmsvc_timeout; struct rpc_timeout timeparms = { .to_initval = increment, .to_increment = increment, .to_maxval = increment * 6UL, .to_retries = 5U, }; struct rpc_create_args args = { .protocol = host->h_proto, .address = nlm_addr(host), .addrsize = host->h_addrlen, .saddress = nlm_srcaddr(host), .timeout = &timeparms, .servername = host->h_name, .program = &nlm_program, .version = host->h_version, .authflavor = RPC_AUTH_UNIX, .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_AUTOBIND), }; /* * lockd retries server side blocks automatically so we want * those to be soft RPC calls. Client side calls need to be * hard RPC tasks. */ if (!host->h_server) args.flags |= RPC_CLNT_CREATE_HARDRTRY; if (host->h_noresvport) args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; clnt = rpc_create(&args); if (!IS_ERR(clnt)) host->h_rpcclnt = clnt; else { printk("lockd: couldn't create RPC handle for %s\n", host->h_name); clnt = NULL; } } mutex_unlock(&host->h_mutex); return clnt;}/* * Force a portmap lookup of the remote lockd port */voidnlm_rebind_host(struct nlm_host *host){ dprintk("lockd: rebind host %s\n", host->h_name); if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) { rpc_force_rebind(host->h_rpcclnt); host->h_nextrebind = jiffies + NLM_HOST_REBIND; }}/* * Increment NLM host count */struct nlm_host * nlm_get_host(struct nlm_host *host){ if (host) { dprintk("lockd: get host %s\n", host->h_name); atomic_inc(&host->h_count); host->h_expires = jiffies + NLM_HOST_EXPIRE; } return host;}/* * Release NLM host after use */void nlm_release_host(struct nlm_host *host){ if (host != NULL) { dprintk("lockd: release host %s\n", host->h_name); BUG_ON(atomic_read(&host->h_count) < 0); if (atomic_dec_and_test(&host->h_count)) { BUG_ON(!list_empty(&host->h_lockowners)); BUG_ON(!list_empty(&host->h_granted)); BUG_ON(!list_empty(&host->h_reclaim)); } }}/** * nlm_host_rebooted - Release all resources held by rebooted host * @info: pointer to decoded results of NLM_SM_NOTIFY call * * We were notified that the specified host has rebooted. Release * all resources held by that peer. */void nlm_host_rebooted(const struct nlm_reboot *info){ struct hlist_head *chain; struct hlist_node *pos; struct nsm_handle *nsm; struct nlm_host *host; nsm = nsm_reboot_lookup(info); if (unlikely(nsm == NULL)) return; /* Mark all hosts tied to this NSM state as having rebooted. * We run the loop repeatedly, because we drop the host table * lock for this. * To avoid processing a host several times, we match the nsmstate. */again: mutex_lock(&nlm_host_mutex); for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { hlist_for_each_entry(host, pos, chain, h_hash) { if (host->h_nsmhandle == nsm && host->h_nsmstate != info->state) { host->h_nsmstate = info->state; host->h_state++; nlm_get_host(host); mutex_unlock(&nlm_host_mutex); if (host->h_server) { /* We're server for this guy, just ditch * all the locks he held. */ nlmsvc_free_host_resources(host); } else { /* He's the server, initiate lock recovery. */ nlmclnt_recovery(host); } nlm_release_host(host); goto again; } } } mutex_unlock(&nlm_host_mutex);}/* * Shut down the hosts module. * Note that this routine is called only at server shutdown time. */voidnlm_shutdown_hosts(void){ struct hlist_head *chain; struct hlist_node *pos; struct nlm_host *host; dprintk("lockd: shutting down host module\n"); mutex_lock(&nlm_host_mutex); /* First, make all hosts eligible for gc */ dprintk("lockd: nuking all hosts...\n"); for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { hlist_for_each_entry(host, pos, chain, h_hash) { host->h_expires = jiffies - 1; if (host->h_rpcclnt) { rpc_shutdown_client(host->h_rpcclnt); host->h_rpcclnt = NULL; } } } /* Then, perform a garbage collection pass */ nlm_gc_hosts(); mutex_unlock(&nlm_host_mutex); /* complain if any hosts are left */ if (nrhosts) { printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); dprintk("lockd: %d hosts left:\n", nrhosts); for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { hlist_for_each_entry(host, pos, chain, h_hash) { dprintk(" %s (cnt %d use %d exp %ld)\n", host->h_name, atomic_read(&host->h_count), host->h_inuse, host->h_expires); } } }}/* * Garbage collect any unused NLM hosts. * This GC combines reference counting for async operations with * mark & sweep for resources held by remote clients. */static voidnlm_gc_hosts(void){ struct hlist_head *chain; struct hlist_node *pos, *next; struct nlm_host *host; dprintk("lockd: host garbage collection\n"); for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { hlist_for_each_entry(host, pos, chain, h_hash) host->h_inuse = 0; } /* Mark all hosts that hold locks, blocks or shares */ nlmsvc_mark_resources(); for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { hlist_for_each_entry_safe(host, pos, next, chain, h_hash) { 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); continue; } dprintk("lockd: delete host %s\n", host->h_name); hlist_del_init(&host->h_hash); nlm_destroy_host(host); nrhosts--; } } next_gc = jiffies + NLM_HOST_COLLECT;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -