// 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 <[email protected]> */ #include <linux/types.h> #include <linux/slab.h> #include <linux/in.h> #include <linux/in6.h> #include <linux/sunrpc/clnt.h> #include <linux/sunrpc/addr.h> #include <linux/sunrpc/svc.h> #include <linux/lockd/lockd.h> #include <linux/mutex.h> #include <linux/sunrpc/svc_xprt.h> #include <net/ipv6.h> #include "netns.h" #define NLMDBG_FACILITY … #define NLM_HOST_NRHASH … #define NLM_HOST_REBIND … #define NLM_HOST_EXPIRE … #define NLM_HOST_COLLECT … static struct hlist_head nlm_server_hosts[NLM_HOST_NRHASH]; static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH]; #define for_each_host(host, chain, table) … #define for_each_host_safe(host, next, chain, table) … static unsigned long nrhosts; static DEFINE_MUTEX(nlm_host_mutex); static void nlm_gc_hosts(struct net *net); struct nlm_lookup_host_info { … }; /* * Hash function must work well on big- and little-endian platforms */ static unsigned int __nlm_hash32(const __be32 n) { … } static unsigned int __nlm_hash_addr4(const struct sockaddr *sap) { … } static unsigned int __nlm_hash_addr6(const struct sockaddr *sap) { … } static unsigned int nlm_hash_address(const struct sockaddr *sap) { … } /* * Allocate and initialize an nlm_host. Common to both client and server. */ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, struct nsm_handle *nsm) { … } /* * Destroy an nlm_host and free associated resources * * Caller must hold nlm_host_mutex. */ static void nlm_destroy_host_locked(struct nlm_host *host) { … } /** * 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(const struct sockaddr *sap, const size_t salen, const unsigned short protocol, const u32 version, const char *hostname, int noresvport, struct net *net, const struct cred *cred) { … } /** * nlmclnt_release_host - release client nlm_host * @host: nlm_host to release * */ void nlmclnt_release_host(struct nlm_host *host) { … } /** * 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(const struct svc_rqst *rqstp, const char *hostname, const size_t hostname_len) { … } /** * nlmsvc_release_host - release server nlm_host * @host: nlm_host to release * * Host is destroyed later in nlm_gc_host(). */ void nlmsvc_release_host(struct nlm_host *host) { … } /* * Create the NLM RPC client for an NLM peer */ struct rpc_clnt * nlm_bind_host(struct nlm_host *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) { … } /* * Increment NLM host count */ struct nlm_host * nlm_get_host(struct nlm_host *host) { … } static struct nlm_host *next_host_state(struct hlist_head *cache, struct nsm_handle *nsm, const struct nlm_reboot *info) { … } /** * 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(const struct net *net, const struct nlm_reboot *info) { … } static void nlm_complain_hosts(struct net *net) { … } void nlm_shutdown_hosts_net(struct net *net) { … } /* * Shut down the hosts module. * Note that this routine is called only at server shutdown time. */ void nlm_shutdown_hosts(void) { … } /* * 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(struct net *net) { … }