⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 host.c

📁 Linux中关于远程文件锁定的支持的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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> */#include <linux/types.h>#include <linux/slab.h>#include <linux/in.h>#include <linux/in6.h>#include <linux/sunrpc/clnt.h>#include <linux/sunrpc/svc.h>#include <linux/lockd/lockd.h>#include <linux/mutex.h>#include <net/ipv6.h>#define NLMDBG_FACILITY		NLMDBG_HOSTCACHE#define NLM_HOST_NRHASH		32#define NLM_HOST_REBIND		(60 * HZ)#define NLM_HOST_EXPIRE		(300 * HZ)#define NLM_HOST_COLLECT	(120 * HZ)static struct hlist_head	nlm_hosts[NLM_HOST_NRHASH];static unsigned long		next_gc;static int			nrhosts;static DEFINE_MUTEX(nlm_host_mutex);static void			nlm_gc_hosts(void);struct nlm_lookup_host_info {	const int		server;		/* search for server|client */	const struct sockaddr	*sap;		/* address to search for */	const size_t		salen;		/* it's length */	const unsigned short	protocol;	/* transport to search for*/	const u32		version;	/* NLM version to search for */	const char		*hostname;	/* remote's hostname */	const size_t		hostname_len;	/* it's length */	const struct sockaddr	*src_sap;	/* our address (optional) */	const size_t		src_len;	/* it's length */	const int		noresvport;	/* use non-priv port */};/* * Hash function must work well on big- and little-endian platforms */static unsigned int __nlm_hash32(const __be32 n){	unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16);	return hash ^ (hash >> 8);}static unsigned int __nlm_hash_addr4(const struct sockaddr *sap){	const struct sockaddr_in *sin = (struct sockaddr_in *)sap;	return __nlm_hash32(sin->sin_addr.s_addr);}static unsigned int __nlm_hash_addr6(const struct sockaddr *sap){	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;	const struct in6_addr addr = sin6->sin6_addr;	return __nlm_hash32(addr.s6_addr32[0]) ^	       __nlm_hash32(addr.s6_addr32[1]) ^	       __nlm_hash32(addr.s6_addr32[2]) ^	       __nlm_hash32(addr.s6_addr32[3]);}static unsigned int nlm_hash_address(const struct sockaddr *sap){	unsigned int hash;	switch (sap->sa_family) {	case AF_INET:		hash = __nlm_hash_addr4(sap);		break;	case AF_INET6:		hash = __nlm_hash_addr6(sap);		break;	default:		hash = 0;	}	return hash & (NLM_HOST_NRHASH - 1);}static void nlm_clear_port(struct sockaddr *sap){	switch (sap->sa_family) {	case AF_INET:		((struct sockaddr_in *)sap)->sin_port = 0;		break;	case AF_INET6:		((struct sockaddr_in6 *)sap)->sin6_port = 0;		break;	}}/* * Common host lookup routine for server & client */static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni){	struct hlist_head *chain;	struct hlist_node *pos;	struct nlm_host	*host;	struct nsm_handle *nsm = NULL;	mutex_lock(&nlm_host_mutex);	if (time_after_eq(jiffies, next_gc))		nlm_gc_hosts();	/* We may keep several nlm_host objects for a peer, because each	 * nlm_host is identified by	 * (address, protocol, version, server/client)	 * We could probably simplify this a little by putting all those	 * different NLM rpc_clients into one single nlm_host object.	 * This would allow us to have one nlm_host per address.	 */	chain = &nlm_hosts[nlm_hash_address(ni->sap)];	hlist_for_each_entry(host, pos, chain, h_hash) {		if (!nlm_cmp_addr(nlm_addr(host), ni->sap))			continue;		/* See if we have an NSM handle for this client */		if (!nsm)			nsm = host->h_nsmhandle;		if (host->h_proto != ni->protocol)			continue;		if (host->h_version != ni->version)			continue;		if (host->h_server != ni->server)			continue;		if (ni->server &&		    !nlm_cmp_addr(nlm_srcaddr(host), ni->src_sap))			continue;		/* Move to head of hash chain. */		hlist_del(&host->h_hash);		hlist_add_head(&host->h_hash, chain);		nlm_get_host(host);		dprintk("lockd: nlm_lookup_host found host %s (%s)\n",				host->h_name, host->h_addrbuf);		goto out;	}	/*	 * The host wasn't in our hash table.  If we don't	 * have an NSM handle for it yet, create one.	 */	if (nsm)		atomic_inc(&nsm->sm_count);	else {		host = NULL;		nsm = nsm_get_handle(ni->sap, ni->salen,					ni->hostname, ni->hostname_len);		if (!nsm) {			dprintk("lockd: nlm_lookup_host failed; "				"no nsm handle\n");			goto out;		}	}	host = kzalloc(sizeof(*host), GFP_KERNEL);	if (!host) {		nsm_release(nsm);		dprintk("lockd: nlm_lookup_host failed; no memory\n");		goto out;	}	host->h_name	   = nsm->sm_name;	host->h_addrbuf    = nsm->sm_addrbuf;	memcpy(nlm_addr(host), ni->sap, ni->salen);	host->h_addrlen = ni->salen;	nlm_clear_port(nlm_addr(host));	memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len);	host->h_version    = ni->version;	host->h_proto      = ni->protocol;	host->h_rpcclnt    = NULL;	mutex_init(&host->h_mutex);	host->h_nextrebind = jiffies + NLM_HOST_REBIND;	host->h_expires    = jiffies + NLM_HOST_EXPIRE;	atomic_set(&host->h_count, 1);	init_waitqueue_head(&host->h_gracewait);	init_rwsem(&host->h_rwsem);	host->h_state      = 0;			/* pseudo NSM state */	host->h_nsmstate   = 0;			/* real NSM state */	host->h_nsmhandle  = nsm;	host->h_server	   = ni->server;	host->h_noresvport = ni->noresvport;	hlist_add_head(&host->h_hash, chain);	INIT_LIST_HEAD(&host->h_lockowners);	spin_lock_init(&host->h_lock);	INIT_LIST_HEAD(&host->h_granted);	INIT_LIST_HEAD(&host->h_reclaim);	nrhosts++;	dprintk("lockd: nlm_lookup_host created host %s\n",			host->h_name);out:	mutex_unlock(&nlm_host_mutex);	return host;}/* * Destroy a host */static voidnlm_destroy_host(struct nlm_host *host){	struct rpc_clnt	*clnt;	BUG_ON(!list_empty(&host->h_lockowners));	BUG_ON(atomic_read(&host->h_count));	nsm_unmonitor(host);	nsm_release(host->h_nsmhandle);	clnt = host->h_rpcclnt;	if (clnt != NULL)		rpc_shutdown_client(clnt);	kfree(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 * * 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){	const struct sockaddr source = {		.sa_family	= AF_UNSPEC,	};	struct nlm_lookup_host_info ni = {		.server		= 0,		.sap		= sap,		.salen		= salen,		.protocol	= protocol,		.version	= version,		.hostname	= hostname,		.hostname_len	= strlen(hostname),		.src_sap	= &source,		.src_len	= sizeof(source),		.noresvport	= noresvport,	};	dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,			(hostname ? hostname : "<none>"), version,			(protocol == IPPROTO_UDP ? "udp" : "tcp"));	return nlm_lookup_host(&ni);}/** * 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -