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

📄 client.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* client.c: NFS client sharing and management code * * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/time.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/errno.h>#include <linux/unistd.h>#include <linux/sunrpc/clnt.h>#include <linux/sunrpc/stats.h>#include <linux/sunrpc/metrics.h>#include <linux/sunrpc/xprtsock.h>#include <linux/sunrpc/xprtrdma.h>#include <linux/nfs_fs.h>#include <linux/nfs_mount.h>#include <linux/nfs4_mount.h>#include <linux/lockd/bind.h>#include <linux/seq_file.h>#include <linux/mount.h>#include <linux/nfs_idmap.h>#include <linux/vfs.h>#include <linux/inet.h>#include <linux/nfs_xdr.h>#include <asm/system.h>#include "nfs4_fs.h"#include "callback.h"#include "delegation.h"#include "iostat.h"#include "internal.h"#define NFSDBG_FACILITY		NFSDBG_CLIENTstatic DEFINE_SPINLOCK(nfs_client_lock);static LIST_HEAD(nfs_client_list);static LIST_HEAD(nfs_volume_list);static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);/* * RPC cruft for NFS */static struct rpc_version *nfs_version[5] = {	[2]			= &nfs_version2,#ifdef CONFIG_NFS_V3	[3]			= &nfs_version3,#endif#ifdef CONFIG_NFS_V4	[4]			= &nfs_version4,#endif};struct rpc_program nfs_program = {	.name			= "nfs",	.number			= NFS_PROGRAM,	.nrvers			= ARRAY_SIZE(nfs_version),	.version		= nfs_version,	.stats			= &nfs_rpcstat,	.pipe_dir_name		= "/nfs",};struct rpc_stat nfs_rpcstat = {	.program		= &nfs_program};#ifdef CONFIG_NFS_V3_ACLstatic struct rpc_stat		nfsacl_rpcstat = { &nfsacl_program };static struct rpc_version *	nfsacl_version[] = {	[3]			= &nfsacl_version3,};struct rpc_program		nfsacl_program = {	.name			= "nfsacl",	.number			= NFS_ACL_PROGRAM,	.nrvers			= ARRAY_SIZE(nfsacl_version),	.version		= nfsacl_version,	.stats			= &nfsacl_rpcstat,};#endif  /* CONFIG_NFS_V3_ACL *//* * Allocate a shared client record * * Since these are allocated/deallocated very rarely, we don't * bother putting them in a slab cache... */static struct nfs_client *nfs_alloc_client(const char *hostname,					   const struct sockaddr_in *addr,					   int nfsversion){	struct nfs_client *clp;	if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)		goto error_0;	if (nfsversion == 4) {		if (nfs_callback_up() < 0)			goto error_2;		__set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);	}	atomic_set(&clp->cl_count, 1);	clp->cl_cons_state = NFS_CS_INITING;	clp->cl_nfsversion = nfsversion;	memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));	if (hostname) {		clp->cl_hostname = kstrdup(hostname, GFP_KERNEL);		if (!clp->cl_hostname)			goto error_3;	}	INIT_LIST_HEAD(&clp->cl_superblocks);	clp->cl_rpcclient = ERR_PTR(-EINVAL);#ifdef CONFIG_NFS_V4	init_rwsem(&clp->cl_sem);	INIT_LIST_HEAD(&clp->cl_delegations);	spin_lock_init(&clp->cl_lock);	INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);	rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");	clp->cl_boot_time = CURRENT_TIME;	clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;#endif	return clp;error_3:	if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))		nfs_callback_down();error_2:	kfree(clp);error_0:	return NULL;}static void nfs4_shutdown_client(struct nfs_client *clp){#ifdef CONFIG_NFS_V4	if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))		nfs4_kill_renewd(clp);	BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners));	if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))		nfs_idmap_delete(clp);#endif}/* * Destroy a shared client record */static void nfs_free_client(struct nfs_client *clp){	dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion);	nfs4_shutdown_client(clp);	/* -EIO all pending I/O */	if (!IS_ERR(clp->cl_rpcclient))		rpc_shutdown_client(clp->cl_rpcclient);	if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))		nfs_callback_down();	kfree(clp->cl_hostname);	kfree(clp);	dprintk("<-- nfs_free_client()\n");}/* * Release a reference to a shared client record */void nfs_put_client(struct nfs_client *clp){	if (!clp)		return;	dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));	if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {		list_del(&clp->cl_share_link);		spin_unlock(&nfs_client_lock);		BUG_ON(!list_empty(&clp->cl_superblocks));		nfs_free_client(clp);	}}/* * Find a client by address * - caller must hold nfs_client_lock */static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion, int match_port){	struct nfs_client *clp;	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {		/* Don't match clients that failed to initialise properly */		if (clp->cl_cons_state < 0)			continue;		/* Different NFS versions cannot share the same nfs_client */		if (clp->cl_nfsversion != nfsversion)			continue;		if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr,			   sizeof(clp->cl_addr.sin_addr)) != 0)			continue;		if (!match_port || clp->cl_addr.sin_port == addr->sin_port)			goto found;	}	return NULL;found:	atomic_inc(&clp->cl_count);	return clp;}/* * Find a client by IP address and protocol version * - returns NULL if no such client */struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion){	struct nfs_client *clp;	spin_lock(&nfs_client_lock);	clp = __nfs_find_client(addr, nfsversion, 0);	spin_unlock(&nfs_client_lock);	if (clp != NULL && clp->cl_cons_state != NFS_CS_READY) {		nfs_put_client(clp);		clp = NULL;	}	return clp;}/* * Look up a client by IP address and protocol version * - creates a new record if one doesn't yet exist */static struct nfs_client *nfs_get_client(const char *hostname,					 const struct sockaddr_in *addr,					 int nfsversion){	struct nfs_client *clp, *new = NULL;	int error;	dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n",		hostname ?: "", NIPQUAD(addr->sin_addr),		addr->sin_port, nfsversion);	/* see if the client already exists */	do {		spin_lock(&nfs_client_lock);		clp = __nfs_find_client(addr, nfsversion, 1);		if (clp)			goto found_client;		if (new)			goto install_client;		spin_unlock(&nfs_client_lock);		new = nfs_alloc_client(hostname, addr, nfsversion);	} while (new);	return ERR_PTR(-ENOMEM);	/* install a new client and return with it unready */install_client:	clp = new;	list_add(&clp->cl_share_link, &nfs_client_list);	spin_unlock(&nfs_client_lock);	dprintk("--> nfs_get_client() = %p [new]\n", clp);	return clp;	/* found an existing client	 * - make sure it's ready before returning	 */found_client:	spin_unlock(&nfs_client_lock);	if (new)		nfs_free_client(new);	error = wait_event_interruptible(nfs_client_active_wq,				clp->cl_cons_state != NFS_CS_INITING);	if (error < 0) {		nfs_put_client(clp);		return ERR_PTR(-ERESTARTSYS);	}	if (clp->cl_cons_state < NFS_CS_READY) {		error = clp->cl_cons_state;		nfs_put_client(clp);		return ERR_PTR(error);	}	BUG_ON(clp->cl_cons_state != NFS_CS_READY);	dprintk("--> nfs_get_client() = %p [share]\n", clp);	return clp;}/* * Mark a server as ready or failed */static void nfs_mark_client_ready(struct nfs_client *clp, int state){	clp->cl_cons_state = state;	wake_up_all(&nfs_client_active_wq);}/* * Initialise the timeout values for a connection */static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,				    unsigned int timeo, unsigned int retrans){	to->to_initval = timeo * HZ / 10;	to->to_retries = retrans;	if (!to->to_retries)		to->to_retries = 2;	switch (proto) {	case XPRT_TRANSPORT_TCP:	case XPRT_TRANSPORT_RDMA:		if (!to->to_initval)			to->to_initval = 60 * HZ;		if (to->to_initval > NFS_MAX_TCP_TIMEOUT)			to->to_initval = NFS_MAX_TCP_TIMEOUT;		to->to_increment = to->to_initval;		to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);		to->to_exponential = 0;		break;	case XPRT_TRANSPORT_UDP:	default:		if (!to->to_initval)			to->to_initval = 11 * HZ / 10;		if (to->to_initval > NFS_MAX_UDP_TIMEOUT)			to->to_initval = NFS_MAX_UDP_TIMEOUT;		to->to_maxval = NFS_MAX_UDP_TIMEOUT;		to->to_exponential = 1;		break;	}}/* * Create an RPC client handle */static int nfs_create_rpc_client(struct nfs_client *clp, int proto,						unsigned int timeo,						unsigned int retrans,						rpc_authflavor_t flavor,						int flags){	struct rpc_timeout	timeparms;	struct rpc_clnt		*clnt = NULL;	struct rpc_create_args args = {		.protocol	= proto,		.address	= (struct sockaddr *)&clp->cl_addr,		.addrsize	= sizeof(clp->cl_addr),		.timeout	= &timeparms,		.servername	= clp->cl_hostname,		.program	= &nfs_program,		.version	= clp->rpc_ops->version,		.authflavor	= flavor,		.flags		= flags,	};	if (!IS_ERR(clp->cl_rpcclient))		return 0;	nfs_init_timeout_values(&timeparms, proto, timeo, retrans);	clp->retrans_timeo = timeparms.to_initval;	clp->retrans_count = timeparms.to_retries;	clnt = rpc_create(&args);	if (IS_ERR(clnt)) {		dprintk("%s: cannot create RPC client. Error = %ld\n",				__FUNCTION__, PTR_ERR(clnt));		return PTR_ERR(clnt);	}	clp->cl_rpcclient = clnt;	return 0;}/* * Version 2 or 3 client destruction */static void nfs_destroy_server(struct nfs_server *server){	if (!(server->flags & NFS_MOUNT_NONLM))		lockd_down();	/* release rpc.lockd */}/* * Version 2 or 3 lockd setup */static int nfs_start_lockd(struct nfs_server *server){	int error = 0;	if (server->nfs_client->cl_nfsversion > 3)		goto out;	if (server->flags & NFS_MOUNT_NONLM)		goto out;	error = lockd_up((server->flags & NFS_MOUNT_TCP) ?			IPPROTO_TCP : IPPROTO_UDP);	if (error < 0)		server->flags |= NFS_MOUNT_NONLM;	else		server->destroy = nfs_destroy_server;out:	return error;}/* * Initialise an NFSv3 ACL client connection */#ifdef CONFIG_NFS_V3_ACLstatic void nfs_init_server_aclclient(struct nfs_server *server){	if (server->nfs_client->cl_nfsversion != 3)		goto out_noacl;	if (server->flags & NFS_MOUNT_NOACL)		goto out_noacl;	server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);	if (IS_ERR(server->client_acl))		goto out_noacl;	/* No errors! Assume that Sun nfsacls are supported */	server->caps |= NFS_CAP_ACLS;	return;out_noacl:	server->caps &= ~NFS_CAP_ACLS;}#elsestatic inline void nfs_init_server_aclclient(struct nfs_server *server){	server->flags &= ~NFS_MOUNT_NOACL;	server->caps &= ~NFS_CAP_ACLS;}#endif/*

⌨️ 快捷键说明

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