// SPDX-License-Identifier: GPL-2.0 /* * linux/fs/lockd/host.c * * Management for NLM peer hosts. The nlm_host struct is shared * between client and server implementation. The only reason to * do so is to reduce code bloat. * * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
/* * Allocate and initialize an nlm_host. Common to both client and server.
*/ staticstruct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, struct nsm_handle *nsm)
{ struct nlm_host *host = NULL; unsignedlong now = jiffies;
if (nsm != NULL)
refcount_inc(&nsm->sm_count); else {
nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
ni->hostname, ni->hostname_len); if (unlikely(nsm == NULL)) {
dprintk("lockd: %s failed; no nsm handle\n",
__func__); goto out;
}
}
host = kmalloc(sizeof(*host), GFP_KERNEL); if (unlikely(host == NULL)) {
dprintk("lockd: %s failed; no memory\n", __func__);
nsm_release(nsm); goto out;
}
clnt = host->h_rpcclnt; if (clnt != NULL)
rpc_shutdown_client(clnt);
put_cred(host->h_cred);
kfree(host);
ln->nrhosts--;
nrhosts--;
}
/** * nlmclnt_lookup_host - Find an NLM host handle matching a remote server * @sap: network address of server * @salen: length of server address * @protocol: transport protocol to use * @version: NLM protocol version * @hostname: '\0'-terminated hostname of server * @noresvport: 1 if non-privileged port should be used * @net: pointer to net namespace * @cred: pointer to cred * * Returns an nlm_host structure that matches the passed-in * [server address, transport protocol, NLM version, server hostname]. * If one doesn't already exist in the host cache, a new handle is * created and returned.
*/ struct nlm_host *nlmclnt_lookup_host(conststruct sockaddr *sap, const size_t salen, constunsignedshort protocol, const u32 version, constchar *hostname, int noresvport, struct net *net, conststruct cred *cred)
{ struct nlm_lookup_host_info ni = {
.server = 0,
.sap = sap,
.salen = salen,
.protocol = protocol,
.version = version,
.hostname = hostname,
.hostname_len = strlen(hostname),
.noresvport = noresvport,
.net = net,
.cred = cred,
}; struct hlist_head *chain; struct nlm_host *host; struct nsm_handle *nsm = NULL; struct lockd_net *ln = net_generic(net, lockd_net_id);
/** * nlmsvc_lookup_host - Find an NLM host handle matching a remote client * @rqstp: incoming NLM request * @hostname: name of client host * @hostname_len: length of client hostname * * Returns an nlm_host structure that matches the [client address, * transport protocol, NLM version, client hostname] of the passed-in * NLM request. If one doesn't already exist in the host cache, a * new handle is created and returned. * * Before possibly creating a new nlm_host, construct a sockaddr * for a specific source address in case the local system has * multiple network addresses. The family of the address in * rq_daddr is guaranteed to be the same as the family of the * address in rq_addr, so it's safe to use the same family for * the source address.
*/ struct nlm_host *nlmsvc_lookup_host(conststruct svc_rqst *rqstp, constchar *hostname, const size_t hostname_len)
{ struct hlist_head *chain; struct nlm_host *host = NULL; struct nsm_handle *nsm = NULL; struct sockaddr *src_sap = svc_daddr(rqstp);
size_t src_len = rqstp->rq_daddrlen; struct net *net = SVC_NET(rqstp); 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,
.net = net,
}; struct lockd_net *ln = net_generic(net, lockd_net_id);
/* * 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; if (host->h_srcaddrlen)
args.saddress = nlm_srcaddr(host);
/** * nlm_rebind_host - If needed, force a portmap lookup of the peer's lockd port * @host: NLM host handle for peer * * This is not needed when using a connection-oriented protocol, such as TCP. * The existing autobind mechanism is sufficient to force a rebind when * required, e.g. on connection state transitions.
*/ void
nlm_rebind_host(struct nlm_host *host)
{ if (host->h_proto != IPPROTO_UDP) return;
/** * nlm_host_rebooted - Release all resources held by rebooted host * @net: network namespace * @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(conststruct net *net, conststruct nlm_reboot *info)
{ struct nsm_handle *nsm; struct nlm_host *host;
nsm = nsm_reboot_lookup(net, 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.
*/ while ((host = next_host_state(nlm_server_hosts, nsm, info)) != NULL) {
nlmsvc_free_host_resources(host);
nlmsvc_release_host(host);
} while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) {
nlmclnt_recovery(host);
nlmclnt_release_host(host);
}
/* * Shut down the hosts module. * Note that this routine is called only at server shutdown time.
*/ void
nlm_shutdown_hosts(void)
{
dprintk("lockd: shutting down host module\n");
nlm_shutdown_hosts_net(NULL);
}
/* * Garbage collect any unused NLM hosts. * This GC combines reference counting for async operations with * mark & sweep for resources held by remote clients.
*/ staticvoid
nlm_gc_hosts(struct net *net)
{ struct hlist_head *chain; struct hlist_node *next; struct nlm_host *host;
dprintk("lockd: host garbage collection for net %x\n",
net ? net->ns.inum : 0);
for_each_host(host, chain, nlm_server_hosts) { if (net && host->net != net) continue;
host->h_inuse = 0;
}
/* Mark all hosts that hold locks, blocks or shares */
nlmsvc_mark_resources(net);
for_each_host_safe(host, next, chain, nlm_server_hosts) { if (net && host->net != net) continue; if (host->h_inuse || time_before(jiffies, host->h_expires)) {
dprintk("nlm_gc_hosts skipping %s " "(cnt %d use %d exp %ld net %x)\n",
host->h_name, refcount_read(&host->h_count),
host->h_inuse, host->h_expires,
host->net->ns.inum); continue;
} if (refcount_dec_if_one(&host->h_count))
nlm_destroy_host_locked(host);
}
if (net) { struct lockd_net *ln = net_generic(net, lockd_net_id);
ln->next_gc = jiffies + NLM_HOST_COLLECT;
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.