NFS client updates for Linux 3.4
New features include:
 - Add NFS client support for containers.
   This should enable most of the necessary functionality, including
   lockd support, and support for rpc.statd, NFSv4 idmapper and
   RPCSEC_GSS upcalls into the correct network namespace from
   which the mount system call was issued.
 - NFSv4 idmapper scalability improvements
   Base the idmapper cache on the keyring interface to allow concurrent
   access to idmapper entries. Start the process of migrating users from
   the single-threaded daemon-based approach to the multi-threaded
   request-key based approach.
 - NFSv4.1 implementation id.
   Allows the NFSv4.1 client and server to mutually identify each other
   for logging and debugging purposes.
 - Support the 'vers=4.1' mount option for mounting NFSv4.1 instead of
   having to use the more counterintuitive 'vers=4,minorversion=1'.
 - SUNRPC tracepoints.
   Start the process of adding tracepoints in order to improve debugging
   of the RPC layer.
 - pNFS object layout support for autologin.
 
 Important bugfixes include:
 - Fix a bug in rpc_wake_up/rpc_wake_up_status that caused them to fail
   to wake up all tasks when applied to priority waitqueues.
 - Ensure that we handle read delegations correctly, when we try to
   truncate a file.
 - A number of fixes for NFSv4 state manager loops (mostly to do with
   delegation recovery).
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJPalZbAAoJEGcL54qWCgDyCi4P+QHcmzQhJO7HWx3Pzjs67bFT
 xMSYaKHGWS4AJKUBVl5OKBxUExfrMHBNbElV3IKUIwBlDx8RVtnwfptKSe146iki
 dn4TrRO5es8nmI4hRDcGMlzJDZq4y0Qg//qiUFmojiNW/Avw0ljfMoVUejJJ09FV
 oeDk4EGtcxkEyH+g48ZjYbyspRnG8qtD3atf70Z3lYE0ELdG/B5Dyzw1RDrA5p73
 xJX3lqy8p/4ROzw/dmNoxdAXOrr3Q4/T58Bvp/lUglPy/EHyPmWzFoH0MU0C/PFu
 5VnAl6QDbNCTcIw9FvJlX/mIyErpNG9eKzUskUc9L9SA+B+J/i4rIap4KATRN3nH
 7QhE5qUacPuJnvxml7MPmlQTuft3fkAQ7NhKIWrbRi1QS9FmJC5NxctIb8loqlFn
 yIXdKeLfMshB+NyuFS9uzStX7SmV3eMgVd+5ZxRjYxm+PKJLw2KXeudArL6M5mHK
 3QeKZpqwaYQ3RfaTNpvAp0doiXHCO5UbWfI0Pe8xQs/QcMCNReffqV2G4IJKFAu6
 WpoN2UDQC9LCBifLw2nS7kku8+ZVXLQU8OC1NVl3TG15xD9cNLXuk3/y5llPGq4O
 odo52uLFpJohbDaHMj5RTKOfchTQCm2iyuVmxZEeAySypMSiAXmW7COSKHs/HxI1
 VBm+EI00Pvmm5+fUjIlp
 =LuHE
 -----END PGP SIGNATURE-----
Merge tag 'nfs-for-3.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates for Linux 3.4 from Trond Myklebust:
 "New features include:
   - Add NFS client support for containers.
     This should enable most of the necessary functionality, including
     lockd support, and support for rpc.statd, NFSv4 idmapper and
     RPCSEC_GSS upcalls into the correct network namespace from which
     the mount system call was issued.
   - NFSv4 idmapper scalability improvements
     Base the idmapper cache on the keyring interface to allow
     concurrent access to idmapper entries.  Start the process of
     migrating users from the single-threaded daemon-based approach to
     the multi-threaded request-key based approach.
   - NFSv4.1 implementation id.
     Allows the NFSv4.1 client and server to mutually identify each
     other for logging and debugging purposes.
   - Support the 'vers=4.1' mount option for mounting NFSv4.1 instead of
     having to use the more counterintuitive 'vers=4,minorversion=1'.
   - SUNRPC tracepoints.
     Start the process of adding tracepoints in order to improve
     debugging of the RPC layer.
   - pNFS object layout support for autologin.
  Important bugfixes include:
   - Fix a bug in rpc_wake_up/rpc_wake_up_status that caused them to
     fail to wake up all tasks when applied to priority waitqueues.
   - Ensure that we handle read delegations correctly, when we try to
     truncate a file.
   - A number of fixes for NFSv4 state manager loops (mostly to do with
     delegation recovery)."
* tag 'nfs-for-3.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (224 commits)
  NFS: fix sb->s_id in nfs debug prints
  xprtrdma: Remove assumption that each segment is <= PAGE_SIZE
  xprtrdma: The transport should not bug-check when a dup reply is received
  pnfs-obj: autologin: Add support for protocol autologin
  NFS: Remove nfs4_setup_sequence from generic rename code
  NFS: Remove nfs4_setup_sequence from generic unlink code
  NFS: Remove nfs4_setup_sequence from generic read code
  NFS: Remove nfs4_setup_sequence from generic write code
  NFS: Fix more NFS debug related build warnings
  SUNRPC/LOCKD: Fix build warnings when CONFIG_SUNRPC_DEBUG is undefined
  nfs: non void functions must return a value
  SUNRPC: Kill compiler warning when RPC_DEBUG is unset
  SUNRPC/NFS: Add Kbuild dependencies for NFS_DEBUG/RPC_DEBUG
  NFS: Use cond_resched_lock() to reduce latencies in the commit scans
  NFSv4: It is not safe to dereference lsp->ls_state in release_lockowner
  NFS: ncommit count is being double decremented
  SUNRPC: We must not use list_for_each_entry_safe() in rpc_wake_up()
  Try using machine credentials for RENEW calls
  NFSv4.1: Fix a few issues in filelayout_commit_pagelist
  NFSv4.1: Clean ups and bugfixes for the pNFS read/writeback/commit code
  ...
	
	
This commit is contained in:
		
				commit
				
					
						f63d395d47
					
				
			
		
					 127 changed files with 5253 additions and 3023 deletions
				
			
		| 
						 | 
					@ -4,13 +4,21 @@ ID Mapper
 | 
				
			||||||
=========
 | 
					=========
 | 
				
			||||||
Id mapper is used by NFS to translate user and group ids into names, and to
 | 
					Id mapper is used by NFS to translate user and group ids into names, and to
 | 
				
			||||||
translate user and group names into ids.  Part of this translation involves
 | 
					translate user and group names into ids.  Part of this translation involves
 | 
				
			||||||
performing an upcall to userspace to request the information.  Id mapper will
 | 
					performing an upcall to userspace to request the information.  There are two
 | 
				
			||||||
user request-key to perform this upcall and cache the result.  The program
 | 
					ways NFS could obtain this information: placing a call to /sbin/request-key
 | 
				
			||||||
/usr/sbin/nfs.idmap should be called by request-key, and will perform the
 | 
					or by placing a call to the rpc.idmap daemon.
 | 
				
			||||||
translation and initialize a key with the resulting information.
 | 
					
 | 
				
			||||||
 | 
					NFS will attempt to call /sbin/request-key first.  If this succeeds, the
 | 
				
			||||||
 | 
					result will be cached using the generic request-key cache.  This call should
 | 
				
			||||||
 | 
					only fail if /etc/request-key.conf is not configured for the id_resolver key
 | 
				
			||||||
 | 
					type, see the "Configuring" section below if you wish to use the request-key
 | 
				
			||||||
 | 
					method.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the call to /sbin/request-key fails (if /etc/request-key.conf is not
 | 
				
			||||||
 | 
					configured with the id_resolver key type), then the idmapper will ask the
 | 
				
			||||||
 | 
					legacy rpc.idmap daemon for the id mapping.  This result will be stored
 | 
				
			||||||
 | 
					in a custom NFS idmap cache.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this
 | 
					 | 
				
			||||||
 feature.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
===========
 | 
					===========
 | 
				
			||||||
Configuring
 | 
					Configuring
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,3 +53,57 @@ lseg maintains an extra reference corresponding to the NFS_LSEG_VALID
 | 
				
			||||||
bit which holds it in the pnfs_layout_hdr's list.  When the final lseg
 | 
					bit which holds it in the pnfs_layout_hdr's list.  When the final lseg
 | 
				
			||||||
is removed from the pnfs_layout_hdr's list, the NFS_LAYOUT_DESTROYED
 | 
					is removed from the pnfs_layout_hdr's list, the NFS_LAYOUT_DESTROYED
 | 
				
			||||||
bit is set, preventing any new lsegs from being added.
 | 
					bit is set, preventing any new lsegs from being added.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout drivers
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PNFS utilizes what is called layout drivers. The STD defines 3 basic
 | 
				
			||||||
 | 
					layout types: "files" "objects" and "blocks". For each of these types
 | 
				
			||||||
 | 
					there is a layout-driver with a common function-vectors table which
 | 
				
			||||||
 | 
					are called by the nfs-client pnfs-core to implement the different layout
 | 
				
			||||||
 | 
					types.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files-layout-driver code is in: fs/nfs/nfs4filelayout.c && nfs4filelayoutdev.c
 | 
				
			||||||
 | 
					Objects-layout-deriver code is in: fs/nfs/objlayout/.. directory
 | 
				
			||||||
 | 
					Blocks-layout-deriver code is in: fs/nfs/blocklayout/.. directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					objects-layout setup
 | 
				
			||||||
 | 
					--------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As part of the full STD implementation the objlayoutdriver.ko needs, at times,
 | 
				
			||||||
 | 
					to automatically login to yet undiscovered iscsi/osd devices. For this the
 | 
				
			||||||
 | 
					driver makes up-calles to a user-mode script called *osd_login*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The path_name of the script to use is by default:
 | 
				
			||||||
 | 
						/sbin/osd_login.
 | 
				
			||||||
 | 
					This name can be overridden by the Kernel module parameter:
 | 
				
			||||||
 | 
						objlayoutdriver.osd_login_prog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If Kernel does not find the osd_login_prog path it will zero it out
 | 
				
			||||||
 | 
					and will not attempt farther logins. An admin can then write new value
 | 
				
			||||||
 | 
					to the objlayoutdriver.osd_login_prog Kernel parameter to re-enable it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The /sbin/osd_login is part of the nfs-utils package, and should usually
 | 
				
			||||||
 | 
					be installed on distributions that support this Kernel version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The API to the login script is as follows:
 | 
				
			||||||
 | 
						Usage: $0 -u <URI> -o <OSDNAME> -s <SYSTEMID>
 | 
				
			||||||
 | 
						Options:
 | 
				
			||||||
 | 
							-u		target uri e.g. iscsi://<ip>:<port>
 | 
				
			||||||
 | 
									(allways exists)
 | 
				
			||||||
 | 
									(More protocols can be defined in the future.
 | 
				
			||||||
 | 
									 The client does not interpret this string it is
 | 
				
			||||||
 | 
									 passed unchanged as recieved from the Server)
 | 
				
			||||||
 | 
							-o		osdname of the requested target OSD
 | 
				
			||||||
 | 
									(Might be empty)
 | 
				
			||||||
 | 
									(A string which denotes the OSD name, there is a
 | 
				
			||||||
 | 
									 limit of 64 chars on this string)
 | 
				
			||||||
 | 
							-s 		systemid of the requested target OSD
 | 
				
			||||||
 | 
									(Might be empty)
 | 
				
			||||||
 | 
									(This string, if not empty is always an hex
 | 
				
			||||||
 | 
									 representation of the 20 bytes osd_system_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					blocks-layout setup
 | 
				
			||||||
 | 
					-------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TODO: Document the setup needs of the blocks layout driver
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1672,6 +1672,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 | 
				
			||||||
			of returning the full 64-bit number.
 | 
								of returning the full 64-bit number.
 | 
				
			||||||
			The default is to return 64-bit inode numbers.
 | 
								The default is to return 64-bit inode numbers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nfs.max_session_slots=
 | 
				
			||||||
 | 
								[NFSv4.1] Sets the maximum number of session slots
 | 
				
			||||||
 | 
								the client will attempt to negotiate with the server.
 | 
				
			||||||
 | 
								This limits the number of simultaneous RPC requests
 | 
				
			||||||
 | 
								that the client can send to the NFSv4.1 server.
 | 
				
			||||||
 | 
								Note that there is little point in setting this
 | 
				
			||||||
 | 
								value higher than the max_tcp_slot_table_limit.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nfs.nfs4_disable_idmapping=
 | 
						nfs.nfs4_disable_idmapping=
 | 
				
			||||||
			[NFSv4] When set to the default of '1', this option
 | 
								[NFSv4] When set to the default of '1', this option
 | 
				
			||||||
			ensures that both the RPC level authentication
 | 
								ensures that both the RPC level authentication
 | 
				
			||||||
| 
						 | 
					@ -1685,6 +1693,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 | 
				
			||||||
			back to using the idmapper.
 | 
								back to using the idmapper.
 | 
				
			||||||
			To turn off this behaviour, set the value to '0'.
 | 
								To turn off this behaviour, set the value to '0'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nfs.send_implementation_id =
 | 
				
			||||||
 | 
								[NFSv4.1] Send client implementation identification
 | 
				
			||||||
 | 
								information in exchange_id requests.
 | 
				
			||||||
 | 
								If zero, no implementation identification information
 | 
				
			||||||
 | 
								will be sent.
 | 
				
			||||||
 | 
								The default is to send the implementation identification
 | 
				
			||||||
 | 
								information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						objlayoutdriver.osd_login_prog=
 | 
				
			||||||
 | 
								[NFS] [OBJLAYOUT] sets the pathname to the program which
 | 
				
			||||||
 | 
								is used to automatically discover and login into new
 | 
				
			||||||
 | 
								osd-targets. Please see:
 | 
				
			||||||
 | 
								Documentation/filesystems/pnfs.txt for more explanations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nmi_debug=	[KNL,AVR32,SH] Specify one or more actions to take
 | 
						nmi_debug=	[KNL,AVR32,SH] Specify one or more actions to take
 | 
				
			||||||
			when a NMI is triggered.
 | 
								when a NMI is triggered.
 | 
				
			||||||
			Format: [state][,regs][,debounce][,die]
 | 
								Format: [state][,regs][,debounce][,die]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -598,7 +598,7 @@ static struct rpc_procinfo	nlm4_procedures[] = {
 | 
				
			||||||
	PROC(GRANTED_RES,	res,		norep),
 | 
						PROC(GRANTED_RES,	res,		norep),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_version	nlm_version4 = {
 | 
					const struct rpc_version nlm_version4 = {
 | 
				
			||||||
	.number		= 4,
 | 
						.number		= 4,
 | 
				
			||||||
	.nrprocs	= ARRAY_SIZE(nlm4_procedures),
 | 
						.nrprocs	= ARRAY_SIZE(nlm4_procedures),
 | 
				
			||||||
	.procs		= nlm4_procedures,
 | 
						.procs		= nlm4_procedures,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,7 +62,8 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
 | 
						host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
 | 
				
			||||||
				   nlm_init->protocol, nlm_version,
 | 
									   nlm_init->protocol, nlm_version,
 | 
				
			||||||
				   nlm_init->hostname, nlm_init->noresvport);
 | 
									   nlm_init->hostname, nlm_init->noresvport,
 | 
				
			||||||
 | 
									   nlm_init->net);
 | 
				
			||||||
	if (host == NULL) {
 | 
						if (host == NULL) {
 | 
				
			||||||
		lockd_down();
 | 
							lockd_down();
 | 
				
			||||||
		return ERR_PTR(-ENOLCK);
 | 
							return ERR_PTR(-ENOLCK);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -596,19 +596,19 @@ static struct rpc_procinfo	nlm_procedures[] = {
 | 
				
			||||||
	PROC(GRANTED_RES,	res,		norep),
 | 
						PROC(GRANTED_RES,	res,		norep),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_version	nlm_version1 = {
 | 
					static const struct rpc_version	nlm_version1 = {
 | 
				
			||||||
		.number		= 1,
 | 
							.number		= 1,
 | 
				
			||||||
		.nrprocs	= ARRAY_SIZE(nlm_procedures),
 | 
							.nrprocs	= ARRAY_SIZE(nlm_procedures),
 | 
				
			||||||
		.procs		= nlm_procedures,
 | 
							.procs		= nlm_procedures,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_version	nlm_version3 = {
 | 
					static const struct rpc_version	nlm_version3 = {
 | 
				
			||||||
		.number		= 3,
 | 
							.number		= 3,
 | 
				
			||||||
		.nrprocs	= ARRAY_SIZE(nlm_procedures),
 | 
							.nrprocs	= ARRAY_SIZE(nlm_procedures),
 | 
				
			||||||
		.procs		= nlm_procedures,
 | 
							.procs		= nlm_procedures,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_version	*nlm_versions[] = {
 | 
					static const struct rpc_version	*nlm_versions[] = {
 | 
				
			||||||
	[1] = &nlm_version1,
 | 
						[1] = &nlm_version1,
 | 
				
			||||||
	[3] = &nlm_version3,
 | 
						[3] = &nlm_version3,
 | 
				
			||||||
#ifdef CONFIG_LOCKD_V4
 | 
					#ifdef CONFIG_LOCKD_V4
 | 
				
			||||||
| 
						 | 
					@ -618,7 +618,7 @@ static struct rpc_version	*nlm_versions[] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_stat		nlm_rpc_stats;
 | 
					static struct rpc_stat		nlm_rpc_stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_program		nlm_program = {
 | 
					const struct rpc_program	nlm_program = {
 | 
				
			||||||
		.name		= "lockd",
 | 
							.name		= "lockd",
 | 
				
			||||||
		.number		= NLM_PROGRAM,
 | 
							.number		= NLM_PROGRAM,
 | 
				
			||||||
		.nrvers		= ARRAY_SIZE(nlm_versions),
 | 
							.nrvers		= ARRAY_SIZE(nlm_versions),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,8 @@
 | 
				
			||||||
#include <linux/lockd/lockd.h>
 | 
					#include <linux/lockd/lockd.h>
 | 
				
			||||||
#include <linux/mutex.h>
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/sunrpc/svc_xprt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <net/ipv6.h>
 | 
					#include <net/ipv6.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
 | 
					#define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
 | 
				
			||||||
| 
						 | 
					@ -54,6 +56,7 @@ struct nlm_lookup_host_info {
 | 
				
			||||||
	const char		*hostname;	/* remote's hostname */
 | 
						const char		*hostname;	/* remote's hostname */
 | 
				
			||||||
	const size_t		hostname_len;	/* it's length */
 | 
						const size_t		hostname_len;	/* it's length */
 | 
				
			||||||
	const int		noresvport;	/* use non-priv port */
 | 
						const int		noresvport;	/* use non-priv port */
 | 
				
			||||||
 | 
						struct net		*net;		/* network namespace to bind */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -155,6 +158,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
 | 
				
			||||||
	INIT_LIST_HEAD(&host->h_reclaim);
 | 
						INIT_LIST_HEAD(&host->h_reclaim);
 | 
				
			||||||
	host->h_nsmhandle  = nsm;
 | 
						host->h_nsmhandle  = nsm;
 | 
				
			||||||
	host->h_addrbuf    = nsm->sm_addrbuf;
 | 
						host->h_addrbuf    = nsm->sm_addrbuf;
 | 
				
			||||||
 | 
						host->net	   = ni->net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return host;
 | 
						return host;
 | 
				
			||||||
| 
						 | 
					@ -206,7 +210,8 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
 | 
				
			||||||
				     const unsigned short protocol,
 | 
									     const unsigned short protocol,
 | 
				
			||||||
				     const u32 version,
 | 
									     const u32 version,
 | 
				
			||||||
				     const char *hostname,
 | 
									     const char *hostname,
 | 
				
			||||||
				     int noresvport)
 | 
									     int noresvport,
 | 
				
			||||||
 | 
									     struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nlm_lookup_host_info ni = {
 | 
						struct nlm_lookup_host_info ni = {
 | 
				
			||||||
		.server		= 0,
 | 
							.server		= 0,
 | 
				
			||||||
| 
						 | 
					@ -217,6 +222,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
 | 
				
			||||||
		.hostname	= hostname,
 | 
							.hostname	= hostname,
 | 
				
			||||||
		.hostname_len	= strlen(hostname),
 | 
							.hostname_len	= strlen(hostname),
 | 
				
			||||||
		.noresvport	= noresvport,
 | 
							.noresvport	= noresvport,
 | 
				
			||||||
 | 
							.net		= net,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct hlist_head *chain;
 | 
						struct hlist_head *chain;
 | 
				
			||||||
	struct hlist_node *pos;
 | 
						struct hlist_node *pos;
 | 
				
			||||||
| 
						 | 
					@ -231,6 +237,8 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	chain = &nlm_client_hosts[nlm_hash_address(sap)];
 | 
						chain = &nlm_client_hosts[nlm_hash_address(sap)];
 | 
				
			||||||
	hlist_for_each_entry(host, pos, chain, h_hash) {
 | 
						hlist_for_each_entry(host, pos, chain, h_hash) {
 | 
				
			||||||
 | 
							if (host->net != net)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
		if (!rpc_cmp_addr(nlm_addr(host), sap))
 | 
							if (!rpc_cmp_addr(nlm_addr(host), sap))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -318,6 +326,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 | 
				
			||||||
	struct nsm_handle *nsm = NULL;
 | 
						struct nsm_handle *nsm = NULL;
 | 
				
			||||||
	struct sockaddr *src_sap = svc_daddr(rqstp);
 | 
						struct sockaddr *src_sap = svc_daddr(rqstp);
 | 
				
			||||||
	size_t src_len = rqstp->rq_daddrlen;
 | 
						size_t src_len = rqstp->rq_daddrlen;
 | 
				
			||||||
 | 
						struct net *net = rqstp->rq_xprt->xpt_net;
 | 
				
			||||||
	struct nlm_lookup_host_info ni = {
 | 
						struct nlm_lookup_host_info ni = {
 | 
				
			||||||
		.server		= 1,
 | 
							.server		= 1,
 | 
				
			||||||
		.sap		= svc_addr(rqstp),
 | 
							.sap		= svc_addr(rqstp),
 | 
				
			||||||
| 
						 | 
					@ -326,6 +335,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 | 
				
			||||||
		.version	= rqstp->rq_vers,
 | 
							.version	= rqstp->rq_vers,
 | 
				
			||||||
		.hostname	= hostname,
 | 
							.hostname	= hostname,
 | 
				
			||||||
		.hostname_len	= hostname_len,
 | 
							.hostname_len	= hostname_len,
 | 
				
			||||||
 | 
							.net		= net,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
 | 
						dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
 | 
				
			||||||
| 
						 | 
					@ -339,6 +349,8 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
 | 
						chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
 | 
				
			||||||
	hlist_for_each_entry(host, pos, chain, h_hash) {
 | 
						hlist_for_each_entry(host, pos, chain, h_hash) {
 | 
				
			||||||
 | 
							if (host->net != net)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
		if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
 | 
							if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -431,7 +443,7 @@ nlm_bind_host(struct nlm_host *host)
 | 
				
			||||||
			.to_retries	= 5U,
 | 
								.to_retries	= 5U,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
		struct rpc_create_args args = {
 | 
							struct rpc_create_args args = {
 | 
				
			||||||
			.net		= &init_net,
 | 
								.net		= host->net,
 | 
				
			||||||
			.protocol	= host->h_proto,
 | 
								.protocol	= host->h_proto,
 | 
				
			||||||
			.address	= nlm_addr(host),
 | 
								.address	= nlm_addr(host),
 | 
				
			||||||
			.addrsize	= host->h_addrlen,
 | 
								.addrsize	= host->h_addrlen,
 | 
				
			||||||
| 
						 | 
					@ -553,12 +565,8 @@ void nlm_host_rebooted(const struct nlm_reboot *info)
 | 
				
			||||||
	nsm_release(nsm);
 | 
						nsm_release(nsm);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Shut down the hosts module.
 | 
					 | 
				
			||||||
 * Note that this routine is called only at server shutdown time.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
nlm_shutdown_hosts(void)
 | 
					nlm_shutdown_hosts_net(struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hlist_head *chain;
 | 
						struct hlist_head *chain;
 | 
				
			||||||
	struct hlist_node *pos;
 | 
						struct hlist_node *pos;
 | 
				
			||||||
| 
						 | 
					@ -570,6 +578,8 @@ nlm_shutdown_hosts(void)
 | 
				
			||||||
	/* First, make all hosts eligible for gc */
 | 
						/* First, make all hosts eligible for gc */
 | 
				
			||||||
	dprintk("lockd: nuking all hosts...\n");
 | 
						dprintk("lockd: nuking all hosts...\n");
 | 
				
			||||||
	for_each_host(host, pos, chain, nlm_server_hosts) {
 | 
						for_each_host(host, pos, chain, nlm_server_hosts) {
 | 
				
			||||||
 | 
							if (net && host->net != net)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
		host->h_expires = jiffies - 1;
 | 
							host->h_expires = jiffies - 1;
 | 
				
			||||||
		if (host->h_rpcclnt) {
 | 
							if (host->h_rpcclnt) {
 | 
				
			||||||
			rpc_shutdown_client(host->h_rpcclnt);
 | 
								rpc_shutdown_client(host->h_rpcclnt);
 | 
				
			||||||
| 
						 | 
					@ -580,15 +590,29 @@ nlm_shutdown_hosts(void)
 | 
				
			||||||
	/* Then, perform a garbage collection pass */
 | 
						/* Then, perform a garbage collection pass */
 | 
				
			||||||
	nlm_gc_hosts();
 | 
						nlm_gc_hosts();
 | 
				
			||||||
	mutex_unlock(&nlm_host_mutex);
 | 
						mutex_unlock(&nlm_host_mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Shut down the hosts module.
 | 
				
			||||||
 | 
					 * Note that this routine is called only at server shutdown time.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					nlm_shutdown_hosts(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct hlist_head *chain;
 | 
				
			||||||
 | 
						struct hlist_node *pos;
 | 
				
			||||||
 | 
						struct nlm_host	*host;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nlm_shutdown_hosts_net(NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* complain if any hosts are left */
 | 
						/* complain if any hosts are left */
 | 
				
			||||||
	if (nrhosts != 0) {
 | 
						if (nrhosts != 0) {
 | 
				
			||||||
		printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
 | 
							printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
 | 
				
			||||||
		dprintk("lockd: %lu hosts left:\n", nrhosts);
 | 
							dprintk("lockd: %lu hosts left:\n", nrhosts);
 | 
				
			||||||
		for_each_host(host, pos, chain, nlm_server_hosts) {
 | 
							for_each_host(host, pos, chain, nlm_server_hosts) {
 | 
				
			||||||
			dprintk("       %s (cnt %d use %d exp %ld)\n",
 | 
								dprintk("       %s (cnt %d use %d exp %ld net %p)\n",
 | 
				
			||||||
				host->h_name, atomic_read(&host->h_count),
 | 
									host->h_name, atomic_read(&host->h_count),
 | 
				
			||||||
				host->h_inuse, host->h_expires);
 | 
									host->h_inuse, host->h_expires, host->net);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,7 +47,7 @@ struct nsm_res {
 | 
				
			||||||
	u32			state;
 | 
						u32			state;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_program	nsm_program;
 | 
					static const struct rpc_program	nsm_program;
 | 
				
			||||||
static				LIST_HEAD(nsm_handles);
 | 
					static				LIST_HEAD(nsm_handles);
 | 
				
			||||||
static				DEFINE_SPINLOCK(nsm_lock);
 | 
					static				DEFINE_SPINLOCK(nsm_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,14 +62,14 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
 | 
				
			||||||
	return (struct sockaddr *)&nsm->sm_addr;
 | 
						return (struct sockaddr *)&nsm->sm_addr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_clnt *nsm_create(void)
 | 
					static struct rpc_clnt *nsm_create(struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sockaddr_in sin = {
 | 
						struct sockaddr_in sin = {
 | 
				
			||||||
		.sin_family		= AF_INET,
 | 
							.sin_family		= AF_INET,
 | 
				
			||||||
		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
 | 
							.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct rpc_create_args args = {
 | 
						struct rpc_create_args args = {
 | 
				
			||||||
		.net			= &init_net,
 | 
							.net			= net,
 | 
				
			||||||
		.protocol		= XPRT_TRANSPORT_UDP,
 | 
							.protocol		= XPRT_TRANSPORT_UDP,
 | 
				
			||||||
		.address		= (struct sockaddr *)&sin,
 | 
							.address		= (struct sockaddr *)&sin,
 | 
				
			||||||
		.addrsize		= sizeof(sin),
 | 
							.addrsize		= sizeof(sin),
 | 
				
			||||||
| 
						 | 
					@ -83,7 +83,8 @@ static struct rpc_clnt *nsm_create(void)
 | 
				
			||||||
	return rpc_create(&args);
 | 
						return rpc_create(&args);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
 | 
					static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
 | 
				
			||||||
 | 
								 struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_clnt	*clnt;
 | 
						struct rpc_clnt	*clnt;
 | 
				
			||||||
	int		status;
 | 
						int		status;
 | 
				
			||||||
| 
						 | 
					@ -99,7 +100,7 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
 | 
				
			||||||
		.rpc_resp	= res,
 | 
							.rpc_resp	= res,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clnt = nsm_create();
 | 
						clnt = nsm_create(net);
 | 
				
			||||||
	if (IS_ERR(clnt)) {
 | 
						if (IS_ERR(clnt)) {
 | 
				
			||||||
		status = PTR_ERR(clnt);
 | 
							status = PTR_ERR(clnt);
 | 
				
			||||||
		dprintk("lockd: failed to create NSM upcall transport, "
 | 
							dprintk("lockd: failed to create NSM upcall transport, "
 | 
				
			||||||
| 
						 | 
					@ -149,7 +150,7 @@ int nsm_monitor(const struct nlm_host *host)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
 | 
						nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status = nsm_mon_unmon(nsm, NSMPROC_MON, &res);
 | 
						status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host->net);
 | 
				
			||||||
	if (unlikely(res.status != 0))
 | 
						if (unlikely(res.status != 0))
 | 
				
			||||||
		status = -EIO;
 | 
							status = -EIO;
 | 
				
			||||||
	if (unlikely(status < 0)) {
 | 
						if (unlikely(status < 0)) {
 | 
				
			||||||
| 
						 | 
					@ -183,7 +184,7 @@ void nsm_unmonitor(const struct nlm_host *host)
 | 
				
			||||||
	 && nsm->sm_monitored && !nsm->sm_sticky) {
 | 
						 && nsm->sm_monitored && !nsm->sm_sticky) {
 | 
				
			||||||
		dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
 | 
							dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res);
 | 
							status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host->net);
 | 
				
			||||||
		if (res.status != 0)
 | 
							if (res.status != 0)
 | 
				
			||||||
			status = -EIO;
 | 
								status = -EIO;
 | 
				
			||||||
		if (status < 0)
 | 
							if (status < 0)
 | 
				
			||||||
| 
						 | 
					@ -534,19 +535,19 @@ static struct rpc_procinfo	nsm_procedures[] = {
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_version	nsm_version1 = {
 | 
					static const struct rpc_version nsm_version1 = {
 | 
				
			||||||
		.number		= 1,
 | 
							.number		= 1,
 | 
				
			||||||
		.nrprocs	= ARRAY_SIZE(nsm_procedures),
 | 
							.nrprocs	= ARRAY_SIZE(nsm_procedures),
 | 
				
			||||||
		.procs		= nsm_procedures
 | 
							.procs		= nsm_procedures
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_version *	nsm_version[] = {
 | 
					static const struct rpc_version *nsm_version[] = {
 | 
				
			||||||
	[1] = &nsm_version1,
 | 
						[1] = &nsm_version1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_stat		nsm_stats;
 | 
					static struct rpc_stat		nsm_stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_program	nsm_program = {
 | 
					static const struct rpc_program nsm_program = {
 | 
				
			||||||
		.name		= "statd",
 | 
							.name		= "statd",
 | 
				
			||||||
		.number		= NSM_PROGRAM,
 | 
							.number		= NSM_PROGRAM,
 | 
				
			||||||
		.nrvers		= ARRAY_SIZE(nsm_version),
 | 
							.nrvers		= ARRAY_SIZE(nsm_version),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								fs/lockd/netns.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								fs/lockd/netns.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					#ifndef __LOCKD_NETNS_H__
 | 
				
			||||||
 | 
					#define __LOCKD_NETNS_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <net/netns/generic.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct lockd_net {
 | 
				
			||||||
 | 
						unsigned int nlmsvc_users;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int lockd_net_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										119
									
								
								fs/lockd/svc.c
									
										
									
									
									
								
							
							
						
						
									
										119
									
								
								fs/lockd/svc.c
									
										
									
									
									
								
							| 
						 | 
					@ -35,6 +35,8 @@
 | 
				
			||||||
#include <linux/lockd/lockd.h>
 | 
					#include <linux/lockd/lockd.h>
 | 
				
			||||||
#include <linux/nfs.h>
 | 
					#include <linux/nfs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "netns.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NLMDBG_FACILITY		NLMDBG_SVC
 | 
					#define NLMDBG_FACILITY		NLMDBG_SVC
 | 
				
			||||||
#define LOCKD_BUFSIZE		(1024 + NLMSVC_XDRSIZE)
 | 
					#define LOCKD_BUFSIZE		(1024 + NLMSVC_XDRSIZE)
 | 
				
			||||||
#define ALLOWED_SIGS		(sigmask(SIGKILL))
 | 
					#define ALLOWED_SIGS		(sigmask(SIGKILL))
 | 
				
			||||||
| 
						 | 
					@ -50,6 +52,8 @@ static struct task_struct	*nlmsvc_task;
 | 
				
			||||||
static struct svc_rqst		*nlmsvc_rqst;
 | 
					static struct svc_rqst		*nlmsvc_rqst;
 | 
				
			||||||
unsigned long			nlmsvc_timeout;
 | 
					unsigned long			nlmsvc_timeout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int lockd_net_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * These can be set at insmod time (useful for NFS as root filesystem),
 | 
					 * These can be set at insmod time (useful for NFS as root filesystem),
 | 
				
			||||||
 * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003
 | 
					 * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003
 | 
				
			||||||
| 
						 | 
					@ -189,27 +193,29 @@ lockd(void *vrqstp)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int create_lockd_listener(struct svc_serv *serv, const char *name,
 | 
					static int create_lockd_listener(struct svc_serv *serv, const char *name,
 | 
				
			||||||
				 const int family, const unsigned short port)
 | 
									 struct net *net, const int family,
 | 
				
			||||||
 | 
									 const unsigned short port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct svc_xprt *xprt;
 | 
						struct svc_xprt *xprt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	xprt = svc_find_xprt(serv, name, family, 0);
 | 
						xprt = svc_find_xprt(serv, name, net, family, 0);
 | 
				
			||||||
	if (xprt == NULL)
 | 
						if (xprt == NULL)
 | 
				
			||||||
		return svc_create_xprt(serv, name, &init_net, family, port,
 | 
							return svc_create_xprt(serv, name, net, family, port,
 | 
				
			||||||
						SVC_SOCK_DEFAULTS);
 | 
											SVC_SOCK_DEFAULTS);
 | 
				
			||||||
	svc_xprt_put(xprt);
 | 
						svc_xprt_put(xprt);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int create_lockd_family(struct svc_serv *serv, const int family)
 | 
					static int create_lockd_family(struct svc_serv *serv, struct net *net,
 | 
				
			||||||
 | 
								       const int family)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = create_lockd_listener(serv, "udp", family, nlm_udpport);
 | 
						err = create_lockd_listener(serv, "udp", net, family, nlm_udpport);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return create_lockd_listener(serv, "tcp", family, nlm_tcpport);
 | 
						return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -222,16 +228,16 @@ static int create_lockd_family(struct svc_serv *serv, const int family)
 | 
				
			||||||
 * Returns zero if all listeners are available; otherwise a
 | 
					 * Returns zero if all listeners are available; otherwise a
 | 
				
			||||||
 * negative errno value is returned.
 | 
					 * negative errno value is returned.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int make_socks(struct svc_serv *serv)
 | 
					static int make_socks(struct svc_serv *serv, struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static int warned;
 | 
						static int warned;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = create_lockd_family(serv, PF_INET);
 | 
						err = create_lockd_family(serv, net, PF_INET);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		goto out_err;
 | 
							goto out_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = create_lockd_family(serv, PF_INET6);
 | 
						err = create_lockd_family(serv, net, PF_INET6);
 | 
				
			||||||
	if (err < 0 && err != -EAFNOSUPPORT)
 | 
						if (err < 0 && err != -EAFNOSUPPORT)
 | 
				
			||||||
		goto out_err;
 | 
							goto out_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,6 +251,47 @@ out_err:
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lockd_up_net(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct lockd_net *ln = net_generic(net, lockd_net_id);
 | 
				
			||||||
 | 
						struct svc_serv *serv = nlmsvc_rqst->rq_server;
 | 
				
			||||||
 | 
						int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ln->nlmsvc_users)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = svc_rpcb_setup(serv, net);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							goto err_rpcb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = make_socks(serv, net);
 | 
				
			||||||
 | 
						if (error < 0)
 | 
				
			||||||
 | 
							goto err_socks;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_socks:
 | 
				
			||||||
 | 
						svc_rpcb_cleanup(serv, net);
 | 
				
			||||||
 | 
					err_rpcb:
 | 
				
			||||||
 | 
						return error;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void lockd_down_net(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct lockd_net *ln = net_generic(net, lockd_net_id);
 | 
				
			||||||
 | 
						struct svc_serv *serv = nlmsvc_rqst->rq_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ln->nlmsvc_users) {
 | 
				
			||||||
 | 
							if (--ln->nlmsvc_users == 0) {
 | 
				
			||||||
 | 
								nlm_shutdown_hosts_net(net);
 | 
				
			||||||
 | 
								svc_shutdown_net(serv, net);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n",
 | 
				
			||||||
 | 
									nlmsvc_task, net);
 | 
				
			||||||
 | 
							BUG();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Bring up the lockd process if it's not already up.
 | 
					 * Bring up the lockd process if it's not already up.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -252,13 +299,16 @@ int lockd_up(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct svc_serv *serv;
 | 
						struct svc_serv *serv;
 | 
				
			||||||
	int		error = 0;
 | 
						int		error = 0;
 | 
				
			||||||
 | 
						struct net *net = current->nsproxy->net_ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&nlmsvc_mutex);
 | 
						mutex_lock(&nlmsvc_mutex);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Check whether we're already up and running.
 | 
						 * Check whether we're already up and running.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (nlmsvc_rqst)
 | 
						if (nlmsvc_rqst) {
 | 
				
			||||||
 | 
							error = lockd_up_net(net);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Sanity check: if there's no pid,
 | 
						 * Sanity check: if there's no pid,
 | 
				
			||||||
| 
						 | 
					@ -275,7 +325,7 @@ int lockd_up(void)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = make_socks(serv);
 | 
						error = make_socks(serv, net);
 | 
				
			||||||
	if (error < 0)
 | 
						if (error < 0)
 | 
				
			||||||
		goto destroy_and_out;
 | 
							goto destroy_and_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -313,8 +363,12 @@ int lockd_up(void)
 | 
				
			||||||
destroy_and_out:
 | 
					destroy_and_out:
 | 
				
			||||||
	svc_destroy(serv);
 | 
						svc_destroy(serv);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	if (!error)
 | 
						if (!error) {
 | 
				
			||||||
 | 
							struct lockd_net *ln = net_generic(net, lockd_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ln->nlmsvc_users++;
 | 
				
			||||||
		nlmsvc_users++;
 | 
							nlmsvc_users++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	mutex_unlock(&nlmsvc_mutex);
 | 
						mutex_unlock(&nlmsvc_mutex);
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -328,8 +382,10 @@ lockd_down(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mutex_lock(&nlmsvc_mutex);
 | 
						mutex_lock(&nlmsvc_mutex);
 | 
				
			||||||
	if (nlmsvc_users) {
 | 
						if (nlmsvc_users) {
 | 
				
			||||||
		if (--nlmsvc_users)
 | 
							if (--nlmsvc_users) {
 | 
				
			||||||
 | 
								lockd_down_net(current->nsproxy->net_ns);
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		printk(KERN_ERR "lockd_down: no users! task=%p\n",
 | 
							printk(KERN_ERR "lockd_down: no users! task=%p\n",
 | 
				
			||||||
			nlmsvc_task);
 | 
								nlmsvc_task);
 | 
				
			||||||
| 
						 | 
					@ -497,24 +553,55 @@ module_param_call(nlm_tcpport, param_set_port, param_get_int,
 | 
				
			||||||
module_param(nsm_use_hostnames, bool, 0644);
 | 
					module_param(nsm_use_hostnames, bool, 0644);
 | 
				
			||||||
module_param(nlm_max_connections, uint, 0644);
 | 
					module_param(nlm_max_connections, uint, 0644);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lockd_init_net(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void lockd_exit_net(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct pernet_operations lockd_net_ops = {
 | 
				
			||||||
 | 
						.init = lockd_init_net,
 | 
				
			||||||
 | 
						.exit = lockd_exit_net,
 | 
				
			||||||
 | 
						.id = &lockd_net_id,
 | 
				
			||||||
 | 
						.size = sizeof(struct lockd_net),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Initialising and terminating the module.
 | 
					 * Initialising and terminating the module.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init init_nlm(void)
 | 
					static int __init init_nlm(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SYSCTL
 | 
					#ifdef CONFIG_SYSCTL
 | 
				
			||||||
 | 
						err = -ENOMEM;
 | 
				
			||||||
	nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root);
 | 
						nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root);
 | 
				
			||||||
	return nlm_sysctl_table ? 0 : -ENOMEM;
 | 
						if (nlm_sysctl_table == NULL)
 | 
				
			||||||
#else
 | 
							goto err_sysctl;
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						err = register_pernet_subsys(&lockd_net_ops);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto err_pernet;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_pernet:
 | 
				
			||||||
 | 
					#ifdef CONFIG_SYSCTL
 | 
				
			||||||
 | 
						unregister_sysctl_table(nlm_sysctl_table);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					err_sysctl:
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __exit exit_nlm(void)
 | 
					static void __exit exit_nlm(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* FIXME: delete all NLM clients */
 | 
						/* FIXME: delete all NLM clients */
 | 
				
			||||||
	nlm_shutdown_hosts();
 | 
						nlm_shutdown_hosts();
 | 
				
			||||||
 | 
						unregister_pernet_subsys(&lockd_net_ops);
 | 
				
			||||||
#ifdef CONFIG_SYSCTL
 | 
					#ifdef CONFIG_SYSCTL
 | 
				
			||||||
	unregister_sysctl_table(nlm_sysctl_table);
 | 
						unregister_sysctl_table(nlm_sysctl_table);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,6 @@ static void	nlmsvc_remove_block(struct nlm_block *block);
 | 
				
			||||||
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
 | 
					static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
 | 
				
			||||||
static void nlmsvc_freegrantargs(struct nlm_rqst *call);
 | 
					static void nlmsvc_freegrantargs(struct nlm_rqst *call);
 | 
				
			||||||
static const struct rpc_call_ops nlmsvc_grant_ops;
 | 
					static const struct rpc_call_ops nlmsvc_grant_ops;
 | 
				
			||||||
static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The list of blocked locks to retry
 | 
					 * The list of blocked locks to retry
 | 
				
			||||||
| 
						 | 
					@ -54,6 +53,35 @@ static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie);
 | 
				
			||||||
static LIST_HEAD(nlm_blocked);
 | 
					static LIST_HEAD(nlm_blocked);
 | 
				
			||||||
static DEFINE_SPINLOCK(nlm_blocked_lock);
 | 
					static DEFINE_SPINLOCK(nlm_blocked_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef LOCKD_DEBUG
 | 
				
			||||||
 | 
					static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We can get away with a static buffer because we're only
 | 
				
			||||||
 | 
						 * called with BKL held.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static char buf[2*NLM_MAXCOOKIELEN+1];
 | 
				
			||||||
 | 
						unsigned int i, len = sizeof(buf);
 | 
				
			||||||
 | 
						char *p = buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len--;	/* allow for trailing \0 */
 | 
				
			||||||
 | 
						if (len < 3)
 | 
				
			||||||
 | 
							return "???";
 | 
				
			||||||
 | 
						for (i = 0 ; i < cookie->len ; i++) {
 | 
				
			||||||
 | 
							if (len < 2) {
 | 
				
			||||||
 | 
								strcpy(p-3, "...");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sprintf(p, "%02x", cookie->data[i]);
 | 
				
			||||||
 | 
							p += 2;
 | 
				
			||||||
 | 
							len -= 2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						*p = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return buf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Insert a blocked lock into the global list
 | 
					 * Insert a blocked lock into the global list
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -935,32 +963,3 @@ nlmsvc_retry_blocked(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return timeout;
 | 
						return timeout;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef RPC_DEBUG
 | 
					 | 
				
			||||||
static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * We can get away with a static buffer because we're only
 | 
					 | 
				
			||||||
	 * called with BKL held.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	static char buf[2*NLM_MAXCOOKIELEN+1];
 | 
					 | 
				
			||||||
	unsigned int i, len = sizeof(buf);
 | 
					 | 
				
			||||||
	char *p = buf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	len--;	/* allow for trailing \0 */
 | 
					 | 
				
			||||||
	if (len < 3)
 | 
					 | 
				
			||||||
		return "???";
 | 
					 | 
				
			||||||
	for (i = 0 ; i < cookie->len ; i++) {
 | 
					 | 
				
			||||||
		if (len < 2) {
 | 
					 | 
				
			||||||
			strcpy(p-3, "...");
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sprintf(p, "%02x", cookie->data[i]);
 | 
					 | 
				
			||||||
		p += 2;
 | 
					 | 
				
			||||||
		len -= 2;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*p = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return buf;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,6 +64,7 @@ config NFS_V4
 | 
				
			||||||
	bool "NFS client support for NFS version 4"
 | 
						bool "NFS client support for NFS version 4"
 | 
				
			||||||
	depends on NFS_FS
 | 
						depends on NFS_FS
 | 
				
			||||||
	select SUNRPC_GSS
 | 
						select SUNRPC_GSS
 | 
				
			||||||
 | 
						select KEYS
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  This option enables support for version 4 of the NFS protocol
 | 
						  This option enables support for version 4 of the NFS protocol
 | 
				
			||||||
	  (RFC 3530) in the kernel's NFS client.
 | 
						  (RFC 3530) in the kernel's NFS client.
 | 
				
			||||||
| 
						 | 
					@ -98,6 +99,18 @@ config PNFS_OBJLAYOUT
 | 
				
			||||||
	depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
 | 
						depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
 | 
				
			||||||
	default m
 | 
						default m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
 | 
				
			||||||
 | 
						string "NFSv4.1 Implementation ID Domain"
 | 
				
			||||||
 | 
						depends on NFS_V4_1
 | 
				
			||||||
 | 
						default "kernel.org"
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  This option defines the domain portion of the implementation ID that
 | 
				
			||||||
 | 
						  may be sent in the NFS exchange_id operation.  The value must be in
 | 
				
			||||||
 | 
						  the format of a DNS domain name and should be set to the DNS domain
 | 
				
			||||||
 | 
						  name of the distribution.
 | 
				
			||||||
 | 
						  If the NFS client is unchanged from the upstream kernel, this
 | 
				
			||||||
 | 
						  option should be set to the default "kernel.org".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config ROOT_NFS
 | 
					config ROOT_NFS
 | 
				
			||||||
	bool "Root file system on NFS"
 | 
						bool "Root file system on NFS"
 | 
				
			||||||
	depends on NFS_FS=y && IP_PNP
 | 
						depends on NFS_FS=y && IP_PNP
 | 
				
			||||||
| 
						 | 
					@ -130,16 +143,10 @@ config NFS_USE_KERNEL_DNS
 | 
				
			||||||
	bool
 | 
						bool
 | 
				
			||||||
	depends on NFS_V4 && !NFS_USE_LEGACY_DNS
 | 
						depends on NFS_V4 && !NFS_USE_LEGACY_DNS
 | 
				
			||||||
	select DNS_RESOLVER
 | 
						select DNS_RESOLVER
 | 
				
			||||||
	select KEYS
 | 
					 | 
				
			||||||
	default y
 | 
						default y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config NFS_USE_NEW_IDMAPPER
 | 
					config NFS_DEBUG
 | 
				
			||||||
	bool "Use the new idmapper upcall routine"
 | 
						bool
 | 
				
			||||||
	depends on NFS_V4 && KEYS
 | 
						depends on NFS_FS && SUNRPC_DEBUG
 | 
				
			||||||
	help
 | 
						select CRC32
 | 
				
			||||||
	  Say Y here if you want NFS to use the new idmapper upcall functions.
 | 
						default y
 | 
				
			||||||
	  You will need /sbin/request-key (usually provided by the keyutils
 | 
					 | 
				
			||||||
	  package).  For details, read
 | 
					 | 
				
			||||||
	  <file:Documentation/filesystems/nfs/idmapper.txt>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	  If you are unsure, say N.
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,9 +46,6 @@ MODULE_LICENSE("GPL");
 | 
				
			||||||
MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>");
 | 
					MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>");
 | 
				
			||||||
MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver");
 | 
					MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dentry *bl_device_pipe;
 | 
					 | 
				
			||||||
wait_queue_head_t bl_wq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void print_page(struct page *page)
 | 
					static void print_page(struct page *page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dprintk("PRINTPAGE page %p\n", page);
 | 
						dprintk("PRINTPAGE page %p\n", page);
 | 
				
			||||||
| 
						 | 
					@ -236,12 +233,11 @@ bl_read_pagelist(struct nfs_read_data *rdata)
 | 
				
			||||||
	sector_t isect, extent_length = 0;
 | 
						sector_t isect, extent_length = 0;
 | 
				
			||||||
	struct parallel_io *par;
 | 
						struct parallel_io *par;
 | 
				
			||||||
	loff_t f_offset = rdata->args.offset;
 | 
						loff_t f_offset = rdata->args.offset;
 | 
				
			||||||
	size_t count = rdata->args.count;
 | 
					 | 
				
			||||||
	struct page **pages = rdata->args.pages;
 | 
						struct page **pages = rdata->args.pages;
 | 
				
			||||||
	int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
 | 
						int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("%s enter nr_pages %u offset %lld count %Zd\n", __func__,
 | 
						dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__,
 | 
				
			||||||
	       rdata->npages, f_offset, count);
 | 
						       rdata->npages, f_offset, (unsigned int)rdata->args.count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	par = alloc_parallel(rdata);
 | 
						par = alloc_parallel(rdata);
 | 
				
			||||||
	if (!par)
 | 
						if (!par)
 | 
				
			||||||
| 
						 | 
					@ -1025,10 +1021,128 @@ static const struct rpc_pipe_ops bl_upcall_ops = {
 | 
				
			||||||
	.destroy_msg	= bl_pipe_destroy_msg,
 | 
						.destroy_msg	= bl_pipe_destroy_msg,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
 | 
				
			||||||
 | 
										    struct rpc_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dentry *dir, *dentry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME);
 | 
				
			||||||
 | 
						if (dir == NULL)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOENT);
 | 
				
			||||||
 | 
						dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
 | 
				
			||||||
 | 
						dput(dir);
 | 
				
			||||||
 | 
						return dentry;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs4blocklayout_unregister_sb(struct super_block *sb,
 | 
				
			||||||
 | 
										  struct rpc_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (pipe->dentry)
 | 
				
			||||||
 | 
							rpc_unlink(pipe->dentry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
 | 
				
			||||||
 | 
								   void *ptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct super_block *sb = ptr;
 | 
				
			||||||
 | 
						struct net *net = sb->s_fs_info;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
						struct dentry *dentry;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!try_module_get(THIS_MODULE))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nn->bl_device_pipe == NULL) {
 | 
				
			||||||
 | 
							module_put(THIS_MODULE);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (event) {
 | 
				
			||||||
 | 
						case RPC_PIPEFS_MOUNT:
 | 
				
			||||||
 | 
							dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
 | 
				
			||||||
 | 
							if (IS_ERR(dentry)) {
 | 
				
			||||||
 | 
								ret = PTR_ERR(dentry);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							nn->bl_device_pipe->dentry = dentry;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case RPC_PIPEFS_UMOUNT:
 | 
				
			||||||
 | 
							if (nn->bl_device_pipe->dentry)
 | 
				
			||||||
 | 
								nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ret = -ENOTSUPP;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						module_put(THIS_MODULE);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct notifier_block nfs4blocklayout_block = {
 | 
				
			||||||
 | 
						.notifier_call = rpc_pipefs_event,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dentry *nfs4blocklayout_register_net(struct net *net,
 | 
				
			||||||
 | 
											   struct rpc_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct super_block *pipefs_sb;
 | 
				
			||||||
 | 
						struct dentry *dentry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pipefs_sb = rpc_get_sb_net(net);
 | 
				
			||||||
 | 
						if (!pipefs_sb)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe);
 | 
				
			||||||
 | 
						rpc_put_sb_net(net);
 | 
				
			||||||
 | 
						return dentry;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs4blocklayout_unregister_net(struct net *net,
 | 
				
			||||||
 | 
										   struct rpc_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct super_block *pipefs_sb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pipefs_sb = rpc_get_sb_net(net);
 | 
				
			||||||
 | 
						if (pipefs_sb) {
 | 
				
			||||||
 | 
							nfs4blocklayout_unregister_sb(pipefs_sb, pipe);
 | 
				
			||||||
 | 
							rpc_put_sb_net(net);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nfs4blocklayout_net_init(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
						struct dentry *dentry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						init_waitqueue_head(&nn->bl_wq);
 | 
				
			||||||
 | 
						nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
 | 
				
			||||||
 | 
						if (IS_ERR(nn->bl_device_pipe))
 | 
				
			||||||
 | 
							return PTR_ERR(nn->bl_device_pipe);
 | 
				
			||||||
 | 
						dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
 | 
				
			||||||
 | 
						if (IS_ERR(dentry)) {
 | 
				
			||||||
 | 
							rpc_destroy_pipe_data(nn->bl_device_pipe);
 | 
				
			||||||
 | 
							return PTR_ERR(dentry);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						nn->bl_device_pipe->dentry = dentry;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs4blocklayout_net_exit(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
 | 
				
			||||||
 | 
						rpc_destroy_pipe_data(nn->bl_device_pipe);
 | 
				
			||||||
 | 
						nn->bl_device_pipe = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct pernet_operations nfs4blocklayout_net_ops = {
 | 
				
			||||||
 | 
						.init = nfs4blocklayout_net_init,
 | 
				
			||||||
 | 
						.exit = nfs4blocklayout_net_exit,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init nfs4blocklayout_init(void)
 | 
					static int __init nfs4blocklayout_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct vfsmount *mnt;
 | 
					 | 
				
			||||||
	struct path path;
 | 
					 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__);
 | 
						dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__);
 | 
				
			||||||
| 
						 | 
					@ -1037,32 +1151,17 @@ static int __init nfs4blocklayout_init(void)
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	init_waitqueue_head(&bl_wq);
 | 
						ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	mnt = rpc_get_mount();
 | 
					 | 
				
			||||||
	if (IS_ERR(mnt)) {
 | 
					 | 
				
			||||||
		ret = PTR_ERR(mnt);
 | 
					 | 
				
			||||||
		goto out_remove;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = vfs_path_lookup(mnt->mnt_root,
 | 
					 | 
				
			||||||
			      mnt,
 | 
					 | 
				
			||||||
			      NFS_PIPE_DIRNAME, 0, &path);
 | 
					 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto out_putrpc;
 | 
							goto out_remove;
 | 
				
			||||||
 | 
						ret = register_pernet_subsys(&nfs4blocklayout_net_ops);
 | 
				
			||||||
	bl_device_pipe = rpc_mkpipe(path.dentry, "blocklayout", NULL,
 | 
						if (ret)
 | 
				
			||||||
				    &bl_upcall_ops, 0);
 | 
							goto out_notifier;
 | 
				
			||||||
	path_put(&path);
 | 
					 | 
				
			||||||
	if (IS_ERR(bl_device_pipe)) {
 | 
					 | 
				
			||||||
		ret = PTR_ERR(bl_device_pipe);
 | 
					 | 
				
			||||||
		goto out_putrpc;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_putrpc:
 | 
					out_notifier:
 | 
				
			||||||
	rpc_put_mount();
 | 
						rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
 | 
				
			||||||
out_remove:
 | 
					out_remove:
 | 
				
			||||||
	pnfs_unregister_layoutdriver(&blocklayout_type);
 | 
						pnfs_unregister_layoutdriver(&blocklayout_type);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
| 
						 | 
					@ -1073,9 +1172,9 @@ static void __exit nfs4blocklayout_exit(void)
 | 
				
			||||||
	dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n",
 | 
						dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n",
 | 
				
			||||||
	       __func__);
 | 
						       __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
 | 
				
			||||||
 | 
						unregister_pernet_subsys(&nfs4blocklayout_net_ops);
 | 
				
			||||||
	pnfs_unregister_layoutdriver(&blocklayout_type);
 | 
						pnfs_unregister_layoutdriver(&blocklayout_type);
 | 
				
			||||||
	rpc_unlink(bl_device_pipe);
 | 
					 | 
				
			||||||
	rpc_put_mount();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_ALIAS("nfs-layouttype4-3");
 | 
					MODULE_ALIAS("nfs-layouttype4-3");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,7 @@
 | 
				
			||||||
#include <linux/sunrpc/rpc_pipe_fs.h>
 | 
					#include <linux/sunrpc/rpc_pipe_fs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../pnfs.h"
 | 
					#include "../pnfs.h"
 | 
				
			||||||
 | 
					#include "../netns.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
 | 
					#define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
 | 
				
			||||||
#define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
 | 
					#define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
 | 
				
			||||||
| 
						 | 
					@ -50,6 +51,7 @@ struct pnfs_block_dev {
 | 
				
			||||||
	struct list_head		bm_node;
 | 
						struct list_head		bm_node;
 | 
				
			||||||
	struct nfs4_deviceid		bm_mdevid;    /* associated devid */
 | 
						struct nfs4_deviceid		bm_mdevid;    /* associated devid */
 | 
				
			||||||
	struct block_device		*bm_mdev;     /* meta device itself */
 | 
						struct block_device		*bm_mdev;     /* meta device itself */
 | 
				
			||||||
 | 
						struct net			*net;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum exstate4 {
 | 
					enum exstate4 {
 | 
				
			||||||
| 
						 | 
					@ -151,9 +153,9 @@ BLK_LSEG2EXT(struct pnfs_layout_segment *lseg)
 | 
				
			||||||
	return BLK_LO2EXT(lseg->pls_layout);
 | 
						return BLK_LO2EXT(lseg->pls_layout);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct bl_dev_msg {
 | 
					struct bl_pipe_msg {
 | 
				
			||||||
	int32_t status;
 | 
						struct rpc_pipe_msg msg;
 | 
				
			||||||
	uint32_t major, minor;
 | 
						wait_queue_head_t *bl_wq;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct bl_msg_hdr {
 | 
					struct bl_msg_hdr {
 | 
				
			||||||
| 
						 | 
					@ -161,9 +163,6 @@ struct bl_msg_hdr {
 | 
				
			||||||
	u16 totallen; /* length of entire message, including hdr itself */
 | 
						u16 totallen; /* length of entire message, including hdr itself */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct dentry *bl_device_pipe;
 | 
					 | 
				
			||||||
extern wait_queue_head_t bl_wq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define BL_DEVICE_UMOUNT               0x0 /* Umount--delete devices */
 | 
					#define BL_DEVICE_UMOUNT               0x0 /* Umount--delete devices */
 | 
				
			||||||
#define BL_DEVICE_MOUNT                0x1 /* Mount--create devices*/
 | 
					#define BL_DEVICE_MOUNT                0x1 /* Mount--create devices*/
 | 
				
			||||||
#define BL_DEVICE_REQUEST_INIT         0x0 /* Start request */
 | 
					#define BL_DEVICE_REQUEST_INIT         0x0 /* Start request */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ static int decode_sector_number(__be32 **rp, sector_t *sp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*rp = xdr_decode_hyper(*rp, &s);
 | 
						*rp = xdr_decode_hyper(*rp, &s);
 | 
				
			||||||
	if (s & 0x1ff) {
 | 
						if (s & 0x1ff) {
 | 
				
			||||||
		printk(KERN_WARNING "%s: sector not aligned\n", __func__);
 | 
							printk(KERN_WARNING "NFS: %s: sector not aligned\n", __func__);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	*sp = s >> SECTOR_SHIFT;
 | 
						*sp = s >> SECTOR_SHIFT;
 | 
				
			||||||
| 
						 | 
					@ -79,27 +79,30 @@ int nfs4_blkdev_put(struct block_device *bdev)
 | 
				
			||||||
	return blkdev_put(bdev, FMODE_READ);
 | 
						return blkdev_put(bdev, FMODE_READ);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct bl_dev_msg bl_mount_reply;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
 | 
					ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
 | 
				
			||||||
			 size_t mlen)
 | 
								 size_t mlen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
 | 
				
			||||||
 | 
										 nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mlen != sizeof (struct bl_dev_msg))
 | 
						if (mlen != sizeof (struct bl_dev_msg))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (copy_from_user(&bl_mount_reply, src, mlen) != 0)
 | 
						if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0)
 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wake_up(&bl_wq);
 | 
						wake_up(&nn->bl_wq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mlen;
 | 
						return mlen;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 | 
					void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct bl_pipe_msg *bl_pipe_msg = container_of(msg, struct bl_pipe_msg, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (msg->errno >= 0)
 | 
						if (msg->errno >= 0)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	wake_up(&bl_wq);
 | 
						wake_up(bl_pipe_msg->bl_wq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -111,29 +114,33 @@ nfs4_blk_decode_device(struct nfs_server *server,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pnfs_block_dev *rv;
 | 
						struct pnfs_block_dev *rv;
 | 
				
			||||||
	struct block_device *bd = NULL;
 | 
						struct block_device *bd = NULL;
 | 
				
			||||||
	struct rpc_pipe_msg msg;
 | 
						struct bl_pipe_msg bl_pipe_msg;
 | 
				
			||||||
 | 
						struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
 | 
				
			||||||
	struct bl_msg_hdr bl_msg = {
 | 
						struct bl_msg_hdr bl_msg = {
 | 
				
			||||||
		.type = BL_DEVICE_MOUNT,
 | 
							.type = BL_DEVICE_MOUNT,
 | 
				
			||||||
		.totallen = dev->mincount,
 | 
							.totallen = dev->mincount,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	uint8_t *dataptr;
 | 
						uint8_t *dataptr;
 | 
				
			||||||
	DECLARE_WAITQUEUE(wq, current);
 | 
						DECLARE_WAITQUEUE(wq, current);
 | 
				
			||||||
	struct bl_dev_msg *reply = &bl_mount_reply;
 | 
					 | 
				
			||||||
	int offset, len, i, rc;
 | 
						int offset, len, i, rc;
 | 
				
			||||||
 | 
						struct net *net = server->nfs_client->net;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
						struct bl_dev_msg *reply = &nn->bl_mount_reply;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
 | 
						dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
 | 
				
			||||||
	dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
 | 
						dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
 | 
				
			||||||
		dev->mincount);
 | 
							dev->mincount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&msg, 0, sizeof(msg));
 | 
						bl_pipe_msg.bl_wq = &nn->bl_wq;
 | 
				
			||||||
	msg.data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS);
 | 
						memset(msg, 0, sizeof(*msg));
 | 
				
			||||||
	if (!msg.data) {
 | 
						msg->data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS);
 | 
				
			||||||
 | 
						if (!msg->data) {
 | 
				
			||||||
		rv = ERR_PTR(-ENOMEM);
 | 
							rv = ERR_PTR(-ENOMEM);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(msg.data, &bl_msg, sizeof(bl_msg));
 | 
						memcpy(msg->data, &bl_msg, sizeof(bl_msg));
 | 
				
			||||||
	dataptr = (uint8_t *) msg.data;
 | 
						dataptr = (uint8_t *) msg->data;
 | 
				
			||||||
	len = dev->mincount;
 | 
						len = dev->mincount;
 | 
				
			||||||
	offset = sizeof(bl_msg);
 | 
						offset = sizeof(bl_msg);
 | 
				
			||||||
	for (i = 0; len > 0; i++) {
 | 
						for (i = 0; len > 0; i++) {
 | 
				
			||||||
| 
						 | 
					@ -142,13 +149,13 @@ nfs4_blk_decode_device(struct nfs_server *server,
 | 
				
			||||||
		len -= PAGE_CACHE_SIZE;
 | 
							len -= PAGE_CACHE_SIZE;
 | 
				
			||||||
		offset += PAGE_CACHE_SIZE;
 | 
							offset += PAGE_CACHE_SIZE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	msg.len = sizeof(bl_msg) + dev->mincount;
 | 
						msg->len = sizeof(bl_msg) + dev->mincount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
 | 
						dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
 | 
				
			||||||
	add_wait_queue(&bl_wq, &wq);
 | 
						add_wait_queue(&nn->bl_wq, &wq);
 | 
				
			||||||
	rc = rpc_queue_upcall(bl_device_pipe->d_inode, &msg);
 | 
						rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		remove_wait_queue(&bl_wq, &wq);
 | 
							remove_wait_queue(&nn->bl_wq, &wq);
 | 
				
			||||||
		rv = ERR_PTR(rc);
 | 
							rv = ERR_PTR(rc);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -156,7 +163,7 @@ nfs4_blk_decode_device(struct nfs_server *server,
 | 
				
			||||||
	set_current_state(TASK_UNINTERRUPTIBLE);
 | 
						set_current_state(TASK_UNINTERRUPTIBLE);
 | 
				
			||||||
	schedule();
 | 
						schedule();
 | 
				
			||||||
	__set_current_state(TASK_RUNNING);
 | 
						__set_current_state(TASK_RUNNING);
 | 
				
			||||||
	remove_wait_queue(&bl_wq, &wq);
 | 
						remove_wait_queue(&nn->bl_wq, &wq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (reply->status != BL_DEVICE_REQUEST_PROC) {
 | 
						if (reply->status != BL_DEVICE_REQUEST_PROC) {
 | 
				
			||||||
		dprintk("%s failed to open device: %d\n",
 | 
							dprintk("%s failed to open device: %d\n",
 | 
				
			||||||
| 
						 | 
					@ -181,13 +188,14 @@ nfs4_blk_decode_device(struct nfs_server *server,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rv->bm_mdev = bd;
 | 
						rv->bm_mdev = bd;
 | 
				
			||||||
	memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid));
 | 
						memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid));
 | 
				
			||||||
 | 
						rv->net = net;
 | 
				
			||||||
	dprintk("%s Created device %s with bd_block_size %u\n",
 | 
						dprintk("%s Created device %s with bd_block_size %u\n",
 | 
				
			||||||
		__func__,
 | 
							__func__,
 | 
				
			||||||
		bd->bd_disk->disk_name,
 | 
							bd->bd_disk->disk_name,
 | 
				
			||||||
		bd->bd_block_size);
 | 
							bd->bd_block_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	kfree(msg.data);
 | 
						kfree(msg->data);
 | 
				
			||||||
	return rv;
 | 
						return rv;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,9 +38,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 | 
					#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dev_remove(dev_t dev)
 | 
					static void dev_remove(struct net *net, dev_t dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_pipe_msg msg;
 | 
						struct bl_pipe_msg bl_pipe_msg;
 | 
				
			||||||
 | 
						struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
 | 
				
			||||||
	struct bl_dev_msg bl_umount_request;
 | 
						struct bl_dev_msg bl_umount_request;
 | 
				
			||||||
	struct bl_msg_hdr bl_msg = {
 | 
						struct bl_msg_hdr bl_msg = {
 | 
				
			||||||
		.type = BL_DEVICE_UMOUNT,
 | 
							.type = BL_DEVICE_UMOUNT,
 | 
				
			||||||
| 
						 | 
					@ -48,36 +49,38 @@ static void dev_remove(dev_t dev)
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	uint8_t *dataptr;
 | 
						uint8_t *dataptr;
 | 
				
			||||||
	DECLARE_WAITQUEUE(wq, current);
 | 
						DECLARE_WAITQUEUE(wq, current);
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("Entering %s\n", __func__);
 | 
						dprintk("Entering %s\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&msg, 0, sizeof(msg));
 | 
						bl_pipe_msg.bl_wq = &nn->bl_wq;
 | 
				
			||||||
	msg.data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
 | 
						memset(msg, 0, sizeof(*msg));
 | 
				
			||||||
	if (!msg.data)
 | 
						msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
 | 
				
			||||||
 | 
						if (!msg->data)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&bl_umount_request, 0, sizeof(bl_umount_request));
 | 
						memset(&bl_umount_request, 0, sizeof(bl_umount_request));
 | 
				
			||||||
	bl_umount_request.major = MAJOR(dev);
 | 
						bl_umount_request.major = MAJOR(dev);
 | 
				
			||||||
	bl_umount_request.minor = MINOR(dev);
 | 
						bl_umount_request.minor = MINOR(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(msg.data, &bl_msg, sizeof(bl_msg));
 | 
						memcpy(msg->data, &bl_msg, sizeof(bl_msg));
 | 
				
			||||||
	dataptr = (uint8_t *) msg.data;
 | 
						dataptr = (uint8_t *) msg->data;
 | 
				
			||||||
	memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
 | 
						memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
 | 
				
			||||||
	msg.len = sizeof(bl_msg) + bl_msg.totallen;
 | 
						msg->len = sizeof(bl_msg) + bl_msg.totallen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	add_wait_queue(&bl_wq, &wq);
 | 
						add_wait_queue(&nn->bl_wq, &wq);
 | 
				
			||||||
	if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
 | 
						if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) {
 | 
				
			||||||
		remove_wait_queue(&bl_wq, &wq);
 | 
							remove_wait_queue(&nn->bl_wq, &wq);
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_current_state(TASK_UNINTERRUPTIBLE);
 | 
						set_current_state(TASK_UNINTERRUPTIBLE);
 | 
				
			||||||
	schedule();
 | 
						schedule();
 | 
				
			||||||
	__set_current_state(TASK_RUNNING);
 | 
						__set_current_state(TASK_RUNNING);
 | 
				
			||||||
	remove_wait_queue(&bl_wq, &wq);
 | 
						remove_wait_queue(&nn->bl_wq, &wq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	kfree(msg.data);
 | 
						kfree(msg->data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -90,10 +93,10 @@ static void nfs4_blk_metadev_release(struct pnfs_block_dev *bdev)
 | 
				
			||||||
	dprintk("%s Releasing\n", __func__);
 | 
						dprintk("%s Releasing\n", __func__);
 | 
				
			||||||
	rv = nfs4_blkdev_put(bdev->bm_mdev);
 | 
						rv = nfs4_blkdev_put(bdev->bm_mdev);
 | 
				
			||||||
	if (rv)
 | 
						if (rv)
 | 
				
			||||||
		printk(KERN_ERR "%s nfs4_blkdev_put returns %d\n",
 | 
							printk(KERN_ERR "NFS: %s nfs4_blkdev_put returns %d\n",
 | 
				
			||||||
				__func__, rv);
 | 
									__func__, rv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_remove(bdev->bm_mdev->bd_dev);
 | 
						dev_remove(bdev->net, bdev->bm_mdev->bd_dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bl_free_block_dev(struct pnfs_block_dev *bdev)
 | 
					void bl_free_block_dev(struct pnfs_block_dev *bdev)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,7 +147,7 @@ static int _preload_range(struct pnfs_inval_markings *marks,
 | 
				
			||||||
	count = (int)(end - start) / (int)tree->mtt_step_size;
 | 
						count = (int)(end - start) / (int)tree->mtt_step_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Pre-malloc what memory we might need */
 | 
						/* Pre-malloc what memory we might need */
 | 
				
			||||||
	storage = kmalloc(sizeof(*storage) * count, GFP_NOFS);
 | 
						storage = kcalloc(count, sizeof(*storage), GFP_NOFS);
 | 
				
			||||||
	if (!storage)
 | 
						if (!storage)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	for (i = 0; i < count; i++) {
 | 
						for (i = 0; i < count; i++) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/sunrpc/cache.h>
 | 
					#include <linux/sunrpc/cache.h>
 | 
				
			||||||
#include <linux/sunrpc/rpc_pipe_fs.h>
 | 
					#include <linux/sunrpc/rpc_pipe_fs.h>
 | 
				
			||||||
 | 
					#include <net/net_namespace.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "cache_lib.h"
 | 
					#include "cache_lib.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,30 +112,54 @@ int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs_cache_register(struct cache_detail *cd)
 | 
					int nfs_cache_register_sb(struct super_block *sb, struct cache_detail *cd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct vfsmount *mnt;
 | 
					 | 
				
			||||||
	struct path path;
 | 
					 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
						struct dentry *dir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mnt = rpc_get_mount();
 | 
						dir = rpc_d_lookup_sb(sb, "cache");
 | 
				
			||||||
	if (IS_ERR(mnt))
 | 
						BUG_ON(dir == NULL);
 | 
				
			||||||
		return PTR_ERR(mnt);
 | 
						ret = sunrpc_cache_register_pipefs(dir, cd->name, 0600, cd);
 | 
				
			||||||
	ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &path);
 | 
						dput(dir);
 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		goto err;
 | 
					 | 
				
			||||||
	ret = sunrpc_cache_register_pipefs(path.dentry, cd->name, 0600, cd);
 | 
					 | 
				
			||||||
	path_put(&path);
 | 
					 | 
				
			||||||
	if (!ret)
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
err:
 | 
					 | 
				
			||||||
	rpc_put_mount();
 | 
					 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_cache_unregister(struct cache_detail *cd)
 | 
					int nfs_cache_register_net(struct net *net, struct cache_detail *cd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	sunrpc_cache_unregister_pipefs(cd);
 | 
						struct super_block *pipefs_sb;
 | 
				
			||||||
	rpc_put_mount();
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pipefs_sb = rpc_get_sb_net(net);
 | 
				
			||||||
 | 
						if (pipefs_sb) {
 | 
				
			||||||
 | 
							ret = nfs_cache_register_sb(pipefs_sb, cd);
 | 
				
			||||||
 | 
							rpc_put_sb_net(net);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void nfs_cache_unregister_sb(struct super_block *sb, struct cache_detail *cd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (cd->u.pipefs.dir)
 | 
				
			||||||
 | 
							sunrpc_cache_unregister_pipefs(cd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct super_block *pipefs_sb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pipefs_sb = rpc_get_sb_net(net);
 | 
				
			||||||
 | 
						if (pipefs_sb) {
 | 
				
			||||||
 | 
							nfs_cache_unregister_sb(pipefs_sb, cd);
 | 
				
			||||||
 | 
							rpc_put_sb_net(net);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void nfs_cache_init(struct cache_detail *cd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sunrpc_init_cache_detail(cd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void nfs_cache_destroy(struct cache_detail *cd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sunrpc_destroy_cache_detail(cd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,5 +23,11 @@ extern struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void);
 | 
				
			||||||
extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq);
 | 
					extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq);
 | 
				
			||||||
extern int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq);
 | 
					extern int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int nfs_cache_register(struct cache_detail *cd);
 | 
					extern void nfs_cache_init(struct cache_detail *cd);
 | 
				
			||||||
extern void nfs_cache_unregister(struct cache_detail *cd);
 | 
					extern void nfs_cache_destroy(struct cache_detail *cd);
 | 
				
			||||||
 | 
					extern int nfs_cache_register_net(struct net *net, struct cache_detail *cd);
 | 
				
			||||||
 | 
					extern void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd);
 | 
				
			||||||
 | 
					extern int nfs_cache_register_sb(struct super_block *sb,
 | 
				
			||||||
 | 
									 struct cache_detail *cd);
 | 
				
			||||||
 | 
					extern void nfs_cache_unregister_sb(struct super_block *sb,
 | 
				
			||||||
 | 
									    struct cache_detail *cd);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -85,7 +85,7 @@ nfs4_callback_svc(void *vrqstp)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (err < 0) {
 | 
							if (err < 0) {
 | 
				
			||||||
			if (err != preverr) {
 | 
								if (err != preverr) {
 | 
				
			||||||
				printk(KERN_WARNING "%s: unexpected error "
 | 
									printk(KERN_WARNING "NFS: %s: unexpected error "
 | 
				
			||||||
					"from svc_recv (%d)\n", __func__, err);
 | 
										"from svc_recv (%d)\n", __func__, err);
 | 
				
			||||||
				preverr = err;
 | 
									preverr = err;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -101,12 +101,12 @@ nfs4_callback_svc(void *vrqstp)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Prepare to bring up the NFSv4 callback service
 | 
					 * Prepare to bring up the NFSv4 callback service
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct svc_rqst *
 | 
					static struct svc_rqst *
 | 
				
			||||||
nfs4_callback_up(struct svc_serv *serv)
 | 
					nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET,
 | 
						ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET,
 | 
				
			||||||
				nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
 | 
									nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
 | 
				
			||||||
	if (ret <= 0)
 | 
						if (ret <= 0)
 | 
				
			||||||
		goto out_err;
 | 
							goto out_err;
 | 
				
			||||||
| 
						 | 
					@ -114,7 +114,7 @@ nfs4_callback_up(struct svc_serv *serv)
 | 
				
			||||||
	dprintk("NFS: Callback listener port = %u (af %u)\n",
 | 
						dprintk("NFS: Callback listener port = %u (af %u)\n",
 | 
				
			||||||
			nfs_callback_tcpport, PF_INET);
 | 
								nfs_callback_tcpport, PF_INET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6,
 | 
						ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET6,
 | 
				
			||||||
				nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
 | 
									nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
 | 
				
			||||||
	if (ret > 0) {
 | 
						if (ret > 0) {
 | 
				
			||||||
		nfs_callback_tcpport6 = ret;
 | 
							nfs_callback_tcpport6 = ret;
 | 
				
			||||||
| 
						 | 
					@ -172,7 +172,7 @@ nfs41_callback_svc(void *vrqstp)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Bring up the NFSv4.1 callback service
 | 
					 * Bring up the NFSv4.1 callback service
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct svc_rqst *
 | 
					static struct svc_rqst *
 | 
				
			||||||
nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
 | 
					nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct svc_rqst *rqstp;
 | 
						struct svc_rqst *rqstp;
 | 
				
			||||||
| 
						 | 
					@ -183,7 +183,7 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
 | 
				
			||||||
	 * fore channel connection.
 | 
						 * fore channel connection.
 | 
				
			||||||
	 * Returns the input port (0) and sets the svc_serv bc_xprt on success
 | 
						 * Returns the input port (0) and sets the svc_serv bc_xprt on success
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0,
 | 
						ret = svc_create_xprt(serv, "tcp-bc", xprt->xprt_net, PF_INET, 0,
 | 
				
			||||||
			      SVC_SOCK_ANONYMOUS);
 | 
								      SVC_SOCK_ANONYMOUS);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		rqstp = ERR_PTR(ret);
 | 
							rqstp = ERR_PTR(ret);
 | 
				
			||||||
| 
						 | 
					@ -269,7 +269,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
 | 
				
			||||||
					serv, xprt, &rqstp, &callback_svc);
 | 
										serv, xprt, &rqstp, &callback_svc);
 | 
				
			||||||
	if (!minorversion_setup) {
 | 
						if (!minorversion_setup) {
 | 
				
			||||||
		/* v4.0 callback setup */
 | 
							/* v4.0 callback setup */
 | 
				
			||||||
		rqstp = nfs4_callback_up(serv);
 | 
							rqstp = nfs4_callback_up(serv, xprt);
 | 
				
			||||||
		callback_svc = nfs4_callback_svc;
 | 
							callback_svc = nfs4_callback_svc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -332,7 +332,6 @@ void nfs_callback_down(int minorversion)
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
 | 
					check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_clnt *r = clp->cl_rpcclient;
 | 
					 | 
				
			||||||
	char *p = svc_gss_principal(rqstp);
 | 
						char *p = svc_gss_principal(rqstp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
 | 
						if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
 | 
				
			||||||
| 
						 | 
					@ -353,7 +352,7 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
 | 
				
			||||||
	if (memcmp(p, "nfs@", 4) != 0)
 | 
						if (memcmp(p, "nfs@", 4) != 0)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	p += 4;
 | 
						p += 4;
 | 
				
			||||||
	if (strcmp(p, r->cl_server) != 0)
 | 
						if (strcmp(p, clp->cl_hostname) != 0)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,8 @@ enum nfs4_callback_opnum {
 | 
				
			||||||
struct cb_process_state {
 | 
					struct cb_process_state {
 | 
				
			||||||
	__be32			drc_status;
 | 
						__be32			drc_status;
 | 
				
			||||||
	struct nfs_client	*clp;
 | 
						struct nfs_client	*clp;
 | 
				
			||||||
	int			slotid;
 | 
						u32			slotid;
 | 
				
			||||||
 | 
						struct net		*net;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cb_compound_hdr_arg {
 | 
					struct cb_compound_hdr_arg {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
#include <linux/nfs4.h>
 | 
					#include <linux/nfs4.h>
 | 
				
			||||||
#include <linux/nfs_fs.h>
 | 
					#include <linux/nfs_fs.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/rcupdate.h>
 | 
				
			||||||
#include "nfs4_fs.h"
 | 
					#include "nfs4_fs.h"
 | 
				
			||||||
#include "callback.h"
 | 
					#include "callback.h"
 | 
				
			||||||
#include "delegation.h"
 | 
					#include "delegation.h"
 | 
				
			||||||
| 
						 | 
					@ -33,7 +34,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
 | 
				
			||||||
	res->bitmap[0] = res->bitmap[1] = 0;
 | 
						res->bitmap[0] = res->bitmap[1] = 0;
 | 
				
			||||||
	res->status = htonl(NFS4ERR_BADHANDLE);
 | 
						res->status = htonl(NFS4ERR_BADHANDLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("NFS: GETATTR callback request from %s\n",
 | 
						dprintk_rcu("NFS: GETATTR callback request from %s\n",
 | 
				
			||||||
		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 | 
							rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inode = nfs_delegation_find_inode(cps->clp, &args->fh);
 | 
						inode = nfs_delegation_find_inode(cps->clp, &args->fh);
 | 
				
			||||||
| 
						 | 
					@ -73,7 +74,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
 | 
				
			||||||
	if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
 | 
						if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("NFS: RECALL callback request from %s\n",
 | 
						dprintk_rcu("NFS: RECALL callback request from %s\n",
 | 
				
			||||||
		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 | 
							rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = htonl(NFS4ERR_BADHANDLE);
 | 
						res = htonl(NFS4ERR_BADHANDLE);
 | 
				
			||||||
| 
						 | 
					@ -86,7 +87,6 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
 | 
				
			||||||
		res = 0;
 | 
							res = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case -ENOENT:
 | 
						case -ENOENT:
 | 
				
			||||||
		if (res != 0)
 | 
					 | 
				
			||||||
		res = htonl(NFS4ERR_BAD_STATEID);
 | 
							res = htonl(NFS4ERR_BAD_STATEID);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
| 
						 | 
					@ -98,52 +98,64 @@ out:
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
 | 
					 | 
				
			||||||
					 sizeof(delegation->stateid.data)) != 0)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					#if defined(CONFIG_NFS_V4_1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u32 initiate_file_draining(struct nfs_client *clp,
 | 
					/*
 | 
				
			||||||
				  struct cb_layoutrecallargs *args)
 | 
					 * Lookup a layout by filehandle.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: gets a refcount on the layout hdr and on its respective inode.
 | 
				
			||||||
 | 
					 * Caller must put the layout hdr and the inode.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * TODO: keep track of all layouts (and delegations) in a hash table
 | 
				
			||||||
 | 
					 * hashed by filehandle.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_server *server;
 | 
						struct nfs_server *server;
 | 
				
			||||||
	struct pnfs_layout_hdr *lo;
 | 
					 | 
				
			||||||
	struct inode *ino;
 | 
						struct inode *ino;
 | 
				
			||||||
	bool found = false;
 | 
						struct pnfs_layout_hdr *lo;
 | 
				
			||||||
	u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
 | 
					 | 
				
			||||||
	LIST_HEAD(free_me_list);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&clp->cl_lock);
 | 
					 | 
				
			||||||
	rcu_read_lock();
 | 
					 | 
				
			||||||
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
 | 
						list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
 | 
				
			||||||
		list_for_each_entry(lo, &server->layouts, plh_layouts) {
 | 
							list_for_each_entry(lo, &server->layouts, plh_layouts) {
 | 
				
			||||||
			if (nfs_compare_fh(&args->cbl_fh,
 | 
								if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))
 | 
				
			||||||
					   &NFS_I(lo->plh_inode)->fh))
 | 
					 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			ino = igrab(lo->plh_inode);
 | 
								ino = igrab(lo->plh_inode);
 | 
				
			||||||
			if (!ino)
 | 
								if (!ino)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			found = true;
 | 
					 | 
				
			||||||
			/* Without this, layout can be freed as soon
 | 
					 | 
				
			||||||
			 * as we release cl_lock.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			get_layout_hdr(lo);
 | 
								get_layout_hdr(lo);
 | 
				
			||||||
			break;
 | 
								return lo;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (found)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pnfs_layout_hdr *lo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock(&clp->cl_lock);
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
						lo = get_layout_by_fh_locked(clp, fh);
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
	spin_unlock(&clp->cl_lock);
 | 
						spin_unlock(&clp->cl_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!found)
 | 
						return lo;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u32 initiate_file_draining(struct nfs_client *clp,
 | 
				
			||||||
 | 
									  struct cb_layoutrecallargs *args)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct inode *ino;
 | 
				
			||||||
 | 
						struct pnfs_layout_hdr *lo;
 | 
				
			||||||
 | 
						u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
 | 
				
			||||||
 | 
						LIST_HEAD(free_me_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lo = get_layout_by_fh(clp, &args->cbl_fh);
 | 
				
			||||||
 | 
						if (!lo)
 | 
				
			||||||
		return NFS4ERR_NOMATCHING_LAYOUT;
 | 
							return NFS4ERR_NOMATCHING_LAYOUT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ino = lo->plh_inode;
 | 
				
			||||||
	spin_lock(&ino->i_lock);
 | 
						spin_lock(&ino->i_lock);
 | 
				
			||||||
	if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
 | 
						if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
 | 
				
			||||||
	    mark_matching_lsegs_invalid(lo, &free_me_list,
 | 
						    mark_matching_lsegs_invalid(lo, &free_me_list,
 | 
				
			||||||
| 
						 | 
					@ -213,17 +225,13 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
 | 
				
			||||||
static u32 do_callback_layoutrecall(struct nfs_client *clp,
 | 
					static u32 do_callback_layoutrecall(struct nfs_client *clp,
 | 
				
			||||||
				    struct cb_layoutrecallargs *args)
 | 
									    struct cb_layoutrecallargs *args)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 res = NFS4ERR_DELAY;
 | 
						u32 res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type);
 | 
						dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type);
 | 
				
			||||||
	if (test_and_set_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state))
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	if (args->cbl_recall_type == RETURN_FILE)
 | 
						if (args->cbl_recall_type == RETURN_FILE)
 | 
				
			||||||
		res = initiate_file_draining(clp, args);
 | 
							res = initiate_file_draining(clp, args);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		res = initiate_bulk_draining(clp, args);
 | 
							res = initiate_bulk_draining(clp, args);
 | 
				
			||||||
	clear_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state);
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	dprintk("%s returning %i\n", __func__, res);
 | 
						dprintk("%s returning %i\n", __func__, res);
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -303,21 +311,6 @@ out:
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (delegation == NULL)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (stateid->stateid.seqid != 0)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	if (memcmp(&delegation->stateid.stateid.other,
 | 
					 | 
				
			||||||
		   &stateid->stateid.other,
 | 
					 | 
				
			||||||
		   NFS4_STATEID_OTHER_SIZE))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Validate the sequenceID sent by the server.
 | 
					 * Validate the sequenceID sent by the server.
 | 
				
			||||||
 * Return success if the sequenceID is one more than what we last saw on
 | 
					 * Return success if the sequenceID is one more than what we last saw on
 | 
				
			||||||
| 
						 | 
					@ -441,7 +434,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	__be32 status = htonl(NFS4ERR_BADSESSION);
 | 
						__be32 status = htonl(NFS4ERR_BADSESSION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
 | 
						clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, &args->csa_sessionid);
 | 
				
			||||||
	if (clp == NULL)
 | 
						if (clp == NULL)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -517,7 +510,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,
 | 
				
			||||||
	if (!cps->clp) /* set in cb_sequence */
 | 
						if (!cps->clp) /* set in cb_sequence */
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("NFS: RECALL_ANY callback request from %s\n",
 | 
						dprintk_rcu("NFS: RECALL_ANY callback request from %s\n",
 | 
				
			||||||
		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 | 
							rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status = cpu_to_be32(NFS4ERR_INVAL);
 | 
						status = cpu_to_be32(NFS4ERR_INVAL);
 | 
				
			||||||
| 
						 | 
					@ -552,7 +545,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
 | 
				
			||||||
	if (!cps->clp) /* set in cb_sequence */
 | 
						if (!cps->clp) /* set in cb_sequence */
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
 | 
						dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
 | 
				
			||||||
		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
 | 
							rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
 | 
				
			||||||
		args->crsa_target_max_slots);
 | 
							args->crsa_target_max_slots);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,8 @@
 | 
				
			||||||
#include <linux/sunrpc/svc.h>
 | 
					#include <linux/sunrpc/svc.h>
 | 
				
			||||||
#include <linux/nfs4.h>
 | 
					#include <linux/nfs4.h>
 | 
				
			||||||
#include <linux/nfs_fs.h>
 | 
					#include <linux/nfs_fs.h>
 | 
				
			||||||
 | 
					#include <linux/ratelimit.h>
 | 
				
			||||||
 | 
					#include <linux/printk.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/sunrpc/bc_xprt.h>
 | 
					#include <linux/sunrpc/bc_xprt.h>
 | 
				
			||||||
#include "nfs4_fs.h"
 | 
					#include "nfs4_fs.h"
 | 
				
			||||||
| 
						 | 
					@ -73,7 +75,7 @@ static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = xdr_inline_decode(xdr, nbytes);
 | 
						p = xdr_inline_decode(xdr, nbytes);
 | 
				
			||||||
	if (unlikely(p == NULL))
 | 
						if (unlikely(p == NULL))
 | 
				
			||||||
		printk(KERN_WARNING "NFSv4 callback reply buffer overflowed!\n");
 | 
							printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n");
 | 
				
			||||||
	return p;
 | 
						return p;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,10 +140,10 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	__be32 *p;
 | 
						__be32 *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = read_buf(xdr, 16);
 | 
						p = read_buf(xdr, NFS4_STATEID_SIZE);
 | 
				
			||||||
	if (unlikely(p == NULL))
 | 
						if (unlikely(p == NULL))
 | 
				
			||||||
		return htonl(NFS4ERR_RESOURCE);
 | 
							return htonl(NFS4ERR_RESOURCE);
 | 
				
			||||||
	memcpy(stateid->data, p, 16);
 | 
						memcpy(stateid, p, NFS4_STATEID_SIZE);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -155,7 +157,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
 | 
				
			||||||
		return status;
 | 
							return status;
 | 
				
			||||||
	/* We do not like overly long tags! */
 | 
						/* We do not like overly long tags! */
 | 
				
			||||||
	if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) {
 | 
						if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) {
 | 
				
			||||||
		printk("NFSv4 CALLBACK %s: client sent tag of length %u\n",
 | 
							printk("NFS: NFSv4 CALLBACK %s: client sent tag of length %u\n",
 | 
				
			||||||
				__func__, hdr->taglen);
 | 
									__func__, hdr->taglen);
 | 
				
			||||||
		return htonl(NFS4ERR_RESOURCE);
 | 
							return htonl(NFS4ERR_RESOURCE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -167,7 +169,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
 | 
				
			||||||
	if (hdr->minorversion <= 1) {
 | 
						if (hdr->minorversion <= 1) {
 | 
				
			||||||
		hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */
 | 
							hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		printk(KERN_WARNING "%s: NFSv4 server callback with "
 | 
							pr_warn_ratelimited("NFS: %s: NFSv4 server callback with "
 | 
				
			||||||
			"illegal minor version %u!\n",
 | 
								"illegal minor version %u!\n",
 | 
				
			||||||
			__func__, hdr->minorversion);
 | 
								__func__, hdr->minorversion);
 | 
				
			||||||
		return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
 | 
							return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
 | 
				
			||||||
| 
						 | 
					@ -759,14 +761,14 @@ static void nfs4_callback_free_slot(struct nfs4_session *session)
 | 
				
			||||||
	 * Let the state manager know callback processing done.
 | 
						 * Let the state manager know callback processing done.
 | 
				
			||||||
	 * A single slot, so highest used slotid is either 0 or -1
 | 
						 * A single slot, so highest used slotid is either 0 or -1
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	tbl->highest_used_slotid = -1;
 | 
						tbl->highest_used_slotid = NFS4_NO_SLOT;
 | 
				
			||||||
	nfs4_check_drain_bc_complete(session);
 | 
						nfs4_check_drain_bc_complete(session);
 | 
				
			||||||
	spin_unlock(&tbl->slot_tbl_lock);
 | 
						spin_unlock(&tbl->slot_tbl_lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfs4_cb_free_slot(struct cb_process_state *cps)
 | 
					static void nfs4_cb_free_slot(struct cb_process_state *cps)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (cps->slotid != -1)
 | 
						if (cps->slotid != NFS4_NO_SLOT)
 | 
				
			||||||
		nfs4_callback_free_slot(cps->clp->cl_session);
 | 
							nfs4_callback_free_slot(cps->clp->cl_session);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -860,7 +862,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
 | 
				
			||||||
	struct cb_process_state cps = {
 | 
						struct cb_process_state cps = {
 | 
				
			||||||
		.drc_status = 0,
 | 
							.drc_status = 0,
 | 
				
			||||||
		.clp = NULL,
 | 
							.clp = NULL,
 | 
				
			||||||
		.slotid = -1,
 | 
							.slotid = NFS4_NO_SLOT,
 | 
				
			||||||
 | 
							.net = rqstp->rq_xprt->xpt_net,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	unsigned int nops = 0;
 | 
						unsigned int nops = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -876,7 +879,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
 | 
				
			||||||
		return rpc_garbage_args;
 | 
							return rpc_garbage_args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (hdr_arg.minorversion == 0) {
 | 
						if (hdr_arg.minorversion == 0) {
 | 
				
			||||||
		cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident);
 | 
							cps.clp = nfs4_find_client_ident(rqstp->rq_xprt->xpt_net, hdr_arg.cb_ident);
 | 
				
			||||||
		if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
 | 
							if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
 | 
				
			||||||
			return rpc_drop_reply;
 | 
								return rpc_drop_reply;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										246
									
								
								fs/nfs/client.c
									
										
									
									
									
								
							
							
						
						
									
										246
									
								
								fs/nfs/client.c
									
										
									
									
									
								
							| 
						 | 
					@ -40,6 +40,8 @@
 | 
				
			||||||
#include <net/ipv6.h>
 | 
					#include <net/ipv6.h>
 | 
				
			||||||
#include <linux/nfs_xdr.h>
 | 
					#include <linux/nfs_xdr.h>
 | 
				
			||||||
#include <linux/sunrpc/bc_xprt.h>
 | 
					#include <linux/sunrpc/bc_xprt.h>
 | 
				
			||||||
 | 
					#include <linux/nsproxy.h>
 | 
				
			||||||
 | 
					#include <linux/pid_namespace.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/system.h>
 | 
					#include <asm/system.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,15 +52,12 @@
 | 
				
			||||||
#include "internal.h"
 | 
					#include "internal.h"
 | 
				
			||||||
#include "fscache.h"
 | 
					#include "fscache.h"
 | 
				
			||||||
#include "pnfs.h"
 | 
					#include "pnfs.h"
 | 
				
			||||||
 | 
					#include "netns.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFSDBG_FACILITY		NFSDBG_CLIENT
 | 
					#define NFSDBG_FACILITY		NFSDBG_CLIENT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static 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);
 | 
					static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
 | 
				
			||||||
#ifdef CONFIG_NFS_V4
 | 
					#ifdef CONFIG_NFS_V4
 | 
				
			||||||
static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Get a unique NFSv4.0 callback identifier which will be used
 | 
					 * Get a unique NFSv4.0 callback identifier which will be used
 | 
				
			||||||
| 
						 | 
					@ -67,15 +66,16 @@ static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */
 | 
				
			||||||
static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
 | 
					static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (clp->rpc_ops->version != 4 || minorversion != 0)
 | 
						if (clp->rpc_ops->version != 4 || minorversion != 0)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
retry:
 | 
					retry:
 | 
				
			||||||
	if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL))
 | 
						if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	spin_lock(&nfs_client_lock);
 | 
						spin_lock(&nn->nfs_client_lock);
 | 
				
			||||||
	ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident);
 | 
						ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident);
 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
	if (ret == -EAGAIN)
 | 
						if (ret == -EAGAIN)
 | 
				
			||||||
		goto retry;
 | 
							goto retry;
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
| 
						 | 
					@ -90,7 +90,7 @@ static bool nfs4_disable_idmapping = true;
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * RPC cruft for NFS
 | 
					 * RPC cruft for NFS
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct rpc_version *nfs_version[5] = {
 | 
					static const struct rpc_version *nfs_version[5] = {
 | 
				
			||||||
	[2]			= &nfs_version2,
 | 
						[2]			= &nfs_version2,
 | 
				
			||||||
#ifdef CONFIG_NFS_V3
 | 
					#ifdef CONFIG_NFS_V3
 | 
				
			||||||
	[3]			= &nfs_version3,
 | 
						[3]			= &nfs_version3,
 | 
				
			||||||
| 
						 | 
					@ -100,7 +100,7 @@ static struct rpc_version *nfs_version[5] = {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_program nfs_program = {
 | 
					const struct rpc_program nfs_program = {
 | 
				
			||||||
	.name			= "nfs",
 | 
						.name			= "nfs",
 | 
				
			||||||
	.number			= NFS_PROGRAM,
 | 
						.number			= NFS_PROGRAM,
 | 
				
			||||||
	.nrvers			= ARRAY_SIZE(nfs_version),
 | 
						.nrvers			= ARRAY_SIZE(nfs_version),
 | 
				
			||||||
| 
						 | 
					@ -116,11 +116,11 @@ struct rpc_stat nfs_rpcstat = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_NFS_V3_ACL
 | 
					#ifdef CONFIG_NFS_V3_ACL
 | 
				
			||||||
static struct rpc_stat		nfsacl_rpcstat = { &nfsacl_program };
 | 
					static struct rpc_stat		nfsacl_rpcstat = { &nfsacl_program };
 | 
				
			||||||
static struct rpc_version *	nfsacl_version[] = {
 | 
					static const struct rpc_version *nfsacl_version[] = {
 | 
				
			||||||
	[3]			= &nfsacl_version3,
 | 
						[3]			= &nfsacl_version3,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_program		nfsacl_program = {
 | 
					const struct rpc_program nfsacl_program = {
 | 
				
			||||||
	.name			= "nfsacl",
 | 
						.name			= "nfsacl",
 | 
				
			||||||
	.number			= NFS_ACL_PROGRAM,
 | 
						.number			= NFS_ACL_PROGRAM,
 | 
				
			||||||
	.nrvers			= ARRAY_SIZE(nfsacl_version),
 | 
						.nrvers			= ARRAY_SIZE(nfsacl_version),
 | 
				
			||||||
| 
						 | 
					@ -136,6 +136,7 @@ struct nfs_client_initdata {
 | 
				
			||||||
	const struct nfs_rpc_ops *rpc_ops;
 | 
						const struct nfs_rpc_ops *rpc_ops;
 | 
				
			||||||
	int proto;
 | 
						int proto;
 | 
				
			||||||
	u32 minorversion;
 | 
						u32 minorversion;
 | 
				
			||||||
 | 
						struct net *net;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -172,6 +173,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
 | 
				
			||||||
	clp->cl_rpcclient = ERR_PTR(-EINVAL);
 | 
						clp->cl_rpcclient = ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clp->cl_proto = cl_init->proto;
 | 
						clp->cl_proto = cl_init->proto;
 | 
				
			||||||
 | 
						clp->net = get_net(cl_init->net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_NFS_V4
 | 
					#ifdef CONFIG_NFS_V4
 | 
				
			||||||
	err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
 | 
						err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
 | 
				
			||||||
| 
						 | 
					@ -203,9 +205,12 @@ error_0:
 | 
				
			||||||
#ifdef CONFIG_NFS_V4_1
 | 
					#ifdef CONFIG_NFS_V4_1
 | 
				
			||||||
static void nfs4_shutdown_session(struct nfs_client *clp)
 | 
					static void nfs4_shutdown_session(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (nfs4_has_session(clp))
 | 
						if (nfs4_has_session(clp)) {
 | 
				
			||||||
 | 
							nfs4_deviceid_purge_client(clp);
 | 
				
			||||||
		nfs4_destroy_session(clp->cl_session);
 | 
							nfs4_destroy_session(clp->cl_session);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#else /* CONFIG_NFS_V4_1 */
 | 
					#else /* CONFIG_NFS_V4_1 */
 | 
				
			||||||
static void nfs4_shutdown_session(struct nfs_client *clp)
 | 
					static void nfs4_shutdown_session(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -234,16 +239,20 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* idr_remove_all is not needed as all id's are removed by nfs_put_client */
 | 
					/* idr_remove_all is not needed as all id's are removed by nfs_put_client */
 | 
				
			||||||
void nfs_cleanup_cb_ident_idr(void)
 | 
					void nfs_cleanup_cb_ident_idr(struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	idr_destroy(&cb_ident_idr);
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						idr_destroy(&nn->cb_ident_idr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* nfs_client_lock held */
 | 
					/* nfs_client_lock held */
 | 
				
			||||||
static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
 | 
					static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (clp->cl_cb_ident)
 | 
						if (clp->cl_cb_ident)
 | 
				
			||||||
		idr_remove(&cb_ident_idr, clp->cl_cb_ident);
 | 
							idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pnfs_init_server(struct nfs_server *server)
 | 
					static void pnfs_init_server(struct nfs_server *server)
 | 
				
			||||||
| 
						 | 
					@ -261,7 +270,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_cleanup_cb_ident_idr(void)
 | 
					void nfs_cleanup_cb_ident_idr(struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -293,10 +302,10 @@ static void nfs_free_client(struct nfs_client *clp)
 | 
				
			||||||
	if (clp->cl_machine_cred != NULL)
 | 
						if (clp->cl_machine_cred != NULL)
 | 
				
			||||||
		put_rpccred(clp->cl_machine_cred);
 | 
							put_rpccred(clp->cl_machine_cred);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nfs4_deviceid_purge_client(clp);
 | 
						put_net(clp->net);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	kfree(clp->cl_hostname);
 | 
						kfree(clp->cl_hostname);
 | 
				
			||||||
	kfree(clp->server_scope);
 | 
						kfree(clp->server_scope);
 | 
				
			||||||
 | 
						kfree(clp->impl_id);
 | 
				
			||||||
	kfree(clp);
 | 
						kfree(clp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("<-- nfs_free_client()\n");
 | 
						dprintk("<-- nfs_free_client()\n");
 | 
				
			||||||
| 
						 | 
					@ -307,15 +316,18 @@ static void nfs_free_client(struct nfs_client *clp)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void nfs_put_client(struct nfs_client *clp)
 | 
					void nfs_put_client(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!clp)
 | 
						if (!clp)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
 | 
						dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
 | 
				
			||||||
 | 
						nn = net_generic(clp->net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {
 | 
						if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {
 | 
				
			||||||
		list_del(&clp->cl_share_link);
 | 
							list_del(&clp->cl_share_link);
 | 
				
			||||||
		nfs_cb_idr_remove_locked(clp);
 | 
							nfs_cb_idr_remove_locked(clp);
 | 
				
			||||||
		spin_unlock(&nfs_client_lock);
 | 
							spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		BUG_ON(!list_empty(&clp->cl_superblocks));
 | 
							BUG_ON(!list_empty(&clp->cl_superblocks));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -393,6 +405,7 @@ static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
 | 
				
			||||||
		(sin1->sin_port == sin2->sin_port);
 | 
							(sin1->sin_port == sin2->sin_port);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(CONFIG_NFS_V4_1)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Test if two socket addresses represent the same actual socket,
 | 
					 * Test if two socket addresses represent the same actual socket,
 | 
				
			||||||
 * by comparing (only) relevant fields, excluding the port number.
 | 
					 * by comparing (only) relevant fields, excluding the port number.
 | 
				
			||||||
| 
						 | 
					@ -411,6 +424,7 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif /* CONFIG_NFS_V4_1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Test if two socket addresses represent the same actual socket,
 | 
					 * Test if two socket addresses represent the same actual socket,
 | 
				
			||||||
| 
						 | 
					@ -431,10 +445,10 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(CONFIG_NFS_V4_1)
 | 
				
			||||||
/* Common match routine for v4.0 and v4.1 callback services */
 | 
					/* Common match routine for v4.0 and v4.1 callback services */
 | 
				
			||||||
bool
 | 
					static bool nfs4_cb_match_client(const struct sockaddr *addr,
 | 
				
			||||||
nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp,
 | 
							struct nfs_client *clp, u32 minorversion)
 | 
				
			||||||
		     u32 minorversion)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
 | 
						struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -454,6 +468,7 @@ nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif /* CONFIG_NFS_V4_1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Find an nfs_client on the list that matches the initialisation data
 | 
					 * Find an nfs_client on the list that matches the initialisation data
 | 
				
			||||||
| 
						 | 
					@ -463,8 +478,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client *clp;
 | 
						struct nfs_client *clp;
 | 
				
			||||||
	const struct sockaddr *sap = data->addr;
 | 
						const struct sockaddr *sap = data->addr;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(data->net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
 | 
						list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
 | 
				
			||||||
	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
 | 
						        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
 | 
				
			||||||
		/* Don't match clients that failed to initialise properly */
 | 
							/* Don't match clients that failed to initialise properly */
 | 
				
			||||||
		if (clp->cl_cons_state < 0)
 | 
							if (clp->cl_cons_state < 0)
 | 
				
			||||||
| 
						 | 
					@ -502,13 +518,14 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client *clp, *new = NULL;
 | 
						struct nfs_client *clp, *new = NULL;
 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("--> nfs_get_client(%s,v%u)\n",
 | 
						dprintk("--> nfs_get_client(%s,v%u)\n",
 | 
				
			||||||
		cl_init->hostname ?: "", cl_init->rpc_ops->version);
 | 
							cl_init->hostname ?: "", cl_init->rpc_ops->version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* see if the client already exists */
 | 
						/* see if the client already exists */
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		spin_lock(&nfs_client_lock);
 | 
							spin_lock(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		clp = nfs_match_client(cl_init);
 | 
							clp = nfs_match_client(cl_init);
 | 
				
			||||||
		if (clp)
 | 
							if (clp)
 | 
				
			||||||
| 
						 | 
					@ -516,7 +533,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
 | 
				
			||||||
		if (new)
 | 
							if (new)
 | 
				
			||||||
			goto install_client;
 | 
								goto install_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		spin_unlock(&nfs_client_lock);
 | 
							spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		new = nfs_alloc_client(cl_init);
 | 
							new = nfs_alloc_client(cl_init);
 | 
				
			||||||
	} while (!IS_ERR(new));
 | 
						} while (!IS_ERR(new));
 | 
				
			||||||
| 
						 | 
					@ -527,8 +544,8 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
 | 
				
			||||||
	/* install a new client and return with it unready */
 | 
						/* install a new client and return with it unready */
 | 
				
			||||||
install_client:
 | 
					install_client:
 | 
				
			||||||
	clp = new;
 | 
						clp = new;
 | 
				
			||||||
	list_add(&clp->cl_share_link, &nfs_client_list);
 | 
						list_add(&clp->cl_share_link, &nn->nfs_client_list);
 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,
 | 
						error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,
 | 
				
			||||||
					      authflavour, noresvport);
 | 
										      authflavour, noresvport);
 | 
				
			||||||
| 
						 | 
					@ -543,7 +560,7 @@ install_client:
 | 
				
			||||||
	 * - make sure it's ready before returning
 | 
						 * - make sure it's ready before returning
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
found_client:
 | 
					found_client:
 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (new)
 | 
						if (new)
 | 
				
			||||||
		nfs_free_client(new);
 | 
							nfs_free_client(new);
 | 
				
			||||||
| 
						 | 
					@ -643,7 +660,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_clnt		*clnt = NULL;
 | 
						struct rpc_clnt		*clnt = NULL;
 | 
				
			||||||
	struct rpc_create_args args = {
 | 
						struct rpc_create_args args = {
 | 
				
			||||||
		.net		= &init_net,
 | 
							.net		= clp->net,
 | 
				
			||||||
		.protocol	= clp->cl_proto,
 | 
							.protocol	= clp->cl_proto,
 | 
				
			||||||
		.address	= (struct sockaddr *)&clp->cl_addr,
 | 
							.address	= (struct sockaddr *)&clp->cl_addr,
 | 
				
			||||||
		.addrsize	= clp->cl_addrlen,
 | 
							.addrsize	= clp->cl_addrlen,
 | 
				
			||||||
| 
						 | 
					@ -697,6 +714,7 @@ static int nfs_start_lockd(struct nfs_server *server)
 | 
				
			||||||
		.nfs_version	= clp->rpc_ops->version,
 | 
							.nfs_version	= clp->rpc_ops->version,
 | 
				
			||||||
		.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?
 | 
							.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?
 | 
				
			||||||
					1 : 0,
 | 
										1 : 0,
 | 
				
			||||||
 | 
							.net		= clp->net,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nlm_init.nfs_version > 3)
 | 
						if (nlm_init.nfs_version > 3)
 | 
				
			||||||
| 
						 | 
					@ -832,6 +850,7 @@ static int nfs_init_server(struct nfs_server *server,
 | 
				
			||||||
		.addrlen = data->nfs_server.addrlen,
 | 
							.addrlen = data->nfs_server.addrlen,
 | 
				
			||||||
		.rpc_ops = &nfs_v2_clientops,
 | 
							.rpc_ops = &nfs_v2_clientops,
 | 
				
			||||||
		.proto = data->nfs_server.protocol,
 | 
							.proto = data->nfs_server.protocol,
 | 
				
			||||||
 | 
							.net = data->net,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct rpc_timeout timeparms;
 | 
						struct rpc_timeout timeparms;
 | 
				
			||||||
	struct nfs_client *clp;
 | 
						struct nfs_client *clp;
 | 
				
			||||||
| 
						 | 
					@ -1030,25 +1049,30 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve
 | 
				
			||||||
static void nfs_server_insert_lists(struct nfs_server *server)
 | 
					static void nfs_server_insert_lists(struct nfs_server *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client *clp = server->nfs_client;
 | 
						struct nfs_client *clp = server->nfs_client;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&nfs_client_lock);
 | 
						spin_lock(&nn->nfs_client_lock);
 | 
				
			||||||
	list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
 | 
						list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
 | 
				
			||||||
	list_add_tail(&server->master_link, &nfs_volume_list);
 | 
						list_add_tail(&server->master_link, &nn->nfs_volume_list);
 | 
				
			||||||
	clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
 | 
						clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfs_server_remove_lists(struct nfs_server *server)
 | 
					static void nfs_server_remove_lists(struct nfs_server *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client *clp = server->nfs_client;
 | 
						struct nfs_client *clp = server->nfs_client;
 | 
				
			||||||
 | 
						struct nfs_net *nn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&nfs_client_lock);
 | 
						if (clp == NULL)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						nn = net_generic(clp->net, nfs_net_id);
 | 
				
			||||||
 | 
						spin_lock(&nn->nfs_client_lock);
 | 
				
			||||||
	list_del_rcu(&server->client_link);
 | 
						list_del_rcu(&server->client_link);
 | 
				
			||||||
	if (clp && list_empty(&clp->cl_superblocks))
 | 
						if (list_empty(&clp->cl_superblocks))
 | 
				
			||||||
		set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
 | 
							set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
 | 
				
			||||||
	list_del(&server->master_link);
 | 
						list_del(&server->master_link);
 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	synchronize_rcu();
 | 
						synchronize_rcu();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1087,6 +1111,8 @@ static struct nfs_server *nfs_alloc_server(void)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ida_init(&server->openowner_id);
 | 
				
			||||||
 | 
						ida_init(&server->lockowner_id);
 | 
				
			||||||
	pnfs_init_server(server);
 | 
						pnfs_init_server(server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return server;
 | 
						return server;
 | 
				
			||||||
| 
						 | 
					@ -1112,6 +1138,8 @@ void nfs_free_server(struct nfs_server *server)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nfs_put_client(server->nfs_client);
 | 
						nfs_put_client(server->nfs_client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ida_destroy(&server->lockowner_id);
 | 
				
			||||||
 | 
						ida_destroy(&server->openowner_id);
 | 
				
			||||||
	nfs_free_iostats(server->io_stats);
 | 
						nfs_free_iostats(server->io_stats);
 | 
				
			||||||
	bdi_destroy(&server->backing_dev_info);
 | 
						bdi_destroy(&server->backing_dev_info);
 | 
				
			||||||
	kfree(server);
 | 
						kfree(server);
 | 
				
			||||||
| 
						 | 
					@ -1187,48 +1215,22 @@ error:
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_NFS_V4
 | 
					#ifdef CONFIG_NFS_V4
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * NFSv4.0 callback thread helper
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Find a client by IP address, protocol version, and minorversion
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Called from the pg_authenticate method. The callback identifier
 | 
					 | 
				
			||||||
 * is not used as it has not been decoded.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns NULL if no such client
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct nfs_client *
 | 
					 | 
				
			||||||
nfs4_find_client_no_ident(const struct sockaddr *addr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nfs_client *clp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spin_lock(&nfs_client_lock);
 | 
					 | 
				
			||||||
	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
 | 
					 | 
				
			||||||
		if (nfs4_cb_match_client(addr, clp, 0) == false)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		atomic_inc(&clp->cl_count);
 | 
					 | 
				
			||||||
		spin_unlock(&nfs_client_lock);
 | 
					 | 
				
			||||||
		return clp;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * NFSv4.0 callback thread helper
 | 
					 * NFSv4.0 callback thread helper
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Find a client by callback identifier
 | 
					 * Find a client by callback identifier
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct nfs_client *
 | 
					struct nfs_client *
 | 
				
			||||||
nfs4_find_client_ident(int cb_ident)
 | 
					nfs4_find_client_ident(struct net *net, int cb_ident)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client *clp;
 | 
						struct nfs_client *clp;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&nfs_client_lock);
 | 
						spin_lock(&nn->nfs_client_lock);
 | 
				
			||||||
	clp = idr_find(&cb_ident_idr, cb_ident);
 | 
						clp = idr_find(&nn->cb_ident_idr, cb_ident);
 | 
				
			||||||
	if (clp)
 | 
						if (clp)
 | 
				
			||||||
		atomic_inc(&clp->cl_count);
 | 
							atomic_inc(&clp->cl_count);
 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
	return clp;
 | 
						return clp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1241,13 +1243,14 @@ nfs4_find_client_ident(int cb_ident)
 | 
				
			||||||
 * Returns NULL if no such client
 | 
					 * Returns NULL if no such client
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct nfs_client *
 | 
					struct nfs_client *
 | 
				
			||||||
nfs4_find_client_sessionid(const struct sockaddr *addr,
 | 
					nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
 | 
				
			||||||
			   struct nfs4_sessionid *sid)
 | 
								   struct nfs4_sessionid *sid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client *clp;
 | 
						struct nfs_client *clp;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&nfs_client_lock);
 | 
						spin_lock(&nn->nfs_client_lock);
 | 
				
			||||||
	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
 | 
						list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
 | 
				
			||||||
		if (nfs4_cb_match_client(addr, clp, 1) == false)
 | 
							if (nfs4_cb_match_client(addr, clp, 1) == false)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1260,17 +1263,17 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		atomic_inc(&clp->cl_count);
 | 
							atomic_inc(&clp->cl_count);
 | 
				
			||||||
		spin_unlock(&nfs_client_lock);
 | 
							spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
		return clp;
 | 
							return clp;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else /* CONFIG_NFS_V4_1 */
 | 
					#else /* CONFIG_NFS_V4_1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs_client *
 | 
					struct nfs_client *
 | 
				
			||||||
nfs4_find_client_sessionid(const struct sockaddr *addr,
 | 
					nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
 | 
				
			||||||
			   struct nfs4_sessionid *sid)
 | 
								   struct nfs4_sessionid *sid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
| 
						 | 
					@ -1285,16 +1288,18 @@ static int nfs4_init_callback(struct nfs_client *clp)
 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (clp->rpc_ops->version == 4) {
 | 
						if (clp->rpc_ops->version == 4) {
 | 
				
			||||||
 | 
							struct rpc_xprt *xprt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (nfs4_has_session(clp)) {
 | 
							if (nfs4_has_session(clp)) {
 | 
				
			||||||
			error = xprt_setup_backchannel(
 | 
								error = xprt_setup_backchannel(xprt,
 | 
				
			||||||
						clp->cl_rpcclient->cl_xprt,
 | 
					 | 
				
			||||||
						NFS41_BC_MIN_CALLBACKS);
 | 
											NFS41_BC_MIN_CALLBACKS);
 | 
				
			||||||
			if (error < 0)
 | 
								if (error < 0)
 | 
				
			||||||
				return error;
 | 
									return error;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		error = nfs_callback_up(clp->cl_mvops->minor_version,
 | 
							error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
 | 
				
			||||||
					clp->cl_rpcclient->cl_xprt);
 | 
					 | 
				
			||||||
		if (error < 0) {
 | 
							if (error < 0) {
 | 
				
			||||||
			dprintk("%s: failed to start callback. Error = %d\n",
 | 
								dprintk("%s: failed to start callback. Error = %d\n",
 | 
				
			||||||
				__func__, error);
 | 
									__func__, error);
 | 
				
			||||||
| 
						 | 
					@ -1345,6 +1350,7 @@ int nfs4_init_client(struct nfs_client *clp,
 | 
				
			||||||
		     rpc_authflavor_t authflavour,
 | 
							     rpc_authflavor_t authflavour,
 | 
				
			||||||
		     int noresvport)
 | 
							     int noresvport)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						char buf[INET6_ADDRSTRLEN + 1];
 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (clp->cl_cons_state == NFS_CS_READY) {
 | 
						if (clp->cl_cons_state == NFS_CS_READY) {
 | 
				
			||||||
| 
						 | 
					@ -1360,6 +1366,20 @@ int nfs4_init_client(struct nfs_client *clp,
 | 
				
			||||||
				      1, noresvport);
 | 
									      1, noresvport);
 | 
				
			||||||
	if (error < 0)
 | 
						if (error < 0)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If no clientaddr= option was specified, find a usable cb address */
 | 
				
			||||||
 | 
						if (ip_addr == NULL) {
 | 
				
			||||||
 | 
							struct sockaddr_storage cb_addr;
 | 
				
			||||||
 | 
							struct sockaddr *sap = (struct sockaddr *)&cb_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
 | 
				
			||||||
 | 
							if (error < 0)
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							error = rpc_ntop(sap, buf, sizeof(buf));
 | 
				
			||||||
 | 
							if (error < 0)
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							ip_addr = (const char *)buf;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
 | 
						strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = nfs_idmap_new(clp);
 | 
						error = nfs_idmap_new(clp);
 | 
				
			||||||
| 
						 | 
					@ -1394,7 +1414,7 @@ static int nfs4_set_client(struct nfs_server *server,
 | 
				
			||||||
		const char *ip_addr,
 | 
							const char *ip_addr,
 | 
				
			||||||
		rpc_authflavor_t authflavour,
 | 
							rpc_authflavor_t authflavour,
 | 
				
			||||||
		int proto, const struct rpc_timeout *timeparms,
 | 
							int proto, const struct rpc_timeout *timeparms,
 | 
				
			||||||
		u32 minorversion)
 | 
							u32 minorversion, struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client_initdata cl_init = {
 | 
						struct nfs_client_initdata cl_init = {
 | 
				
			||||||
		.hostname = hostname,
 | 
							.hostname = hostname,
 | 
				
			||||||
| 
						 | 
					@ -1403,6 +1423,7 @@ static int nfs4_set_client(struct nfs_server *server,
 | 
				
			||||||
		.rpc_ops = &nfs_v4_clientops,
 | 
							.rpc_ops = &nfs_v4_clientops,
 | 
				
			||||||
		.proto = proto,
 | 
							.proto = proto,
 | 
				
			||||||
		.minorversion = minorversion,
 | 
							.minorversion = minorversion,
 | 
				
			||||||
 | 
							.net = net,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct nfs_client *clp;
 | 
						struct nfs_client *clp;
 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
| 
						 | 
					@ -1454,6 +1475,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
 | 
				
			||||||
		.rpc_ops = &nfs_v4_clientops,
 | 
							.rpc_ops = &nfs_v4_clientops,
 | 
				
			||||||
		.proto = ds_proto,
 | 
							.proto = ds_proto,
 | 
				
			||||||
		.minorversion = mds_clp->cl_minorversion,
 | 
							.minorversion = mds_clp->cl_minorversion,
 | 
				
			||||||
 | 
							.net = mds_clp->net,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct rpc_timeout ds_timeout = {
 | 
						struct rpc_timeout ds_timeout = {
 | 
				
			||||||
		.to_initval = 15 * HZ,
 | 
							.to_initval = 15 * HZ,
 | 
				
			||||||
| 
						 | 
					@ -1581,7 +1603,8 @@ static int nfs4_init_server(struct nfs_server *server,
 | 
				
			||||||
			data->auth_flavors[0],
 | 
								data->auth_flavors[0],
 | 
				
			||||||
			data->nfs_server.protocol,
 | 
								data->nfs_server.protocol,
 | 
				
			||||||
			&timeparms,
 | 
								&timeparms,
 | 
				
			||||||
			data->minorversion);
 | 
								data->minorversion,
 | 
				
			||||||
 | 
								data->net);
 | 
				
			||||||
	if (error < 0)
 | 
						if (error < 0)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1676,9 +1699,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
 | 
				
			||||||
				data->addrlen,
 | 
									data->addrlen,
 | 
				
			||||||
				parent_client->cl_ipaddr,
 | 
									parent_client->cl_ipaddr,
 | 
				
			||||||
				data->authflavor,
 | 
									data->authflavor,
 | 
				
			||||||
				parent_server->client->cl_xprt->prot,
 | 
									rpc_protocol(parent_server->client),
 | 
				
			||||||
				parent_server->client->cl_timeout,
 | 
									parent_server->client->cl_timeout,
 | 
				
			||||||
				parent_client->cl_mvops->minor_version);
 | 
									parent_client->cl_mvops->minor_version,
 | 
				
			||||||
 | 
									parent_client->net);
 | 
				
			||||||
	if (error < 0)
 | 
						if (error < 0)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1771,6 +1795,18 @@ out_free_server:
 | 
				
			||||||
	return ERR_PTR(error);
 | 
						return ERR_PTR(error);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void nfs_clients_init(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&nn->nfs_client_list);
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&nn->nfs_volume_list);
 | 
				
			||||||
 | 
					#ifdef CONFIG_NFS_V4
 | 
				
			||||||
 | 
						idr_init(&nn->cb_ident_idr);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						spin_lock_init(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PROC_FS
 | 
					#ifdef CONFIG_PROC_FS
 | 
				
			||||||
static struct proc_dir_entry *proc_fs_nfs;
 | 
					static struct proc_dir_entry *proc_fs_nfs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1824,13 +1860,15 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct seq_file *m;
 | 
						struct seq_file *m;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
						struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
 | 
				
			||||||
 | 
						struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = seq_open(file, &nfs_server_list_ops);
 | 
						ret = seq_open(file, &nfs_server_list_ops);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m = file->private_data;
 | 
						m = file->private_data;
 | 
				
			||||||
	m->private = PDE(inode)->data;
 | 
						m->private = net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1840,9 +1878,11 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
 | 
					static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(m->private, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* lock the list against modification */
 | 
						/* lock the list against modification */
 | 
				
			||||||
	spin_lock(&nfs_client_lock);
 | 
						spin_lock(&nn->nfs_client_lock);
 | 
				
			||||||
	return seq_list_start_head(&nfs_client_list, *_pos);
 | 
						return seq_list_start_head(&nn->nfs_client_list, *_pos);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1850,7 +1890,9 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
 | 
					static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return seq_list_next(v, &nfs_client_list, pos);
 | 
						struct nfs_net *nn = net_generic(p->private, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return seq_list_next(v, &nn->nfs_client_list, pos);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1858,7 +1900,9 @@ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void nfs_server_list_stop(struct seq_file *p, void *v)
 | 
					static void nfs_server_list_stop(struct seq_file *p, void *v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
						struct nfs_net *nn = net_generic(p->private, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1867,9 +1911,10 @@ static void nfs_server_list_stop(struct seq_file *p, void *v)
 | 
				
			||||||
static int nfs_server_list_show(struct seq_file *m, void *v)
 | 
					static int nfs_server_list_show(struct seq_file *m, void *v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client *clp;
 | 
						struct nfs_client *clp;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(m->private, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* display header on line 1 */
 | 
						/* display header on line 1 */
 | 
				
			||||||
	if (v == &nfs_client_list) {
 | 
						if (v == &nn->nfs_client_list) {
 | 
				
			||||||
		seq_puts(m, "NV SERVER   PORT USE HOSTNAME\n");
 | 
							seq_puts(m, "NV SERVER   PORT USE HOSTNAME\n");
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1881,12 +1926,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v)
 | 
				
			||||||
	if (clp->cl_cons_state != NFS_CS_READY)
 | 
						if (clp->cl_cons_state != NFS_CS_READY)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
	seq_printf(m, "v%u %s %s %3d %s\n",
 | 
						seq_printf(m, "v%u %s %s %3d %s\n",
 | 
				
			||||||
		   clp->rpc_ops->version,
 | 
							   clp->rpc_ops->version,
 | 
				
			||||||
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
 | 
							   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
 | 
				
			||||||
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
 | 
							   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
 | 
				
			||||||
		   atomic_read(&clp->cl_count),
 | 
							   atomic_read(&clp->cl_count),
 | 
				
			||||||
		   clp->cl_hostname);
 | 
							   clp->cl_hostname);
 | 
				
			||||||
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1898,13 +1945,15 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct seq_file *m;
 | 
						struct seq_file *m;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
						struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
 | 
				
			||||||
 | 
						struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = seq_open(file, &nfs_volume_list_ops);
 | 
						ret = seq_open(file, &nfs_volume_list_ops);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m = file->private_data;
 | 
						m = file->private_data;
 | 
				
			||||||
	m->private = PDE(inode)->data;
 | 
						m->private = net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1914,9 +1963,11 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
 | 
					static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(m->private, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* lock the list against modification */
 | 
						/* lock the list against modification */
 | 
				
			||||||
	spin_lock(&nfs_client_lock);
 | 
						spin_lock(&nn->nfs_client_lock);
 | 
				
			||||||
	return seq_list_start_head(&nfs_volume_list, *_pos);
 | 
						return seq_list_start_head(&nn->nfs_volume_list, *_pos);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1924,7 +1975,9 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
 | 
					static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return seq_list_next(v, &nfs_volume_list, pos);
 | 
						struct nfs_net *nn = net_generic(p->private, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return seq_list_next(v, &nn->nfs_volume_list, pos);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1932,7 +1985,9 @@ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void nfs_volume_list_stop(struct seq_file *p, void *v)
 | 
					static void nfs_volume_list_stop(struct seq_file *p, void *v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	spin_unlock(&nfs_client_lock);
 | 
						struct nfs_net *nn = net_generic(p->private, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1943,9 +1998,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
 | 
				
			||||||
	struct nfs_server *server;
 | 
						struct nfs_server *server;
 | 
				
			||||||
	struct nfs_client *clp;
 | 
						struct nfs_client *clp;
 | 
				
			||||||
	char dev[8], fsid[17];
 | 
						char dev[8], fsid[17];
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(m->private, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* display header on line 1 */
 | 
						/* display header on line 1 */
 | 
				
			||||||
	if (v == &nfs_volume_list) {
 | 
						if (v == &nn->nfs_volume_list) {
 | 
				
			||||||
		seq_puts(m, "NV SERVER   PORT DEV     FSID              FSC\n");
 | 
							seq_puts(m, "NV SERVER   PORT DEV     FSID              FSC\n");
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1960,6 +2016,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
 | 
				
			||||||
		 (unsigned long long) server->fsid.major,
 | 
							 (unsigned long long) server->fsid.major,
 | 
				
			||||||
		 (unsigned long long) server->fsid.minor);
 | 
							 (unsigned long long) server->fsid.minor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
	seq_printf(m, "v%u %s %s %-7s %-17s %s\n",
 | 
						seq_printf(m, "v%u %s %s %-7s %-17s %s\n",
 | 
				
			||||||
		   clp->rpc_ops->version,
 | 
							   clp->rpc_ops->version,
 | 
				
			||||||
		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
 | 
							   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
 | 
				
			||||||
| 
						 | 
					@ -1967,6 +2024,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
 | 
				
			||||||
		   dev,
 | 
							   dev,
 | 
				
			||||||
		   fsid,
 | 
							   fsid,
 | 
				
			||||||
		   nfs_server_fscache_state(server));
 | 
							   nfs_server_fscache_state(server));
 | 
				
			||||||
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,7 +105,7 @@ again:
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
 | 
							if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
 | 
							if (!nfs4_stateid_match(&state->stateid, stateid))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		get_nfs_open_context(ctx);
 | 
							get_nfs_open_context(ctx);
 | 
				
			||||||
		spin_unlock(&inode->i_lock);
 | 
							spin_unlock(&inode->i_lock);
 | 
				
			||||||
| 
						 | 
					@ -139,8 +139,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
 | 
				
			||||||
	if (delegation != NULL) {
 | 
						if (delegation != NULL) {
 | 
				
			||||||
		spin_lock(&delegation->lock);
 | 
							spin_lock(&delegation->lock);
 | 
				
			||||||
		if (delegation->inode != NULL) {
 | 
							if (delegation->inode != NULL) {
 | 
				
			||||||
			memcpy(delegation->stateid.data, res->delegation.data,
 | 
								nfs4_stateid_copy(&delegation->stateid, &res->delegation);
 | 
				
			||||||
			       sizeof(delegation->stateid.data));
 | 
					 | 
				
			||||||
			delegation->type = res->delegation_type;
 | 
								delegation->type = res->delegation_type;
 | 
				
			||||||
			delegation->maxsize = res->maxsize;
 | 
								delegation->maxsize = res->maxsize;
 | 
				
			||||||
			oldcred = delegation->cred;
 | 
								oldcred = delegation->cred;
 | 
				
			||||||
| 
						 | 
					@ -236,8 +235,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
 | 
				
			||||||
	delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
 | 
						delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
 | 
				
			||||||
	if (delegation == NULL)
 | 
						if (delegation == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	memcpy(delegation->stateid.data, res->delegation.data,
 | 
						nfs4_stateid_copy(&delegation->stateid, &res->delegation);
 | 
				
			||||||
			sizeof(delegation->stateid.data));
 | 
					 | 
				
			||||||
	delegation->type = res->delegation_type;
 | 
						delegation->type = res->delegation_type;
 | 
				
			||||||
	delegation->maxsize = res->maxsize;
 | 
						delegation->maxsize = res->maxsize;
 | 
				
			||||||
	delegation->change_attr = inode->i_version;
 | 
						delegation->change_attr = inode->i_version;
 | 
				
			||||||
| 
						 | 
					@ -250,19 +248,22 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
 | 
				
			||||||
	old_delegation = rcu_dereference_protected(nfsi->delegation,
 | 
						old_delegation = rcu_dereference_protected(nfsi->delegation,
 | 
				
			||||||
					lockdep_is_held(&clp->cl_lock));
 | 
										lockdep_is_held(&clp->cl_lock));
 | 
				
			||||||
	if (old_delegation != NULL) {
 | 
						if (old_delegation != NULL) {
 | 
				
			||||||
		if (memcmp(&delegation->stateid, &old_delegation->stateid,
 | 
							if (nfs4_stateid_match(&delegation->stateid,
 | 
				
			||||||
					sizeof(old_delegation->stateid)) == 0 &&
 | 
										&old_delegation->stateid) &&
 | 
				
			||||||
				delegation->type == old_delegation->type) {
 | 
									delegation->type == old_delegation->type) {
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Deal with broken servers that hand out two
 | 
							 * Deal with broken servers that hand out two
 | 
				
			||||||
		 * delegations for the same file.
 | 
							 * delegations for the same file.
 | 
				
			||||||
 | 
							 * Allow for upgrades to a WRITE delegation, but
 | 
				
			||||||
 | 
							 * nothing else.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		dfprintk(FILE, "%s: server %s handed out "
 | 
							dfprintk(FILE, "%s: server %s handed out "
 | 
				
			||||||
				"a duplicate delegation!\n",
 | 
									"a duplicate delegation!\n",
 | 
				
			||||||
				__func__, clp->cl_hostname);
 | 
									__func__, clp->cl_hostname);
 | 
				
			||||||
		if (delegation->type <= old_delegation->type) {
 | 
							if (delegation->type == old_delegation->type ||
 | 
				
			||||||
 | 
							    !(delegation->type & FMODE_WRITE)) {
 | 
				
			||||||
			freeme = delegation;
 | 
								freeme = delegation;
 | 
				
			||||||
			delegation = NULL;
 | 
								delegation = NULL;
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
| 
						 | 
					@ -455,17 +456,24 @@ static void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp,
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void nfs_delegation_run_state_manager(struct nfs_client *clp)
 | 
					static void nfs_delegation_run_state_manager(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
 | 
						if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
 | 
				
			||||||
		nfs4_schedule_state_manager(clp);
 | 
							nfs4_schedule_state_manager(clp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void nfs_remove_bad_delegation(struct inode *inode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_delegation *delegation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode));
 | 
				
			||||||
 | 
						if (delegation) {
 | 
				
			||||||
 | 
							nfs_inode_find_state_and_recover(inode, &delegation->stateid);
 | 
				
			||||||
 | 
							nfs_free_delegation(delegation);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * nfs_expire_all_delegation_types
 | 
					 * nfs_expire_all_delegation_types
 | 
				
			||||||
 * @clp: client to process
 | 
					 * @clp: client to process
 | 
				
			||||||
| 
						 | 
					@ -488,18 +496,6 @@ void nfs_expire_all_delegations(struct nfs_client *clp)
 | 
				
			||||||
	nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
 | 
						nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * nfs_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
 | 
					 | 
				
			||||||
 * @clp: client to process
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void nfs_handle_cb_pathdown(struct nfs_client *clp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (clp == NULL)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	nfs_client_mark_return_all_delegations(clp);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
 | 
					static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_delegation *delegation;
 | 
						struct nfs_delegation *delegation;
 | 
				
			||||||
| 
						 | 
					@ -531,7 +527,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * nfs_async_inode_return_delegation - asynchronously return a delegation
 | 
					 * nfs_async_inode_return_delegation - asynchronously return a delegation
 | 
				
			||||||
 * @inode: inode to process
 | 
					 * @inode: inode to process
 | 
				
			||||||
 * @stateid: state ID information from CB_RECALL arguments
 | 
					 * @stateid: state ID information
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns zero on success, or a negative errno value.
 | 
					 * Returns zero on success, or a negative errno value.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -545,7 +541,7 @@ int nfs_async_inode_return_delegation(struct inode *inode,
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	delegation = rcu_dereference(NFS_I(inode)->delegation);
 | 
						delegation = rcu_dereference(NFS_I(inode)->delegation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!clp->cl_mvops->validate_stateid(delegation, stateid)) {
 | 
						if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
 | 
				
			||||||
		rcu_read_unlock();
 | 
							rcu_read_unlock();
 | 
				
			||||||
		return -ENOENT;
 | 
							return -ENOENT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -684,21 +680,25 @@ int nfs_delegations_present(struct nfs_client *clp)
 | 
				
			||||||
 * nfs4_copy_delegation_stateid - Copy inode's state ID information
 | 
					 * nfs4_copy_delegation_stateid - Copy inode's state ID information
 | 
				
			||||||
 * @dst: stateid data structure to fill in
 | 
					 * @dst: stateid data structure to fill in
 | 
				
			||||||
 * @inode: inode to check
 | 
					 * @inode: inode to check
 | 
				
			||||||
 | 
					 * @flags: delegation type requirement
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns one and fills in "dst->data" * if inode had a delegation,
 | 
					 * Returns "true" and fills in "dst->data" * if inode had a delegation,
 | 
				
			||||||
 * otherwise zero is returned.
 | 
					 * otherwise "false" is returned.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
 | 
					bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
 | 
				
			||||||
 | 
							fmode_t flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_inode *nfsi = NFS_I(inode);
 | 
						struct nfs_inode *nfsi = NFS_I(inode);
 | 
				
			||||||
	struct nfs_delegation *delegation;
 | 
						struct nfs_delegation *delegation;
 | 
				
			||||||
	int ret = 0;
 | 
						bool ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						flags &= FMODE_READ|FMODE_WRITE;
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	delegation = rcu_dereference(nfsi->delegation);
 | 
						delegation = rcu_dereference(nfsi->delegation);
 | 
				
			||||||
	if (delegation != NULL) {
 | 
						ret = (delegation != NULL && (delegation->type & flags) == flags);
 | 
				
			||||||
		memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
 | 
						if (ret) {
 | 
				
			||||||
		ret = 1;
 | 
							nfs4_stateid_copy(dst, &delegation->stateid);
 | 
				
			||||||
 | 
							nfs_mark_delegation_referenced(delegation);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,9 +42,9 @@ void nfs_super_return_all_delegations(struct super_block *sb);
 | 
				
			||||||
void nfs_expire_all_delegations(struct nfs_client *clp);
 | 
					void nfs_expire_all_delegations(struct nfs_client *clp);
 | 
				
			||||||
void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags);
 | 
					void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags);
 | 
				
			||||||
void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
 | 
					void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
 | 
				
			||||||
void nfs_handle_cb_pathdown(struct nfs_client *clp);
 | 
					 | 
				
			||||||
int nfs_client_return_marked_delegations(struct nfs_client *clp);
 | 
					int nfs_client_return_marked_delegations(struct nfs_client *clp);
 | 
				
			||||||
int nfs_delegations_present(struct nfs_client *clp);
 | 
					int nfs_delegations_present(struct nfs_client *clp);
 | 
				
			||||||
 | 
					void nfs_remove_bad_delegation(struct inode *inode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_delegation_mark_reclaim(struct nfs_client *clp);
 | 
					void nfs_delegation_mark_reclaim(struct nfs_client *clp);
 | 
				
			||||||
void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
 | 
					void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
 | 
				
			||||||
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync);
 | 
					int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync);
 | 
				
			||||||
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
 | 
					int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
 | 
				
			||||||
int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
 | 
					int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
 | 
				
			||||||
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
 | 
					bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
 | 
					void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
 | 
				
			||||||
int nfs_have_delegation(struct inode *inode, fmode_t flags);
 | 
					int nfs_have_delegation(struct inode *inode, fmode_t flags);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										27
									
								
								fs/nfs/dir.c
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								fs/nfs/dir.c
									
										
									
									
									
								
							| 
						 | 
					@ -207,7 +207,7 @@ struct nfs_cache_array_entry {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs_cache_array {
 | 
					struct nfs_cache_array {
 | 
				
			||||||
	unsigned int size;
 | 
						int size;
 | 
				
			||||||
	int eof_index;
 | 
						int eof_index;
 | 
				
			||||||
	u64 last_cookie;
 | 
						u64 last_cookie;
 | 
				
			||||||
	struct nfs_cache_array_entry array[0];
 | 
						struct nfs_cache_array_entry array[0];
 | 
				
			||||||
| 
						 | 
					@ -1429,6 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	open_flags = nd->intent.open.flags;
 | 
						open_flags = nd->intent.open.flags;
 | 
				
			||||||
 | 
						attr.ia_valid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx = create_nfs_open_context(dentry, open_flags);
 | 
						ctx = create_nfs_open_context(dentry, open_flags);
 | 
				
			||||||
	res = ERR_CAST(ctx);
 | 
						res = ERR_CAST(ctx);
 | 
				
			||||||
| 
						 | 
					@ -1437,11 +1438,14 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nd->flags & LOOKUP_CREATE) {
 | 
						if (nd->flags & LOOKUP_CREATE) {
 | 
				
			||||||
		attr.ia_mode = nd->intent.open.create_mode;
 | 
							attr.ia_mode = nd->intent.open.create_mode;
 | 
				
			||||||
		attr.ia_valid = ATTR_MODE;
 | 
							attr.ia_valid |= ATTR_MODE;
 | 
				
			||||||
		attr.ia_mode &= ~current_umask();
 | 
							attr.ia_mode &= ~current_umask();
 | 
				
			||||||
	} else {
 | 
						} else
 | 
				
			||||||
		open_flags &= ~(O_EXCL | O_CREAT);
 | 
							open_flags &= ~(O_EXCL | O_CREAT);
 | 
				
			||||||
		attr.ia_valid = 0;
 | 
					
 | 
				
			||||||
 | 
						if (open_flags & O_TRUNC) {
 | 
				
			||||||
 | 
							attr.ia_valid |= ATTR_SIZE;
 | 
				
			||||||
 | 
							attr.ia_size = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Open the file on the server */
 | 
						/* Open the file on the server */
 | 
				
			||||||
| 
						 | 
					@ -1495,6 +1499,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
 | 
				
			||||||
	struct inode *inode;
 | 
						struct inode *inode;
 | 
				
			||||||
	struct inode *dir;
 | 
						struct inode *dir;
 | 
				
			||||||
	struct nfs_open_context *ctx;
 | 
						struct nfs_open_context *ctx;
 | 
				
			||||||
 | 
						struct iattr attr;
 | 
				
			||||||
	int openflags, ret = 0;
 | 
						int openflags, ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nd->flags & LOOKUP_RCU)
 | 
						if (nd->flags & LOOKUP_RCU)
 | 
				
			||||||
| 
						 | 
					@ -1523,19 +1528,27 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
 | 
				
			||||||
	/* We cannot do exclusive creation on a positive dentry */
 | 
						/* We cannot do exclusive creation on a positive dentry */
 | 
				
			||||||
	if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
 | 
						if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
 | 
				
			||||||
		goto no_open_dput;
 | 
							goto no_open_dput;
 | 
				
			||||||
	/* We can't create new files, or truncate existing ones here */
 | 
						/* We can't create new files here */
 | 
				
			||||||
	openflags &= ~(O_CREAT|O_EXCL|O_TRUNC);
 | 
						openflags &= ~(O_CREAT|O_EXCL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx = create_nfs_open_context(dentry, openflags);
 | 
						ctx = create_nfs_open_context(dentry, openflags);
 | 
				
			||||||
	ret = PTR_ERR(ctx);
 | 
						ret = PTR_ERR(ctx);
 | 
				
			||||||
	if (IS_ERR(ctx))
 | 
						if (IS_ERR(ctx))
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						attr.ia_valid = 0;
 | 
				
			||||||
 | 
						if (openflags & O_TRUNC) {
 | 
				
			||||||
 | 
							attr.ia_valid |= ATTR_SIZE;
 | 
				
			||||||
 | 
							attr.ia_size = 0;
 | 
				
			||||||
 | 
							nfs_wb_all(inode);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Note: we're not holding inode->i_mutex and so may be racing with
 | 
						 * Note: we're not holding inode->i_mutex and so may be racing with
 | 
				
			||||||
	 * operations that change the directory. We therefore save the
 | 
						 * operations that change the directory. We therefore save the
 | 
				
			||||||
	 * change attribute *before* we do the RPC call.
 | 
						 * change attribute *before* we do the RPC call.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL);
 | 
						inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
 | 
				
			||||||
	if (IS_ERR(inode)) {
 | 
						if (IS_ERR(inode)) {
 | 
				
			||||||
		ret = PTR_ERR(inode);
 | 
							ret = PTR_ERR(inode);
 | 
				
			||||||
		switch (ret) {
 | 
							switch (ret) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -265,9 +265,7 @@ static void nfs_direct_read_release(void *calldata)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_read_direct_ops = {
 | 
					static const struct rpc_call_ops nfs_read_direct_ops = {
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_read_prepare,
 | 
						.rpc_call_prepare = nfs_read_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
	.rpc_call_done = nfs_direct_read_result,
 | 
						.rpc_call_done = nfs_direct_read_result,
 | 
				
			||||||
	.rpc_release = nfs_direct_read_release,
 | 
						.rpc_release = nfs_direct_read_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -554,9 +552,7 @@ static void nfs_direct_commit_release(void *calldata)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_commit_direct_ops = {
 | 
					static const struct rpc_call_ops nfs_commit_direct_ops = {
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_write_prepare,
 | 
						.rpc_call_prepare = nfs_write_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
	.rpc_call_done = nfs_direct_commit_result,
 | 
						.rpc_call_done = nfs_direct_commit_result,
 | 
				
			||||||
	.rpc_release = nfs_direct_commit_release,
 | 
						.rpc_release = nfs_direct_commit_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -696,9 +692,7 @@ out_unlock:
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_write_direct_ops = {
 | 
					static const struct rpc_call_ops nfs_write_direct_ops = {
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_write_prepare,
 | 
						.rpc_call_prepare = nfs_write_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
	.rpc_call_done = nfs_direct_write_result,
 | 
						.rpc_call_done = nfs_direct_write_result,
 | 
				
			||||||
	.rpc_release = nfs_direct_write_release,
 | 
						.rpc_release = nfs_direct_write_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,8 +10,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/sunrpc/clnt.h>
 | 
					#include <linux/sunrpc/clnt.h>
 | 
				
			||||||
#include <linux/dns_resolver.h>
 | 
					#include <linux/dns_resolver.h>
 | 
				
			||||||
 | 
					#include "dns_resolve.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
 | 
					ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
 | 
				
			||||||
		struct sockaddr *sa, size_t salen)
 | 
							struct sockaddr *sa, size_t salen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t ret;
 | 
						ssize_t ret;
 | 
				
			||||||
| 
						 | 
					@ -20,7 +21,7 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL);
 | 
						ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL);
 | 
				
			||||||
	if (ip_len > 0)
 | 
						if (ip_len > 0)
 | 
				
			||||||
		ret = rpc_pton(ip_addr, ip_len, sa, salen);
 | 
							ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		ret = -ESRCH;
 | 
							ret = -ESRCH;
 | 
				
			||||||
	kfree(ip_addr);
 | 
						kfree(ip_addr);
 | 
				
			||||||
| 
						 | 
					@ -40,15 +41,15 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
 | 
				
			||||||
#include <linux/sunrpc/clnt.h>
 | 
					#include <linux/sunrpc/clnt.h>
 | 
				
			||||||
#include <linux/sunrpc/cache.h>
 | 
					#include <linux/sunrpc/cache.h>
 | 
				
			||||||
#include <linux/sunrpc/svcauth.h>
 | 
					#include <linux/sunrpc/svcauth.h>
 | 
				
			||||||
 | 
					#include <linux/sunrpc/rpc_pipe_fs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "dns_resolve.h"
 | 
					#include "dns_resolve.h"
 | 
				
			||||||
#include "cache_lib.h"
 | 
					#include "cache_lib.h"
 | 
				
			||||||
 | 
					#include "netns.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFS_DNS_HASHBITS 4
 | 
					#define NFS_DNS_HASHBITS 4
 | 
				
			||||||
#define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)
 | 
					#define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct nfs_dns_ent {
 | 
					struct nfs_dns_ent {
 | 
				
			||||||
	struct cache_head h;
 | 
						struct cache_head h;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -224,7 +225,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
 | 
				
			||||||
	len = qword_get(&buf, buf1, sizeof(buf1));
 | 
						len = qword_get(&buf, buf1, sizeof(buf1));
 | 
				
			||||||
	if (len <= 0)
 | 
						if (len <= 0)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	key.addrlen = rpc_pton(buf1, len,
 | 
						key.addrlen = rpc_pton(cd->net, buf1, len,
 | 
				
			||||||
			(struct sockaddr *)&key.addr,
 | 
								(struct sockaddr *)&key.addr,
 | 
				
			||||||
			sizeof(key.addr));
 | 
								sizeof(key.addr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -259,21 +260,6 @@ out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct cache_detail nfs_dns_resolve = {
 | 
					 | 
				
			||||||
	.owner = THIS_MODULE,
 | 
					 | 
				
			||||||
	.hash_size = NFS_DNS_HASHTBL_SIZE,
 | 
					 | 
				
			||||||
	.hash_table = nfs_dns_table,
 | 
					 | 
				
			||||||
	.name = "dns_resolve",
 | 
					 | 
				
			||||||
	.cache_put = nfs_dns_ent_put,
 | 
					 | 
				
			||||||
	.cache_upcall = nfs_dns_upcall,
 | 
					 | 
				
			||||||
	.cache_parse = nfs_dns_parse,
 | 
					 | 
				
			||||||
	.cache_show = nfs_dns_show,
 | 
					 | 
				
			||||||
	.match = nfs_dns_match,
 | 
					 | 
				
			||||||
	.init = nfs_dns_ent_init,
 | 
					 | 
				
			||||||
	.update = nfs_dns_ent_update,
 | 
					 | 
				
			||||||
	.alloc = nfs_dns_ent_alloc,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int do_cache_lookup(struct cache_detail *cd,
 | 
					static int do_cache_lookup(struct cache_detail *cd,
 | 
				
			||||||
		struct nfs_dns_ent *key,
 | 
							struct nfs_dns_ent *key,
 | 
				
			||||||
		struct nfs_dns_ent **item,
 | 
							struct nfs_dns_ent **item,
 | 
				
			||||||
| 
						 | 
					@ -336,8 +322,8 @@ out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
 | 
					ssize_t nfs_dns_resolve_name(struct net *net, char *name,
 | 
				
			||||||
		struct sockaddr *sa, size_t salen)
 | 
							size_t namelen, struct sockaddr *sa, size_t salen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_dns_ent key = {
 | 
						struct nfs_dns_ent key = {
 | 
				
			||||||
		.hostname = name,
 | 
							.hostname = name,
 | 
				
			||||||
| 
						 | 
					@ -345,28 +331,118 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct nfs_dns_ent *item = NULL;
 | 
						struct nfs_dns_ent *item = NULL;
 | 
				
			||||||
	ssize_t ret;
 | 
						ssize_t ret;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = do_cache_lookup_wait(&nfs_dns_resolve, &key, &item);
 | 
						ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item);
 | 
				
			||||||
	if (ret == 0) {
 | 
						if (ret == 0) {
 | 
				
			||||||
		if (salen >= item->addrlen) {
 | 
							if (salen >= item->addrlen) {
 | 
				
			||||||
			memcpy(sa, &item->addr, item->addrlen);
 | 
								memcpy(sa, &item->addr, item->addrlen);
 | 
				
			||||||
			ret = item->addrlen;
 | 
								ret = item->addrlen;
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			ret = -EOVERFLOW;
 | 
								ret = -EOVERFLOW;
 | 
				
			||||||
		cache_put(&item->h, &nfs_dns_resolve);
 | 
							cache_put(&item->h, nn->nfs_dns_resolve);
 | 
				
			||||||
	} else if (ret == -ENOENT)
 | 
						} else if (ret == -ENOENT)
 | 
				
			||||||
		ret = -ESRCH;
 | 
							ret = -ESRCH;
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int nfs_dns_resolver_cache_init(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err = -ENOMEM;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
						struct cache_detail *cd;
 | 
				
			||||||
 | 
						struct cache_head **tbl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (cd == NULL)
 | 
				
			||||||
 | 
							goto err_cd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tbl = kzalloc(NFS_DNS_HASHTBL_SIZE * sizeof(struct cache_head *),
 | 
				
			||||||
 | 
								GFP_KERNEL);
 | 
				
			||||||
 | 
						if (tbl == NULL)
 | 
				
			||||||
 | 
							goto err_tbl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cd->owner = THIS_MODULE,
 | 
				
			||||||
 | 
						cd->hash_size = NFS_DNS_HASHTBL_SIZE,
 | 
				
			||||||
 | 
						cd->hash_table = tbl,
 | 
				
			||||||
 | 
						cd->name = "dns_resolve",
 | 
				
			||||||
 | 
						cd->cache_put = nfs_dns_ent_put,
 | 
				
			||||||
 | 
						cd->cache_upcall = nfs_dns_upcall,
 | 
				
			||||||
 | 
						cd->cache_parse = nfs_dns_parse,
 | 
				
			||||||
 | 
						cd->cache_show = nfs_dns_show,
 | 
				
			||||||
 | 
						cd->match = nfs_dns_match,
 | 
				
			||||||
 | 
						cd->init = nfs_dns_ent_init,
 | 
				
			||||||
 | 
						cd->update = nfs_dns_ent_update,
 | 
				
			||||||
 | 
						cd->alloc = nfs_dns_ent_alloc,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nfs_cache_init(cd);
 | 
				
			||||||
 | 
						err = nfs_cache_register_net(net, cd);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto err_reg;
 | 
				
			||||||
 | 
						nn->nfs_dns_resolve = cd;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_reg:
 | 
				
			||||||
 | 
						nfs_cache_destroy(cd);
 | 
				
			||||||
 | 
						kfree(cd->hash_table);
 | 
				
			||||||
 | 
					err_tbl:
 | 
				
			||||||
 | 
						kfree(cd);
 | 
				
			||||||
 | 
					err_cd:
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void nfs_dns_resolver_cache_destroy(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
						struct cache_detail *cd = nn->nfs_dns_resolve;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nfs_cache_unregister_net(net, cd);
 | 
				
			||||||
 | 
						nfs_cache_destroy(cd);
 | 
				
			||||||
 | 
						kfree(cd->hash_table);
 | 
				
			||||||
 | 
						kfree(cd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
 | 
				
			||||||
 | 
								   void *ptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct super_block *sb = ptr;
 | 
				
			||||||
 | 
						struct net *net = sb->s_fs_info;
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
						struct cache_detail *cd = nn->nfs_dns_resolve;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cd == NULL)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!try_module_get(THIS_MODULE))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (event) {
 | 
				
			||||||
 | 
						case RPC_PIPEFS_MOUNT:
 | 
				
			||||||
 | 
							ret = nfs_cache_register_sb(sb, cd);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case RPC_PIPEFS_UMOUNT:
 | 
				
			||||||
 | 
							nfs_cache_unregister_sb(sb, cd);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ret = -ENOTSUPP;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						module_put(THIS_MODULE);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct notifier_block nfs_dns_resolver_block = {
 | 
				
			||||||
 | 
						.notifier_call	= rpc_pipefs_event,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs_dns_resolver_init(void)
 | 
					int nfs_dns_resolver_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return nfs_cache_register(&nfs_dns_resolve);
 | 
						return rpc_pipefs_notifier_register(&nfs_dns_resolver_block);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_dns_resolver_destroy(void)
 | 
					void nfs_dns_resolver_destroy(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	nfs_cache_unregister(&nfs_dns_resolve);
 | 
						rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,12 +15,22 @@ static inline int nfs_dns_resolver_init(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void nfs_dns_resolver_destroy(void)
 | 
					static inline void nfs_dns_resolver_destroy(void)
 | 
				
			||||||
{}
 | 
					{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int nfs_dns_resolver_cache_init(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void nfs_dns_resolver_cache_destroy(struct net *net)
 | 
				
			||||||
 | 
					{}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
extern int nfs_dns_resolver_init(void);
 | 
					extern int nfs_dns_resolver_init(void);
 | 
				
			||||||
extern void nfs_dns_resolver_destroy(void);
 | 
					extern void nfs_dns_resolver_destroy(void);
 | 
				
			||||||
 | 
					extern int nfs_dns_resolver_cache_init(struct net *net);
 | 
				
			||||||
 | 
					extern void nfs_dns_resolver_cache_destroy(struct net *net);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
 | 
					extern ssize_t nfs_dns_resolve_name(struct net *net, char *name,
 | 
				
			||||||
		struct sockaddr *sa, size_t salen);
 | 
							size_t namelen,	struct sockaddr *sa, size_t salen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -530,6 +530,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 | 
				
			||||||
	if (mapping != dentry->d_inode->i_mapping)
 | 
						if (mapping != dentry->d_inode->i_mapping)
 | 
				
			||||||
		goto out_unlock;
 | 
							goto out_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wait_on_page_writeback(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pagelen = nfs_page_length(page);
 | 
						pagelen = nfs_page_length(page);
 | 
				
			||||||
	if (pagelen == 0)
 | 
						if (pagelen == 0)
 | 
				
			||||||
		goto out_unlock;
 | 
							goto out_unlock;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -327,7 +327,7 @@ void nfs_fscache_reset_inode_cookie(struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_inode *nfsi = NFS_I(inode);
 | 
						struct nfs_inode *nfsi = NFS_I(inode);
 | 
				
			||||||
	struct nfs_server *nfss = NFS_SERVER(inode);
 | 
						struct nfs_server *nfss = NFS_SERVER(inode);
 | 
				
			||||||
	struct fscache_cookie *old = nfsi->fscache;
 | 
						NFS_IFDEBUG(struct fscache_cookie *old = nfsi->fscache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nfs_fscache_inode_lock(inode);
 | 
						nfs_fscache_inode_lock(inode);
 | 
				
			||||||
	if (nfsi->fscache) {
 | 
						if (nfsi->fscache) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										777
									
								
								fs/nfs/idmap.c
									
										
									
									
									
								
							
							
						
						
									
										777
									
								
								fs/nfs/idmap.c
									
										
									
									
									
								
							| 
						 | 
					@ -34,11 +34,29 @@
 | 
				
			||||||
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
					 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
#include <linux/string.h>
 | 
					#include <linux/parser.h>
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/fs.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					 | 
				
			||||||
#include <linux/nfs_idmap.h>
 | 
					#include <linux/nfs_idmap.h>
 | 
				
			||||||
 | 
					#include <net/net_namespace.h>
 | 
				
			||||||
 | 
					#include <linux/sunrpc/rpc_pipe_fs.h>
 | 
				
			||||||
#include <linux/nfs_fs.h>
 | 
					#include <linux/nfs_fs.h>
 | 
				
			||||||
 | 
					#include <linux/nfs_fs_sb.h>
 | 
				
			||||||
 | 
					#include <linux/key.h>
 | 
				
			||||||
 | 
					#include <linux/keyctl.h>
 | 
				
			||||||
 | 
					#include <linux/key-type.h>
 | 
				
			||||||
 | 
					#include <keys/user-type.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					#include "netns.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NFS_UINT_MAXLEN 11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Default cache timeout is 10 minutes */
 | 
				
			||||||
 | 
					unsigned int nfs_idmap_cache_timeout = 600;
 | 
				
			||||||
 | 
					static const struct cred *id_resolver_cache;
 | 
				
			||||||
 | 
					static struct key_type key_type_id_resolver_legacy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
 | 
					 * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
 | 
				
			||||||
| 
						 | 
					@ -142,24 +160,7 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
 | 
				
			||||||
	return snprintf(buf, buflen, "%u", id);
 | 
						return snprintf(buf, buflen, "%u", id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
 | 
					static struct key_type key_type_id_resolver = {
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/cred.h>
 | 
					 | 
				
			||||||
#include <linux/sunrpc/sched.h>
 | 
					 | 
				
			||||||
#include <linux/nfs4.h>
 | 
					 | 
				
			||||||
#include <linux/nfs_fs_sb.h>
 | 
					 | 
				
			||||||
#include <linux/keyctl.h>
 | 
					 | 
				
			||||||
#include <linux/key-type.h>
 | 
					 | 
				
			||||||
#include <linux/rcupdate.h>
 | 
					 | 
				
			||||||
#include <linux/err.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <keys/user-type.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define NFS_UINT_MAXLEN 11
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const struct cred *id_resolver_cache;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct key_type key_type_id_resolver = {
 | 
					 | 
				
			||||||
	.name		= "id_resolver",
 | 
						.name		= "id_resolver",
 | 
				
			||||||
	.instantiate	= user_instantiate,
 | 
						.instantiate	= user_instantiate,
 | 
				
			||||||
	.match		= user_match,
 | 
						.match		= user_match,
 | 
				
			||||||
| 
						 | 
					@ -169,13 +170,14 @@ struct key_type key_type_id_resolver = {
 | 
				
			||||||
	.read		= user_read,
 | 
						.read		= user_read,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs_idmap_init(void)
 | 
					static int nfs_idmap_init_keyring(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cred *cred;
 | 
						struct cred *cred;
 | 
				
			||||||
	struct key *keyring;
 | 
						struct key *keyring;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name);
 | 
						printk(KERN_NOTICE "NFS: Registering the %s key type\n",
 | 
				
			||||||
 | 
							key_type_id_resolver.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cred = prepare_kernel_cred(NULL);
 | 
						cred = prepare_kernel_cred(NULL);
 | 
				
			||||||
	if (!cred)
 | 
						if (!cred)
 | 
				
			||||||
| 
						 | 
					@ -211,7 +213,7 @@ failed_put_cred:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_idmap_quit(void)
 | 
					static void nfs_idmap_quit_keyring(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	key_revoke(id_resolver_cache->thread_keyring);
 | 
						key_revoke(id_resolver_cache->thread_keyring);
 | 
				
			||||||
	unregister_key_type(&key_type_id_resolver);
 | 
						unregister_key_type(&key_type_id_resolver);
 | 
				
			||||||
| 
						 | 
					@ -246,8 +248,10 @@ static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
 | 
				
			||||||
	return desclen;
 | 
						return desclen;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
 | 
					static ssize_t nfs_idmap_request_key(struct key_type *key_type,
 | 
				
			||||||
		const char *type, void *data, size_t data_size)
 | 
									     const char *name, size_t namelen,
 | 
				
			||||||
 | 
									     const char *type, void *data,
 | 
				
			||||||
 | 
									     size_t data_size, struct idmap *idmap)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct cred *saved_cred;
 | 
						const struct cred *saved_cred;
 | 
				
			||||||
	struct key *rkey;
 | 
						struct key *rkey;
 | 
				
			||||||
| 
						 | 
					@ -260,8 +264,12 @@ static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	saved_cred = override_creds(id_resolver_cache);
 | 
						saved_cred = override_creds(id_resolver_cache);
 | 
				
			||||||
 | 
						if (idmap)
 | 
				
			||||||
 | 
							rkey = request_key_with_auxdata(key_type, desc, "", 0, idmap);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		rkey = request_key(&key_type_id_resolver, desc, "");
 | 
							rkey = request_key(&key_type_id_resolver, desc, "");
 | 
				
			||||||
	revert_creds(saved_cred);
 | 
						revert_creds(saved_cred);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(desc);
 | 
						kfree(desc);
 | 
				
			||||||
	if (IS_ERR(rkey)) {
 | 
						if (IS_ERR(rkey)) {
 | 
				
			||||||
		ret = PTR_ERR(rkey);
 | 
							ret = PTR_ERR(rkey);
 | 
				
			||||||
| 
						 | 
					@ -294,31 +302,46 @@ out:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
 | 
				
			||||||
 | 
									 const char *type, void *data,
 | 
				
			||||||
 | 
									 size_t data_size, struct idmap *idmap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ssize_t ret = nfs_idmap_request_key(&key_type_id_resolver,
 | 
				
			||||||
 | 
										    name, namelen, type, data,
 | 
				
			||||||
 | 
										    data_size, NULL);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
 | 
				
			||||||
 | 
										    name, namelen, type, data,
 | 
				
			||||||
 | 
										    data_size, idmap);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ID -> Name */
 | 
					/* ID -> Name */
 | 
				
			||||||
static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen)
 | 
					static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
 | 
				
			||||||
 | 
									     size_t buflen, struct idmap *idmap)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char id_str[NFS_UINT_MAXLEN];
 | 
						char id_str[NFS_UINT_MAXLEN];
 | 
				
			||||||
	int id_len;
 | 
						int id_len;
 | 
				
			||||||
	ssize_t ret;
 | 
						ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	id_len = snprintf(id_str, sizeof(id_str), "%u", id);
 | 
						id_len = snprintf(id_str, sizeof(id_str), "%u", id);
 | 
				
			||||||
	ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen);
 | 
						ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Name -> ID */
 | 
					/* Name -> ID */
 | 
				
			||||||
static int nfs_idmap_lookup_id(const char *name, size_t namelen,
 | 
					static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
 | 
				
			||||||
				const char *type, __u32 *id)
 | 
								       __u32 *id, struct idmap *idmap)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char id_str[NFS_UINT_MAXLEN];
 | 
						char id_str[NFS_UINT_MAXLEN];
 | 
				
			||||||
	long id_long;
 | 
						long id_long;
 | 
				
			||||||
	ssize_t data_size;
 | 
						ssize_t data_size;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN);
 | 
						data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap);
 | 
				
			||||||
	if (data_size <= 0) {
 | 
						if (data_size <= 0) {
 | 
				
			||||||
		ret = -EINVAL;
 | 
							ret = -EINVAL;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -328,114 +351,103 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen,
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
 | 
					/* idmap classic begins here */
 | 
				
			||||||
{
 | 
					module_param(nfs_idmap_cache_timeout, int, 0644);
 | 
				
			||||||
	if (nfs_map_string_to_numeric(name, namelen, uid))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	return nfs_idmap_lookup_id(name, namelen, "uid", uid);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (nfs_map_string_to_numeric(name, namelen, gid))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	return nfs_idmap_lookup_id(name, namelen, "gid", gid);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int ret = -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
 | 
					 | 
				
			||||||
		ret = nfs_idmap_lookup_name(uid, "user", buf, buflen);
 | 
					 | 
				
			||||||
	if (ret < 0)
 | 
					 | 
				
			||||||
		ret = nfs_map_numeric_to_string(uid, buf, buflen);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int ret = -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
 | 
					 | 
				
			||||||
		ret = nfs_idmap_lookup_name(gid, "group", buf, buflen);
 | 
					 | 
				
			||||||
	if (ret < 0)
 | 
					 | 
				
			||||||
		ret = nfs_map_numeric_to_string(gid, buf, buflen);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#else  /* CONFIG_NFS_USE_NEW_IDMAPPER not defined */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/module.h>
 | 
					 | 
				
			||||||
#include <linux/mutex.h>
 | 
					 | 
				
			||||||
#include <linux/init.h>
 | 
					 | 
				
			||||||
#include <linux/socket.h>
 | 
					 | 
				
			||||||
#include <linux/in.h>
 | 
					 | 
				
			||||||
#include <linux/sched.h>
 | 
					 | 
				
			||||||
#include <linux/sunrpc/clnt.h>
 | 
					 | 
				
			||||||
#include <linux/workqueue.h>
 | 
					 | 
				
			||||||
#include <linux/sunrpc/rpc_pipe_fs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/nfs_fs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "nfs4_fs.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define IDMAP_HASH_SZ          128
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Default cache timeout is 10 minutes */
 | 
					 | 
				
			||||||
unsigned int nfs_idmap_cache_timeout = 600 * HZ;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char *endp;
 | 
					 | 
				
			||||||
	int num = simple_strtol(val, &endp, 0);
 | 
					 | 
				
			||||||
	int jif = num * HZ;
 | 
					 | 
				
			||||||
	if (endp == val || *endp || num < 0 || jif < num)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	*((int *)kp->arg) = jif;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
 | 
					 | 
				
			||||||
		 &nfs_idmap_cache_timeout, 0644);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct idmap_hashent {
 | 
					 | 
				
			||||||
	unsigned long		ih_expires;
 | 
					 | 
				
			||||||
	__u32			ih_id;
 | 
					 | 
				
			||||||
	size_t			ih_namelen;
 | 
					 | 
				
			||||||
	char			ih_name[IDMAP_NAMESZ];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct idmap_hashtable {
 | 
					 | 
				
			||||||
	__u8			h_type;
 | 
					 | 
				
			||||||
	struct idmap_hashent	h_entries[IDMAP_HASH_SZ];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct idmap {
 | 
					struct idmap {
 | 
				
			||||||
	struct dentry		*idmap_dentry;
 | 
						struct rpc_pipe		*idmap_pipe;
 | 
				
			||||||
	wait_queue_head_t	idmap_wq;
 | 
						struct key_construction	*idmap_key_cons;
 | 
				
			||||||
	struct idmap_msg	idmap_im;
 | 
					 | 
				
			||||||
	struct mutex		idmap_lock;	/* Serializes upcalls */
 | 
					 | 
				
			||||||
	struct mutex		idmap_im_lock;	/* Protects the hashtable */
 | 
					 | 
				
			||||||
	struct idmap_hashtable	idmap_user_hash;
 | 
					 | 
				
			||||||
	struct idmap_hashtable	idmap_group_hash;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const match_table_t nfs_idmap_tokens = {
 | 
				
			||||||
 | 
						{ Opt_find_uid, "uid:%s" },
 | 
				
			||||||
 | 
						{ Opt_find_gid, "gid:%s" },
 | 
				
			||||||
 | 
						{ Opt_find_user, "user:%s" },
 | 
				
			||||||
 | 
						{ Opt_find_group, "group:%s" },
 | 
				
			||||||
 | 
						{ Opt_find_err, NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
 | 
				
			||||||
static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
 | 
					static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
 | 
				
			||||||
				   size_t);
 | 
									   size_t);
 | 
				
			||||||
static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
 | 
					static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int fnvhash32(const void *, size_t);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct rpc_pipe_ops idmap_upcall_ops = {
 | 
					static const struct rpc_pipe_ops idmap_upcall_ops = {
 | 
				
			||||||
	.upcall		= rpc_pipe_generic_upcall,
 | 
						.upcall		= rpc_pipe_generic_upcall,
 | 
				
			||||||
	.downcall	= idmap_pipe_downcall,
 | 
						.downcall	= idmap_pipe_downcall,
 | 
				
			||||||
	.destroy_msg	= idmap_pipe_destroy_msg,
 | 
						.destroy_msg	= idmap_pipe_destroy_msg,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct key_type key_type_id_resolver_legacy = {
 | 
				
			||||||
 | 
						.name		= "id_resolver",
 | 
				
			||||||
 | 
						.instantiate	= user_instantiate,
 | 
				
			||||||
 | 
						.match		= user_match,
 | 
				
			||||||
 | 
						.revoke		= user_revoke,
 | 
				
			||||||
 | 
						.destroy	= user_destroy,
 | 
				
			||||||
 | 
						.describe	= user_describe,
 | 
				
			||||||
 | 
						.read		= user_read,
 | 
				
			||||||
 | 
						.request_key	= nfs_idmap_legacy_upcall,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __nfs_idmap_unregister(struct rpc_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (pipe->dentry)
 | 
				
			||||||
 | 
							rpc_unlink(pipe->dentry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __nfs_idmap_register(struct dentry *dir,
 | 
				
			||||||
 | 
									     struct idmap *idmap,
 | 
				
			||||||
 | 
									     struct rpc_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dentry *dentry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
 | 
				
			||||||
 | 
						if (IS_ERR(dentry))
 | 
				
			||||||
 | 
							return PTR_ERR(dentry);
 | 
				
			||||||
 | 
						pipe->dentry = dentry;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs_idmap_unregister(struct nfs_client *clp,
 | 
				
			||||||
 | 
									      struct rpc_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net *net = clp->net;
 | 
				
			||||||
 | 
						struct super_block *pipefs_sb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pipefs_sb = rpc_get_sb_net(net);
 | 
				
			||||||
 | 
						if (pipefs_sb) {
 | 
				
			||||||
 | 
							__nfs_idmap_unregister(pipe);
 | 
				
			||||||
 | 
							rpc_put_sb_net(net);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nfs_idmap_register(struct nfs_client *clp,
 | 
				
			||||||
 | 
									   struct idmap *idmap,
 | 
				
			||||||
 | 
									   struct rpc_pipe *pipe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net *net = clp->net;
 | 
				
			||||||
 | 
						struct super_block *pipefs_sb;
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pipefs_sb = rpc_get_sb_net(net);
 | 
				
			||||||
 | 
						if (pipefs_sb) {
 | 
				
			||||||
 | 
							if (clp->cl_rpcclient->cl_dentry)
 | 
				
			||||||
 | 
								err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
 | 
				
			||||||
 | 
											   idmap, pipe);
 | 
				
			||||||
 | 
							rpc_put_sb_net(net);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
nfs_idmap_new(struct nfs_client *clp)
 | 
					nfs_idmap_new(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct idmap *idmap;
 | 
						struct idmap *idmap;
 | 
				
			||||||
 | 
						struct rpc_pipe *pipe;
 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BUG_ON(clp->cl_idmap != NULL);
 | 
						BUG_ON(clp->cl_idmap != NULL);
 | 
				
			||||||
| 
						 | 
					@ -444,19 +456,19 @@ nfs_idmap_new(struct nfs_client *clp)
 | 
				
			||||||
	if (idmap == NULL)
 | 
						if (idmap == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry,
 | 
						pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0);
 | 
				
			||||||
			"idmap", idmap, &idmap_upcall_ops, 0);
 | 
						if (IS_ERR(pipe)) {
 | 
				
			||||||
	if (IS_ERR(idmap->idmap_dentry)) {
 | 
							error = PTR_ERR(pipe);
 | 
				
			||||||
		error = PTR_ERR(idmap->idmap_dentry);
 | 
					 | 
				
			||||||
		kfree(idmap);
 | 
							kfree(idmap);
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						error = nfs_idmap_register(clp, idmap, pipe);
 | 
				
			||||||
	mutex_init(&idmap->idmap_lock);
 | 
						if (error) {
 | 
				
			||||||
	mutex_init(&idmap->idmap_im_lock);
 | 
							rpc_destroy_pipe_data(pipe);
 | 
				
			||||||
	init_waitqueue_head(&idmap->idmap_wq);
 | 
							kfree(idmap);
 | 
				
			||||||
	idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
 | 
							return error;
 | 
				
			||||||
	idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
 | 
						}
 | 
				
			||||||
 | 
						idmap->idmap_pipe = pipe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clp->cl_idmap = idmap;
 | 
						clp->cl_idmap = idmap;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -469,211 +481,220 @@ nfs_idmap_delete(struct nfs_client *clp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!idmap)
 | 
						if (!idmap)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	rpc_unlink(idmap->idmap_dentry);
 | 
						nfs_idmap_unregister(clp, idmap->idmap_pipe);
 | 
				
			||||||
 | 
						rpc_destroy_pipe_data(idmap->idmap_pipe);
 | 
				
			||||||
	clp->cl_idmap = NULL;
 | 
						clp->cl_idmap = NULL;
 | 
				
			||||||
	kfree(idmap);
 | 
						kfree(idmap);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event,
 | 
				
			||||||
 * Helper routines for manipulating the hashtable
 | 
								      struct super_block *sb)
 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static inline struct idmap_hashent *
 | 
					 | 
				
			||||||
idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ];
 | 
						int err = 0;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct idmap_hashent *
 | 
						switch (event) {
 | 
				
			||||||
idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
 | 
						case RPC_PIPEFS_MOUNT:
 | 
				
			||||||
{
 | 
							BUG_ON(clp->cl_rpcclient->cl_dentry == NULL);
 | 
				
			||||||
	struct idmap_hashent *he = idmap_name_hash(h, name, len);
 | 
							err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
 | 
				
			||||||
 | 
											clp->cl_idmap,
 | 
				
			||||||
	if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
 | 
											clp->cl_idmap->idmap_pipe);
 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	if (time_after(jiffies, he->ih_expires))
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	return he;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline struct idmap_hashent *
 | 
					 | 
				
			||||||
idmap_id_hash(struct idmap_hashtable* h, __u32 id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct idmap_hashent *
 | 
					 | 
				
			||||||
idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct idmap_hashent *he = idmap_id_hash(h, id);
 | 
					 | 
				
			||||||
	if (he->ih_id != id || he->ih_namelen == 0)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	if (time_after(jiffies, he->ih_expires))
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	return he;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Routines for allocating new entries in the hashtable.
 | 
					 | 
				
			||||||
 * For now, we just have 1 entry per bucket, so it's all
 | 
					 | 
				
			||||||
 * pretty trivial.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static inline struct idmap_hashent *
 | 
					 | 
				
			||||||
idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return idmap_name_hash(h, name, len);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline struct idmap_hashent *
 | 
					 | 
				
			||||||
idmap_alloc_id(struct idmap_hashtable *h, __u32 id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return idmap_id_hash(h, id);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
idmap_update_entry(struct idmap_hashent *he, const char *name,
 | 
					 | 
				
			||||||
		size_t namelen, __u32 id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	he->ih_id = id;
 | 
					 | 
				
			||||||
	memcpy(he->ih_name, name, namelen);
 | 
					 | 
				
			||||||
	he->ih_name[namelen] = '\0';
 | 
					 | 
				
			||||||
	he->ih_namelen = namelen;
 | 
					 | 
				
			||||||
	he->ih_expires = jiffies + nfs_idmap_cache_timeout;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Name -> ID
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
 | 
					 | 
				
			||||||
		const char *name, size_t namelen, __u32 *id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct rpc_pipe_msg msg;
 | 
					 | 
				
			||||||
	struct idmap_msg *im;
 | 
					 | 
				
			||||||
	struct idmap_hashent *he;
 | 
					 | 
				
			||||||
	DECLARE_WAITQUEUE(wq, current);
 | 
					 | 
				
			||||||
	int ret = -EIO;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	im = &idmap->idmap_im;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * String sanity checks
 | 
					 | 
				
			||||||
	 * Note that the userland daemon expects NUL terminated strings
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	for (;;) {
 | 
					 | 
				
			||||||
		if (namelen == 0)
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		if (name[namelen-1] != '\0')
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
		namelen--;
 | 
						case RPC_PIPEFS_UMOUNT:
 | 
				
			||||||
 | 
							if (clp->cl_idmap->idmap_pipe) {
 | 
				
			||||||
 | 
								struct dentry *parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								parent = clp->cl_idmap->idmap_pipe->dentry->d_parent;
 | 
				
			||||||
 | 
								__nfs_idmap_unregister(clp->cl_idmap->idmap_pipe);
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * Note: This is a dirty hack. SUNRPC hook has been
 | 
				
			||||||
 | 
								 * called already but simple_rmdir() call for the
 | 
				
			||||||
 | 
								 * directory returned with error because of idmap pipe
 | 
				
			||||||
 | 
								 * inside. Thus now we have to remove this directory
 | 
				
			||||||
 | 
								 * here.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (rpc_rmdir(parent))
 | 
				
			||||||
 | 
									printk(KERN_ERR "NFS: %s: failed to remove "
 | 
				
			||||||
 | 
										"clnt dir!\n", __func__);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__,
 | 
				
			||||||
 | 
								event);
 | 
				
			||||||
 | 
							return -ENOTSUPP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
	if (namelen >= IDMAP_NAMESZ)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&idmap->idmap_lock);
 | 
					static struct nfs_client *nfs_get_client_for_event(struct net *net, int event)
 | 
				
			||||||
	mutex_lock(&idmap->idmap_im_lock);
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_net *nn = net_generic(net, nfs_net_id);
 | 
				
			||||||
 | 
						struct dentry *cl_dentry;
 | 
				
			||||||
 | 
						struct nfs_client *clp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	he = idmap_lookup_name(h, name, namelen);
 | 
						spin_lock(&nn->nfs_client_lock);
 | 
				
			||||||
	if (he != NULL) {
 | 
						list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
 | 
				
			||||||
		*id = he->ih_id;
 | 
							if (clp->rpc_ops != &nfs_v4_clientops)
 | 
				
			||||||
		ret = 0;
 | 
								continue;
 | 
				
			||||||
 | 
							cl_dentry = clp->cl_idmap->idmap_pipe->dentry;
 | 
				
			||||||
 | 
							if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) ||
 | 
				
			||||||
 | 
							    ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							atomic_inc(&clp->cl_count);
 | 
				
			||||||
 | 
							spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
							return clp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock(&nn->nfs_client_lock);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
 | 
				
			||||||
 | 
								    void *ptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct super_block *sb = ptr;
 | 
				
			||||||
 | 
						struct nfs_client *clp;
 | 
				
			||||||
 | 
						int error = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) {
 | 
				
			||||||
 | 
							error = __rpc_pipefs_event(clp, event, sb);
 | 
				
			||||||
 | 
							nfs_put_client(clp);
 | 
				
			||||||
 | 
							if (error)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return error;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PIPEFS_NFS_PRIO		1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct notifier_block nfs_idmap_block = {
 | 
				
			||||||
 | 
						.notifier_call	= rpc_pipefs_event,
 | 
				
			||||||
 | 
						.priority	= SUNRPC_PIPEFS_NFS_PRIO,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int nfs_idmap_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						ret = nfs_idmap_init_keyring();
 | 
				
			||||||
 | 
						if (ret != 0)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						ret = rpc_pipefs_notifier_register(&nfs_idmap_block);
 | 
				
			||||||
 | 
						if (ret != 0)
 | 
				
			||||||
	memset(im, 0, sizeof(*im));
 | 
							nfs_idmap_quit_keyring();
 | 
				
			||||||
	memcpy(im->im_name, name, namelen);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	im->im_type = h->h_type;
 | 
					 | 
				
			||||||
	im->im_conv = IDMAP_CONV_NAMETOID;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&msg, 0, sizeof(msg));
 | 
					 | 
				
			||||||
	msg.data = im;
 | 
					 | 
				
			||||||
	msg.len = sizeof(*im);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	add_wait_queue(&idmap->idmap_wq, &wq);
 | 
					 | 
				
			||||||
	if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
 | 
					 | 
				
			||||||
		remove_wait_queue(&idmap->idmap_wq, &wq);
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set_current_state(TASK_UNINTERRUPTIBLE);
 | 
					 | 
				
			||||||
	mutex_unlock(&idmap->idmap_im_lock);
 | 
					 | 
				
			||||||
	schedule();
 | 
					 | 
				
			||||||
	__set_current_state(TASK_RUNNING);
 | 
					 | 
				
			||||||
	remove_wait_queue(&idmap->idmap_wq, &wq);
 | 
					 | 
				
			||||||
	mutex_lock(&idmap->idmap_im_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (im->im_status & IDMAP_STATUS_SUCCESS) {
 | 
					 | 
				
			||||||
		*id = im->im_id;
 | 
					 | 
				
			||||||
		ret = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	memset(im, 0, sizeof(*im));
 | 
					 | 
				
			||||||
	mutex_unlock(&idmap->idmap_im_lock);
 | 
					 | 
				
			||||||
	mutex_unlock(&idmap->idmap_lock);
 | 
					 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					void nfs_idmap_quit(void)
 | 
				
			||||||
 * ID -> Name
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
 | 
					 | 
				
			||||||
		__u32 id, char *name)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_pipe_msg msg;
 | 
						rpc_pipefs_notifier_unregister(&nfs_idmap_block);
 | 
				
			||||||
	struct idmap_msg *im;
 | 
						nfs_idmap_quit_keyring();
 | 
				
			||||||
	struct idmap_hashent *he;
 | 
					 | 
				
			||||||
	DECLARE_WAITQUEUE(wq, current);
 | 
					 | 
				
			||||||
	int ret = -EIO;
 | 
					 | 
				
			||||||
	unsigned int len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	im = &idmap->idmap_im;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&idmap->idmap_lock);
 | 
					 | 
				
			||||||
	mutex_lock(&idmap->idmap_im_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	he = idmap_lookup_id(h, id);
 | 
					 | 
				
			||||||
	if (he) {
 | 
					 | 
				
			||||||
		memcpy(name, he->ih_name, he->ih_namelen);
 | 
					 | 
				
			||||||
		ret = he->ih_namelen;
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
 | 
				
			||||||
 | 
									     struct rpc_pipe_msg *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						substring_t substr;
 | 
				
			||||||
 | 
						int token, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(im,  0, sizeof(*im));
 | 
						memset(im,  0, sizeof(*im));
 | 
				
			||||||
	im->im_type = h->h_type;
 | 
						memset(msg, 0, sizeof(*msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						im->im_type = IDMAP_TYPE_GROUP;
 | 
				
			||||||
 | 
						token = match_token(desc, nfs_idmap_tokens, &substr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (token) {
 | 
				
			||||||
 | 
						case Opt_find_uid:
 | 
				
			||||||
 | 
							im->im_type = IDMAP_TYPE_USER;
 | 
				
			||||||
 | 
						case Opt_find_gid:
 | 
				
			||||||
 | 
							im->im_conv = IDMAP_CONV_NAMETOID;
 | 
				
			||||||
 | 
							ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case Opt_find_user:
 | 
				
			||||||
 | 
							im->im_type = IDMAP_TYPE_USER;
 | 
				
			||||||
 | 
						case Opt_find_group:
 | 
				
			||||||
		im->im_conv = IDMAP_CONV_IDTONAME;
 | 
							im->im_conv = IDMAP_CONV_IDTONAME;
 | 
				
			||||||
	im->im_id = id;
 | 
							ret = match_int(&substr, &im->im_id);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&msg, 0, sizeof(msg));
 | 
						default:
 | 
				
			||||||
	msg.data = im;
 | 
							ret = -EINVAL;
 | 
				
			||||||
	msg.len = sizeof(*im);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	add_wait_queue(&idmap->idmap_wq, &wq);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
 | 
					 | 
				
			||||||
		remove_wait_queue(&idmap->idmap_wq, &wq);
 | 
					 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_current_state(TASK_UNINTERRUPTIBLE);
 | 
						msg->data = im;
 | 
				
			||||||
	mutex_unlock(&idmap->idmap_im_lock);
 | 
						msg->len  = sizeof(struct idmap_msg);
 | 
				
			||||||
	schedule();
 | 
					 | 
				
			||||||
	__set_current_state(TASK_RUNNING);
 | 
					 | 
				
			||||||
	remove_wait_queue(&idmap->idmap_wq, &wq);
 | 
					 | 
				
			||||||
	mutex_lock(&idmap->idmap_im_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (im->im_status & IDMAP_STATUS_SUCCESS) {
 | 
					 | 
				
			||||||
		if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0)
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
		memcpy(name, im->im_name, len);
 | 
					 | 
				
			||||||
		ret = len;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	memset(im, 0, sizeof(*im));
 | 
						return ret;
 | 
				
			||||||
	mutex_unlock(&idmap->idmap_im_lock);
 | 
					}
 | 
				
			||||||
	mutex_unlock(&idmap->idmap_lock);
 | 
					
 | 
				
			||||||
 | 
					static int nfs_idmap_legacy_upcall(struct key_construction *cons,
 | 
				
			||||||
 | 
									   const char *op,
 | 
				
			||||||
 | 
									   void *aux)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rpc_pipe_msg *msg;
 | 
				
			||||||
 | 
						struct idmap_msg *im;
 | 
				
			||||||
 | 
						struct idmap *idmap = (struct idmap *)aux;
 | 
				
			||||||
 | 
						struct key *key = cons->key;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* msg and im are freed in idmap_pipe_destroy_msg */
 | 
				
			||||||
 | 
						msg = kmalloc(sizeof(*msg), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (IS_ERR(msg)) {
 | 
				
			||||||
 | 
							ret = PTR_ERR(msg);
 | 
				
			||||||
 | 
							goto out0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						im = kmalloc(sizeof(*im), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (IS_ERR(im)) {
 | 
				
			||||||
 | 
							ret = PTR_ERR(im);
 | 
				
			||||||
 | 
							goto out1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = nfs_idmap_prepare_message(key->description, im, msg);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						idmap->idmap_key_cons = cons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out2:
 | 
				
			||||||
 | 
						kfree(im);
 | 
				
			||||||
 | 
					out1:
 | 
				
			||||||
 | 
						kfree(msg);
 | 
				
			||||||
 | 
					out0:
 | 
				
			||||||
 | 
						key_revoke(cons->key);
 | 
				
			||||||
 | 
						key_revoke(cons->authkey);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return key_instantiate_and_link(key, data, strlen(data) + 1,
 | 
				
			||||||
 | 
										id_resolver_cache->thread_keyring,
 | 
				
			||||||
 | 
										authkey);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char id_str[NFS_UINT_MAXLEN];
 | 
				
			||||||
 | 
						int ret = -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (im->im_conv) {
 | 
				
			||||||
 | 
						case IDMAP_CONV_NAMETOID:
 | 
				
			||||||
 | 
							sprintf(id_str, "%d", im->im_id);
 | 
				
			||||||
 | 
							ret = nfs_idmap_instantiate(key, authkey, id_str);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case IDMAP_CONV_IDTONAME:
 | 
				
			||||||
 | 
							ret = nfs_idmap_instantiate(key, authkey, im->im_name);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -682,115 +703,51 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
 | 
						struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
 | 
				
			||||||
	struct idmap *idmap = (struct idmap *)rpci->private;
 | 
						struct idmap *idmap = (struct idmap *)rpci->private;
 | 
				
			||||||
	struct idmap_msg im_in, *im = &idmap->idmap_im;
 | 
						struct key_construction *cons = idmap->idmap_key_cons;
 | 
				
			||||||
	struct idmap_hashtable *h;
 | 
						struct idmap_msg im;
 | 
				
			||||||
	struct idmap_hashent *he = NULL;
 | 
					 | 
				
			||||||
	size_t namelen_in;
 | 
						size_t namelen_in;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mlen != sizeof(im_in))
 | 
						if (mlen != sizeof(im)) {
 | 
				
			||||||
		return -ENOSPC;
 | 
							ret = -ENOSPC;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (copy_from_user(&im_in, src, mlen) != 0)
 | 
					 | 
				
			||||||
		return -EFAULT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&idmap->idmap_im_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = mlen;
 | 
					 | 
				
			||||||
	im->im_status = im_in.im_status;
 | 
					 | 
				
			||||||
	/* If we got an error, terminate now, and wake up pending upcalls */
 | 
					 | 
				
			||||||
	if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) {
 | 
					 | 
				
			||||||
		wake_up(&idmap->idmap_wq);
 | 
					 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Sanity checking of strings */
 | 
						if (copy_from_user(&im, src, mlen) != 0) {
 | 
				
			||||||
 | 
							ret = -EFAULT;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
 | 
				
			||||||
 | 
							ret = mlen;
 | 
				
			||||||
 | 
							complete_request_key(idmap->idmap_key_cons, -ENOKEY);
 | 
				
			||||||
 | 
							goto out_incomplete;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
 | 
				
			||||||
 | 
						if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
 | 
				
			||||||
		ret = -EINVAL;
 | 
							ret = -EINVAL;
 | 
				
			||||||
	namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ);
 | 
					 | 
				
			||||||
	if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (im_in.im_type) {
 | 
					 | 
				
			||||||
		case IDMAP_TYPE_USER:
 | 
					 | 
				
			||||||
			h = &idmap->idmap_user_hash;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case IDMAP_TYPE_GROUP:
 | 
					 | 
				
			||||||
			h = &idmap->idmap_group_hash;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (im_in.im_conv) {
 | 
						ret = nfs_idmap_read_message(&im, cons->key, cons->authkey);
 | 
				
			||||||
	case IDMAP_CONV_IDTONAME:
 | 
						if (ret >= 0) {
 | 
				
			||||||
		/* Did we match the current upcall? */
 | 
							key_set_timeout(cons->key, nfs_idmap_cache_timeout);
 | 
				
			||||||
		if (im->im_conv == IDMAP_CONV_IDTONAME
 | 
					 | 
				
			||||||
				&& im->im_type == im_in.im_type
 | 
					 | 
				
			||||||
				&& im->im_id == im_in.im_id) {
 | 
					 | 
				
			||||||
			/* Yes: copy string, including the terminating '\0'  */
 | 
					 | 
				
			||||||
			memcpy(im->im_name, im_in.im_name, namelen_in);
 | 
					 | 
				
			||||||
			im->im_name[namelen_in] = '\0';
 | 
					 | 
				
			||||||
			wake_up(&idmap->idmap_wq);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		he = idmap_alloc_id(h, im_in.im_id);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case IDMAP_CONV_NAMETOID:
 | 
					 | 
				
			||||||
		/* Did we match the current upcall? */
 | 
					 | 
				
			||||||
		if (im->im_conv == IDMAP_CONV_NAMETOID
 | 
					 | 
				
			||||||
				&& im->im_type == im_in.im_type
 | 
					 | 
				
			||||||
				&& strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in
 | 
					 | 
				
			||||||
				&& memcmp(im->im_name, im_in.im_name, namelen_in) == 0) {
 | 
					 | 
				
			||||||
			im->im_id = im_in.im_id;
 | 
					 | 
				
			||||||
			wake_up(&idmap->idmap_wq);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		he = idmap_alloc_name(h, im_in.im_name, namelen_in);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* If the entry is valid, also copy it to the cache */
 | 
					 | 
				
			||||||
	if (he != NULL)
 | 
					 | 
				
			||||||
		idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id);
 | 
					 | 
				
			||||||
		ret = mlen;
 | 
							ret = mlen;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	mutex_unlock(&idmap->idmap_im_lock);
 | 
						complete_request_key(idmap->idmap_key_cons, ret);
 | 
				
			||||||
 | 
					out_incomplete:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 | 
					idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct idmap_msg *im = msg->data;
 | 
						/* Free memory allocated in nfs_idmap_legacy_upcall() */
 | 
				
			||||||
	struct idmap *idmap = container_of(im, struct idmap, idmap_im); 
 | 
						kfree(msg->data);
 | 
				
			||||||
 | 
						kfree(msg);
 | 
				
			||||||
	if (msg->errno >= 0)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	mutex_lock(&idmap->idmap_im_lock);
 | 
					 | 
				
			||||||
	im->im_status = IDMAP_STATUS_LOOKUPFAIL;
 | 
					 | 
				
			||||||
	wake_up(&idmap->idmap_wq);
 | 
					 | 
				
			||||||
	mutex_unlock(&idmap->idmap_im_lock);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 
 | 
					 | 
				
			||||||
 * Fowler/Noll/Vo hash
 | 
					 | 
				
			||||||
 *    http://www.isthe.com/chongo/tech/comp/fnv/
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
 | 
					 | 
				
			||||||
#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned int fnvhash32(const void *buf, size_t buflen)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const unsigned char *p, *end = (const unsigned char *)buf + buflen;
 | 
					 | 
				
			||||||
	unsigned int hash = FNV_1_32;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (p = buf; p < end; p++) {
 | 
					 | 
				
			||||||
		hash *= FNV_P_32;
 | 
					 | 
				
			||||||
		hash ^= (unsigned int)*p;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return hash;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
 | 
					int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
 | 
				
			||||||
| 
						 | 
					@ -799,16 +756,16 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nfs_map_string_to_numeric(name, namelen, uid))
 | 
						if (nfs_map_string_to_numeric(name, namelen, uid))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
 | 
						return nfs_idmap_lookup_id(name, namelen, "uid", uid, idmap);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
 | 
					int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct idmap *idmap = server->nfs_client->cl_idmap;
 | 
						struct idmap *idmap = server->nfs_client->cl_idmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nfs_map_string_to_numeric(name, namelen, uid))
 | 
						if (nfs_map_string_to_numeric(name, namelen, gid))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
 | 
						return nfs_idmap_lookup_id(name, namelen, "gid", gid, idmap);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
 | 
					int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
 | 
				
			||||||
| 
						 | 
					@ -817,21 +774,19 @@ int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, s
 | 
				
			||||||
	int ret = -EINVAL;
 | 
						int ret = -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
 | 
						if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
 | 
				
			||||||
		ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
 | 
							ret = nfs_idmap_lookup_name(uid, "user", buf, buflen, idmap);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		ret = nfs_map_numeric_to_string(uid, buf, buflen);
 | 
							ret = nfs_map_numeric_to_string(uid, buf, buflen);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
 | 
					int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct idmap *idmap = server->nfs_client->cl_idmap;
 | 
						struct idmap *idmap = server->nfs_client->cl_idmap;
 | 
				
			||||||
	int ret = -EINVAL;
 | 
						int ret = -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
 | 
						if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
 | 
				
			||||||
		ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
 | 
							ret = nfs_idmap_lookup_name(gid, "group", buf, buflen, idmap);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		ret = nfs_map_numeric_to_string(uid, buf, buflen);
 | 
							ret = nfs_map_numeric_to_string(gid, buf, buflen);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										119
									
								
								fs/nfs/inode.c
									
										
									
									
									
								
							
							
						
						
									
										119
									
								
								fs/nfs/inode.c
									
										
									
									
									
								
							| 
						 | 
					@ -39,6 +39,7 @@
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/compat.h>
 | 
					#include <linux/compat.h>
 | 
				
			||||||
#include <linux/freezer.h>
 | 
					#include <linux/freezer.h>
 | 
				
			||||||
 | 
					#include <linux/crc32.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/system.h>
 | 
					#include <asm/system.h>
 | 
				
			||||||
#include <asm/uaccess.h>
 | 
					#include <asm/uaccess.h>
 | 
				
			||||||
| 
						 | 
					@ -51,6 +52,7 @@
 | 
				
			||||||
#include "fscache.h"
 | 
					#include "fscache.h"
 | 
				
			||||||
#include "dns_resolve.h"
 | 
					#include "dns_resolve.h"
 | 
				
			||||||
#include "pnfs.h"
 | 
					#include "pnfs.h"
 | 
				
			||||||
 | 
					#include "netns.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFSDBG_FACILITY		NFSDBG_VFS
 | 
					#define NFSDBG_FACILITY		NFSDBG_VFS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -388,9 +390,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 | 
				
			||||||
		unlock_new_inode(inode);
 | 
							unlock_new_inode(inode);
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		nfs_refresh_inode(inode, fattr);
 | 
							nfs_refresh_inode(inode, fattr);
 | 
				
			||||||
	dprintk("NFS: nfs_fhget(%s/%Ld ct=%d)\n",
 | 
						dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
 | 
				
			||||||
		inode->i_sb->s_id,
 | 
							inode->i_sb->s_id,
 | 
				
			||||||
		(long long)NFS_FILEID(inode),
 | 
							(long long)NFS_FILEID(inode),
 | 
				
			||||||
 | 
							nfs_display_fhandle_hash(fh),
 | 
				
			||||||
		atomic_read(&inode->i_count));
 | 
							atomic_read(&inode->i_count));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
| 
						 | 
					@ -401,7 +404,7 @@ out_no_inode:
 | 
				
			||||||
	goto out;
 | 
						goto out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE)
 | 
					#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE|ATTR_OPEN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
nfs_setattr(struct dentry *dentry, struct iattr *attr)
 | 
					nfs_setattr(struct dentry *dentry, struct iattr *attr)
 | 
				
			||||||
| 
						 | 
					@ -423,7 +426,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Optimization: if the end result is no change, don't RPC */
 | 
						/* Optimization: if the end result is no change, don't RPC */
 | 
				
			||||||
	attr->ia_valid &= NFS_VALID_ATTRS;
 | 
						attr->ia_valid &= NFS_VALID_ATTRS;
 | 
				
			||||||
	if ((attr->ia_valid & ~ATTR_FILE) == 0)
 | 
						if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Write all dirty data */
 | 
						/* Write all dirty data */
 | 
				
			||||||
| 
						 | 
					@ -1044,6 +1047,67 @@ struct nfs_fh *nfs_alloc_fhandle(void)
 | 
				
			||||||
	return fh;
 | 
						return fh;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef NFS_DEBUG
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle
 | 
				
			||||||
 | 
					 *                             in the same way that wireshark does
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @fh: file handle
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For debugging only.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* wireshark uses 32-bit AUTODIN crc and does a bitwise
 | 
				
			||||||
 | 
						 * not on the result */
 | 
				
			||||||
 | 
						return ~crc32(0xFFFFFFFF, &fh->data[0], fh->size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * _nfs_display_fhandle - display an NFS file handle on the console
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @fh: file handle to display
 | 
				
			||||||
 | 
					 * @caption: display caption
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For debugging only.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned short i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fh == NULL || fh->size == 0) {
 | 
				
			||||||
 | 
							printk(KERN_DEFAULT "%s at %p is empty\n", caption, fh);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printk(KERN_DEFAULT "%s at %p is %u bytes, crc: 0x%08x:\n",
 | 
				
			||||||
 | 
						       caption, fh, fh->size, _nfs_display_fhandle_hash(fh));
 | 
				
			||||||
 | 
						for (i = 0; i < fh->size; i += 16) {
 | 
				
			||||||
 | 
							__be32 *pos = (__be32 *)&fh->data[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch ((fh->size - i - 1) >> 2) {
 | 
				
			||||||
 | 
							case 0:
 | 
				
			||||||
 | 
								printk(KERN_DEFAULT " %08x\n",
 | 
				
			||||||
 | 
									be32_to_cpup(pos));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 1:
 | 
				
			||||||
 | 
								printk(KERN_DEFAULT " %08x %08x\n",
 | 
				
			||||||
 | 
									be32_to_cpup(pos), be32_to_cpup(pos + 1));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 2:
 | 
				
			||||||
 | 
								printk(KERN_DEFAULT " %08x %08x %08x\n",
 | 
				
			||||||
 | 
									be32_to_cpup(pos), be32_to_cpup(pos + 1),
 | 
				
			||||||
 | 
									be32_to_cpup(pos + 2));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								printk(KERN_DEFAULT " %08x %08x %08x %08x\n",
 | 
				
			||||||
 | 
									be32_to_cpup(pos), be32_to_cpup(pos + 1),
 | 
				
			||||||
 | 
									be32_to_cpup(pos + 2), be32_to_cpup(pos + 3));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * nfs_inode_attrs_need_update - check if the inode attributes need updating
 | 
					 * nfs_inode_attrs_need_update - check if the inode attributes need updating
 | 
				
			||||||
 * @inode - pointer to inode
 | 
					 * @inode - pointer to inode
 | 
				
			||||||
| 
						 | 
					@ -1211,8 +1275,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 | 
				
			||||||
	unsigned long now = jiffies;
 | 
						unsigned long now = jiffies;
 | 
				
			||||||
	unsigned long save_cache_validity;
 | 
						unsigned long save_cache_validity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
 | 
						dfprintk(VFS, "NFS: %s(%s/%ld fh_crc=0x%08x ct=%d info=0x%x)\n",
 | 
				
			||||||
			__func__, inode->i_sb->s_id, inode->i_ino,
 | 
								__func__, inode->i_sb->s_id, inode->i_ino,
 | 
				
			||||||
 | 
								nfs_display_fhandle_hash(NFS_FH(inode)),
 | 
				
			||||||
			atomic_read(&inode->i_count), fattr->valid);
 | 
								atomic_read(&inode->i_count), fattr->valid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
 | 
						if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
 | 
				
			||||||
| 
						 | 
					@ -1406,7 +1471,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Big trouble! The inode has become a different object.
 | 
						 * Big trouble! The inode has become a different object.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
 | 
						printk(KERN_DEBUG "NFS: %s: inode %ld mode changed, %07o to %07o\n",
 | 
				
			||||||
			__func__, inode->i_ino, inode->i_mode, fattr->mode);
 | 
								__func__, inode->i_ino, inode->i_mode, fattr->mode);
 | 
				
			||||||
 out_err:
 | 
					 out_err:
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -1495,7 +1560,7 @@ static void init_once(void *foo)
 | 
				
			||||||
	INIT_LIST_HEAD(&nfsi->open_files);
 | 
						INIT_LIST_HEAD(&nfsi->open_files);
 | 
				
			||||||
	INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
 | 
						INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
 | 
				
			||||||
	INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
 | 
						INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
 | 
				
			||||||
	INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
 | 
						INIT_LIST_HEAD(&nfsi->commit_list);
 | 
				
			||||||
	nfsi->npages = 0;
 | 
						nfsi->npages = 0;
 | 
				
			||||||
	nfsi->ncommit = 0;
 | 
						nfsi->ncommit = 0;
 | 
				
			||||||
	atomic_set(&nfsi->silly_count, 1);
 | 
						atomic_set(&nfsi->silly_count, 1);
 | 
				
			||||||
| 
						 | 
					@ -1552,6 +1617,28 @@ static void nfsiod_stop(void)
 | 
				
			||||||
	destroy_workqueue(wq);
 | 
						destroy_workqueue(wq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int nfs_net_id;
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(nfs_net_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nfs_net_init(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						nfs_clients_init(net);
 | 
				
			||||||
 | 
						return nfs_dns_resolver_cache_init(net);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs_net_exit(struct net *net)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						nfs_dns_resolver_cache_destroy(net);
 | 
				
			||||||
 | 
						nfs_cleanup_cb_ident_idr(net);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct pernet_operations nfs_net_ops = {
 | 
				
			||||||
 | 
						.init = nfs_net_init,
 | 
				
			||||||
 | 
						.exit = nfs_net_exit,
 | 
				
			||||||
 | 
						.id   = &nfs_net_id,
 | 
				
			||||||
 | 
						.size = sizeof(struct nfs_net),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Initialize NFS
 | 
					 * Initialize NFS
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -1561,9 +1648,13 @@ static int __init init_nfs_fs(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = nfs_idmap_init();
 | 
						err = nfs_idmap_init();
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		goto out9;
 | 
							goto out10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = nfs_dns_resolver_init();
 | 
						err = nfs_dns_resolver_init();
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							goto out9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = register_pernet_subsys(&nfs_net_ops);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		goto out8;
 | 
							goto out8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1600,14 +1691,14 @@ static int __init init_nfs_fs(void)
 | 
				
			||||||
		goto out0;
 | 
							goto out0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PROC_FS
 | 
					#ifdef CONFIG_PROC_FS
 | 
				
			||||||
	rpc_proc_register(&nfs_rpcstat);
 | 
						rpc_proc_register(&init_net, &nfs_rpcstat);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	if ((err = register_nfs_fs()) != 0)
 | 
						if ((err = register_nfs_fs()) != 0)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
#ifdef CONFIG_PROC_FS
 | 
					#ifdef CONFIG_PROC_FS
 | 
				
			||||||
	rpc_proc_unregister("nfs");
 | 
						rpc_proc_unregister(&init_net, "nfs");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	nfs_destroy_directcache();
 | 
						nfs_destroy_directcache();
 | 
				
			||||||
out0:
 | 
					out0:
 | 
				
			||||||
| 
						 | 
					@ -1625,10 +1716,12 @@ out5:
 | 
				
			||||||
out6:
 | 
					out6:
 | 
				
			||||||
	nfs_fscache_unregister();
 | 
						nfs_fscache_unregister();
 | 
				
			||||||
out7:
 | 
					out7:
 | 
				
			||||||
	nfs_dns_resolver_destroy();
 | 
						unregister_pernet_subsys(&nfs_net_ops);
 | 
				
			||||||
out8:
 | 
					out8:
 | 
				
			||||||
	nfs_idmap_quit();
 | 
						nfs_dns_resolver_destroy();
 | 
				
			||||||
out9:
 | 
					out9:
 | 
				
			||||||
 | 
						nfs_idmap_quit();
 | 
				
			||||||
 | 
					out10:
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1640,12 +1733,12 @@ static void __exit exit_nfs_fs(void)
 | 
				
			||||||
	nfs_destroy_inodecache();
 | 
						nfs_destroy_inodecache();
 | 
				
			||||||
	nfs_destroy_nfspagecache();
 | 
						nfs_destroy_nfspagecache();
 | 
				
			||||||
	nfs_fscache_unregister();
 | 
						nfs_fscache_unregister();
 | 
				
			||||||
 | 
						unregister_pernet_subsys(&nfs_net_ops);
 | 
				
			||||||
	nfs_dns_resolver_destroy();
 | 
						nfs_dns_resolver_destroy();
 | 
				
			||||||
	nfs_idmap_quit();
 | 
						nfs_idmap_quit();
 | 
				
			||||||
#ifdef CONFIG_PROC_FS
 | 
					#ifdef CONFIG_PROC_FS
 | 
				
			||||||
	rpc_proc_unregister("nfs");
 | 
						rpc_proc_unregister(&init_net, "nfs");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	nfs_cleanup_cb_ident_idr();
 | 
					 | 
				
			||||||
	unregister_nfs_fs();
 | 
						unregister_nfs_fs();
 | 
				
			||||||
	nfs_fs_proc_exit();
 | 
						nfs_fs_proc_exit();
 | 
				
			||||||
	nfsiod_stop();
 | 
						nfsiod_stop();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,6 +123,7 @@ struct nfs_parsed_mount_data {
 | 
				
			||||||
	} nfs_server;
 | 
						} nfs_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct security_mnt_opts lsm_opts;
 | 
						struct security_mnt_opts lsm_opts;
 | 
				
			||||||
 | 
						struct net		*net;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* mount_clnt.c */
 | 
					/* mount_clnt.c */
 | 
				
			||||||
| 
						 | 
					@ -137,20 +138,22 @@ struct nfs_mount_request {
 | 
				
			||||||
	int			noresvport;
 | 
						int			noresvport;
 | 
				
			||||||
	unsigned int		*auth_flav_len;
 | 
						unsigned int		*auth_flav_len;
 | 
				
			||||||
	rpc_authflavor_t	*auth_flavs;
 | 
						rpc_authflavor_t	*auth_flavs;
 | 
				
			||||||
 | 
						struct net		*net;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int nfs_mount(struct nfs_mount_request *info);
 | 
					extern int nfs_mount(struct nfs_mount_request *info);
 | 
				
			||||||
extern void nfs_umount(const struct nfs_mount_request *info);
 | 
					extern void nfs_umount(const struct nfs_mount_request *info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* client.c */
 | 
					/* client.c */
 | 
				
			||||||
extern struct rpc_program nfs_program;
 | 
					extern const struct rpc_program nfs_program;
 | 
				
			||||||
 | 
					extern void nfs_clients_init(struct net *net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void nfs_cleanup_cb_ident_idr(void);
 | 
					extern void nfs_cleanup_cb_ident_idr(struct net *);
 | 
				
			||||||
extern void nfs_put_client(struct nfs_client *);
 | 
					extern void nfs_put_client(struct nfs_client *);
 | 
				
			||||||
extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *);
 | 
					extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
 | 
				
			||||||
extern struct nfs_client *nfs4_find_client_ident(int);
 | 
					 | 
				
			||||||
extern struct nfs_client *
 | 
					extern struct nfs_client *
 | 
				
			||||||
nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *);
 | 
					nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
 | 
				
			||||||
 | 
									struct nfs4_sessionid *);
 | 
				
			||||||
extern struct nfs_server *nfs_create_server(
 | 
					extern struct nfs_server *nfs_create_server(
 | 
				
			||||||
					const struct nfs_parsed_mount_data *,
 | 
										const struct nfs_parsed_mount_data *,
 | 
				
			||||||
					struct nfs_fh *);
 | 
										struct nfs_fh *);
 | 
				
			||||||
| 
						 | 
					@ -329,6 +332,8 @@ void nfs_retry_commit(struct list_head *page_list,
 | 
				
			||||||
void nfs_commit_clear_lock(struct nfs_inode *nfsi);
 | 
					void nfs_commit_clear_lock(struct nfs_inode *nfsi);
 | 
				
			||||||
void nfs_commitdata_release(void *data);
 | 
					void nfs_commitdata_release(void *data);
 | 
				
			||||||
void nfs_commit_release_pages(struct nfs_write_data *data);
 | 
					void nfs_commit_release_pages(struct nfs_write_data *data);
 | 
				
			||||||
 | 
					void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head);
 | 
				
			||||||
 | 
					void nfs_request_remove_commit_list(struct nfs_page *req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_MIGRATION
 | 
					#ifdef CONFIG_MIGRATION
 | 
				
			||||||
extern int nfs_migrate_page(struct address_space *,
 | 
					extern int nfs_migrate_page(struct address_space *,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,7 +16,7 @@
 | 
				
			||||||
#include <linux/nfs_fs.h>
 | 
					#include <linux/nfs_fs.h>
 | 
				
			||||||
#include "internal.h"
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef RPC_DEBUG
 | 
					#ifdef NFS_DEBUG
 | 
				
			||||||
# define NFSDBG_FACILITY	NFSDBG_MOUNT
 | 
					# define NFSDBG_FACILITY	NFSDBG_MOUNT
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,7 +67,7 @@ enum {
 | 
				
			||||||
	MOUNTPROC3_EXPORT	= 5,
 | 
						MOUNTPROC3_EXPORT	= 5,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_program	mnt_program;
 | 
					static const struct rpc_program mnt_program;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Defined by OpenGroup XNFS Version 3W, chapter 8
 | 
					 * Defined by OpenGroup XNFS Version 3W, chapter 8
 | 
				
			||||||
| 
						 | 
					@ -153,7 +153,7 @@ int nfs_mount(struct nfs_mount_request *info)
 | 
				
			||||||
		.rpc_resp	= &result,
 | 
							.rpc_resp	= &result,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct rpc_create_args args = {
 | 
						struct rpc_create_args args = {
 | 
				
			||||||
		.net		= &init_net,
 | 
							.net		= info->net,
 | 
				
			||||||
		.protocol	= info->protocol,
 | 
							.protocol	= info->protocol,
 | 
				
			||||||
		.address	= info->sap,
 | 
							.address	= info->sap,
 | 
				
			||||||
		.addrsize	= info->salen,
 | 
							.addrsize	= info->salen,
 | 
				
			||||||
| 
						 | 
					@ -225,7 +225,7 @@ void nfs_umount(const struct nfs_mount_request *info)
 | 
				
			||||||
		.to_retries = 2,
 | 
							.to_retries = 2,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct rpc_create_args args = {
 | 
						struct rpc_create_args args = {
 | 
				
			||||||
		.net		= &init_net,
 | 
							.net		= info->net,
 | 
				
			||||||
		.protocol	= IPPROTO_UDP,
 | 
							.protocol	= IPPROTO_UDP,
 | 
				
			||||||
		.address	= info->sap,
 | 
							.address	= info->sap,
 | 
				
			||||||
		.addrsize	= info->salen,
 | 
							.addrsize	= info->salen,
 | 
				
			||||||
| 
						 | 
					@ -488,19 +488,19 @@ static struct rpc_procinfo mnt3_procedures[] = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_version mnt_version1 = {
 | 
					static const struct rpc_version mnt_version1 = {
 | 
				
			||||||
	.number		= 1,
 | 
						.number		= 1,
 | 
				
			||||||
	.nrprocs	= ARRAY_SIZE(mnt_procedures),
 | 
						.nrprocs	= ARRAY_SIZE(mnt_procedures),
 | 
				
			||||||
	.procs		= mnt_procedures,
 | 
						.procs		= mnt_procedures,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_version mnt_version3 = {
 | 
					static const struct rpc_version mnt_version3 = {
 | 
				
			||||||
	.number		= 3,
 | 
						.number		= 3,
 | 
				
			||||||
	.nrprocs	= ARRAY_SIZE(mnt3_procedures),
 | 
						.nrprocs	= ARRAY_SIZE(mnt3_procedures),
 | 
				
			||||||
	.procs		= mnt3_procedures,
 | 
						.procs		= mnt3_procedures,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_version *mnt_version[] = {
 | 
					static const struct rpc_version *mnt_version[] = {
 | 
				
			||||||
	NULL,
 | 
						NULL,
 | 
				
			||||||
	&mnt_version1,
 | 
						&mnt_version1,
 | 
				
			||||||
	NULL,
 | 
						NULL,
 | 
				
			||||||
| 
						 | 
					@ -509,7 +509,7 @@ static struct rpc_version *mnt_version[] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_stat mnt_stats;
 | 
					static struct rpc_stat mnt_stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_program mnt_program = {
 | 
					static const struct rpc_program mnt_program = {
 | 
				
			||||||
	.name		= "mount",
 | 
						.name		= "mount",
 | 
				
			||||||
	.number		= NFS_MNT_PROGRAM,
 | 
						.number		= NFS_MNT_PROGRAM,
 | 
				
			||||||
	.nrvers		= ARRAY_SIZE(mnt_version),
 | 
						.nrvers		= ARRAY_SIZE(mnt_version),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -276,7 +276,10 @@ out:
 | 
				
			||||||
	nfs_free_fattr(fattr);
 | 
						nfs_free_fattr(fattr);
 | 
				
			||||||
	nfs_free_fhandle(fh);
 | 
						nfs_free_fhandle(fh);
 | 
				
			||||||
out_nofree:
 | 
					out_nofree:
 | 
				
			||||||
	dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt);
 | 
						if (IS_ERR(mnt))
 | 
				
			||||||
 | 
							dprintk("<-- %s(): error %ld\n", __func__, PTR_ERR(mnt));
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							dprintk("<-- %s() = %p\n", __func__, mnt);
 | 
				
			||||||
	return mnt;
 | 
						return mnt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										27
									
								
								fs/nfs/netns.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								fs/nfs/netns.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					#ifndef __NFS_NETNS_H__
 | 
				
			||||||
 | 
					#define __NFS_NETNS_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <net/net_namespace.h>
 | 
				
			||||||
 | 
					#include <net/netns/generic.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bl_dev_msg {
 | 
				
			||||||
 | 
						int32_t status;
 | 
				
			||||||
 | 
						uint32_t major, minor;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct nfs_net {
 | 
				
			||||||
 | 
						struct cache_detail *nfs_dns_resolve;
 | 
				
			||||||
 | 
						struct rpc_pipe *bl_device_pipe;
 | 
				
			||||||
 | 
						struct bl_dev_msg bl_mount_reply;
 | 
				
			||||||
 | 
						wait_queue_head_t bl_wq;
 | 
				
			||||||
 | 
						struct list_head nfs_client_list;
 | 
				
			||||||
 | 
						struct list_head nfs_volume_list;
 | 
				
			||||||
 | 
					#ifdef CONFIG_NFS_V4
 | 
				
			||||||
 | 
						struct idr cb_ident_idr; /* Protected by nfs_client_lock */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						spinlock_t nfs_client_lock;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int nfs_net_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -1150,7 +1150,7 @@ struct rpc_procinfo	nfs_procedures[] = {
 | 
				
			||||||
	PROC(STATFS,	fhandle,	statfsres,	0),
 | 
						PROC(STATFS,	fhandle,	statfsres,	0),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_version		nfs_version2 = {
 | 
					const struct rpc_version nfs_version2 = {
 | 
				
			||||||
	.number			= 2,
 | 
						.number			= 2,
 | 
				
			||||||
	.nrprocs		= ARRAY_SIZE(nfs_procedures),
 | 
						.nrprocs		= ARRAY_SIZE(nfs_procedures),
 | 
				
			||||||
	.procs			= nfs_procedures
 | 
						.procs			= nfs_procedures
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -192,7 +192,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
 | 
				
			||||||
		.pages = pages,
 | 
							.pages = pages,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct nfs3_getaclres res = {
 | 
						struct nfs3_getaclres res = {
 | 
				
			||||||
		0
 | 
							NULL,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct rpc_message msg = {
 | 
						struct rpc_message msg = {
 | 
				
			||||||
		.rpc_argp	= &args,
 | 
							.rpc_argp	= &args,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -428,6 +428,11 @@ nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 | 
				
			||||||
	msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
 | 
						msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs3_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rpc_call_start(task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 | 
					nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -445,6 +450,11 @@ nfs3_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
 | 
				
			||||||
	msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME];
 | 
						msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs3_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rpc_call_start(task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
 | 
					nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
 | 
				
			||||||
		      struct inode *new_dir)
 | 
							      struct inode *new_dir)
 | 
				
			||||||
| 
						 | 
					@ -814,6 +824,11 @@ static void nfs3_proc_read_setup(struct nfs_read_data *data, struct rpc_message
 | 
				
			||||||
	msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ];
 | 
						msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rpc_call_start(task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
 | 
					static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (nfs3_async_handle_jukebox(task, data->inode))
 | 
						if (nfs3_async_handle_jukebox(task, data->inode))
 | 
				
			||||||
| 
						 | 
					@ -828,6 +843,11 @@ static void nfs3_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
 | 
				
			||||||
	msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE];
 | 
						msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs3_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rpc_call_start(task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data)
 | 
					static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (nfs3_async_handle_jukebox(task, data->inode))
 | 
						if (nfs3_async_handle_jukebox(task, data->inode))
 | 
				
			||||||
| 
						 | 
					@ -864,9 +884,11 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
 | 
				
			||||||
	.create		= nfs3_proc_create,
 | 
						.create		= nfs3_proc_create,
 | 
				
			||||||
	.remove		= nfs3_proc_remove,
 | 
						.remove		= nfs3_proc_remove,
 | 
				
			||||||
	.unlink_setup	= nfs3_proc_unlink_setup,
 | 
						.unlink_setup	= nfs3_proc_unlink_setup,
 | 
				
			||||||
 | 
						.unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare,
 | 
				
			||||||
	.unlink_done	= nfs3_proc_unlink_done,
 | 
						.unlink_done	= nfs3_proc_unlink_done,
 | 
				
			||||||
	.rename		= nfs3_proc_rename,
 | 
						.rename		= nfs3_proc_rename,
 | 
				
			||||||
	.rename_setup	= nfs3_proc_rename_setup,
 | 
						.rename_setup	= nfs3_proc_rename_setup,
 | 
				
			||||||
 | 
						.rename_rpc_prepare = nfs3_proc_rename_rpc_prepare,
 | 
				
			||||||
	.rename_done	= nfs3_proc_rename_done,
 | 
						.rename_done	= nfs3_proc_rename_done,
 | 
				
			||||||
	.link		= nfs3_proc_link,
 | 
						.link		= nfs3_proc_link,
 | 
				
			||||||
	.symlink	= nfs3_proc_symlink,
 | 
						.symlink	= nfs3_proc_symlink,
 | 
				
			||||||
| 
						 | 
					@ -879,8 +901,10 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
 | 
				
			||||||
	.pathconf	= nfs3_proc_pathconf,
 | 
						.pathconf	= nfs3_proc_pathconf,
 | 
				
			||||||
	.decode_dirent	= nfs3_decode_dirent,
 | 
						.decode_dirent	= nfs3_decode_dirent,
 | 
				
			||||||
	.read_setup	= nfs3_proc_read_setup,
 | 
						.read_setup	= nfs3_proc_read_setup,
 | 
				
			||||||
 | 
						.read_rpc_prepare = nfs3_proc_read_rpc_prepare,
 | 
				
			||||||
	.read_done	= nfs3_read_done,
 | 
						.read_done	= nfs3_read_done,
 | 
				
			||||||
	.write_setup	= nfs3_proc_write_setup,
 | 
						.write_setup	= nfs3_proc_write_setup,
 | 
				
			||||||
 | 
						.write_rpc_prepare = nfs3_proc_write_rpc_prepare,
 | 
				
			||||||
	.write_done	= nfs3_write_done,
 | 
						.write_done	= nfs3_write_done,
 | 
				
			||||||
	.commit_setup	= nfs3_proc_commit_setup,
 | 
						.commit_setup	= nfs3_proc_commit_setup,
 | 
				
			||||||
	.commit_done	= nfs3_commit_done,
 | 
						.commit_done	= nfs3_commit_done,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2461,7 +2461,7 @@ struct rpc_procinfo	nfs3_procedures[] = {
 | 
				
			||||||
	PROC(COMMIT,		commit,		commit,		5),
 | 
						PROC(COMMIT,		commit,		commit,		5),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_version		nfs_version3 = {
 | 
					const struct rpc_version nfs_version3 = {
 | 
				
			||||||
	.number			= 3,
 | 
						.number			= 3,
 | 
				
			||||||
	.nrprocs		= ARRAY_SIZE(nfs3_procedures),
 | 
						.nrprocs		= ARRAY_SIZE(nfs3_procedures),
 | 
				
			||||||
	.procs			= nfs3_procedures
 | 
						.procs			= nfs3_procedures
 | 
				
			||||||
| 
						 | 
					@ -2489,7 +2489,7 @@ static struct rpc_procinfo	nfs3_acl_procedures[] = {
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_version		nfsacl_version3 = {
 | 
					const struct rpc_version nfsacl_version3 = {
 | 
				
			||||||
	.number			= 3,
 | 
						.number			= 3,
 | 
				
			||||||
	.nrprocs		= sizeof(nfs3_acl_procedures)/
 | 
						.nrprocs		= sizeof(nfs3_acl_procedures)/
 | 
				
			||||||
				  sizeof(nfs3_acl_procedures[0]),
 | 
									  sizeof(nfs3_acl_procedures[0]),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,6 @@ enum nfs4_client_state {
 | 
				
			||||||
	NFS4CLNT_RECLAIM_REBOOT,
 | 
						NFS4CLNT_RECLAIM_REBOOT,
 | 
				
			||||||
	NFS4CLNT_RECLAIM_NOGRACE,
 | 
						NFS4CLNT_RECLAIM_NOGRACE,
 | 
				
			||||||
	NFS4CLNT_DELEGRETURN,
 | 
						NFS4CLNT_DELEGRETURN,
 | 
				
			||||||
	NFS4CLNT_LAYOUTRECALL,
 | 
					 | 
				
			||||||
	NFS4CLNT_SESSION_RESET,
 | 
						NFS4CLNT_SESSION_RESET,
 | 
				
			||||||
	NFS4CLNT_RECALL_SLOT,
 | 
						NFS4CLNT_RECALL_SLOT,
 | 
				
			||||||
	NFS4CLNT_LEASE_CONFIRM,
 | 
						NFS4CLNT_LEASE_CONFIRM,
 | 
				
			||||||
| 
						 | 
					@ -44,7 +43,7 @@ struct nfs4_minor_version_ops {
 | 
				
			||||||
			struct nfs4_sequence_args *args,
 | 
								struct nfs4_sequence_args *args,
 | 
				
			||||||
			struct nfs4_sequence_res *res,
 | 
								struct nfs4_sequence_res *res,
 | 
				
			||||||
			int cache_reply);
 | 
								int cache_reply);
 | 
				
			||||||
	int	(*validate_stateid)(struct nfs_delegation *,
 | 
						bool	(*match_stateid)(const nfs4_stateid *,
 | 
				
			||||||
			const nfs4_stateid *);
 | 
								const nfs4_stateid *);
 | 
				
			||||||
	int	(*find_root_sec)(struct nfs_server *, struct nfs_fh *,
 | 
						int	(*find_root_sec)(struct nfs_server *, struct nfs_fh *,
 | 
				
			||||||
			struct nfs_fsinfo *);
 | 
								struct nfs_fsinfo *);
 | 
				
			||||||
| 
						 | 
					@ -53,26 +52,25 @@ struct nfs4_minor_version_ops {
 | 
				
			||||||
	const struct nfs4_state_maintenance_ops *state_renewal_ops;
 | 
						const struct nfs4_state_maintenance_ops *state_renewal_ops;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					struct nfs_unique_id {
 | 
				
			||||||
 * struct rpc_sequence ensures that RPC calls are sent in the exact
 | 
						struct rb_node rb_node;
 | 
				
			||||||
 * order that they appear on the list.
 | 
						__u64 id;
 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct rpc_sequence {
 | 
					 | 
				
			||||||
	struct rpc_wait_queue	wait;	/* RPC call delay queue */
 | 
					 | 
				
			||||||
	spinlock_t lock;		/* Protects the list */
 | 
					 | 
				
			||||||
	struct list_head list;		/* Defines sequence of RPC calls */
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFS_SEQID_CONFIRMED 1
 | 
					#define NFS_SEQID_CONFIRMED 1
 | 
				
			||||||
struct nfs_seqid_counter {
 | 
					struct nfs_seqid_counter {
 | 
				
			||||||
	struct rpc_sequence *sequence;
 | 
						int owner_id;
 | 
				
			||||||
	int flags;
 | 
						int flags;
 | 
				
			||||||
	u32 counter;
 | 
						u32 counter;
 | 
				
			||||||
 | 
						spinlock_t lock;		/* Protects the list */
 | 
				
			||||||
 | 
						struct list_head list;		/* Defines sequence of RPC calls */
 | 
				
			||||||
 | 
						struct rpc_wait_queue	wait;	/* RPC call delay queue */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs_seqid {
 | 
					struct nfs_seqid {
 | 
				
			||||||
	struct nfs_seqid_counter *sequence;
 | 
						struct nfs_seqid_counter *sequence;
 | 
				
			||||||
	struct list_head list;
 | 
						struct list_head list;
 | 
				
			||||||
 | 
						struct rpc_task *task;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status)
 | 
					static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status)
 | 
				
			||||||
| 
						 | 
					@ -81,18 +79,12 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status
 | 
				
			||||||
		seqid->flags |= NFS_SEQID_CONFIRMED;
 | 
							seqid->flags |= NFS_SEQID_CONFIRMED;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs_unique_id {
 | 
					 | 
				
			||||||
	struct rb_node rb_node;
 | 
					 | 
				
			||||||
	__u64 id;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * NFS4 state_owners and lock_owners are simply labels for ordered
 | 
					 * NFS4 state_owners and lock_owners are simply labels for ordered
 | 
				
			||||||
 * sequences of RPC calls. Their sole purpose is to provide once-only
 | 
					 * sequences of RPC calls. Their sole purpose is to provide once-only
 | 
				
			||||||
 * semantics by allowing the server to identify replayed requests.
 | 
					 * semantics by allowing the server to identify replayed requests.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct nfs4_state_owner {
 | 
					struct nfs4_state_owner {
 | 
				
			||||||
	struct nfs_unique_id so_owner_id;
 | 
					 | 
				
			||||||
	struct nfs_server    *so_server;
 | 
						struct nfs_server    *so_server;
 | 
				
			||||||
	struct list_head     so_lru;
 | 
						struct list_head     so_lru;
 | 
				
			||||||
	unsigned long        so_expires;
 | 
						unsigned long        so_expires;
 | 
				
			||||||
| 
						 | 
					@ -105,7 +97,6 @@ struct nfs4_state_owner {
 | 
				
			||||||
	unsigned long	     so_flags;
 | 
						unsigned long	     so_flags;
 | 
				
			||||||
	struct list_head     so_states;
 | 
						struct list_head     so_states;
 | 
				
			||||||
	struct nfs_seqid_counter so_seqid;
 | 
						struct nfs_seqid_counter so_seqid;
 | 
				
			||||||
	struct rpc_sequence  so_sequence;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
| 
						 | 
					@ -146,8 +137,6 @@ struct nfs4_lock_state {
 | 
				
			||||||
#define NFS_LOCK_INITIALIZED 1
 | 
					#define NFS_LOCK_INITIALIZED 1
 | 
				
			||||||
	int			ls_flags;
 | 
						int			ls_flags;
 | 
				
			||||||
	struct nfs_seqid_counter	ls_seqid;
 | 
						struct nfs_seqid_counter	ls_seqid;
 | 
				
			||||||
	struct rpc_sequence	ls_sequence;
 | 
					 | 
				
			||||||
	struct nfs_unique_id	ls_id;
 | 
					 | 
				
			||||||
	nfs4_stateid		ls_stateid;
 | 
						nfs4_stateid		ls_stateid;
 | 
				
			||||||
	atomic_t		ls_count;
 | 
						atomic_t		ls_count;
 | 
				
			||||||
	struct nfs4_lock_owner	ls_owner;
 | 
						struct nfs4_lock_owner	ls_owner;
 | 
				
			||||||
| 
						 | 
					@ -193,6 +182,7 @@ struct nfs4_exception {
 | 
				
			||||||
	long timeout;
 | 
						long timeout;
 | 
				
			||||||
	int retry;
 | 
						int retry;
 | 
				
			||||||
	struct nfs4_state *state;
 | 
						struct nfs4_state *state;
 | 
				
			||||||
 | 
						struct inode *inode;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs4_state_recovery_ops {
 | 
					struct nfs4_state_recovery_ops {
 | 
				
			||||||
| 
						 | 
					@ -224,7 +214,7 @@ extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, boo
 | 
				
			||||||
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
 | 
					extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
 | 
				
			||||||
extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
 | 
					extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
 | 
				
			||||||
		struct nfs4_fs_locations *fs_locations, struct page *page);
 | 
							struct nfs4_fs_locations *fs_locations, struct page *page);
 | 
				
			||||||
extern void nfs4_release_lockowner(const struct nfs4_lock_state *);
 | 
					extern int nfs4_release_lockowner(struct nfs4_lock_state *);
 | 
				
			||||||
extern const struct xattr_handler *nfs4_xattr_handlers[];
 | 
					extern const struct xattr_handler *nfs4_xattr_handlers[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					#if defined(CONFIG_NFS_V4_1)
 | 
				
			||||||
| 
						 | 
					@ -233,12 +223,13 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
 | 
				
			||||||
	return server->nfs_client->cl_session;
 | 
						return server->nfs_client->cl_session;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy);
 | 
				
			||||||
extern int nfs4_setup_sequence(const struct nfs_server *server,
 | 
					extern int nfs4_setup_sequence(const struct nfs_server *server,
 | 
				
			||||||
		struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
 | 
							struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
 | 
				
			||||||
		int cache_reply, struct rpc_task *task);
 | 
							struct rpc_task *task);
 | 
				
			||||||
extern int nfs41_setup_sequence(struct nfs4_session *session,
 | 
					extern int nfs41_setup_sequence(struct nfs4_session *session,
 | 
				
			||||||
		struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
 | 
							struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
 | 
				
			||||||
		int cache_reply, struct rpc_task *task);
 | 
							struct rpc_task *task);
 | 
				
			||||||
extern void nfs4_destroy_session(struct nfs4_session *session);
 | 
					extern void nfs4_destroy_session(struct nfs4_session *session);
 | 
				
			||||||
extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
 | 
					extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
 | 
				
			||||||
extern int nfs4_proc_create_session(struct nfs_client *);
 | 
					extern int nfs4_proc_create_session(struct nfs_client *);
 | 
				
			||||||
| 
						 | 
					@ -269,7 +260,7 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int nfs4_setup_sequence(const struct nfs_server *server,
 | 
					static inline int nfs4_setup_sequence(const struct nfs_server *server,
 | 
				
			||||||
		struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
 | 
							struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
 | 
				
			||||||
		int cache_reply, struct rpc_task *task)
 | 
							struct rpc_task *task)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -319,7 +310,7 @@ static inline void nfs4_schedule_session_recovery(struct nfs4_session *session)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					#endif /* CONFIG_NFS_V4_1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
 | 
					extern struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *, gfp_t);
 | 
				
			||||||
extern void nfs4_put_state_owner(struct nfs4_state_owner *);
 | 
					extern void nfs4_put_state_owner(struct nfs4_state_owner *);
 | 
				
			||||||
extern void nfs4_purge_state_owners(struct nfs_server *);
 | 
					extern void nfs4_purge_state_owners(struct nfs_server *);
 | 
				
			||||||
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
 | 
					extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
 | 
				
			||||||
| 
						 | 
					@ -327,6 +318,8 @@ extern void nfs4_put_open_state(struct nfs4_state *);
 | 
				
			||||||
extern void nfs4_close_state(struct nfs4_state *, fmode_t);
 | 
					extern void nfs4_close_state(struct nfs4_state *, fmode_t);
 | 
				
			||||||
extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
 | 
					extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
 | 
				
			||||||
extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
 | 
					extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
 | 
				
			||||||
 | 
					extern void nfs_inode_find_state_and_recover(struct inode *inode,
 | 
				
			||||||
 | 
							const nfs4_stateid *stateid);
 | 
				
			||||||
extern void nfs4_schedule_lease_recovery(struct nfs_client *);
 | 
					extern void nfs4_schedule_lease_recovery(struct nfs_client *);
 | 
				
			||||||
extern void nfs4_schedule_state_manager(struct nfs_client *);
 | 
					extern void nfs4_schedule_state_manager(struct nfs_client *);
 | 
				
			||||||
extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
 | 
					extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
 | 
				
			||||||
| 
						 | 
					@ -337,7 +330,8 @@ extern void nfs41_handle_server_scope(struct nfs_client *,
 | 
				
			||||||
				      struct server_scope **);
 | 
									      struct server_scope **);
 | 
				
			||||||
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
 | 
					extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
 | 
				
			||||||
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
 | 
					extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
 | 
				
			||||||
extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t);
 | 
					extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
 | 
				
			||||||
 | 
							fmode_t, fl_owner_t, pid_t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
 | 
					extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
 | 
				
			||||||
extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
 | 
					extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
 | 
				
			||||||
| 
						 | 
					@ -346,6 +340,8 @@ extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid);
 | 
				
			||||||
extern void nfs_release_seqid(struct nfs_seqid *seqid);
 | 
					extern void nfs_release_seqid(struct nfs_seqid *seqid);
 | 
				
			||||||
extern void nfs_free_seqid(struct nfs_seqid *seqid);
 | 
					extern void nfs_free_seqid(struct nfs_seqid *seqid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const nfs4_stateid zero_stateid;
 | 
					extern const nfs4_stateid zero_stateid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* nfs4xdr.c */
 | 
					/* nfs4xdr.c */
 | 
				
			||||||
| 
						 | 
					@ -357,6 +353,16 @@ struct nfs4_mount_data;
 | 
				
			||||||
extern struct svc_version nfs4_callback_version1;
 | 
					extern struct svc_version nfs4_callback_version1;
 | 
				
			||||||
extern struct svc_version nfs4_callback_version4;
 | 
					extern struct svc_version nfs4_callback_version4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void nfs4_stateid_copy(nfs4_stateid *dst, const nfs4_stateid *src)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						memcpy(dst, src, sizeof(*dst));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_stateid *src)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return memcmp(dst, src, sizeof(*dst)) == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define nfs4_close_state(a, b) do { } while (0)
 | 
					#define nfs4_close_state(a, b) do { } while (0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,10 @@
 | 
				
			||||||
#include <linux/nfs_page.h>
 | 
					#include <linux/nfs_page.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/sunrpc/metrics.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "internal.h"
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					#include "delegation.h"
 | 
				
			||||||
#include "nfs4filelayout.h"
 | 
					#include "nfs4filelayout.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 | 
					#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 | 
				
			||||||
| 
						 | 
					@ -84,12 +87,27 @@ static int filelayout_async_handle_error(struct rpc_task *task,
 | 
				
			||||||
					 struct nfs_client *clp,
 | 
										 struct nfs_client *clp,
 | 
				
			||||||
					 int *reset)
 | 
										 int *reset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_server *mds_server = NFS_SERVER(state->inode);
 | 
				
			||||||
 | 
						struct nfs_client *mds_client = mds_server->nfs_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (task->tk_status >= 0)
 | 
						if (task->tk_status >= 0)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	*reset = 0;
 | 
						*reset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (task->tk_status) {
 | 
						switch (task->tk_status) {
 | 
				
			||||||
 | 
						/* MDS state errors */
 | 
				
			||||||
 | 
						case -NFS4ERR_DELEG_REVOKED:
 | 
				
			||||||
 | 
						case -NFS4ERR_ADMIN_REVOKED:
 | 
				
			||||||
 | 
						case -NFS4ERR_BAD_STATEID:
 | 
				
			||||||
 | 
							nfs_remove_bad_delegation(state->inode);
 | 
				
			||||||
 | 
						case -NFS4ERR_OPENMODE:
 | 
				
			||||||
 | 
							nfs4_schedule_stateid_recovery(mds_server, state);
 | 
				
			||||||
 | 
							goto wait_on_recovery;
 | 
				
			||||||
 | 
						case -NFS4ERR_EXPIRED:
 | 
				
			||||||
 | 
							nfs4_schedule_stateid_recovery(mds_server, state);
 | 
				
			||||||
 | 
							nfs4_schedule_lease_recovery(mds_client);
 | 
				
			||||||
 | 
							goto wait_on_recovery;
 | 
				
			||||||
 | 
						/* DS session errors */
 | 
				
			||||||
	case -NFS4ERR_BADSESSION:
 | 
						case -NFS4ERR_BADSESSION:
 | 
				
			||||||
	case -NFS4ERR_BADSLOT:
 | 
						case -NFS4ERR_BADSLOT:
 | 
				
			||||||
	case -NFS4ERR_BAD_HIGH_SLOT:
 | 
						case -NFS4ERR_BAD_HIGH_SLOT:
 | 
				
			||||||
| 
						 | 
					@ -115,8 +133,14 @@ static int filelayout_async_handle_error(struct rpc_task *task,
 | 
				
			||||||
		*reset = 1;
 | 
							*reset = 1;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
	task->tk_status = 0;
 | 
						task->tk_status = 0;
 | 
				
			||||||
	return -EAGAIN;
 | 
						return -EAGAIN;
 | 
				
			||||||
 | 
					wait_on_recovery:
 | 
				
			||||||
 | 
						rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL);
 | 
				
			||||||
 | 
						if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0)
 | 
				
			||||||
 | 
							rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task);
 | 
				
			||||||
 | 
						goto out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* NFS_PROTO call done callback routines */
 | 
					/* NFS_PROTO call done callback routines */
 | 
				
			||||||
| 
						 | 
					@ -173,7 +197,7 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
 | 
						if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
 | 
				
			||||||
				&rdata->args.seq_args, &rdata->res.seq_res,
 | 
									&rdata->args.seq_args, &rdata->res.seq_res,
 | 
				
			||||||
				0, task))
 | 
									task))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rpc_call_start(task);
 | 
						rpc_call_start(task);
 | 
				
			||||||
| 
						 | 
					@ -189,10 +213,18 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data)
 | 
				
			||||||
	rdata->mds_ops->rpc_call_done(task, data);
 | 
						rdata->mds_ops->rpc_call_done(task, data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void filelayout_read_count_stats(struct rpc_task *task, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_read_data *rdata = (struct nfs_read_data *)data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rpc_count_iostats(task, NFS_SERVER(rdata->inode)->client->cl_metrics);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void filelayout_read_release(void *data)
 | 
					static void filelayout_read_release(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_read_data *rdata = (struct nfs_read_data *)data;
 | 
						struct nfs_read_data *rdata = (struct nfs_read_data *)data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						put_lseg(rdata->lseg);
 | 
				
			||||||
	rdata->mds_ops->rpc_release(data);
 | 
						rdata->mds_ops->rpc_release(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -254,7 +286,7 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
 | 
						if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
 | 
				
			||||||
				&wdata->args.seq_args, &wdata->res.seq_res,
 | 
									&wdata->args.seq_args, &wdata->res.seq_res,
 | 
				
			||||||
				0, task))
 | 
									task))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rpc_call_start(task);
 | 
						rpc_call_start(task);
 | 
				
			||||||
| 
						 | 
					@ -268,10 +300,18 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data)
 | 
				
			||||||
	wdata->mds_ops->rpc_call_done(task, data);
 | 
						wdata->mds_ops->rpc_call_done(task, data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void filelayout_write_count_stats(struct rpc_task *task, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_write_data *wdata = (struct nfs_write_data *)data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rpc_count_iostats(task, NFS_SERVER(wdata->inode)->client->cl_metrics);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void filelayout_write_release(void *data)
 | 
					static void filelayout_write_release(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_write_data *wdata = (struct nfs_write_data *)data;
 | 
						struct nfs_write_data *wdata = (struct nfs_write_data *)data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						put_lseg(wdata->lseg);
 | 
				
			||||||
	wdata->mds_ops->rpc_release(data);
 | 
						wdata->mds_ops->rpc_release(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -282,24 +322,28 @@ static void filelayout_commit_release(void *data)
 | 
				
			||||||
	nfs_commit_release_pages(wdata);
 | 
						nfs_commit_release_pages(wdata);
 | 
				
			||||||
	if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding))
 | 
						if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding))
 | 
				
			||||||
		nfs_commit_clear_lock(NFS_I(wdata->inode));
 | 
							nfs_commit_clear_lock(NFS_I(wdata->inode));
 | 
				
			||||||
 | 
						put_lseg(wdata->lseg);
 | 
				
			||||||
	nfs_commitdata_release(wdata);
 | 
						nfs_commitdata_release(wdata);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_call_ops filelayout_read_call_ops = {
 | 
					static const struct rpc_call_ops filelayout_read_call_ops = {
 | 
				
			||||||
	.rpc_call_prepare = filelayout_read_prepare,
 | 
						.rpc_call_prepare = filelayout_read_prepare,
 | 
				
			||||||
	.rpc_call_done = filelayout_read_call_done,
 | 
						.rpc_call_done = filelayout_read_call_done,
 | 
				
			||||||
 | 
						.rpc_count_stats = filelayout_read_count_stats,
 | 
				
			||||||
	.rpc_release = filelayout_read_release,
 | 
						.rpc_release = filelayout_read_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_call_ops filelayout_write_call_ops = {
 | 
					static const struct rpc_call_ops filelayout_write_call_ops = {
 | 
				
			||||||
	.rpc_call_prepare = filelayout_write_prepare,
 | 
						.rpc_call_prepare = filelayout_write_prepare,
 | 
				
			||||||
	.rpc_call_done = filelayout_write_call_done,
 | 
						.rpc_call_done = filelayout_write_call_done,
 | 
				
			||||||
 | 
						.rpc_count_stats = filelayout_write_count_stats,
 | 
				
			||||||
	.rpc_release = filelayout_write_release,
 | 
						.rpc_release = filelayout_write_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_call_ops filelayout_commit_call_ops = {
 | 
					static const struct rpc_call_ops filelayout_commit_call_ops = {
 | 
				
			||||||
	.rpc_call_prepare = filelayout_write_prepare,
 | 
						.rpc_call_prepare = filelayout_write_prepare,
 | 
				
			||||||
	.rpc_call_done = filelayout_write_call_done,
 | 
						.rpc_call_done = filelayout_write_call_done,
 | 
				
			||||||
 | 
						.rpc_count_stats = filelayout_write_count_stats,
 | 
				
			||||||
	.rpc_release = filelayout_commit_release,
 | 
						.rpc_release = filelayout_commit_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -367,7 +411,8 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
 | 
				
			||||||
	idx = nfs4_fl_calc_ds_index(lseg, j);
 | 
						idx = nfs4_fl_calc_ds_index(lseg, j);
 | 
				
			||||||
	ds = nfs4_fl_prepare_ds(lseg, idx);
 | 
						ds = nfs4_fl_prepare_ds(lseg, idx);
 | 
				
			||||||
	if (!ds) {
 | 
						if (!ds) {
 | 
				
			||||||
		printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__);
 | 
							printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n",
 | 
				
			||||||
 | 
								__func__);
 | 
				
			||||||
		set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
 | 
							set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
 | 
				
			||||||
		set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
 | 
							set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
 | 
				
			||||||
		return PNFS_NOT_ATTEMPTED;
 | 
							return PNFS_NOT_ATTEMPTED;
 | 
				
			||||||
| 
						 | 
					@ -575,7 +620,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
 | 
				
			||||||
			goto out_err_free;
 | 
								goto out_err_free;
 | 
				
			||||||
		fl->fh_array[i]->size = be32_to_cpup(p++);
 | 
							fl->fh_array[i]->size = be32_to_cpup(p++);
 | 
				
			||||||
		if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
 | 
							if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
 | 
				
			||||||
			printk(KERN_ERR "Too big fh %d received %d\n",
 | 
								printk(KERN_ERR "NFS: Too big fh %d received %d\n",
 | 
				
			||||||
			       i, fl->fh_array[i]->size);
 | 
								       i, fl->fh_array[i]->size);
 | 
				
			||||||
			goto out_err_free;
 | 
								goto out_err_free;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -640,14 +685,16 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
 | 
				
			||||||
		int size = (fl->stripe_type == STRIPE_SPARSE) ?
 | 
							int size = (fl->stripe_type == STRIPE_SPARSE) ?
 | 
				
			||||||
			fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
 | 
								fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fl->commit_buckets = kcalloc(size, sizeof(struct list_head), gfp_flags);
 | 
							fl->commit_buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket), gfp_flags);
 | 
				
			||||||
		if (!fl->commit_buckets) {
 | 
							if (!fl->commit_buckets) {
 | 
				
			||||||
			filelayout_free_lseg(&fl->generic_hdr);
 | 
								filelayout_free_lseg(&fl->generic_hdr);
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		fl->number_of_buckets = size;
 | 
							fl->number_of_buckets = size;
 | 
				
			||||||
		for (i = 0; i < size; i++)
 | 
							for (i = 0; i < size; i++) {
 | 
				
			||||||
			INIT_LIST_HEAD(&fl->commit_buckets[i]);
 | 
								INIT_LIST_HEAD(&fl->commit_buckets[i].written);
 | 
				
			||||||
 | 
								INIT_LIST_HEAD(&fl->commit_buckets[i].committing);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return &fl->generic_hdr;
 | 
						return &fl->generic_hdr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -679,7 +726,7 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
 | 
				
			||||||
	return (p_stripe == r_stripe);
 | 
						return (p_stripe == r_stripe);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					static void
 | 
				
			||||||
filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
 | 
					filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
 | 
				
			||||||
			struct nfs_page *req)
 | 
								struct nfs_page *req)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -696,7 +743,7 @@ filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
 | 
				
			||||||
		nfs_pageio_reset_read_mds(pgio);
 | 
							nfs_pageio_reset_read_mds(pgio);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					static void
 | 
				
			||||||
filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
 | 
					filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
 | 
				
			||||||
			 struct nfs_page *req)
 | 
								 struct nfs_page *req)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -725,11 +772,6 @@ static const struct nfs_pageio_ops filelayout_pg_write_ops = {
 | 
				
			||||||
	.pg_doio = pnfs_generic_pg_writepages,
 | 
						.pg_doio = pnfs_generic_pg_writepages,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return !FILELAYOUT_LSEG(lseg)->commit_through_mds;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
 | 
					static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (fl->stripe_type == STRIPE_SPARSE)
 | 
						if (fl->stripe_type == STRIPE_SPARSE)
 | 
				
			||||||
| 
						 | 
					@ -738,13 +780,49 @@ static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
 | 
				
			||||||
		return j;
 | 
							return j;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct list_head *filelayout_choose_commit_list(struct nfs_page *req)
 | 
					/* The generic layer is about to remove the req from the commit list.
 | 
				
			||||||
 | 
					 * If this will make the bucket empty, it will need to put the lseg reference.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					filelayout_clear_request_commit(struct nfs_page *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pnfs_layout_segment *freeme = NULL;
 | 
				
			||||||
 | 
						struct inode *inode = req->wb_context->dentry->d_inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock(&inode->i_lock);
 | 
				
			||||||
 | 
						if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						if (list_is_singular(&req->wb_list)) {
 | 
				
			||||||
 | 
							struct inode *inode = req->wb_context->dentry->d_inode;
 | 
				
			||||||
 | 
							struct pnfs_layout_segment *lseg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* From here we can find the bucket, but for the moment,
 | 
				
			||||||
 | 
							 * since there is only one relevant lseg...
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
 | 
				
			||||||
 | 
								if (lseg->pls_range.iomode == IOMODE_RW) {
 | 
				
			||||||
 | 
									freeme = lseg;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						nfs_request_remove_commit_list(req);
 | 
				
			||||||
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
 | 
						put_lseg(freeme);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct list_head *
 | 
				
			||||||
 | 
					filelayout_choose_commit_list(struct nfs_page *req,
 | 
				
			||||||
 | 
								      struct pnfs_layout_segment *lseg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pnfs_layout_segment *lseg = req->wb_commit_lseg;
 | 
					 | 
				
			||||||
	struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
 | 
						struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
 | 
				
			||||||
	u32 i, j;
 | 
						u32 i, j;
 | 
				
			||||||
	struct list_head *list;
 | 
						struct list_head *list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fl->commit_through_mds)
 | 
				
			||||||
 | 
							return &NFS_I(req->wb_context->dentry->d_inode)->commit_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note that we are calling nfs4_fl_calc_j_index on each page
 | 
						/* Note that we are calling nfs4_fl_calc_j_index on each page
 | 
				
			||||||
	 * that ends up being committed to a data server.  An attractive
 | 
						 * that ends up being committed to a data server.  An attractive
 | 
				
			||||||
	 * alternative is to add a field to nfs_write_data and nfs_page
 | 
						 * alternative is to add a field to nfs_write_data and nfs_page
 | 
				
			||||||
| 
						 | 
					@ -754,14 +832,30 @@ struct list_head *filelayout_choose_commit_list(struct nfs_page *req)
 | 
				
			||||||
	j = nfs4_fl_calc_j_index(lseg,
 | 
						j = nfs4_fl_calc_j_index(lseg,
 | 
				
			||||||
				 (loff_t)req->wb_index << PAGE_CACHE_SHIFT);
 | 
									 (loff_t)req->wb_index << PAGE_CACHE_SHIFT);
 | 
				
			||||||
	i = select_bucket_index(fl, j);
 | 
						i = select_bucket_index(fl, j);
 | 
				
			||||||
	list = &fl->commit_buckets[i];
 | 
						list = &fl->commit_buckets[i].written;
 | 
				
			||||||
	if (list_empty(list)) {
 | 
						if (list_empty(list)) {
 | 
				
			||||||
		/* Non-empty buckets hold a reference on the lseg */
 | 
							/* Non-empty buckets hold a reference on the lseg.  That ref
 | 
				
			||||||
 | 
							 * is normally transferred to the COMMIT call and released
 | 
				
			||||||
 | 
							 * there.  It could also be released if the last req is pulled
 | 
				
			||||||
 | 
							 * off due to a rewrite, in which case it will be done in
 | 
				
			||||||
 | 
							 * filelayout_remove_commit_req
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		get_lseg(lseg);
 | 
							get_lseg(lseg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
 | 
				
			||||||
	return list;
 | 
						return list;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					filelayout_mark_request_commit(struct nfs_page *req,
 | 
				
			||||||
 | 
							struct pnfs_layout_segment *lseg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct list_head *list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list = filelayout_choose_commit_list(req, lseg);
 | 
				
			||||||
 | 
						nfs_request_add_commit_list(req, list);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
 | 
					static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
 | 
						struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
 | 
				
			||||||
| 
						 | 
					@ -797,11 +891,12 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how)
 | 
				
			||||||
	idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
 | 
						idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
 | 
				
			||||||
	ds = nfs4_fl_prepare_ds(lseg, idx);
 | 
						ds = nfs4_fl_prepare_ds(lseg, idx);
 | 
				
			||||||
	if (!ds) {
 | 
						if (!ds) {
 | 
				
			||||||
		printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__);
 | 
							printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n",
 | 
				
			||||||
 | 
								__func__);
 | 
				
			||||||
		set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
 | 
							set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
 | 
				
			||||||
		set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
 | 
							set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
 | 
				
			||||||
		prepare_to_resend_writes(data);
 | 
							prepare_to_resend_writes(data);
 | 
				
			||||||
		data->mds_ops->rpc_release(data);
 | 
							filelayout_commit_release(data);
 | 
				
			||||||
		return -EAGAIN;
 | 
							return -EAGAIN;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how);
 | 
						dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how);
 | 
				
			||||||
| 
						 | 
					@ -817,24 +912,87 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This is only useful while we are using whole file layouts.
 | 
					 * This is only useful while we are using whole file layouts.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
 | 
					static struct pnfs_layout_segment *
 | 
				
			||||||
 | 
					find_only_write_lseg_locked(struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pnfs_layout_segment *lseg, *rv = NULL;
 | 
						struct pnfs_layout_segment *lseg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&inode->i_lock);
 | 
					 | 
				
			||||||
	list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
 | 
						list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
 | 
				
			||||||
		if (lseg->pls_range.iomode == IOMODE_RW)
 | 
							if (lseg->pls_range.iomode == IOMODE_RW)
 | 
				
			||||||
			rv = get_lseg(lseg);
 | 
								return lseg;
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pnfs_layout_segment *rv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock(&inode->i_lock);
 | 
				
			||||||
 | 
						rv = find_only_write_lseg_locked(inode);
 | 
				
			||||||
 | 
						if (rv)
 | 
				
			||||||
 | 
							get_lseg(rv);
 | 
				
			||||||
	spin_unlock(&inode->i_lock);
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
	return rv;
 | 
						return rv;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int alloc_ds_commits(struct inode *inode, struct list_head *list)
 | 
					static int
 | 
				
			||||||
 | 
					filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max,
 | 
				
			||||||
 | 
							spinlock_t *lock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct list_head *src = &bucket->written;
 | 
				
			||||||
 | 
						struct list_head *dst = &bucket->committing;
 | 
				
			||||||
 | 
						struct nfs_page *req, *tmp;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry_safe(req, tmp, src, wb_list) {
 | 
				
			||||||
 | 
							if (!nfs_lock_request(req))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (cond_resched_lock(lock))
 | 
				
			||||||
 | 
								list_safe_reset_next(req, tmp, wb_list);
 | 
				
			||||||
 | 
							nfs_request_remove_commit_list(req);
 | 
				
			||||||
 | 
							clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);
 | 
				
			||||||
 | 
							nfs_list_add_request(req, dst);
 | 
				
			||||||
 | 
							ret++;
 | 
				
			||||||
 | 
							if (ret == max)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Move reqs from written to committing lists, returning count of number moved.
 | 
				
			||||||
 | 
					 * Note called with i_lock held.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int filelayout_scan_commit_lists(struct inode *inode, int max,
 | 
				
			||||||
 | 
							spinlock_t *lock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pnfs_layout_segment *lseg;
 | 
				
			||||||
 | 
						struct nfs4_filelayout_segment *fl;
 | 
				
			||||||
 | 
						int i, rv = 0, cnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lseg = find_only_write_lseg_locked(inode);
 | 
				
			||||||
 | 
						if (!lseg)
 | 
				
			||||||
 | 
							goto out_done;
 | 
				
			||||||
 | 
						fl = FILELAYOUT_LSEG(lseg);
 | 
				
			||||||
 | 
						if (fl->commit_through_mds)
 | 
				
			||||||
 | 
							goto out_done;
 | 
				
			||||||
 | 
						for (i = 0; i < fl->number_of_buckets && max != 0; i++) {
 | 
				
			||||||
 | 
							cnt = filelayout_scan_ds_commit_list(&fl->commit_buckets[i],
 | 
				
			||||||
 | 
									max, lock);
 | 
				
			||||||
 | 
							max -= cnt;
 | 
				
			||||||
 | 
							rv += cnt;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					out_done:
 | 
				
			||||||
 | 
						return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned int
 | 
				
			||||||
 | 
					alloc_ds_commits(struct inode *inode, struct list_head *list)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pnfs_layout_segment *lseg;
 | 
						struct pnfs_layout_segment *lseg;
 | 
				
			||||||
	struct nfs4_filelayout_segment *fl;
 | 
						struct nfs4_filelayout_segment *fl;
 | 
				
			||||||
	struct nfs_write_data *data;
 | 
						struct nfs_write_data *data;
 | 
				
			||||||
	int i, j;
 | 
						int i, j;
 | 
				
			||||||
 | 
						unsigned int nreq = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Won't need this when non-whole file layout segments are supported
 | 
						/* Won't need this when non-whole file layout segments are supported
 | 
				
			||||||
	 * instead we will use a pnfs_layout_hdr structure */
 | 
						 * instead we will use a pnfs_layout_hdr structure */
 | 
				
			||||||
| 
						 | 
					@ -843,28 +1001,27 @@ static int alloc_ds_commits(struct inode *inode, struct list_head *list)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	fl = FILELAYOUT_LSEG(lseg);
 | 
						fl = FILELAYOUT_LSEG(lseg);
 | 
				
			||||||
	for (i = 0; i < fl->number_of_buckets; i++) {
 | 
						for (i = 0; i < fl->number_of_buckets; i++) {
 | 
				
			||||||
		if (list_empty(&fl->commit_buckets[i]))
 | 
							if (list_empty(&fl->commit_buckets[i].committing))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		data = nfs_commitdata_alloc();
 | 
							data = nfs_commitdata_alloc();
 | 
				
			||||||
		if (!data)
 | 
							if (!data)
 | 
				
			||||||
			goto out_bad;
 | 
								break;
 | 
				
			||||||
		data->ds_commit_index = i;
 | 
							data->ds_commit_index = i;
 | 
				
			||||||
		data->lseg = lseg;
 | 
							data->lseg = lseg;
 | 
				
			||||||
		list_add(&data->pages, list);
 | 
							list_add(&data->pages, list);
 | 
				
			||||||
 | 
							nreq++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	put_lseg(lseg);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_bad:
 | 
						/* Clean up on error */
 | 
				
			||||||
	for (j = i; j < fl->number_of_buckets; j++) {
 | 
						for (j = i; j < fl->number_of_buckets; j++) {
 | 
				
			||||||
		if (list_empty(&fl->commit_buckets[i]))
 | 
							if (list_empty(&fl->commit_buckets[i].committing))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		nfs_retry_commit(&fl->commit_buckets[i], lseg);
 | 
							nfs_retry_commit(&fl->commit_buckets[i].committing, lseg);
 | 
				
			||||||
		put_lseg(lseg);  /* associated with emptying bucket */
 | 
							put_lseg(lseg);  /* associated with emptying bucket */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	put_lseg(lseg);
 | 
						put_lseg(lseg);
 | 
				
			||||||
	/* Caller will clean up entries put on list */
 | 
						/* Caller will clean up entries put on list */
 | 
				
			||||||
	return -ENOMEM;
 | 
						return nreq;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This follows nfs_commit_list pretty closely */
 | 
					/* This follows nfs_commit_list pretty closely */
 | 
				
			||||||
| 
						 | 
					@ -874,40 +1031,40 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_write_data	*data, *tmp;
 | 
						struct nfs_write_data	*data, *tmp;
 | 
				
			||||||
	LIST_HEAD(list);
 | 
						LIST_HEAD(list);
 | 
				
			||||||
 | 
						unsigned int nreq = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!list_empty(mds_pages)) {
 | 
						if (!list_empty(mds_pages)) {
 | 
				
			||||||
		data = nfs_commitdata_alloc();
 | 
							data = nfs_commitdata_alloc();
 | 
				
			||||||
		if (!data)
 | 
							if (data != NULL) {
 | 
				
			||||||
			goto out_bad;
 | 
					 | 
				
			||||||
			data->lseg = NULL;
 | 
								data->lseg = NULL;
 | 
				
			||||||
			list_add(&data->pages, &list);
 | 
								list_add(&data->pages, &list);
 | 
				
			||||||
 | 
								nreq++;
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								nfs_retry_commit(mds_pages, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (alloc_ds_commits(inode, &list))
 | 
						nreq += alloc_ds_commits(inode, &list);
 | 
				
			||||||
		goto out_bad;
 | 
					
 | 
				
			||||||
 | 
						if (nreq == 0) {
 | 
				
			||||||
 | 
							nfs_commit_clear_lock(NFS_I(inode));
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atomic_add(nreq, &NFS_I(inode)->commits_outstanding);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry_safe(data, tmp, &list, pages) {
 | 
						list_for_each_entry_safe(data, tmp, &list, pages) {
 | 
				
			||||||
		list_del_init(&data->pages);
 | 
							list_del_init(&data->pages);
 | 
				
			||||||
		atomic_inc(&NFS_I(inode)->commits_outstanding);
 | 
					 | 
				
			||||||
		if (!data->lseg) {
 | 
							if (!data->lseg) {
 | 
				
			||||||
			nfs_init_commit(data, mds_pages, NULL);
 | 
								nfs_init_commit(data, mds_pages, NULL);
 | 
				
			||||||
			nfs_initiate_commit(data, NFS_CLIENT(inode),
 | 
								nfs_initiate_commit(data, NFS_CLIENT(inode),
 | 
				
			||||||
					    data->mds_ops, how);
 | 
										    data->mds_ops, how);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index], data->lseg);
 | 
								nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index].committing, data->lseg);
 | 
				
			||||||
			filelayout_initiate_commit(data, how);
 | 
								filelayout_initiate_commit(data, how);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
					out:
 | 
				
			||||||
 out_bad:
 | 
						return PNFS_ATTEMPTED;
 | 
				
			||||||
	list_for_each_entry_safe(data, tmp, &list, pages) {
 | 
					 | 
				
			||||||
		nfs_retry_commit(&data->pages, data->lseg);
 | 
					 | 
				
			||||||
		list_del_init(&data->pages);
 | 
					 | 
				
			||||||
		nfs_commit_free(data);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	nfs_retry_commit(mds_pages, NULL);
 | 
					 | 
				
			||||||
	nfs_commit_clear_lock(NFS_I(inode));
 | 
					 | 
				
			||||||
	return -ENOMEM;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -924,8 +1081,9 @@ static struct pnfs_layoutdriver_type filelayout_type = {
 | 
				
			||||||
	.free_lseg		= filelayout_free_lseg,
 | 
						.free_lseg		= filelayout_free_lseg,
 | 
				
			||||||
	.pg_read_ops		= &filelayout_pg_read_ops,
 | 
						.pg_read_ops		= &filelayout_pg_read_ops,
 | 
				
			||||||
	.pg_write_ops		= &filelayout_pg_write_ops,
 | 
						.pg_write_ops		= &filelayout_pg_write_ops,
 | 
				
			||||||
	.mark_pnfs_commit	= filelayout_mark_pnfs_commit,
 | 
						.mark_request_commit	= filelayout_mark_request_commit,
 | 
				
			||||||
	.choose_commit_list	= filelayout_choose_commit_list,
 | 
						.clear_request_commit	= filelayout_clear_request_commit,
 | 
				
			||||||
 | 
						.scan_commit_lists	= filelayout_scan_commit_lists,
 | 
				
			||||||
	.commit_pagelist	= filelayout_commit_pagelist,
 | 
						.commit_pagelist	= filelayout_commit_pagelist,
 | 
				
			||||||
	.read_pagelist		= filelayout_read_pagelist,
 | 
						.read_pagelist		= filelayout_read_pagelist,
 | 
				
			||||||
	.write_pagelist		= filelayout_write_pagelist,
 | 
						.write_pagelist		= filelayout_write_pagelist,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,6 +74,11 @@ struct nfs4_file_layout_dsaddr {
 | 
				
			||||||
	struct nfs4_pnfs_ds		*ds_list[1];
 | 
						struct nfs4_pnfs_ds		*ds_list[1];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct nfs4_fl_commit_bucket {
 | 
				
			||||||
 | 
						struct list_head written;
 | 
				
			||||||
 | 
						struct list_head committing;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs4_filelayout_segment {
 | 
					struct nfs4_filelayout_segment {
 | 
				
			||||||
	struct pnfs_layout_segment generic_hdr;
 | 
						struct pnfs_layout_segment generic_hdr;
 | 
				
			||||||
	u32 stripe_type;
 | 
						u32 stripe_type;
 | 
				
			||||||
| 
						 | 
					@ -84,7 +89,7 @@ struct nfs4_filelayout_segment {
 | 
				
			||||||
	struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
 | 
						struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
 | 
				
			||||||
	unsigned int num_fh;
 | 
						unsigned int num_fh;
 | 
				
			||||||
	struct nfs_fh **fh_array;
 | 
						struct nfs_fh **fh_array;
 | 
				
			||||||
	struct list_head *commit_buckets; /* Sort commits to ds */
 | 
						struct nfs4_fl_commit_bucket *commit_buckets; /* Sort commits to ds */
 | 
				
			||||||
	int number_of_buckets;
 | 
						int number_of_buckets;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,7 @@
 | 
				
			||||||
 *   - incremented when a device id maps a data server already in the cache.
 | 
					 *   - incremented when a device id maps a data server already in the cache.
 | 
				
			||||||
 *   - decremented when deviceid is removed from the cache.
 | 
					 *   - decremented when deviceid is removed from the cache.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
DEFINE_SPINLOCK(nfs4_ds_cache_lock);
 | 
					static DEFINE_SPINLOCK(nfs4_ds_cache_lock);
 | 
				
			||||||
static LIST_HEAD(nfs4_data_server_cache);
 | 
					static LIST_HEAD(nfs4_data_server_cache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Debug routines */
 | 
					/* Debug routines */
 | 
				
			||||||
| 
						 | 
					@ -108,58 +108,40 @@ same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Lookup DS by addresses.  The first matching address returns true.
 | 
					 | 
				
			||||||
 * nfs4_ds_cache_lock is held
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static struct nfs4_pnfs_ds *
 | 
					 | 
				
			||||||
_data_server_lookup_locked(struct list_head *dsaddrs)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nfs4_pnfs_ds *ds;
 | 
					 | 
				
			||||||
	struct nfs4_pnfs_ds_addr *da1, *da2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	list_for_each_entry(da1, dsaddrs, da_node) {
 | 
					 | 
				
			||||||
		list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) {
 | 
					 | 
				
			||||||
			list_for_each_entry(da2, &ds->ds_addrs, da_node) {
 | 
					 | 
				
			||||||
				if (same_sockaddr(
 | 
					 | 
				
			||||||
					(struct sockaddr *)&da1->da_addr,
 | 
					 | 
				
			||||||
					(struct sockaddr *)&da2->da_addr))
 | 
					 | 
				
			||||||
					return ds;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Compare two lists of addresses.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
_data_server_match_all_addrs_locked(struct list_head *dsaddrs1,
 | 
					_same_data_server_addrs_locked(const struct list_head *dsaddrs1,
 | 
				
			||||||
				    struct list_head *dsaddrs2)
 | 
								       const struct list_head *dsaddrs2)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs4_pnfs_ds_addr *da1, *da2;
 | 
						struct nfs4_pnfs_ds_addr *da1, *da2;
 | 
				
			||||||
	size_t count1 = 0,
 | 
					 | 
				
			||||||
	       count2 = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry(da1, dsaddrs1, da_node)
 | 
						/* step through both lists, comparing as we go */
 | 
				
			||||||
		count1++;
 | 
						for (da1 = list_first_entry(dsaddrs1, typeof(*da1), da_node),
 | 
				
			||||||
 | 
						     da2 = list_first_entry(dsaddrs2, typeof(*da2), da_node);
 | 
				
			||||||
 | 
						     da1 != NULL && da2 != NULL;
 | 
				
			||||||
 | 
						     da1 = list_entry(da1->da_node.next, typeof(*da1), da_node),
 | 
				
			||||||
 | 
						     da2 = list_entry(da2->da_node.next, typeof(*da2), da_node)) {
 | 
				
			||||||
 | 
							if (!same_sockaddr((struct sockaddr *)&da1->da_addr,
 | 
				
			||||||
 | 
									   (struct sockaddr *)&da2->da_addr))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (da1 == NULL && da2 == NULL)
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry(da2, dsaddrs2, da_node) {
 | 
					 | 
				
			||||||
		bool found = false;
 | 
					 | 
				
			||||||
		count2++;
 | 
					 | 
				
			||||||
		list_for_each_entry(da1, dsaddrs1, da_node) {
 | 
					 | 
				
			||||||
			if (same_sockaddr((struct sockaddr *)&da1->da_addr,
 | 
					 | 
				
			||||||
				(struct sockaddr *)&da2->da_addr)) {
 | 
					 | 
				
			||||||
				found = true;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (!found)
 | 
					 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (count1 == count2);
 | 
					/*
 | 
				
			||||||
 | 
					 * Lookup DS by addresses.  nfs4_ds_cache_lock is held
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct nfs4_pnfs_ds *
 | 
				
			||||||
 | 
					_data_server_lookup_locked(const struct list_head *dsaddrs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs4_pnfs_ds *ds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
 | 
				
			||||||
 | 
							if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
 | 
				
			||||||
 | 
								return ds;
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -356,11 +338,6 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
 | 
				
			||||||
		dprintk("%s add new data server %s\n", __func__,
 | 
							dprintk("%s add new data server %s\n", __func__,
 | 
				
			||||||
			ds->ds_remotestr);
 | 
								ds->ds_remotestr);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (!_data_server_match_all_addrs_locked(&tmp_ds->ds_addrs,
 | 
					 | 
				
			||||||
							 dsaddrs)) {
 | 
					 | 
				
			||||||
			dprintk("%s:  multipath address mismatch: %s != %s",
 | 
					 | 
				
			||||||
				__func__, tmp_ds->ds_remotestr, remotestr);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		kfree(remotestr);
 | 
							kfree(remotestr);
 | 
				
			||||||
		kfree(ds);
 | 
							kfree(ds);
 | 
				
			||||||
		atomic_inc(&tmp_ds->ds_count);
 | 
							atomic_inc(&tmp_ds->ds_count);
 | 
				
			||||||
| 
						 | 
					@ -378,7 +355,7 @@ out:
 | 
				
			||||||
 * Currently only supports ipv4, ipv6 and one multi-path address.
 | 
					 * Currently only supports ipv4, ipv6 and one multi-path address.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct nfs4_pnfs_ds_addr *
 | 
					static struct nfs4_pnfs_ds_addr *
 | 
				
			||||||
decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags)
 | 
					decode_ds_addr(struct net *net, struct xdr_stream *streamp, gfp_t gfp_flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs4_pnfs_ds_addr *da = NULL;
 | 
						struct nfs4_pnfs_ds_addr *da = NULL;
 | 
				
			||||||
	char *buf, *portstr;
 | 
						char *buf, *portstr;
 | 
				
			||||||
| 
						 | 
					@ -457,7 +434,7 @@ decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LIST_HEAD(&da->da_node);
 | 
						INIT_LIST_HEAD(&da->da_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rpc_pton(buf, portstr-buf, (struct sockaddr *)&da->da_addr,
 | 
						if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
 | 
				
			||||||
		      sizeof(da->da_addr))) {
 | 
							      sizeof(da->da_addr))) {
 | 
				
			||||||
		dprintk("%s: error parsing address %s\n", __func__, buf);
 | 
							dprintk("%s: error parsing address %s\n", __func__, buf);
 | 
				
			||||||
		goto out_free_da;
 | 
							goto out_free_da;
 | 
				
			||||||
| 
						 | 
					@ -554,7 +531,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
 | 
				
			||||||
	cnt = be32_to_cpup(p);
 | 
						cnt = be32_to_cpup(p);
 | 
				
			||||||
	dprintk("%s stripe count  %d\n", __func__, cnt);
 | 
						dprintk("%s stripe count  %d\n", __func__, cnt);
 | 
				
			||||||
	if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
 | 
						if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
 | 
				
			||||||
		printk(KERN_WARNING "%s: stripe count %d greater than "
 | 
							printk(KERN_WARNING "NFS: %s: stripe count %d greater than "
 | 
				
			||||||
		       "supported maximum %d\n", __func__,
 | 
							       "supported maximum %d\n", __func__,
 | 
				
			||||||
			cnt, NFS4_PNFS_MAX_STRIPE_CNT);
 | 
								cnt, NFS4_PNFS_MAX_STRIPE_CNT);
 | 
				
			||||||
		goto out_err_free_scratch;
 | 
							goto out_err_free_scratch;
 | 
				
			||||||
| 
						 | 
					@ -585,7 +562,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
 | 
				
			||||||
	num = be32_to_cpup(p);
 | 
						num = be32_to_cpup(p);
 | 
				
			||||||
	dprintk("%s ds_num %u\n", __func__, num);
 | 
						dprintk("%s ds_num %u\n", __func__, num);
 | 
				
			||||||
	if (num > NFS4_PNFS_MAX_MULTI_CNT) {
 | 
						if (num > NFS4_PNFS_MAX_MULTI_CNT) {
 | 
				
			||||||
		printk(KERN_WARNING "%s: multipath count %d greater than "
 | 
							printk(KERN_WARNING "NFS: %s: multipath count %d greater than "
 | 
				
			||||||
			"supported maximum %d\n", __func__,
 | 
								"supported maximum %d\n", __func__,
 | 
				
			||||||
			num, NFS4_PNFS_MAX_MULTI_CNT);
 | 
								num, NFS4_PNFS_MAX_MULTI_CNT);
 | 
				
			||||||
		goto out_err_free_stripe_indices;
 | 
							goto out_err_free_stripe_indices;
 | 
				
			||||||
| 
						 | 
					@ -593,7 +570,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* validate stripe indices are all < num */
 | 
						/* validate stripe indices are all < num */
 | 
				
			||||||
	if (max_stripe_index >= num) {
 | 
						if (max_stripe_index >= num) {
 | 
				
			||||||
		printk(KERN_WARNING "%s: stripe index %u >= num ds %u\n",
 | 
							printk(KERN_WARNING "NFS: %s: stripe index %u >= num ds %u\n",
 | 
				
			||||||
			__func__, max_stripe_index, num);
 | 
								__func__, max_stripe_index, num);
 | 
				
			||||||
		goto out_err_free_stripe_indices;
 | 
							goto out_err_free_stripe_indices;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -625,7 +602,8 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mp_count = be32_to_cpup(p); /* multipath count */
 | 
							mp_count = be32_to_cpup(p); /* multipath count */
 | 
				
			||||||
		for (j = 0; j < mp_count; j++) {
 | 
							for (j = 0; j < mp_count; j++) {
 | 
				
			||||||
			da = decode_ds_addr(&stream, gfp_flags);
 | 
								da = decode_ds_addr(NFS_SERVER(ino)->nfs_client->net,
 | 
				
			||||||
 | 
										    &stream, gfp_flags);
 | 
				
			||||||
			if (da)
 | 
								if (da)
 | 
				
			||||||
				list_add_tail(&da->da_node, &dsaddrs);
 | 
									list_add_tail(&da->da_node, &dsaddrs);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -686,7 +664,7 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_fl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	new = decode_device(inode, dev, gfp_flags);
 | 
						new = decode_device(inode, dev, gfp_flags);
 | 
				
			||||||
	if (!new) {
 | 
						if (!new) {
 | 
				
			||||||
		printk(KERN_WARNING "%s: Could not decode or add device\n",
 | 
							printk(KERN_WARNING "NFS: %s: Could not decode or add device\n",
 | 
				
			||||||
			__func__);
 | 
								__func__);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -835,7 +813,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
 | 
				
			||||||
	struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
 | 
						struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ds == NULL) {
 | 
						if (ds == NULL) {
 | 
				
			||||||
		printk(KERN_ERR "%s: No data server for offset index %d\n",
 | 
							printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
 | 
				
			||||||
			__func__, ds_idx);
 | 
								__func__, ds_idx);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,13 +94,14 @@ static int nfs4_validate_fspath(struct dentry *dentry,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static size_t nfs_parse_server_name(char *string, size_t len,
 | 
					static size_t nfs_parse_server_name(char *string, size_t len,
 | 
				
			||||||
		struct sockaddr *sa, size_t salen)
 | 
							struct sockaddr *sa, size_t salen, struct nfs_server *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct net *net = rpc_net_ns(server->client);
 | 
				
			||||||
	ssize_t ret;
 | 
						ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = rpc_pton(string, len, sa, salen);
 | 
						ret = rpc_pton(net, string, len, sa, salen);
 | 
				
			||||||
	if (ret == 0) {
 | 
						if (ret == 0) {
 | 
				
			||||||
		ret = nfs_dns_resolve_name(string, len, sa, salen);
 | 
							ret = nfs_dns_resolve_name(net, string, len, sa, salen);
 | 
				
			||||||
		if (ret < 0)
 | 
							if (ret < 0)
 | 
				
			||||||
			ret = 0;
 | 
								ret = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -137,7 +138,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
 | 
							mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
 | 
				
			||||||
				mountdata->addr, addr_bufsize);
 | 
									mountdata->addr, addr_bufsize,
 | 
				
			||||||
 | 
									NFS_SB(mountdata->sb));
 | 
				
			||||||
		if (mountdata->addrlen == 0)
 | 
							if (mountdata->addrlen == 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -146,6 +146,11 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
 | 
				
			||||||
	struct rpc_cred *cred = NULL;
 | 
						struct rpc_cred *cred = NULL;
 | 
				
			||||||
	struct nfs_server *server;
 | 
						struct nfs_server *server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Use machine credentials if available */
 | 
				
			||||||
 | 
						cred = nfs4_get_machine_cred_locked(clp);
 | 
				
			||||||
 | 
						if (cred != NULL)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
 | 
						list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
 | 
				
			||||||
		cred = nfs4_get_renew_cred_server_locked(server);
 | 
							cred = nfs4_get_renew_cred_server_locked(server);
 | 
				
			||||||
| 
						 | 
					@ -153,6 +158,8 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
	return cred;
 | 
						return cred;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -190,30 +197,29 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp)
 | 
				
			||||||
static void nfs4_end_drain_session(struct nfs_client *clp)
 | 
					static void nfs4_end_drain_session(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs4_session *ses = clp->cl_session;
 | 
						struct nfs4_session *ses = clp->cl_session;
 | 
				
			||||||
 | 
						struct nfs4_slot_table *tbl;
 | 
				
			||||||
	int max_slots;
 | 
						int max_slots;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ses == NULL)
 | 
						if (ses == NULL)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
						tbl = &ses->fc_slot_table;
 | 
				
			||||||
	if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
 | 
						if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
 | 
				
			||||||
		spin_lock(&ses->fc_slot_table.slot_tbl_lock);
 | 
							spin_lock(&tbl->slot_tbl_lock);
 | 
				
			||||||
		max_slots = ses->fc_slot_table.max_slots;
 | 
							max_slots = tbl->max_slots;
 | 
				
			||||||
		while (max_slots--) {
 | 
							while (max_slots--) {
 | 
				
			||||||
			struct rpc_task *task;
 | 
								if (rpc_wake_up_first(&tbl->slot_tbl_waitq,
 | 
				
			||||||
 | 
											nfs4_set_task_privileged,
 | 
				
			||||||
			task = rpc_wake_up_next(&ses->fc_slot_table.
 | 
											NULL) == NULL)
 | 
				
			||||||
						slot_tbl_waitq);
 | 
					 | 
				
			||||||
			if (!task)
 | 
					 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		spin_unlock(&ses->fc_slot_table.slot_tbl_lock);
 | 
							spin_unlock(&tbl->slot_tbl_lock);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
 | 
					static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	spin_lock(&tbl->slot_tbl_lock);
 | 
						spin_lock(&tbl->slot_tbl_lock);
 | 
				
			||||||
	if (tbl->highest_used_slotid != -1) {
 | 
						if (tbl->highest_used_slotid != NFS4_NO_SLOT) {
 | 
				
			||||||
		INIT_COMPLETION(tbl->complete);
 | 
							INIT_COMPLETION(tbl->complete);
 | 
				
			||||||
		spin_unlock(&tbl->slot_tbl_lock);
 | 
							spin_unlock(&tbl->slot_tbl_lock);
 | 
				
			||||||
		return wait_for_completion_interruptible(&tbl->complete);
 | 
							return wait_for_completion_interruptible(&tbl->complete);
 | 
				
			||||||
| 
						 | 
					@ -317,62 +323,6 @@ out:
 | 
				
			||||||
	return cred;
 | 
						return cred;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfs_alloc_unique_id_locked(struct rb_root *root,
 | 
					 | 
				
			||||||
				       struct nfs_unique_id *new,
 | 
					 | 
				
			||||||
				       __u64 minval, int maxbits)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct rb_node **p, *parent;
 | 
					 | 
				
			||||||
	struct nfs_unique_id *pos;
 | 
					 | 
				
			||||||
	__u64 mask = ~0ULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (maxbits < 64)
 | 
					 | 
				
			||||||
		mask = (1ULL << maxbits) - 1ULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Ensure distribution is more or less flat */
 | 
					 | 
				
			||||||
	get_random_bytes(&new->id, sizeof(new->id));
 | 
					 | 
				
			||||||
	new->id &= mask;
 | 
					 | 
				
			||||||
	if (new->id < minval)
 | 
					 | 
				
			||||||
		new->id += minval;
 | 
					 | 
				
			||||||
retry:
 | 
					 | 
				
			||||||
	p = &root->rb_node;
 | 
					 | 
				
			||||||
	parent = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	while (*p != NULL) {
 | 
					 | 
				
			||||||
		parent = *p;
 | 
					 | 
				
			||||||
		pos = rb_entry(parent, struct nfs_unique_id, rb_node);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (new->id < pos->id)
 | 
					 | 
				
			||||||
			p = &(*p)->rb_left;
 | 
					 | 
				
			||||||
		else if (new->id > pos->id)
 | 
					 | 
				
			||||||
			p = &(*p)->rb_right;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			goto id_exists;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	rb_link_node(&new->rb_node, parent, p);
 | 
					 | 
				
			||||||
	rb_insert_color(&new->rb_node, root);
 | 
					 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
id_exists:
 | 
					 | 
				
			||||||
	for (;;) {
 | 
					 | 
				
			||||||
		new->id++;
 | 
					 | 
				
			||||||
		if (new->id < minval || (new->id & mask) != new->id) {
 | 
					 | 
				
			||||||
			new->id = minval;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		parent = rb_next(parent);
 | 
					 | 
				
			||||||
		if (parent == NULL)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		pos = rb_entry(parent, struct nfs_unique_id, rb_node);
 | 
					 | 
				
			||||||
		if (new->id < pos->id)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	goto retry;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	rb_erase(&id->rb_node, root);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct nfs4_state_owner *
 | 
					static struct nfs4_state_owner *
 | 
				
			||||||
nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred)
 | 
					nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -405,6 +355,7 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
 | 
				
			||||||
	struct rb_node **p = &server->state_owners.rb_node,
 | 
						struct rb_node **p = &server->state_owners.rb_node,
 | 
				
			||||||
		       *parent = NULL;
 | 
							       *parent = NULL;
 | 
				
			||||||
	struct nfs4_state_owner *sp;
 | 
						struct nfs4_state_owner *sp;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (*p != NULL) {
 | 
						while (*p != NULL) {
 | 
				
			||||||
		parent = *p;
 | 
							parent = *p;
 | 
				
			||||||
| 
						 | 
					@ -421,8 +372,9 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
 | 
				
			||||||
			return sp;
 | 
								return sp;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	nfs_alloc_unique_id_locked(&server->openowner_id,
 | 
						err = ida_get_new(&server->openowner_id, &new->so_seqid.owner_id);
 | 
				
			||||||
					&new->so_owner_id, 1, 64);
 | 
						if (err)
 | 
				
			||||||
 | 
							return ERR_PTR(err);
 | 
				
			||||||
	rb_link_node(&new->so_server_node, parent, p);
 | 
						rb_link_node(&new->so_server_node, parent, p);
 | 
				
			||||||
	rb_insert_color(&new->so_server_node, &server->state_owners);
 | 
						rb_insert_color(&new->so_server_node, &server->state_owners);
 | 
				
			||||||
	return new;
 | 
						return new;
 | 
				
			||||||
| 
						 | 
					@ -435,7 +387,23 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!RB_EMPTY_NODE(&sp->so_server_node))
 | 
						if (!RB_EMPTY_NODE(&sp->so_server_node))
 | 
				
			||||||
		rb_erase(&sp->so_server_node, &server->state_owners);
 | 
							rb_erase(&sp->so_server_node, &server->state_owners);
 | 
				
			||||||
	nfs_free_unique_id(&server->openowner_id, &sp->so_owner_id);
 | 
						ida_remove(&server->openowner_id, sp->so_seqid.owner_id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sc->flags = 0;
 | 
				
			||||||
 | 
						sc->counter = 0;
 | 
				
			||||||
 | 
						spin_lock_init(&sc->lock);
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&sc->list);
 | 
				
			||||||
 | 
						rpc_init_wait_queue(&sc->wait, "Seqid_waitqueue");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					nfs4_destroy_seqid_counter(struct nfs_seqid_counter *sc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rpc_destroy_wait_queue(&sc->wait);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -444,19 +412,20 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct nfs4_state_owner *
 | 
					static struct nfs4_state_owner *
 | 
				
			||||||
nfs4_alloc_state_owner(void)
 | 
					nfs4_alloc_state_owner(struct nfs_server *server,
 | 
				
			||||||
 | 
							struct rpc_cred *cred,
 | 
				
			||||||
 | 
							gfp_t gfp_flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs4_state_owner *sp;
 | 
						struct nfs4_state_owner *sp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sp = kzalloc(sizeof(*sp),GFP_NOFS);
 | 
						sp = kzalloc(sizeof(*sp), gfp_flags);
 | 
				
			||||||
	if (!sp)
 | 
						if (!sp)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
						sp->so_server = server;
 | 
				
			||||||
 | 
						sp->so_cred = get_rpccred(cred);
 | 
				
			||||||
	spin_lock_init(&sp->so_lock);
 | 
						spin_lock_init(&sp->so_lock);
 | 
				
			||||||
	INIT_LIST_HEAD(&sp->so_states);
 | 
						INIT_LIST_HEAD(&sp->so_states);
 | 
				
			||||||
	rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue");
 | 
						nfs4_init_seqid_counter(&sp->so_seqid);
 | 
				
			||||||
	sp->so_seqid.sequence = &sp->so_sequence;
 | 
					 | 
				
			||||||
	spin_lock_init(&sp->so_sequence.lock);
 | 
					 | 
				
			||||||
	INIT_LIST_HEAD(&sp->so_sequence.list);
 | 
					 | 
				
			||||||
	atomic_set(&sp->so_count, 1);
 | 
						atomic_set(&sp->so_count, 1);
 | 
				
			||||||
	INIT_LIST_HEAD(&sp->so_lru);
 | 
						INIT_LIST_HEAD(&sp->so_lru);
 | 
				
			||||||
	return sp;
 | 
						return sp;
 | 
				
			||||||
| 
						 | 
					@ -478,7 +447,7 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
 | 
					static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	rpc_destroy_wait_queue(&sp->so_sequence.wait);
 | 
						nfs4_destroy_seqid_counter(&sp->so_seqid);
 | 
				
			||||||
	put_rpccred(sp->so_cred);
 | 
						put_rpccred(sp->so_cred);
 | 
				
			||||||
	kfree(sp);
 | 
						kfree(sp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -516,7 +485,8 @@ static void nfs4_gc_state_owners(struct nfs_server *server)
 | 
				
			||||||
 * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL.
 | 
					 * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
 | 
					struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
 | 
				
			||||||
					      struct rpc_cred *cred)
 | 
										      struct rpc_cred *cred,
 | 
				
			||||||
 | 
										      gfp_t gfp_flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client *clp = server->nfs_client;
 | 
						struct nfs_client *clp = server->nfs_client;
 | 
				
			||||||
	struct nfs4_state_owner *sp, *new;
 | 
						struct nfs4_state_owner *sp, *new;
 | 
				
			||||||
| 
						 | 
					@ -526,20 +496,18 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
 | 
				
			||||||
	spin_unlock(&clp->cl_lock);
 | 
						spin_unlock(&clp->cl_lock);
 | 
				
			||||||
	if (sp != NULL)
 | 
						if (sp != NULL)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	new = nfs4_alloc_state_owner();
 | 
						new = nfs4_alloc_state_owner(server, cred, gfp_flags);
 | 
				
			||||||
	if (new == NULL)
 | 
						if (new == NULL)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	new->so_server = server;
 | 
						do {
 | 
				
			||||||
	new->so_cred = cred;
 | 
							if (ida_pre_get(&server->openowner_id, gfp_flags) == 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		spin_lock(&clp->cl_lock);
 | 
							spin_lock(&clp->cl_lock);
 | 
				
			||||||
		sp = nfs4_insert_state_owner_locked(new);
 | 
							sp = nfs4_insert_state_owner_locked(new);
 | 
				
			||||||
		spin_unlock(&clp->cl_lock);
 | 
							spin_unlock(&clp->cl_lock);
 | 
				
			||||||
	if (sp == new)
 | 
						} while (sp == ERR_PTR(-EAGAIN));
 | 
				
			||||||
		get_rpccred(cred);
 | 
						if (sp != new)
 | 
				
			||||||
	else {
 | 
							nfs4_free_state_owner(new);
 | 
				
			||||||
		rpc_destroy_wait_queue(&new->so_sequence.wait);
 | 
					 | 
				
			||||||
		kfree(new);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	nfs4_gc_state_owners(server);
 | 
						nfs4_gc_state_owners(server);
 | 
				
			||||||
	return sp;
 | 
						return sp;
 | 
				
			||||||
| 
						 | 
					@ -795,15 +763,11 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs4_lock_state *lsp;
 | 
						struct nfs4_lock_state *lsp;
 | 
				
			||||||
	struct nfs_server *server = state->owner->so_server;
 | 
						struct nfs_server *server = state->owner->so_server;
 | 
				
			||||||
	struct nfs_client *clp = server->nfs_client;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
 | 
						lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
 | 
				
			||||||
	if (lsp == NULL)
 | 
						if (lsp == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue");
 | 
						nfs4_init_seqid_counter(&lsp->ls_seqid);
 | 
				
			||||||
	spin_lock_init(&lsp->ls_sequence.lock);
 | 
					 | 
				
			||||||
	INIT_LIST_HEAD(&lsp->ls_sequence.list);
 | 
					 | 
				
			||||||
	lsp->ls_seqid.sequence = &lsp->ls_sequence;
 | 
					 | 
				
			||||||
	atomic_set(&lsp->ls_count, 1);
 | 
						atomic_set(&lsp->ls_count, 1);
 | 
				
			||||||
	lsp->ls_state = state;
 | 
						lsp->ls_state = state;
 | 
				
			||||||
	lsp->ls_owner.lo_type = type;
 | 
						lsp->ls_owner.lo_type = type;
 | 
				
			||||||
| 
						 | 
					@ -815,25 +779,22 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
 | 
				
			||||||
		lsp->ls_owner.lo_u.posix_owner = fl_owner;
 | 
							lsp->ls_owner.lo_u.posix_owner = fl_owner;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
 | 
							goto out_free;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS);
 | 
				
			||||||
 | 
						if (lsp->ls_seqid.owner_id < 0)
 | 
				
			||||||
 | 
							goto out_free;
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&lsp->ls_locks);
 | 
				
			||||||
 | 
						return lsp;
 | 
				
			||||||
 | 
					out_free:
 | 
				
			||||||
	kfree(lsp);
 | 
						kfree(lsp);
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
	spin_lock(&clp->cl_lock);
 | 
					 | 
				
			||||||
	nfs_alloc_unique_id_locked(&server->lockowner_id, &lsp->ls_id, 1, 64);
 | 
					 | 
				
			||||||
	spin_unlock(&clp->cl_lock);
 | 
					 | 
				
			||||||
	INIT_LIST_HEAD(&lsp->ls_locks);
 | 
					 | 
				
			||||||
	return lsp;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
 | 
					void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_server *server = lsp->ls_state->owner->so_server;
 | 
						ida_simple_remove(&server->lockowner_id, lsp->ls_seqid.owner_id);
 | 
				
			||||||
	struct nfs_client *clp = server->nfs_client;
 | 
						nfs4_destroy_seqid_counter(&lsp->ls_seqid);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	spin_lock(&clp->cl_lock);
 | 
					 | 
				
			||||||
	nfs_free_unique_id(&server->lockowner_id, &lsp->ls_id);
 | 
					 | 
				
			||||||
	spin_unlock(&clp->cl_lock);
 | 
					 | 
				
			||||||
	rpc_destroy_wait_queue(&lsp->ls_sequence.wait);
 | 
					 | 
				
			||||||
	kfree(lsp);
 | 
						kfree(lsp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -865,7 +826,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock(&state->state_lock);
 | 
						spin_unlock(&state->state_lock);
 | 
				
			||||||
	if (new != NULL)
 | 
						if (new != NULL)
 | 
				
			||||||
		nfs4_free_lock_state(new);
 | 
							nfs4_free_lock_state(state->owner->so_server, new);
 | 
				
			||||||
	return lsp;
 | 
						return lsp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -886,9 +847,11 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
 | 
				
			||||||
	if (list_empty(&state->lock_states))
 | 
						if (list_empty(&state->lock_states))
 | 
				
			||||||
		clear_bit(LK_STATE_IN_USE, &state->flags);
 | 
							clear_bit(LK_STATE_IN_USE, &state->flags);
 | 
				
			||||||
	spin_unlock(&state->state_lock);
 | 
						spin_unlock(&state->state_lock);
 | 
				
			||||||
	if (lsp->ls_flags & NFS_LOCK_INITIALIZED)
 | 
						if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
 | 
				
			||||||
		nfs4_release_lockowner(lsp);
 | 
							if (nfs4_release_lockowner(lsp) == 0)
 | 
				
			||||||
	nfs4_free_lock_state(lsp);
 | 
								return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						nfs4_free_lock_state(lsp->ls_state->owner->so_server, lsp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
 | 
					static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
 | 
				
			||||||
| 
						 | 
					@ -918,7 +881,8 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
 | 
				
			||||||
	if (fl->fl_flags & FL_POSIX)
 | 
						if (fl->fl_flags & FL_POSIX)
 | 
				
			||||||
		lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE);
 | 
							lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE);
 | 
				
			||||||
	else if (fl->fl_flags & FL_FLOCK)
 | 
						else if (fl->fl_flags & FL_FLOCK)
 | 
				
			||||||
		lsp = nfs4_get_lock_state(state, 0, fl->fl_pid, NFS4_FLOCK_LOCK_TYPE);
 | 
							lsp = nfs4_get_lock_state(state, NULL, fl->fl_pid,
 | 
				
			||||||
 | 
									NFS4_FLOCK_LOCK_TYPE);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (lsp == NULL)
 | 
						if (lsp == NULL)
 | 
				
			||||||
| 
						 | 
					@ -928,28 +892,49 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
 | 
				
			||||||
 * Byte-range lock aware utility to initialize the stateid of read/write
 | 
							fl_owner_t fl_owner, pid_t fl_pid)
 | 
				
			||||||
 * requests.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs4_lock_state *lsp;
 | 
						struct nfs4_lock_state *lsp;
 | 
				
			||||||
 | 
						bool ret = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock(&state->state_lock);
 | 
				
			||||||
 | 
						lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
 | 
				
			||||||
 | 
						if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {
 | 
				
			||||||
 | 
							nfs4_stateid_copy(dst, &lsp->ls_stateid);
 | 
				
			||||||
 | 
							ret = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock(&state->state_lock);
 | 
				
			||||||
 | 
						nfs4_put_lock_state(lsp);
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
	int seq;
 | 
						int seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		seq = read_seqbegin(&state->seqlock);
 | 
							seq = read_seqbegin(&state->seqlock);
 | 
				
			||||||
		memcpy(dst, &state->stateid, sizeof(*dst));
 | 
							nfs4_stateid_copy(dst, &state->stateid);
 | 
				
			||||||
	} while (read_seqretry(&state->seqlock, seq));
 | 
						} while (read_seqretry(&state->seqlock, seq));
 | 
				
			||||||
	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
 | 
					}
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&state->state_lock);
 | 
					/*
 | 
				
			||||||
	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
 | 
					 * Byte-range lock aware utility to initialize the stateid of read/write
 | 
				
			||||||
	if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
 | 
					 * requests.
 | 
				
			||||||
		memcpy(dst, &lsp->ls_stateid, sizeof(*dst));
 | 
					 */
 | 
				
			||||||
	spin_unlock(&state->state_lock);
 | 
					void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
 | 
				
			||||||
	nfs4_put_lock_state(lsp);
 | 
							fmode_t fmode, fl_owner_t fl_owner, pid_t fl_pid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						if (nfs4_copy_lock_stateid(dst, state, fl_owner, fl_pid))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						nfs4_copy_open_stateid(dst, state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
 | 
					struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
 | 
				
			||||||
| 
						 | 
					@ -960,20 +945,28 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_m
 | 
				
			||||||
	if (new != NULL) {
 | 
						if (new != NULL) {
 | 
				
			||||||
		new->sequence = counter;
 | 
							new->sequence = counter;
 | 
				
			||||||
		INIT_LIST_HEAD(&new->list);
 | 
							INIT_LIST_HEAD(&new->list);
 | 
				
			||||||
 | 
							new->task = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return new;
 | 
						return new;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_release_seqid(struct nfs_seqid *seqid)
 | 
					void nfs_release_seqid(struct nfs_seqid *seqid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!list_empty(&seqid->list)) {
 | 
						struct nfs_seqid_counter *sequence;
 | 
				
			||||||
		struct rpc_sequence *sequence = seqid->sequence->sequence;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (list_empty(&seqid->list))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						sequence = seqid->sequence;
 | 
				
			||||||
	spin_lock(&sequence->lock);
 | 
						spin_lock(&sequence->lock);
 | 
				
			||||||
	list_del_init(&seqid->list);
 | 
						list_del_init(&seqid->list);
 | 
				
			||||||
		spin_unlock(&sequence->lock);
 | 
						if (!list_empty(&sequence->list)) {
 | 
				
			||||||
		rpc_wake_up(&sequence->wait);
 | 
							struct nfs_seqid *next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							next = list_first_entry(&sequence->list,
 | 
				
			||||||
 | 
									struct nfs_seqid, list);
 | 
				
			||||||
 | 
							rpc_wake_up_queued_task(&sequence->wait, next->task);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock(&sequence->lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_free_seqid(struct nfs_seqid *seqid)
 | 
					void nfs_free_seqid(struct nfs_seqid *seqid)
 | 
				
			||||||
| 
						 | 
					@ -989,14 +982,14 @@ void nfs_free_seqid(struct nfs_seqid *seqid)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
 | 
					static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid);
 | 
						BUG_ON(list_first_entry(&seqid->sequence->list, struct nfs_seqid, list) != seqid);
 | 
				
			||||||
	switch (status) {
 | 
						switch (status) {
 | 
				
			||||||
		case 0:
 | 
							case 0:
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case -NFS4ERR_BAD_SEQID:
 | 
							case -NFS4ERR_BAD_SEQID:
 | 
				
			||||||
			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
 | 
								if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			printk(KERN_WARNING "NFS: v4 server returned a bad"
 | 
								pr_warn_ratelimited("NFS: v4 server returned a bad"
 | 
				
			||||||
					" sequence-id error on an"
 | 
										" sequence-id error on an"
 | 
				
			||||||
					" unconfirmed sequence %p!\n",
 | 
										" unconfirmed sequence %p!\n",
 | 
				
			||||||
					seqid->sequence);
 | 
										seqid->sequence);
 | 
				
			||||||
| 
						 | 
					@ -1040,10 +1033,11 @@ void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
 | 
					int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_sequence *sequence = seqid->sequence->sequence;
 | 
						struct nfs_seqid_counter *sequence = seqid->sequence;
 | 
				
			||||||
	int status = 0;
 | 
						int status = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&sequence->lock);
 | 
						spin_lock(&sequence->lock);
 | 
				
			||||||
 | 
						seqid->task = task;
 | 
				
			||||||
	if (list_empty(&seqid->list))
 | 
						if (list_empty(&seqid->list))
 | 
				
			||||||
		list_add_tail(&seqid->list, &sequence->list);
 | 
							list_add_tail(&seqid->list, &sequence->list);
 | 
				
			||||||
	if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid)
 | 
						if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid)
 | 
				
			||||||
| 
						 | 
					@ -1072,20 +1066,29 @@ static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
 | 
				
			||||||
void nfs4_schedule_state_manager(struct nfs_client *clp)
 | 
					void nfs4_schedule_state_manager(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *task;
 | 
						struct task_struct *task;
 | 
				
			||||||
 | 
						char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
 | 
						if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	__module_get(THIS_MODULE);
 | 
						__module_get(THIS_MODULE);
 | 
				
			||||||
	atomic_inc(&clp->cl_count);
 | 
						atomic_inc(&clp->cl_count);
 | 
				
			||||||
	task = kthread_run(nfs4_run_state_manager, clp, "%s-manager",
 | 
					
 | 
				
			||||||
				rpc_peeraddr2str(clp->cl_rpcclient,
 | 
						/* The rcu_read_lock() is not strictly necessary, as the state
 | 
				
			||||||
							RPC_DISPLAY_ADDR));
 | 
						 * manager is the only thread that ever changes the rpc_xprt
 | 
				
			||||||
	if (!IS_ERR(task))
 | 
						 * after it's initialized.  At this point, we're single threaded. */
 | 
				
			||||||
		return;
 | 
						rcu_read_lock();
 | 
				
			||||||
 | 
						snprintf(buf, sizeof(buf), "%s-manager",
 | 
				
			||||||
 | 
								rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 | 
				
			||||||
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
						task = kthread_run(nfs4_run_state_manager, clp, buf);
 | 
				
			||||||
 | 
						if (IS_ERR(task)) {
 | 
				
			||||||
 | 
							printk(KERN_ERR "%s: kthread_run: %ld\n",
 | 
				
			||||||
 | 
								__func__, PTR_ERR(task));
 | 
				
			||||||
		nfs4_clear_state_manager_bit(clp);
 | 
							nfs4_clear_state_manager_bit(clp);
 | 
				
			||||||
		nfs_put_client(clp);
 | 
							nfs_put_client(clp);
 | 
				
			||||||
		module_put(THIS_MODULE);
 | 
							module_put(THIS_MODULE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Schedule a lease recovery attempt
 | 
					 * Schedule a lease recovery attempt
 | 
				
			||||||
| 
						 | 
					@ -1098,10 +1101,25 @@ void nfs4_schedule_lease_recovery(struct nfs_client *clp)
 | 
				
			||||||
		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
 | 
							set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
 | 
				
			||||||
	nfs4_schedule_state_manager(clp);
 | 
						nfs4_schedule_state_manager(clp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
 | 
				
			||||||
 | 
					 * @clp: client to process
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Set the NFS4CLNT_LEASE_EXPIRED state in order to force a
 | 
				
			||||||
 | 
					 * resend of the SETCLIENTID and hence re-establish the
 | 
				
			||||||
 | 
					 * callback channel. Then return all existing delegations.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void nfs40_handle_cb_pathdown(struct nfs_client *clp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
 | 
				
			||||||
 | 
						nfs_expire_all_delegations(clp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
 | 
					void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	nfs_handle_cb_pathdown(clp);
 | 
						nfs40_handle_cb_pathdown(clp);
 | 
				
			||||||
	nfs4_schedule_state_manager(clp);
 | 
						nfs4_schedule_state_manager(clp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1132,11 +1150,37 @@ void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_client *clp = server->nfs_client;
 | 
						struct nfs_client *clp = server->nfs_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (test_and_clear_bit(NFS_DELEGATED_STATE, &state->flags))
 | 
					 | 
				
			||||||
		nfs_async_inode_return_delegation(state->inode, &state->stateid);
 | 
					 | 
				
			||||||
	nfs4_state_mark_reclaim_nograce(clp, state);
 | 
						nfs4_state_mark_reclaim_nograce(clp, state);
 | 
				
			||||||
	nfs4_schedule_state_manager(clp);
 | 
						nfs4_schedule_state_manager(clp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void nfs_inode_find_state_and_recover(struct inode *inode,
 | 
				
			||||||
 | 
							const nfs4_stateid *stateid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
 | 
				
			||||||
 | 
						struct nfs_inode *nfsi = NFS_I(inode);
 | 
				
			||||||
 | 
						struct nfs_open_context *ctx;
 | 
				
			||||||
 | 
						struct nfs4_state *state;
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock(&inode->i_lock);
 | 
				
			||||||
 | 
						list_for_each_entry(ctx, &nfsi->open_files, list) {
 | 
				
			||||||
 | 
							state = ctx->state;
 | 
				
			||||||
 | 
							if (state == NULL)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (!nfs4_stateid_match(&state->stateid, stateid))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							nfs4_state_mark_reclaim_nograce(clp, state);
 | 
				
			||||||
 | 
							found = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
 | 
						if (found)
 | 
				
			||||||
 | 
							nfs4_schedule_state_manager(clp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
 | 
					static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1175,8 +1219,8 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
 | 
				
			||||||
			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
 | 
								case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
 | 
				
			||||||
				goto out;
 | 
									goto out;
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
 | 
									printk(KERN_ERR "NFS: %s: unhandled error %d. "
 | 
				
			||||||
						__func__, status);
 | 
										"Zeroing state\n", __func__, status);
 | 
				
			||||||
			case -ENOMEM:
 | 
								case -ENOMEM:
 | 
				
			||||||
			case -NFS4ERR_DENIED:
 | 
								case -NFS4ERR_DENIED:
 | 
				
			||||||
			case -NFS4ERR_RECLAIM_BAD:
 | 
								case -NFS4ERR_RECLAIM_BAD:
 | 
				
			||||||
| 
						 | 
					@ -1222,8 +1266,9 @@ restart:
 | 
				
			||||||
				spin_lock(&state->state_lock);
 | 
									spin_lock(&state->state_lock);
 | 
				
			||||||
				list_for_each_entry(lock, &state->lock_states, ls_locks) {
 | 
									list_for_each_entry(lock, &state->lock_states, ls_locks) {
 | 
				
			||||||
					if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
 | 
										if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
 | 
				
			||||||
						printk("%s: Lock reclaim failed!\n",
 | 
											pr_warn_ratelimited("NFS: "
 | 
				
			||||||
							__func__);
 | 
												"%s: Lock reclaim "
 | 
				
			||||||
 | 
												"failed!\n", __func__);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				spin_unlock(&state->state_lock);
 | 
									spin_unlock(&state->state_lock);
 | 
				
			||||||
				nfs4_put_open_state(state);
 | 
									nfs4_put_open_state(state);
 | 
				
			||||||
| 
						 | 
					@ -1232,8 +1277,8 @@ restart:
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		switch (status) {
 | 
							switch (status) {
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
 | 
									printk(KERN_ERR "NFS: %s: unhandled error %d. "
 | 
				
			||||||
						__func__, status);
 | 
										"Zeroing state\n", __func__, status);
 | 
				
			||||||
			case -ENOENT:
 | 
								case -ENOENT:
 | 
				
			||||||
			case -ENOMEM:
 | 
								case -ENOMEM:
 | 
				
			||||||
			case -ESTALE:
 | 
								case -ESTALE:
 | 
				
			||||||
| 
						 | 
					@ -1241,8 +1286,8 @@ restart:
 | 
				
			||||||
				 * Open state on this file cannot be recovered
 | 
									 * Open state on this file cannot be recovered
 | 
				
			||||||
				 * All we can do is revert to using the zero stateid.
 | 
									 * All we can do is revert to using the zero stateid.
 | 
				
			||||||
				 */
 | 
									 */
 | 
				
			||||||
				memset(state->stateid.data, 0,
 | 
									memset(&state->stateid, 0,
 | 
				
			||||||
					sizeof(state->stateid.data));
 | 
										sizeof(state->stateid));
 | 
				
			||||||
				/* Mark the file as being 'closed' */
 | 
									/* Mark the file as being 'closed' */
 | 
				
			||||||
				state->state = 0;
 | 
									state->state = 0;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
| 
						 | 
					@ -1420,7 +1465,7 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
 | 
				
			||||||
		case 0:
 | 
							case 0:
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case -NFS4ERR_CB_PATH_DOWN:
 | 
							case -NFS4ERR_CB_PATH_DOWN:
 | 
				
			||||||
			nfs_handle_cb_pathdown(clp);
 | 
								nfs40_handle_cb_pathdown(clp);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case -NFS4ERR_NO_GRACE:
 | 
							case -NFS4ERR_NO_GRACE:
 | 
				
			||||||
			nfs4_state_end_reclaim_reboot(clp);
 | 
								nfs4_state_end_reclaim_reboot(clp);
 | 
				
			||||||
| 
						 | 
					@ -1801,7 +1846,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
 | 
				
			||||||
	} while (atomic_read(&clp->cl_count) > 1);
 | 
						} while (atomic_read(&clp->cl_count) > 1);
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
out_error:
 | 
					out_error:
 | 
				
			||||||
	printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
 | 
						pr_warn_ratelimited("NFS: state manager failed on NFSv4 server %s"
 | 
				
			||||||
			" with error %d\n", clp->cl_hostname, -status);
 | 
								" with error %d\n", clp->cl_hostname, -status);
 | 
				
			||||||
	nfs4_end_drain_session(clp);
 | 
						nfs4_end_drain_session(clp);
 | 
				
			||||||
	nfs4_clear_state_manager_bit(clp);
 | 
						nfs4_clear_state_manager_bit(clp);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										689
									
								
								fs/nfs/nfs4xdr.c
									
										
									
									
									
								
							
							
						
						
									
										689
									
								
								fs/nfs/nfs4xdr.c
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -104,7 +104,7 @@ static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = "";
 | 
				
			||||||
/* server:export path string passed to super.c */
 | 
					/* server:export path string passed to super.c */
 | 
				
			||||||
static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = "";
 | 
					static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef RPC_DEBUG
 | 
					#ifdef NFS_DEBUG
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * When the "nfsrootdebug" kernel command line option is specified,
 | 
					 * When the "nfsrootdebug" kernel command line option is specified,
 | 
				
			||||||
 * enable debugging messages for NFSROOT.
 | 
					 * enable debugging messages for NFSROOT.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -137,6 +137,7 @@ static int objio_devices_lookup(struct pnfs_layout_hdr *pnfslay,
 | 
				
			||||||
	struct objio_dev_ent *ode;
 | 
						struct objio_dev_ent *ode;
 | 
				
			||||||
	struct osd_dev *od;
 | 
						struct osd_dev *od;
 | 
				
			||||||
	struct osd_dev_info odi;
 | 
						struct osd_dev_info odi;
 | 
				
			||||||
 | 
						bool retry_flag = true;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ode = _dev_list_find(NFS_SERVER(pnfslay->plh_inode), d_id);
 | 
						ode = _dev_list_find(NFS_SERVER(pnfslay->plh_inode), d_id);
 | 
				
			||||||
| 
						 | 
					@ -171,10 +172,18 @@ static int objio_devices_lookup(struct pnfs_layout_hdr *pnfslay,
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					retry_lookup:
 | 
				
			||||||
	od = osduld_info_lookup(&odi);
 | 
						od = osduld_info_lookup(&odi);
 | 
				
			||||||
	if (unlikely(IS_ERR(od))) {
 | 
						if (unlikely(IS_ERR(od))) {
 | 
				
			||||||
		err = PTR_ERR(od);
 | 
							err = PTR_ERR(od);
 | 
				
			||||||
		dprintk("%s: osduld_info_lookup => %d\n", __func__, err);
 | 
							dprintk("%s: osduld_info_lookup => %d\n", __func__, err);
 | 
				
			||||||
 | 
							if (err == -ENODEV && retry_flag) {
 | 
				
			||||||
 | 
								err = objlayout_autologin(deviceaddr);
 | 
				
			||||||
 | 
								if (likely(!err)) {
 | 
				
			||||||
 | 
									retry_flag = false;
 | 
				
			||||||
 | 
									goto retry_lookup;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -205,25 +214,36 @@ static void copy_single_comp(struct ore_components *oc, unsigned c,
 | 
				
			||||||
int __alloc_objio_seg(unsigned numdevs, gfp_t gfp_flags,
 | 
					int __alloc_objio_seg(unsigned numdevs, gfp_t gfp_flags,
 | 
				
			||||||
		       struct objio_segment **pseg)
 | 
							       struct objio_segment **pseg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct __alloc_objio_segment {
 | 
					/*	This is the in memory structure of the objio_segment
 | 
				
			||||||
		struct objio_segment olseg;
 | 
					 *
 | 
				
			||||||
		struct ore_dev *ods[numdevs];
 | 
					 *	struct __alloc_objio_segment {
 | 
				
			||||||
		struct ore_comp	comps[numdevs];
 | 
					 *		struct objio_segment olseg;
 | 
				
			||||||
	} *aolseg;
 | 
					 *		struct ore_dev *ods[numdevs];
 | 
				
			||||||
 | 
					 *		struct ore_comp	comps[numdevs];
 | 
				
			||||||
 | 
					 *	} *aolseg;
 | 
				
			||||||
 | 
					 *	NOTE: The code as above compiles and runs perfectly. It is elegant,
 | 
				
			||||||
 | 
					 *	type safe and compact. At some Past time Linus has decided he does not
 | 
				
			||||||
 | 
					 *	like variable length arrays, For the sake of this principal we uglify
 | 
				
			||||||
 | 
					 *	the code as below.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
						struct objio_segment *lseg;
 | 
				
			||||||
 | 
						size_t lseg_size = sizeof(*lseg) +
 | 
				
			||||||
 | 
								numdevs * sizeof(lseg->oc.ods[0]) +
 | 
				
			||||||
 | 
								numdevs * sizeof(*lseg->oc.comps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	aolseg = kzalloc(sizeof(*aolseg), gfp_flags);
 | 
						lseg = kzalloc(lseg_size, gfp_flags);
 | 
				
			||||||
	if (unlikely(!aolseg)) {
 | 
						if (unlikely(!lseg)) {
 | 
				
			||||||
		dprintk("%s: Faild allocation numdevs=%d size=%zd\n", __func__,
 | 
							dprintk("%s: Faild allocation numdevs=%d size=%zd\n", __func__,
 | 
				
			||||||
			numdevs, sizeof(*aolseg));
 | 
								numdevs, lseg_size);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	aolseg->olseg.oc.numdevs = numdevs;
 | 
						lseg->oc.numdevs = numdevs;
 | 
				
			||||||
	aolseg->olseg.oc.single_comp = EC_MULTPLE_COMPS;
 | 
						lseg->oc.single_comp = EC_MULTPLE_COMPS;
 | 
				
			||||||
	aolseg->olseg.oc.comps = aolseg->comps;
 | 
						lseg->oc.ods = (void *)(lseg + 1);
 | 
				
			||||||
	aolseg->olseg.oc.ods = aolseg->ods;
 | 
						lseg->oc.comps = (void *)(lseg->oc.ods + numdevs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*pseg = &aolseg->olseg;
 | 
						*pseg = lseg;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -582,10 +602,10 @@ objlayout_init(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		printk(KERN_INFO
 | 
							printk(KERN_INFO
 | 
				
			||||||
			"%s: Registering OSD pNFS Layout Driver failed: error=%d\n",
 | 
								"NFS: %s: Registering OSD pNFS Layout Driver failed: error=%d\n",
 | 
				
			||||||
			__func__, ret);
 | 
								__func__, ret);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		printk(KERN_INFO "%s: Registered OSD pNFS Layout Driver\n",
 | 
							printk(KERN_INFO "NFS: %s: Registered OSD pNFS Layout Driver\n",
 | 
				
			||||||
			__func__);
 | 
								__func__);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -594,7 +614,7 @@ static void __exit
 | 
				
			||||||
objlayout_exit(void)
 | 
					objlayout_exit(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pnfs_unregister_layoutdriver(&objlayout_type);
 | 
						pnfs_unregister_layoutdriver(&objlayout_type);
 | 
				
			||||||
	printk(KERN_INFO "%s: Unregistered OSD pNFS Layout Driver\n",
 | 
						printk(KERN_INFO "NFS: %s: Unregistered OSD pNFS Layout Driver\n",
 | 
				
			||||||
	       __func__);
 | 
						       __func__);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,9 @@
 | 
				
			||||||
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
					 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kmod.h>
 | 
				
			||||||
 | 
					#include <linux/moduleparam.h>
 | 
				
			||||||
 | 
					#include <linux/ratelimit.h>
 | 
				
			||||||
#include <scsi/osd_initiator.h>
 | 
					#include <scsi/osd_initiator.h>
 | 
				
			||||||
#include "objlayout.h"
 | 
					#include "objlayout.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -156,7 +159,7 @@ last_byte_offset(u64 start, u64 len)
 | 
				
			||||||
	return end > start ? end - 1 : NFS4_MAX_UINT64;
 | 
						return end > start ? end - 1 : NFS4_MAX_UINT64;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void _fix_verify_io_params(struct pnfs_layout_segment *lseg,
 | 
					static void _fix_verify_io_params(struct pnfs_layout_segment *lseg,
 | 
				
			||||||
			   struct page ***p_pages, unsigned *p_pgbase,
 | 
								   struct page ***p_pages, unsigned *p_pgbase,
 | 
				
			||||||
			   u64 offset, unsigned long count)
 | 
								   u64 offset, unsigned long count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -490,9 +493,9 @@ encode_accumulated_error(struct objlayout *objlay, __be32 *p)
 | 
				
			||||||
			if (!ioerr->oer_errno)
 | 
								if (!ioerr->oer_errno)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			printk(KERN_ERR "%s: err[%d]: errno=%d is_write=%d "
 | 
								printk(KERN_ERR "NFS: %s: err[%d]: errno=%d "
 | 
				
			||||||
				"dev(%llx:%llx) par=0x%llx obj=0x%llx "
 | 
									"is_write=%d dev(%llx:%llx) par=0x%llx "
 | 
				
			||||||
				"offset=0x%llx length=0x%llx\n",
 | 
									"obj=0x%llx offset=0x%llx length=0x%llx\n",
 | 
				
			||||||
				__func__, i, ioerr->oer_errno,
 | 
									__func__, i, ioerr->oer_errno,
 | 
				
			||||||
				ioerr->oer_iswrite,
 | 
									ioerr->oer_iswrite,
 | 
				
			||||||
				_DEVID_LO(&ioerr->oer_component.oid_device_id),
 | 
									_DEVID_LO(&ioerr->oer_component.oid_device_id),
 | 
				
			||||||
| 
						 | 
					@ -651,3 +654,134 @@ void objlayout_put_deviceinfo(struct pnfs_osd_deviceaddr *deviceaddr)
 | 
				
			||||||
	__free_page(odi->page);
 | 
						__free_page(odi->page);
 | 
				
			||||||
	kfree(odi);
 | 
						kfree(odi);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						OBJLAYOUT_MAX_URI_LEN = 256, OBJLAYOUT_MAX_OSDNAME_LEN = 64,
 | 
				
			||||||
 | 
						OBJLAYOUT_MAX_SYSID_HEX_LEN = OSD_SYSTEMID_LEN * 2 + 1,
 | 
				
			||||||
 | 
						OSD_LOGIN_UPCALL_PATHLEN  = 256
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char osd_login_prog[OSD_LOGIN_UPCALL_PATHLEN] = "/sbin/osd_login";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_param_string(osd_login_prog, osd_login_prog, sizeof(osd_login_prog),
 | 
				
			||||||
 | 
							    0600);
 | 
				
			||||||
 | 
					MODULE_PARM_DESC(osd_login_prog, "Path to the osd_login upcall program");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct __auto_login {
 | 
				
			||||||
 | 
						char uri[OBJLAYOUT_MAX_URI_LEN];
 | 
				
			||||||
 | 
						char osdname[OBJLAYOUT_MAX_OSDNAME_LEN];
 | 
				
			||||||
 | 
						char systemid_hex[OBJLAYOUT_MAX_SYSID_HEX_LEN];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __objlayout_upcall(struct __auto_login *login)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static char *envp[] = { "HOME=/",
 | 
				
			||||||
 | 
							"TERM=linux",
 | 
				
			||||||
 | 
							"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
 | 
				
			||||||
 | 
							NULL
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						char *argv[8];
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(!osd_login_prog[0])) {
 | 
				
			||||||
 | 
							dprintk("%s: osd_login_prog is disabled\n", __func__);
 | 
				
			||||||
 | 
							return -EACCES;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dprintk("%s uri: %s\n", __func__, login->uri);
 | 
				
			||||||
 | 
						dprintk("%s osdname %s\n", __func__, login->osdname);
 | 
				
			||||||
 | 
						dprintk("%s systemid_hex %s\n", __func__, login->systemid_hex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						argv[0] = (char *)osd_login_prog;
 | 
				
			||||||
 | 
						argv[1] = "-u";
 | 
				
			||||||
 | 
						argv[2] = login->uri;
 | 
				
			||||||
 | 
						argv[3] = "-o";
 | 
				
			||||||
 | 
						argv[4] = login->osdname;
 | 
				
			||||||
 | 
						argv[5] = "-s";
 | 
				
			||||||
 | 
						argv[6] = login->systemid_hex;
 | 
				
			||||||
 | 
						argv[7] = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Disable the upcall mechanism if we're getting an ENOENT or
 | 
				
			||||||
 | 
						 * EACCES error. The admin can re-enable it on the fly by using
 | 
				
			||||||
 | 
						 * sysfs to set the objlayoutdriver.osd_login_prog module parameter once
 | 
				
			||||||
 | 
						 * the problem has been fixed.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (ret == -ENOENT || ret == -EACCES) {
 | 
				
			||||||
 | 
							printk(KERN_ERR "PNFS-OBJ: %s was not found please set "
 | 
				
			||||||
 | 
								"objlayoutdriver.osd_login_prog kernel parameter!\n",
 | 
				
			||||||
 | 
								osd_login_prog);
 | 
				
			||||||
 | 
							osd_login_prog[0] = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dprintk("%s %s return value: %d\n", __func__, osd_login_prog, ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Assume dest is all zeros */
 | 
				
			||||||
 | 
					static void __copy_nfsS_and_zero_terminate(struct nfs4_string s,
 | 
				
			||||||
 | 
										   char *dest, int max_len,
 | 
				
			||||||
 | 
										   const char *var_name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!s.len)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (s.len >= max_len) {
 | 
				
			||||||
 | 
							pr_warn_ratelimited(
 | 
				
			||||||
 | 
								"objlayout_autologin: %s: s.len(%d) >= max_len(%d)",
 | 
				
			||||||
 | 
								var_name, s.len, max_len);
 | 
				
			||||||
 | 
							s.len = max_len - 1; /* space for null terminator */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(dest, s.data, s.len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Assume sysid is all zeros */
 | 
				
			||||||
 | 
					static void _sysid_2_hex(struct nfs4_string s,
 | 
				
			||||||
 | 
							  char sysid[OBJLAYOUT_MAX_SYSID_HEX_LEN])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						char *cur;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!s.len)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (s.len != OSD_SYSTEMID_LEN) {
 | 
				
			||||||
 | 
							pr_warn_ratelimited(
 | 
				
			||||||
 | 
							    "objlayout_autologin: systemid_len(%d) != OSD_SYSTEMID_LEN",
 | 
				
			||||||
 | 
							    s.len);
 | 
				
			||||||
 | 
							if (s.len > OSD_SYSTEMID_LEN)
 | 
				
			||||||
 | 
								s.len = OSD_SYSTEMID_LEN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cur = sysid;
 | 
				
			||||||
 | 
						for (i = 0; i < s.len; i++)
 | 
				
			||||||
 | 
							cur = hex_byte_pack(cur, s.data[i]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int objlayout_autologin(struct pnfs_osd_deviceaddr *deviceaddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						struct __auto_login login;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!deviceaddr->oda_targetaddr.ota_netaddr.r_addr.len)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&login, 0, sizeof(login));
 | 
				
			||||||
 | 
						__copy_nfsS_and_zero_terminate(
 | 
				
			||||||
 | 
							deviceaddr->oda_targetaddr.ota_netaddr.r_addr,
 | 
				
			||||||
 | 
							login.uri, sizeof(login.uri), "URI");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__copy_nfsS_and_zero_terminate(
 | 
				
			||||||
 | 
							deviceaddr->oda_osdname,
 | 
				
			||||||
 | 
							login.osdname, sizeof(login.osdname), "OSDNAME");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_sysid_2_hex(deviceaddr->oda_systemid, login.systemid_hex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = __objlayout_upcall(&login);
 | 
				
			||||||
 | 
						if (rc > 0) /* script returns positive values */
 | 
				
			||||||
 | 
							rc = -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,4 +184,6 @@ extern void objlayout_encode_layoutreturn(
 | 
				
			||||||
	struct xdr_stream *,
 | 
						struct xdr_stream *,
 | 
				
			||||||
	const struct nfs4_layoutreturn_args *);
 | 
						const struct nfs4_layoutreturn_args *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int objlayout_autologin(struct pnfs_osd_deviceaddr *deviceaddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _OBJLAYOUT_H */
 | 
					#endif /* _OBJLAYOUT_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@
 | 
				
			||||||
#include <linux/file.h>
 | 
					#include <linux/file.h>
 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
#include <linux/sunrpc/clnt.h>
 | 
					#include <linux/sunrpc/clnt.h>
 | 
				
			||||||
 | 
					#include <linux/nfs.h>
 | 
				
			||||||
#include <linux/nfs3.h>
 | 
					#include <linux/nfs3.h>
 | 
				
			||||||
#include <linux/nfs4.h>
 | 
					#include <linux/nfs4.h>
 | 
				
			||||||
#include <linux/nfs_page.h>
 | 
					#include <linux/nfs_page.h>
 | 
				
			||||||
| 
						 | 
					@ -106,36 +107,6 @@ void nfs_unlock_request(struct nfs_page *req)
 | 
				
			||||||
	nfs_release_request(req);
 | 
						nfs_release_request(req);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * nfs_set_page_tag_locked - Tag a request as locked
 | 
					 | 
				
			||||||
 * @req:
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int nfs_set_page_tag_locked(struct nfs_page *req)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (!nfs_lock_request_dontget(req))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	if (test_bit(PG_MAPPED, &req->wb_flags))
 | 
					 | 
				
			||||||
		radix_tree_tag_set(&NFS_I(req->wb_context->dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * nfs_clear_page_tag_locked - Clear request tag and wake up sleepers
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void nfs_clear_page_tag_locked(struct nfs_page *req)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (test_bit(PG_MAPPED, &req->wb_flags)) {
 | 
					 | 
				
			||||||
		struct inode *inode = req->wb_context->dentry->d_inode;
 | 
					 | 
				
			||||||
		struct nfs_inode *nfsi = NFS_I(inode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		spin_lock(&inode->i_lock);
 | 
					 | 
				
			||||||
		radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
 | 
					 | 
				
			||||||
		nfs_unlock_request(req);
 | 
					 | 
				
			||||||
		spin_unlock(&inode->i_lock);
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		nfs_unlock_request(req);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * nfs_clear_request - Free up all resources allocated to the request
 | 
					 * nfs_clear_request - Free up all resources allocated to the request
 | 
				
			||||||
 * @req:
 | 
					 * @req:
 | 
				
			||||||
| 
						 | 
					@ -425,67 +396,6 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFS_SCAN_MAXENTRIES 16
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * nfs_scan_list - Scan a list for matching requests
 | 
					 | 
				
			||||||
 * @nfsi: NFS inode
 | 
					 | 
				
			||||||
 * @dst: Destination list
 | 
					 | 
				
			||||||
 * @idx_start: lower bound of page->index to scan
 | 
					 | 
				
			||||||
 * @npages: idx_start + npages sets the upper bound to scan.
 | 
					 | 
				
			||||||
 * @tag: tag to scan for
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Moves elements from one of the inode request lists.
 | 
					 | 
				
			||||||
 * If the number of requests is set to 0, the entire address_space
 | 
					 | 
				
			||||||
 * starting at index idx_start, is scanned.
 | 
					 | 
				
			||||||
 * The requests are *not* checked to ensure that they form a contiguous set.
 | 
					 | 
				
			||||||
 * You must be holding the inode's i_lock when calling this function
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int nfs_scan_list(struct nfs_inode *nfsi,
 | 
					 | 
				
			||||||
		struct list_head *dst, pgoff_t idx_start,
 | 
					 | 
				
			||||||
		unsigned int npages, int tag)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
 | 
					 | 
				
			||||||
	struct nfs_page *req;
 | 
					 | 
				
			||||||
	pgoff_t idx_end;
 | 
					 | 
				
			||||||
	int found, i;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
	struct list_head *list;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	res = 0;
 | 
					 | 
				
			||||||
	if (npages == 0)
 | 
					 | 
				
			||||||
		idx_end = ~0;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		idx_end = idx_start + npages - 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (;;) {
 | 
					 | 
				
			||||||
		found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,
 | 
					 | 
				
			||||||
				(void **)&pgvec[0], idx_start,
 | 
					 | 
				
			||||||
				NFS_SCAN_MAXENTRIES, tag);
 | 
					 | 
				
			||||||
		if (found <= 0)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		for (i = 0; i < found; i++) {
 | 
					 | 
				
			||||||
			req = pgvec[i];
 | 
					 | 
				
			||||||
			if (req->wb_index > idx_end)
 | 
					 | 
				
			||||||
				goto out;
 | 
					 | 
				
			||||||
			idx_start = req->wb_index + 1;
 | 
					 | 
				
			||||||
			if (nfs_set_page_tag_locked(req)) {
 | 
					 | 
				
			||||||
				kref_get(&req->wb_kref);
 | 
					 | 
				
			||||||
				radix_tree_tag_clear(&nfsi->nfs_page_tree,
 | 
					 | 
				
			||||||
						req->wb_index, tag);
 | 
					 | 
				
			||||||
				list = pnfs_choose_commit_list(req, dst);
 | 
					 | 
				
			||||||
				nfs_list_add_request(req, list);
 | 
					 | 
				
			||||||
				res++;
 | 
					 | 
				
			||||||
				if (res == INT_MAX)
 | 
					 | 
				
			||||||
					goto out;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* for latency reduction */
 | 
					 | 
				
			||||||
		cond_resched_lock(&nfsi->vfs_inode.i_lock);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int __init nfs_init_nfspagecache(void)
 | 
					int __init nfs_init_nfspagecache(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	nfs_page_cachep = kmem_cache_create("nfs_page",
 | 
						nfs_page_cachep = kmem_cache_create("nfs_page",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,8 +101,8 @@ set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
 | 
				
			||||||
		goto out_no_driver;
 | 
							goto out_no_driver;
 | 
				
			||||||
	if (!(server->nfs_client->cl_exchange_flags &
 | 
						if (!(server->nfs_client->cl_exchange_flags &
 | 
				
			||||||
		 (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
 | 
							 (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
 | 
				
			||||||
		printk(KERN_ERR "%s: id %u cl_exchange_flags 0x%x\n", __func__,
 | 
							printk(KERN_ERR "NFS: %s: id %u cl_exchange_flags 0x%x\n",
 | 
				
			||||||
		       id, server->nfs_client->cl_exchange_flags);
 | 
								__func__, id, server->nfs_client->cl_exchange_flags);
 | 
				
			||||||
		goto out_no_driver;
 | 
							goto out_no_driver;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ld_type = find_pnfs_driver(id);
 | 
						ld_type = find_pnfs_driver(id);
 | 
				
			||||||
| 
						 | 
					@ -122,8 +122,8 @@ set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
 | 
				
			||||||
	server->pnfs_curr_ld = ld_type;
 | 
						server->pnfs_curr_ld = ld_type;
 | 
				
			||||||
	if (ld_type->set_layoutdriver
 | 
						if (ld_type->set_layoutdriver
 | 
				
			||||||
	    && ld_type->set_layoutdriver(server, mntfh)) {
 | 
						    && ld_type->set_layoutdriver(server, mntfh)) {
 | 
				
			||||||
		printk(KERN_ERR "%s: Error initializing pNFS layout driver %u.\n",
 | 
							printk(KERN_ERR "NFS: %s: Error initializing pNFS layout "
 | 
				
			||||||
				__func__, id);
 | 
								"driver %u.\n", __func__, id);
 | 
				
			||||||
		module_put(ld_type->owner);
 | 
							module_put(ld_type->owner);
 | 
				
			||||||
		goto out_no_driver;
 | 
							goto out_no_driver;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -143,11 +143,11 @@ pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
 | 
				
			||||||
	struct pnfs_layoutdriver_type *tmp;
 | 
						struct pnfs_layoutdriver_type *tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ld_type->id == 0) {
 | 
						if (ld_type->id == 0) {
 | 
				
			||||||
		printk(KERN_ERR "%s id 0 is reserved\n", __func__);
 | 
							printk(KERN_ERR "NFS: %s id 0 is reserved\n", __func__);
 | 
				
			||||||
		return status;
 | 
							return status;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!ld_type->alloc_lseg || !ld_type->free_lseg) {
 | 
						if (!ld_type->alloc_lseg || !ld_type->free_lseg) {
 | 
				
			||||||
		printk(KERN_ERR "%s Layout driver must provide "
 | 
							printk(KERN_ERR "NFS: %s Layout driver must provide "
 | 
				
			||||||
		       "alloc_lseg and free_lseg.\n", __func__);
 | 
							       "alloc_lseg and free_lseg.\n", __func__);
 | 
				
			||||||
		return status;
 | 
							return status;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -160,7 +160,7 @@ pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
 | 
				
			||||||
		dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id,
 | 
							dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id,
 | 
				
			||||||
			ld_type->name);
 | 
								ld_type->name);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		printk(KERN_ERR "%s Module with id %d already loaded!\n",
 | 
							printk(KERN_ERR "NFS: %s Module with id %d already loaded!\n",
 | 
				
			||||||
			__func__, ld_type->id);
 | 
								__func__, ld_type->id);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_unlock(&pnfs_spinlock);
 | 
						spin_unlock(&pnfs_spinlock);
 | 
				
			||||||
| 
						 | 
					@ -496,12 +496,12 @@ pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 oldseq, newseq;
 | 
						u32 oldseq, newseq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	oldseq = be32_to_cpu(lo->plh_stateid.stateid.seqid);
 | 
						oldseq = be32_to_cpu(lo->plh_stateid.seqid);
 | 
				
			||||||
	newseq = be32_to_cpu(new->stateid.seqid);
 | 
						newseq = be32_to_cpu(new->seqid);
 | 
				
			||||||
	if ((int)(newseq - oldseq) > 0) {
 | 
						if ((int)(newseq - oldseq) > 0) {
 | 
				
			||||||
		memcpy(&lo->plh_stateid, &new->stateid, sizeof(new->stateid));
 | 
							nfs4_stateid_copy(&lo->plh_stateid, new);
 | 
				
			||||||
		if (update_barrier) {
 | 
							if (update_barrier) {
 | 
				
			||||||
			u32 new_barrier = be32_to_cpu(new->stateid.seqid);
 | 
								u32 new_barrier = be32_to_cpu(new->seqid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if ((int)(new_barrier - lo->plh_barrier))
 | 
								if ((int)(new_barrier - lo->plh_barrier))
 | 
				
			||||||
				lo->plh_barrier = new_barrier;
 | 
									lo->plh_barrier = new_barrier;
 | 
				
			||||||
| 
						 | 
					@ -525,7 +525,7 @@ pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid,
 | 
				
			||||||
			int lget)
 | 
								int lget)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if ((stateid) &&
 | 
						if ((stateid) &&
 | 
				
			||||||
	    (int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0)
 | 
						    (int)(lo->plh_barrier - be32_to_cpu(stateid->seqid)) >= 0)
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	return lo->plh_block_lgets ||
 | 
						return lo->plh_block_lgets ||
 | 
				
			||||||
		test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) ||
 | 
							test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) ||
 | 
				
			||||||
| 
						 | 
					@ -549,11 +549,10 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		do {
 | 
							do {
 | 
				
			||||||
			seq = read_seqbegin(&open_state->seqlock);
 | 
								seq = read_seqbegin(&open_state->seqlock);
 | 
				
			||||||
			memcpy(dst->data, open_state->stateid.data,
 | 
								nfs4_stateid_copy(dst, &open_state->stateid);
 | 
				
			||||||
			       sizeof(open_state->stateid.data));
 | 
					 | 
				
			||||||
		} while (read_seqretry(&open_state->seqlock, seq));
 | 
							} while (read_seqretry(&open_state->seqlock, seq));
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		memcpy(dst->data, lo->plh_stateid.data, sizeof(lo->plh_stateid.data));
 | 
							nfs4_stateid_copy(dst, &lo->plh_stateid);
 | 
				
			||||||
	spin_unlock(&lo->plh_inode->i_lock);
 | 
						spin_unlock(&lo->plh_inode->i_lock);
 | 
				
			||||||
	dprintk("<-- %s\n", __func__);
 | 
						dprintk("<-- %s\n", __func__);
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
| 
						 | 
					@ -590,7 +589,7 @@ send_layoutget(struct pnfs_layout_hdr *lo,
 | 
				
			||||||
	max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
 | 
						max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
 | 
				
			||||||
	max_pages = max_resp_sz >> PAGE_SHIFT;
 | 
						max_pages = max_resp_sz >> PAGE_SHIFT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags);
 | 
						pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
 | 
				
			||||||
	if (!pages)
 | 
						if (!pages)
 | 
				
			||||||
		goto out_err_free;
 | 
							goto out_err_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -760,7 +759,7 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	if (!found) {
 | 
						if (!found) {
 | 
				
			||||||
		struct pnfs_layout_hdr *lo = nfsi->layout;
 | 
							struct pnfs_layout_hdr *lo = nfsi->layout;
 | 
				
			||||||
		u32 current_seqid = be32_to_cpu(lo->plh_stateid.stateid.seqid);
 | 
							u32 current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Since close does not return a layout stateid for use as
 | 
							/* Since close does not return a layout stateid for use as
 | 
				
			||||||
		 * a barrier, we choose the worst-case barrier.
 | 
							 * a barrier, we choose the worst-case barrier.
 | 
				
			||||||
| 
						 | 
					@ -966,8 +965,7 @@ pnfs_update_layout(struct inode *ino,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Do we even need to bother with this? */
 | 
						/* Do we even need to bother with this? */
 | 
				
			||||||
	if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) ||
 | 
						if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
 | 
				
			||||||
	    test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
 | 
					 | 
				
			||||||
		dprintk("%s matches recall, use MDS\n", __func__);
 | 
							dprintk("%s matches recall, use MDS\n", __func__);
 | 
				
			||||||
		goto out_unlock;
 | 
							goto out_unlock;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1032,7 +1030,6 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
 | 
				
			||||||
	struct nfs4_layoutget_res *res = &lgp->res;
 | 
						struct nfs4_layoutget_res *res = &lgp->res;
 | 
				
			||||||
	struct pnfs_layout_segment *lseg;
 | 
						struct pnfs_layout_segment *lseg;
 | 
				
			||||||
	struct inode *ino = lo->plh_inode;
 | 
						struct inode *ino = lo->plh_inode;
 | 
				
			||||||
	struct nfs_client *clp = NFS_SERVER(ino)->nfs_client;
 | 
					 | 
				
			||||||
	int status = 0;
 | 
						int status = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Inject layout blob into I/O device driver */
 | 
						/* Inject layout blob into I/O device driver */
 | 
				
			||||||
| 
						 | 
					@ -1048,8 +1045,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&ino->i_lock);
 | 
						spin_lock(&ino->i_lock);
 | 
				
			||||||
	if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) ||
 | 
						if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
 | 
				
			||||||
	    test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
 | 
					 | 
				
			||||||
		dprintk("%s forget reply due to recall\n", __func__);
 | 
							dprintk("%s forget reply due to recall\n", __func__);
 | 
				
			||||||
		goto out_forget_reply;
 | 
							goto out_forget_reply;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1214,6 +1210,7 @@ void pnfs_ld_write_done(struct nfs_write_data *data)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages);
 | 
							data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						put_lseg(data->lseg);
 | 
				
			||||||
	data->mds_ops->rpc_release(data);
 | 
						data->mds_ops->rpc_release(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
 | 
					EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
 | 
				
			||||||
| 
						 | 
					@ -1227,6 +1224,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
 | 
				
			||||||
		nfs_list_add_request(data->req, &desc->pg_list);
 | 
							nfs_list_add_request(data->req, &desc->pg_list);
 | 
				
			||||||
	nfs_pageio_reset_write_mds(desc);
 | 
						nfs_pageio_reset_write_mds(desc);
 | 
				
			||||||
	desc->pg_recoalesce = 1;
 | 
						desc->pg_recoalesce = 1;
 | 
				
			||||||
 | 
						put_lseg(data->lseg);
 | 
				
			||||||
	nfs_writedata_release(data);
 | 
						nfs_writedata_release(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1327,6 +1325,7 @@ void pnfs_ld_read_done(struct nfs_read_data *data)
 | 
				
			||||||
		data->mds_ops->rpc_call_done(&data->task, data);
 | 
							data->mds_ops->rpc_call_done(&data->task, data);
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		pnfs_ld_handle_read_error(data);
 | 
							pnfs_ld_handle_read_error(data);
 | 
				
			||||||
 | 
						put_lseg(data->lseg);
 | 
				
			||||||
	data->mds_ops->rpc_release(data);
 | 
						data->mds_ops->rpc_release(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
 | 
					EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
 | 
				
			||||||
| 
						 | 
					@ -1530,8 +1529,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 | 
				
			||||||
	end_pos = nfsi->layout->plh_lwb;
 | 
						end_pos = nfsi->layout->plh_lwb;
 | 
				
			||||||
	nfsi->layout->plh_lwb = 0;
 | 
						nfsi->layout->plh_lwb = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data,
 | 
						nfs4_stateid_copy(&data->args.stateid, &nfsi->layout->plh_stateid);
 | 
				
			||||||
		sizeof(nfsi->layout->plh_stateid.data));
 | 
					 | 
				
			||||||
	spin_unlock(&inode->i_lock);
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->args.inode = inode;
 | 
						data->args.inode = inode;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										102
									
								
								fs/nfs/pnfs.h
									
										
									
									
									
								
							
							
						
						
									
										102
									
								
								fs/nfs/pnfs.h
									
										
									
									
									
								
							| 
						 | 
					@ -94,11 +94,10 @@ struct pnfs_layoutdriver_type {
 | 
				
			||||||
	const struct nfs_pageio_ops *pg_read_ops;
 | 
						const struct nfs_pageio_ops *pg_read_ops;
 | 
				
			||||||
	const struct nfs_pageio_ops *pg_write_ops;
 | 
						const struct nfs_pageio_ops *pg_write_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Returns true if layoutdriver wants to divert this request to
 | 
						void (*mark_request_commit) (struct nfs_page *req,
 | 
				
			||||||
	 * driver's commit routine.
 | 
										struct pnfs_layout_segment *lseg);
 | 
				
			||||||
	 */
 | 
						void (*clear_request_commit) (struct nfs_page *req);
 | 
				
			||||||
	bool (*mark_pnfs_commit)(struct pnfs_layout_segment *lseg);
 | 
						int (*scan_commit_lists) (struct inode *inode, int max, spinlock_t *lock);
 | 
				
			||||||
	struct list_head * (*choose_commit_list) (struct nfs_page *req);
 | 
					 | 
				
			||||||
	int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how);
 | 
						int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -229,7 +228,6 @@ struct nfs4_deviceid_node {
 | 
				
			||||||
	atomic_t			ref;
 | 
						atomic_t			ref;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id);
 | 
					 | 
				
			||||||
struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 | 
					struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 | 
				
			||||||
void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 | 
					void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 | 
				
			||||||
void nfs4_init_deviceid_node(struct nfs4_deviceid_node *,
 | 
					void nfs4_init_deviceid_node(struct nfs4_deviceid_node *,
 | 
				
			||||||
| 
						 | 
					@ -262,20 +260,6 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss)
 | 
				
			||||||
	return nfss->pnfs_curr_ld != NULL;
 | 
						return nfss->pnfs_curr_ld != NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void
 | 
					 | 
				
			||||||
pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (lseg) {
 | 
					 | 
				
			||||||
		struct pnfs_layoutdriver_type *ld;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ld = NFS_SERVER(req->wb_page->mapping->host)->pnfs_curr_ld;
 | 
					 | 
				
			||||||
		if (ld->mark_pnfs_commit && ld->mark_pnfs_commit(lseg)) {
 | 
					 | 
				
			||||||
			set_bit(PG_PNFS_COMMIT, &req->wb_flags);
 | 
					 | 
				
			||||||
			req->wb_commit_lseg = get_lseg(lseg);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int
 | 
					static inline int
 | 
				
			||||||
pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
 | 
					pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -284,27 +268,42 @@ pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
 | 
				
			||||||
	return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how);
 | 
						return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct list_head *
 | 
					static inline bool
 | 
				
			||||||
pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
 | 
					pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct list_head *rv;
 | 
						struct inode *inode = req->wb_context->dentry->d_inode;
 | 
				
			||||||
 | 
						struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) {
 | 
						if (lseg == NULL || ld->mark_request_commit == NULL)
 | 
				
			||||||
		struct inode *inode = req->wb_commit_lseg->pls_layout->plh_inode;
 | 
							return false;
 | 
				
			||||||
 | 
						ld->mark_request_commit(req, lseg);
 | 
				
			||||||
		set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
 | 
						return true;
 | 
				
			||||||
		rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req);
 | 
					 | 
				
			||||||
		/* matched by ref taken when PG_PNFS_COMMIT is set */
 | 
					 | 
				
			||||||
		put_lseg(req->wb_commit_lseg);
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		rv = mds;
 | 
					 | 
				
			||||||
	return rv;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void pnfs_clear_request_commit(struct nfs_page *req)
 | 
					static inline bool
 | 
				
			||||||
 | 
					pnfs_clear_request_commit(struct nfs_page *req)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags))
 | 
						struct inode *inode = req->wb_context->dentry->d_inode;
 | 
				
			||||||
		put_lseg(req->wb_commit_lseg);
 | 
						struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ld == NULL || ld->clear_request_commit == NULL)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						ld->clear_request_commit(req);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ld == NULL || ld->scan_commit_lists == NULL)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						ret = ld->scan_commit_lists(inode, max, lock);
 | 
				
			||||||
 | 
						if (ret != 0)
 | 
				
			||||||
 | 
							set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Should the pNFS client commit and return the layout upon a setattr */
 | 
					/* Should the pNFS client commit and return the layout upon a setattr */
 | 
				
			||||||
| 
						 | 
					@ -328,6 +327,13 @@ static inline int pnfs_return_layout(struct inode *ino)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef NFS_DEBUG
 | 
				
			||||||
 | 
					void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* NFS_DEBUG */
 | 
				
			||||||
#else  /* CONFIG_NFS_V4_1 */
 | 
					#else  /* CONFIG_NFS_V4_1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
 | 
					static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
 | 
				
			||||||
| 
						 | 
					@ -400,25 +406,28 @@ static inline bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, st
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void
 | 
					 | 
				
			||||||
pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int
 | 
					static inline int
 | 
				
			||||||
pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
 | 
					pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return PNFS_NOT_ATTEMPTED;
 | 
						return PNFS_NOT_ATTEMPTED;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct list_head *
 | 
					static inline bool
 | 
				
			||||||
pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
 | 
					pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return mds;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void pnfs_clear_request_commit(struct nfs_page *req)
 | 
					static inline bool
 | 
				
			||||||
 | 
					pnfs_clear_request_commit(struct nfs_page *req)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 | 
					static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 | 
				
			||||||
| 
						 | 
					@ -426,9 +435,6 @@ static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void nfs4_deviceid_purge_client(struct nfs_client *ncl)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					#endif /* CONFIG_NFS_V4_1 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* FS_NFS_PNFS_H */
 | 
					#endif /* FS_NFS_PNFS_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@
 | 
				
			||||||
static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
 | 
					static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
 | 
				
			||||||
static DEFINE_SPINLOCK(nfs4_deviceid_lock);
 | 
					static DEFINE_SPINLOCK(nfs4_deviceid_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef NFS_DEBUG
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
nfs4_print_deviceid(const struct nfs4_deviceid *id)
 | 
					nfs4_print_deviceid(const struct nfs4_deviceid *id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -52,6 +53,7 @@ nfs4_print_deviceid(const struct nfs4_deviceid *id)
 | 
				
			||||||
		p[0], p[1], p[2], p[3]);
 | 
							p[0], p[1], p[2], p[3]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(nfs4_print_deviceid);
 | 
					EXPORT_SYMBOL_GPL(nfs4_print_deviceid);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline u32
 | 
					static inline u32
 | 
				
			||||||
nfs4_deviceid_hash(const struct nfs4_deviceid *id)
 | 
					nfs4_deviceid_hash(const struct nfs4_deviceid *id)
 | 
				
			||||||
| 
						 | 
					@ -92,7 +94,7 @@ _lookup_deviceid(const struct pnfs_layoutdriver_type *ld,
 | 
				
			||||||
 * @clp nfs_client associated with deviceid
 | 
					 * @clp nfs_client associated with deviceid
 | 
				
			||||||
 * @id deviceid to look up
 | 
					 * @id deviceid to look up
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct nfs4_deviceid_node *
 | 
					static struct nfs4_deviceid_node *
 | 
				
			||||||
_find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
 | 
					_find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
 | 
				
			||||||
		   const struct nfs_client *clp, const struct nfs4_deviceid *id,
 | 
							   const struct nfs_client *clp, const struct nfs4_deviceid *id,
 | 
				
			||||||
		   long hash)
 | 
							   long hash)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -358,6 +358,11 @@ nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 | 
				
			||||||
	msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
 | 
						msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rpc_call_start(task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 | 
					static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (nfs_async_handle_expired_key(task))
 | 
						if (nfs_async_handle_expired_key(task))
 | 
				
			||||||
| 
						 | 
					@ -372,6 +377,11 @@ nfs_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
 | 
				
			||||||
	msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME];
 | 
						msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rpc_call_start(task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
 | 
					nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
 | 
				
			||||||
		     struct inode *new_dir)
 | 
							     struct inode *new_dir)
 | 
				
			||||||
| 
						 | 
					@ -651,6 +661,11 @@ static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message *
 | 
				
			||||||
	msg->rpc_proc = &nfs_procedures[NFSPROC_READ];
 | 
						msg->rpc_proc = &nfs_procedures[NFSPROC_READ];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rpc_call_start(task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
 | 
					static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (nfs_async_handle_expired_key(task))
 | 
						if (nfs_async_handle_expired_key(task))
 | 
				
			||||||
| 
						 | 
					@ -668,6 +683,11 @@ static void nfs_proc_write_setup(struct nfs_write_data *data, struct rpc_message
 | 
				
			||||||
	msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE];
 | 
						msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rpc_call_start(task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
nfs_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg)
 | 
					nfs_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -721,9 +741,11 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
 | 
				
			||||||
	.create		= nfs_proc_create,
 | 
						.create		= nfs_proc_create,
 | 
				
			||||||
	.remove		= nfs_proc_remove,
 | 
						.remove		= nfs_proc_remove,
 | 
				
			||||||
	.unlink_setup	= nfs_proc_unlink_setup,
 | 
						.unlink_setup	= nfs_proc_unlink_setup,
 | 
				
			||||||
 | 
						.unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare,
 | 
				
			||||||
	.unlink_done	= nfs_proc_unlink_done,
 | 
						.unlink_done	= nfs_proc_unlink_done,
 | 
				
			||||||
	.rename		= nfs_proc_rename,
 | 
						.rename		= nfs_proc_rename,
 | 
				
			||||||
	.rename_setup	= nfs_proc_rename_setup,
 | 
						.rename_setup	= nfs_proc_rename_setup,
 | 
				
			||||||
 | 
						.rename_rpc_prepare = nfs_proc_rename_rpc_prepare,
 | 
				
			||||||
	.rename_done	= nfs_proc_rename_done,
 | 
						.rename_done	= nfs_proc_rename_done,
 | 
				
			||||||
	.link		= nfs_proc_link,
 | 
						.link		= nfs_proc_link,
 | 
				
			||||||
	.symlink	= nfs_proc_symlink,
 | 
						.symlink	= nfs_proc_symlink,
 | 
				
			||||||
| 
						 | 
					@ -736,8 +758,10 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
 | 
				
			||||||
	.pathconf	= nfs_proc_pathconf,
 | 
						.pathconf	= nfs_proc_pathconf,
 | 
				
			||||||
	.decode_dirent	= nfs2_decode_dirent,
 | 
						.decode_dirent	= nfs2_decode_dirent,
 | 
				
			||||||
	.read_setup	= nfs_proc_read_setup,
 | 
						.read_setup	= nfs_proc_read_setup,
 | 
				
			||||||
 | 
						.read_rpc_prepare = nfs_proc_read_rpc_prepare,
 | 
				
			||||||
	.read_done	= nfs_read_done,
 | 
						.read_done	= nfs_read_done,
 | 
				
			||||||
	.write_setup	= nfs_proc_write_setup,
 | 
						.write_setup	= nfs_proc_write_setup,
 | 
				
			||||||
 | 
						.write_rpc_prepare = nfs_proc_write_rpc_prepare,
 | 
				
			||||||
	.write_done	= nfs_write_done,
 | 
						.write_done	= nfs_write_done,
 | 
				
			||||||
	.commit_setup	= nfs_proc_commit_setup,
 | 
						.commit_setup	= nfs_proc_commit_setup,
 | 
				
			||||||
	.lock		= nfs_proc_lock,
 | 
						.lock		= nfs_proc_lock,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,7 +66,6 @@ void nfs_readdata_free(struct nfs_read_data *p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_readdata_release(struct nfs_read_data *rdata)
 | 
					void nfs_readdata_release(struct nfs_read_data *rdata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	put_lseg(rdata->lseg);
 | 
					 | 
				
			||||||
	put_nfs_open_context(rdata->args.context);
 | 
						put_nfs_open_context(rdata->args.context);
 | 
				
			||||||
	nfs_readdata_free(rdata);
 | 
						nfs_readdata_free(rdata);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -465,23 +464,14 @@ static void nfs_readpage_release_partial(void *calldata)
 | 
				
			||||||
	nfs_readdata_release(calldata);
 | 
						nfs_readdata_release(calldata);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
void nfs_read_prepare(struct rpc_task *task, void *calldata)
 | 
					void nfs_read_prepare(struct rpc_task *task, void *calldata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_read_data *data = calldata;
 | 
						struct nfs_read_data *data = calldata;
 | 
				
			||||||
 | 
						NFS_PROTO(data->inode)->read_rpc_prepare(task, data);
 | 
				
			||||||
	if (nfs4_setup_sequence(NFS_SERVER(data->inode),
 | 
					 | 
				
			||||||
				&data->args.seq_args, &data->res.seq_res,
 | 
					 | 
				
			||||||
				0, task))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	rpc_call_start(task);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_read_partial_ops = {
 | 
					static const struct rpc_call_ops nfs_read_partial_ops = {
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_read_prepare,
 | 
						.rpc_call_prepare = nfs_read_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
	.rpc_call_done = nfs_readpage_result_partial,
 | 
						.rpc_call_done = nfs_readpage_result_partial,
 | 
				
			||||||
	.rpc_release = nfs_readpage_release_partial,
 | 
						.rpc_release = nfs_readpage_release_partial,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -545,9 +535,7 @@ static void nfs_readpage_release_full(void *calldata)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_read_full_ops = {
 | 
					static const struct rpc_call_ops nfs_read_full_ops = {
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_read_prepare,
 | 
						.rpc_call_prepare = nfs_read_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
	.rpc_call_done = nfs_readpage_result_full,
 | 
						.rpc_call_done = nfs_readpage_result_full,
 | 
				
			||||||
	.rpc_release = nfs_readpage_release_full,
 | 
						.rpc_release = nfs_readpage_release_full,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										167
									
								
								fs/nfs/super.c
									
										
									
									
									
								
							
							
						
						
									
										167
									
								
								fs/nfs/super.c
									
										
									
									
									
								
							| 
						 | 
					@ -52,6 +52,8 @@
 | 
				
			||||||
#include <linux/nfs_xdr.h>
 | 
					#include <linux/nfs_xdr.h>
 | 
				
			||||||
#include <linux/magic.h>
 | 
					#include <linux/magic.h>
 | 
				
			||||||
#include <linux/parser.h>
 | 
					#include <linux/parser.h>
 | 
				
			||||||
 | 
					#include <linux/nsproxy.h>
 | 
				
			||||||
 | 
					#include <linux/rcupdate.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/system.h>
 | 
					#include <asm/system.h>
 | 
				
			||||||
#include <asm/uaccess.h>
 | 
					#include <asm/uaccess.h>
 | 
				
			||||||
| 
						 | 
					@ -79,7 +81,6 @@ enum {
 | 
				
			||||||
	Opt_cto, Opt_nocto,
 | 
						Opt_cto, Opt_nocto,
 | 
				
			||||||
	Opt_ac, Opt_noac,
 | 
						Opt_ac, Opt_noac,
 | 
				
			||||||
	Opt_lock, Opt_nolock,
 | 
						Opt_lock, Opt_nolock,
 | 
				
			||||||
	Opt_v2, Opt_v3, Opt_v4,
 | 
					 | 
				
			||||||
	Opt_udp, Opt_tcp, Opt_rdma,
 | 
						Opt_udp, Opt_tcp, Opt_rdma,
 | 
				
			||||||
	Opt_acl, Opt_noacl,
 | 
						Opt_acl, Opt_noacl,
 | 
				
			||||||
	Opt_rdirplus, Opt_nordirplus,
 | 
						Opt_rdirplus, Opt_nordirplus,
 | 
				
			||||||
| 
						 | 
					@ -97,10 +98,10 @@ enum {
 | 
				
			||||||
	Opt_namelen,
 | 
						Opt_namelen,
 | 
				
			||||||
	Opt_mountport,
 | 
						Opt_mountport,
 | 
				
			||||||
	Opt_mountvers,
 | 
						Opt_mountvers,
 | 
				
			||||||
	Opt_nfsvers,
 | 
					 | 
				
			||||||
	Opt_minorversion,
 | 
						Opt_minorversion,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Mount options that take string arguments */
 | 
						/* Mount options that take string arguments */
 | 
				
			||||||
 | 
						Opt_nfsvers,
 | 
				
			||||||
	Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
 | 
						Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
 | 
				
			||||||
	Opt_addr, Opt_mountaddr, Opt_clientaddr,
 | 
						Opt_addr, Opt_mountaddr, Opt_clientaddr,
 | 
				
			||||||
	Opt_lookupcache,
 | 
						Opt_lookupcache,
 | 
				
			||||||
| 
						 | 
					@ -132,9 +133,6 @@ static const match_table_t nfs_mount_option_tokens = {
 | 
				
			||||||
	{ Opt_noac, "noac" },
 | 
						{ Opt_noac, "noac" },
 | 
				
			||||||
	{ Opt_lock, "lock" },
 | 
						{ Opt_lock, "lock" },
 | 
				
			||||||
	{ Opt_nolock, "nolock" },
 | 
						{ Opt_nolock, "nolock" },
 | 
				
			||||||
	{ Opt_v2, "v2" },
 | 
					 | 
				
			||||||
	{ Opt_v3, "v3" },
 | 
					 | 
				
			||||||
	{ Opt_v4, "v4" },
 | 
					 | 
				
			||||||
	{ Opt_udp, "udp" },
 | 
						{ Opt_udp, "udp" },
 | 
				
			||||||
	{ Opt_tcp, "tcp" },
 | 
						{ Opt_tcp, "tcp" },
 | 
				
			||||||
	{ Opt_rdma, "rdma" },
 | 
						{ Opt_rdma, "rdma" },
 | 
				
			||||||
| 
						 | 
					@ -163,9 +161,10 @@ static const match_table_t nfs_mount_option_tokens = {
 | 
				
			||||||
	{ Opt_namelen, "namlen=%s" },
 | 
						{ Opt_namelen, "namlen=%s" },
 | 
				
			||||||
	{ Opt_mountport, "mountport=%s" },
 | 
						{ Opt_mountport, "mountport=%s" },
 | 
				
			||||||
	{ Opt_mountvers, "mountvers=%s" },
 | 
						{ Opt_mountvers, "mountvers=%s" },
 | 
				
			||||||
 | 
						{ Opt_minorversion, "minorversion=%s" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{ Opt_nfsvers, "nfsvers=%s" },
 | 
						{ Opt_nfsvers, "nfsvers=%s" },
 | 
				
			||||||
	{ Opt_nfsvers, "vers=%s" },
 | 
						{ Opt_nfsvers, "vers=%s" },
 | 
				
			||||||
	{ Opt_minorversion, "minorversion=%s" },
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{ Opt_sec, "sec=%s" },
 | 
						{ Opt_sec, "sec=%s" },
 | 
				
			||||||
	{ Opt_proto, "proto=%s" },
 | 
						{ Opt_proto, "proto=%s" },
 | 
				
			||||||
| 
						 | 
					@ -179,6 +178,9 @@ static const match_table_t nfs_mount_option_tokens = {
 | 
				
			||||||
	{ Opt_fscache_uniq, "fsc=%s" },
 | 
						{ Opt_fscache_uniq, "fsc=%s" },
 | 
				
			||||||
	{ Opt_local_lock, "local_lock=%s" },
 | 
						{ Opt_local_lock, "local_lock=%s" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The following needs to be listed after all other options */
 | 
				
			||||||
 | 
						{ Opt_nfsvers, "v%s" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{ Opt_err, NULL }
 | 
						{ Opt_err, NULL }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -259,6 +261,22 @@ static match_table_t nfs_local_lock_tokens = {
 | 
				
			||||||
	{ Opt_local_lock_err, NULL }
 | 
						{ Opt_local_lock_err, NULL }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
 | 
				
			||||||
 | 
						Opt_vers_4_1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Opt_vers_err
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static match_table_t nfs_vers_tokens = {
 | 
				
			||||||
 | 
						{ Opt_vers_2, "2" },
 | 
				
			||||||
 | 
						{ Opt_vers_3, "3" },
 | 
				
			||||||
 | 
						{ Opt_vers_4, "4" },
 | 
				
			||||||
 | 
						{ Opt_vers_4_0, "4.0" },
 | 
				
			||||||
 | 
						{ Opt_vers_4_1, "4.1" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{ Opt_vers_err, NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfs_umount_begin(struct super_block *);
 | 
					static void nfs_umount_begin(struct super_block *);
 | 
				
			||||||
static int  nfs_statfs(struct dentry *, struct kstatfs *);
 | 
					static int  nfs_statfs(struct dentry *, struct kstatfs *);
 | 
				
			||||||
| 
						 | 
					@ -620,7 +638,6 @@ static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
 | 
				
			||||||
	struct nfs_client *clp = nfss->nfs_client;
 | 
						struct nfs_client *clp = nfss->nfs_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
 | 
						seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
 | 
				
			||||||
	seq_printf(m, ",minorversion=%u", clp->cl_minorversion);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
 | 
					static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
 | 
				
			||||||
| 
						 | 
					@ -629,6 +646,15 @@ static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nfs_show_nfs_version(struct seq_file *m,
 | 
				
			||||||
 | 
							unsigned int version,
 | 
				
			||||||
 | 
							unsigned int minorversion)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						seq_printf(m, ",vers=%u", version);
 | 
				
			||||||
 | 
						if (version == 4)
 | 
				
			||||||
 | 
							seq_printf(m, ".%u", minorversion);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Describe the mount options in force on this server representation
 | 
					 * Describe the mount options in force on this server representation
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -656,7 +682,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
 | 
				
			||||||
	u32 version = clp->rpc_ops->version;
 | 
						u32 version = clp->rpc_ops->version;
 | 
				
			||||||
	int local_flock, local_fcntl;
 | 
						int local_flock, local_fcntl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seq_printf(m, ",vers=%u", version);
 | 
						nfs_show_nfs_version(m, version, clp->cl_minorversion);
 | 
				
			||||||
	seq_printf(m, ",rsize=%u", nfss->rsize);
 | 
						seq_printf(m, ",rsize=%u", nfss->rsize);
 | 
				
			||||||
	seq_printf(m, ",wsize=%u", nfss->wsize);
 | 
						seq_printf(m, ",wsize=%u", nfss->wsize);
 | 
				
			||||||
	if (nfss->bsize != 0)
 | 
						if (nfss->bsize != 0)
 | 
				
			||||||
| 
						 | 
					@ -676,8 +702,10 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			seq_puts(m, nfs_infop->nostr);
 | 
								seq_puts(m, nfs_infop->nostr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
	seq_printf(m, ",proto=%s",
 | 
						seq_printf(m, ",proto=%s",
 | 
				
			||||||
		   rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
 | 
							   rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
 | 
				
			||||||
 | 
						rcu_read_unlock();
 | 
				
			||||||
	if (version == 4) {
 | 
						if (version == 4) {
 | 
				
			||||||
		if (nfss->port != NFS_PORT)
 | 
							if (nfss->port != NFS_PORT)
 | 
				
			||||||
			seq_printf(m, ",port=%u", nfss->port);
 | 
								seq_printf(m, ",port=%u", nfss->port);
 | 
				
			||||||
| 
						 | 
					@ -726,9 +754,11 @@ static int nfs_show_options(struct seq_file *m, struct dentry *root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nfs_show_mount_options(m, nfss, 0);
 | 
						nfs_show_mount_options(m, nfss, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock();
 | 
				
			||||||
	seq_printf(m, ",addr=%s",
 | 
						seq_printf(m, ",addr=%s",
 | 
				
			||||||
			rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient,
 | 
								rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient,
 | 
				
			||||||
							RPC_DISPLAY_ADDR));
 | 
												RPC_DISPLAY_ADDR));
 | 
				
			||||||
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -745,7 +775,6 @@ static void show_sessions(struct seq_file *m, struct nfs_server *server) {}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_NFS_V4
 | 
					 | 
				
			||||||
#ifdef CONFIG_NFS_V4_1
 | 
					#ifdef CONFIG_NFS_V4_1
 | 
				
			||||||
static void show_pnfs(struct seq_file *m, struct nfs_server *server)
 | 
					static void show_pnfs(struct seq_file *m, struct nfs_server *server)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -755,9 +784,26 @@ static void show_pnfs(struct seq_file *m, struct nfs_server *server)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		seq_printf(m, "not configured");
 | 
							seq_printf(m, "not configured");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (nfss->nfs_client && nfss->nfs_client->impl_id) {
 | 
				
			||||||
 | 
							struct nfs41_impl_id *impl_id = nfss->nfs_client->impl_id;
 | 
				
			||||||
 | 
							seq_printf(m, "\n\timpl_id:\tname='%s',domain='%s',"
 | 
				
			||||||
 | 
								   "date='%llu,%u'",
 | 
				
			||||||
 | 
								   impl_id->name, impl_id->domain,
 | 
				
			||||||
 | 
								   impl_id->date.seconds, impl_id->date.nseconds);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static void show_pnfs(struct seq_file *m, struct nfs_server *server) {}
 | 
					#ifdef CONFIG_NFS_V4
 | 
				
			||||||
 | 
					static void show_pnfs(struct seq_file *m, struct nfs_server *server)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfs_show_devname(struct seq_file *m, struct dentry *root)
 | 
					static int nfs_show_devname(struct seq_file *m, struct dentry *root)
 | 
				
			||||||
| 
						 | 
					@ -806,6 +852,8 @@ static int nfs_show_stats(struct seq_file *m, struct dentry *root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
 | 
						seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						show_implementation_id(m, nfss);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seq_printf(m, "\n\tcaps:\t");
 | 
						seq_printf(m, "\n\tcaps:\t");
 | 
				
			||||||
	seq_printf(m, "caps=0x%x", nfss->caps);
 | 
						seq_printf(m, "caps=0x%x", nfss->caps);
 | 
				
			||||||
	seq_printf(m, ",wtmult=%u", nfss->wtmult);
 | 
						seq_printf(m, ",wtmult=%u", nfss->wtmult);
 | 
				
			||||||
| 
						 | 
					@ -908,6 +956,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve
 | 
				
			||||||
		data->auth_flavor_len	= 1;
 | 
							data->auth_flavor_len	= 1;
 | 
				
			||||||
		data->version		= version;
 | 
							data->version		= version;
 | 
				
			||||||
		data->minorversion	= 0;
 | 
							data->minorversion	= 0;
 | 
				
			||||||
 | 
							data->net		= current->nsproxy->net_ns;
 | 
				
			||||||
		security_init_mnt_opts(&data->lsm_opts);
 | 
							security_init_mnt_opts(&data->lsm_opts);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return data;
 | 
						return data;
 | 
				
			||||||
| 
						 | 
					@ -1052,6 +1101,40 @@ static int nfs_parse_security_flavors(char *value,
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int nfs_parse_version_string(char *string,
 | 
				
			||||||
 | 
							struct nfs_parsed_mount_data *mnt,
 | 
				
			||||||
 | 
							substring_t *args)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mnt->flags &= ~NFS_MOUNT_VER3;
 | 
				
			||||||
 | 
						switch (match_token(string, nfs_vers_tokens, args)) {
 | 
				
			||||||
 | 
						case Opt_vers_2:
 | 
				
			||||||
 | 
							mnt->version = 2;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case Opt_vers_3:
 | 
				
			||||||
 | 
							mnt->flags |= NFS_MOUNT_VER3;
 | 
				
			||||||
 | 
							mnt->version = 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case Opt_vers_4:
 | 
				
			||||||
 | 
							/* Backward compatibility option. In future,
 | 
				
			||||||
 | 
							 * the mount program should always supply
 | 
				
			||||||
 | 
							 * a NFSv4 minor version number.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							mnt->version = 4;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case Opt_vers_4_0:
 | 
				
			||||||
 | 
							mnt->version = 4;
 | 
				
			||||||
 | 
							mnt->minorversion = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case Opt_vers_4_1:
 | 
				
			||||||
 | 
							mnt->version = 4;
 | 
				
			||||||
 | 
							mnt->minorversion = 1;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfs_get_option_str(substring_t args[], char **option)
 | 
					static int nfs_get_option_str(substring_t args[], char **option)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	kfree(*option);
 | 
						kfree(*option);
 | 
				
			||||||
| 
						 | 
					@ -1157,18 +1240,6 @@ static int nfs_parse_mount_options(char *raw,
 | 
				
			||||||
			mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
 | 
								mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
 | 
				
			||||||
				       NFS_MOUNT_LOCAL_FCNTL);
 | 
									       NFS_MOUNT_LOCAL_FCNTL);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case Opt_v2:
 | 
					 | 
				
			||||||
			mnt->flags &= ~NFS_MOUNT_VER3;
 | 
					 | 
				
			||||||
			mnt->version = 2;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case Opt_v3:
 | 
					 | 
				
			||||||
			mnt->flags |= NFS_MOUNT_VER3;
 | 
					 | 
				
			||||||
			mnt->version = 3;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case Opt_v4:
 | 
					 | 
				
			||||||
			mnt->flags &= ~NFS_MOUNT_VER3;
 | 
					 | 
				
			||||||
			mnt->version = 4;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case Opt_udp:
 | 
							case Opt_udp:
 | 
				
			||||||
			mnt->flags &= ~NFS_MOUNT_TCP;
 | 
								mnt->flags &= ~NFS_MOUNT_TCP;
 | 
				
			||||||
			mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
 | 
								mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
 | 
				
			||||||
| 
						 | 
					@ -1295,26 +1366,6 @@ static int nfs_parse_mount_options(char *raw,
 | 
				
			||||||
				goto out_invalid_value;
 | 
									goto out_invalid_value;
 | 
				
			||||||
			mnt->mount_server.version = option;
 | 
								mnt->mount_server.version = option;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case Opt_nfsvers:
 | 
					 | 
				
			||||||
			if (nfs_get_option_ul(args, &option))
 | 
					 | 
				
			||||||
				goto out_invalid_value;
 | 
					 | 
				
			||||||
			switch (option) {
 | 
					 | 
				
			||||||
			case NFS2_VERSION:
 | 
					 | 
				
			||||||
				mnt->flags &= ~NFS_MOUNT_VER3;
 | 
					 | 
				
			||||||
				mnt->version = 2;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			case NFS3_VERSION:
 | 
					 | 
				
			||||||
				mnt->flags |= NFS_MOUNT_VER3;
 | 
					 | 
				
			||||||
				mnt->version = 3;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			case NFS4_VERSION:
 | 
					 | 
				
			||||||
				mnt->flags &= ~NFS_MOUNT_VER3;
 | 
					 | 
				
			||||||
				mnt->version = 4;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			default:
 | 
					 | 
				
			||||||
				goto out_invalid_value;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case Opt_minorversion:
 | 
							case Opt_minorversion:
 | 
				
			||||||
			if (nfs_get_option_ul(args, &option))
 | 
								if (nfs_get_option_ul(args, &option))
 | 
				
			||||||
				goto out_invalid_value;
 | 
									goto out_invalid_value;
 | 
				
			||||||
| 
						 | 
					@ -1326,6 +1377,15 @@ static int nfs_parse_mount_options(char *raw,
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * options that take text values
 | 
							 * options that take text values
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
 | 
							case Opt_nfsvers:
 | 
				
			||||||
 | 
								string = match_strdup(args);
 | 
				
			||||||
 | 
								if (string == NULL)
 | 
				
			||||||
 | 
									goto out_nomem;
 | 
				
			||||||
 | 
								rc = nfs_parse_version_string(string, mnt, args);
 | 
				
			||||||
 | 
								kfree(string);
 | 
				
			||||||
 | 
								if (!rc)
 | 
				
			||||||
 | 
									goto out_invalid_value;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case Opt_sec:
 | 
							case Opt_sec:
 | 
				
			||||||
			string = match_strdup(args);
 | 
								string = match_strdup(args);
 | 
				
			||||||
			if (string == NULL)
 | 
								if (string == NULL)
 | 
				
			||||||
| 
						 | 
					@ -1405,7 +1465,7 @@ static int nfs_parse_mount_options(char *raw,
 | 
				
			||||||
			if (string == NULL)
 | 
								if (string == NULL)
 | 
				
			||||||
				goto out_nomem;
 | 
									goto out_nomem;
 | 
				
			||||||
			mnt->nfs_server.addrlen =
 | 
								mnt->nfs_server.addrlen =
 | 
				
			||||||
				rpc_pton(string, strlen(string),
 | 
									rpc_pton(mnt->net, string, strlen(string),
 | 
				
			||||||
					(struct sockaddr *)
 | 
										(struct sockaddr *)
 | 
				
			||||||
					&mnt->nfs_server.address,
 | 
										&mnt->nfs_server.address,
 | 
				
			||||||
					sizeof(mnt->nfs_server.address));
 | 
										sizeof(mnt->nfs_server.address));
 | 
				
			||||||
| 
						 | 
					@ -1427,7 +1487,7 @@ static int nfs_parse_mount_options(char *raw,
 | 
				
			||||||
			if (string == NULL)
 | 
								if (string == NULL)
 | 
				
			||||||
				goto out_nomem;
 | 
									goto out_nomem;
 | 
				
			||||||
			mnt->mount_server.addrlen =
 | 
								mnt->mount_server.addrlen =
 | 
				
			||||||
				rpc_pton(string, strlen(string),
 | 
									rpc_pton(mnt->net, string, strlen(string),
 | 
				
			||||||
					(struct sockaddr *)
 | 
										(struct sockaddr *)
 | 
				
			||||||
					&mnt->mount_server.address,
 | 
										&mnt->mount_server.address,
 | 
				
			||||||
					sizeof(mnt->mount_server.address));
 | 
										sizeof(mnt->mount_server.address));
 | 
				
			||||||
| 
						 | 
					@ -1516,6 +1576,9 @@ static int nfs_parse_mount_options(char *raw,
 | 
				
			||||||
	if (!sloppy && invalid_option)
 | 
						if (!sloppy && invalid_option)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mnt->minorversion && mnt->version != 4)
 | 
				
			||||||
 | 
							goto out_minorversion_mismatch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * verify that any proto=/mountproto= options match the address
 | 
						 * verify that any proto=/mountproto= options match the address
 | 
				
			||||||
	 * familiies in the addr=/mountaddr= options.
 | 
						 * familiies in the addr=/mountaddr= options.
 | 
				
			||||||
| 
						 | 
					@ -1549,6 +1612,10 @@ out_invalid_address:
 | 
				
			||||||
out_invalid_value:
 | 
					out_invalid_value:
 | 
				
			||||||
	printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
 | 
						printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					out_minorversion_mismatch:
 | 
				
			||||||
 | 
						printk(KERN_INFO "NFS: mount option vers=%u does not support "
 | 
				
			||||||
 | 
								 "minorversion=%u\n", mnt->version, mnt->minorversion);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
out_nomem:
 | 
					out_nomem:
 | 
				
			||||||
	printk(KERN_INFO "NFS: not enough memory to parse option\n");
 | 
						printk(KERN_INFO "NFS: not enough memory to parse option\n");
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -1622,6 +1689,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
 | 
				
			||||||
		.noresvport	= args->flags & NFS_MOUNT_NORESVPORT,
 | 
							.noresvport	= args->flags & NFS_MOUNT_NORESVPORT,
 | 
				
			||||||
		.auth_flav_len	= &server_authlist_len,
 | 
							.auth_flav_len	= &server_authlist_len,
 | 
				
			||||||
		.auth_flavs	= server_authlist,
 | 
							.auth_flavs	= server_authlist,
 | 
				
			||||||
 | 
							.net		= args->net,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	int status;
 | 
						int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2047,7 +2115,7 @@ static inline void nfs_initialise_sb(struct super_block *sb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We probably want something more informative here */
 | 
						/* We probably want something more informative here */
 | 
				
			||||||
	snprintf(sb->s_id, sizeof(sb->s_id),
 | 
						snprintf(sb->s_id, sizeof(sb->s_id),
 | 
				
			||||||
		 "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
 | 
							 "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sb->s_blocksize == 0)
 | 
						if (sb->s_blocksize == 0)
 | 
				
			||||||
		sb->s_blocksize = nfs_block_bits(server->wsize,
 | 
							sb->s_blocksize = nfs_block_bits(server->wsize,
 | 
				
			||||||
| 
						 | 
					@ -2499,12 +2567,6 @@ static int nfs4_validate_text_mount_data(void *options,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (args->client_address == NULL) {
 | 
					 | 
				
			||||||
		dfprintk(MOUNT,
 | 
					 | 
				
			||||||
			 "NFS4: mount program didn't pass callback address\n");
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nfs_parse_devname(dev_name,
 | 
						return nfs_parse_devname(dev_name,
 | 
				
			||||||
				   &args->nfs_server.hostname,
 | 
									   &args->nfs_server.hostname,
 | 
				
			||||||
				   NFS4_MAXNAMLEN,
 | 
									   NFS4_MAXNAMLEN,
 | 
				
			||||||
| 
						 | 
					@ -2663,8 +2725,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
 | 
				
			||||||
	if (!s->s_root) {
 | 
						if (!s->s_root) {
 | 
				
			||||||
		/* initial superblock/root creation */
 | 
							/* initial superblock/root creation */
 | 
				
			||||||
		nfs4_fill_super(s);
 | 
							nfs4_fill_super(s);
 | 
				
			||||||
		nfs_fscache_get_super_cookie(
 | 
							nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL);
 | 
				
			||||||
			s, data ? data->fscache_uniq : NULL, NULL);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mntroot = nfs4_get_root(s, mntfh, dev_name);
 | 
						mntroot = nfs4_get_root(s, mntfh, dev_name);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,6 @@ static ctl_table nfs_cb_sysctls[] = {
 | 
				
			||||||
		.extra1 = (int *)&nfs_set_port_min,
 | 
							.extra1 = (int *)&nfs_set_port_min,
 | 
				
			||||||
		.extra2 = (int *)&nfs_set_port_max,
 | 
							.extra2 = (int *)&nfs_set_port_max,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
#ifndef CONFIG_NFS_USE_NEW_IDMAPPER
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.procname = "idmap_cache_timeout",
 | 
							.procname = "idmap_cache_timeout",
 | 
				
			||||||
		.data = &nfs_idmap_cache_timeout,
 | 
							.data = &nfs_idmap_cache_timeout,
 | 
				
			||||||
| 
						 | 
					@ -40,7 +39,6 @@ static ctl_table nfs_cb_sysctls[] = {
 | 
				
			||||||
		.mode = 0644,
 | 
							.mode = 0644,
 | 
				
			||||||
		.proc_handler = proc_dointvec_jiffies,
 | 
							.proc_handler = proc_dointvec_jiffies,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.procname	= "nfs_mountpoint_timeout",
 | 
							.procname	= "nfs_mountpoint_timeout",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,15 +20,6 @@
 | 
				
			||||||
#include "iostat.h"
 | 
					#include "iostat.h"
 | 
				
			||||||
#include "delegation.h"
 | 
					#include "delegation.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs_unlinkdata {
 | 
					 | 
				
			||||||
	struct hlist_node list;
 | 
					 | 
				
			||||||
	struct nfs_removeargs args;
 | 
					 | 
				
			||||||
	struct nfs_removeres res;
 | 
					 | 
				
			||||||
	struct inode *dir;
 | 
					 | 
				
			||||||
	struct rpc_cred	*cred;
 | 
					 | 
				
			||||||
	struct nfs_fattr dir_attr;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * nfs_free_unlinkdata - release data from a sillydelete operation.
 | 
					 * nfs_free_unlinkdata - release data from a sillydelete operation.
 | 
				
			||||||
 * @data: pointer to unlink structure.
 | 
					 * @data: pointer to unlink structure.
 | 
				
			||||||
| 
						 | 
					@ -107,25 +98,16 @@ static void nfs_async_unlink_release(void *calldata)
 | 
				
			||||||
	nfs_sb_deactive(sb);
 | 
						nfs_sb_deactive(sb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					static void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
 | 
				
			||||||
void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_unlinkdata *data = calldata;
 | 
						struct nfs_unlinkdata *data = calldata;
 | 
				
			||||||
	struct nfs_server *server = NFS_SERVER(data->dir);
 | 
						NFS_PROTO(data->dir)->unlink_rpc_prepare(task, data);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (nfs4_setup_sequence(server, &data->args.seq_args,
 | 
					 | 
				
			||||||
				&data->res.seq_res, 1, task))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	rpc_call_start(task);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_unlink_ops = {
 | 
					static const struct rpc_call_ops nfs_unlink_ops = {
 | 
				
			||||||
	.rpc_call_done = nfs_async_unlink_done,
 | 
						.rpc_call_done = nfs_async_unlink_done,
 | 
				
			||||||
	.rpc_release = nfs_async_unlink_release,
 | 
						.rpc_release = nfs_async_unlink_release,
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_unlink_prepare,
 | 
						.rpc_call_prepare = nfs_unlink_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data)
 | 
					static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data)
 | 
				
			||||||
| 
						 | 
					@ -341,18 +323,6 @@ nfs_cancel_async_unlink(struct dentry *dentry)
 | 
				
			||||||
	spin_unlock(&dentry->d_lock);
 | 
						spin_unlock(&dentry->d_lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs_renamedata {
 | 
					 | 
				
			||||||
	struct nfs_renameargs	args;
 | 
					 | 
				
			||||||
	struct nfs_renameres	res;
 | 
					 | 
				
			||||||
	struct rpc_cred		*cred;
 | 
					 | 
				
			||||||
	struct inode		*old_dir;
 | 
					 | 
				
			||||||
	struct dentry		*old_dentry;
 | 
					 | 
				
			||||||
	struct nfs_fattr	old_fattr;
 | 
					 | 
				
			||||||
	struct inode		*new_dir;
 | 
					 | 
				
			||||||
	struct dentry		*new_dentry;
 | 
					 | 
				
			||||||
	struct nfs_fattr	new_fattr;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * nfs_async_rename_done - Sillyrename post-processing
 | 
					 * nfs_async_rename_done - Sillyrename post-processing
 | 
				
			||||||
 * @task: rpc_task of the sillyrename
 | 
					 * @task: rpc_task of the sillyrename
 | 
				
			||||||
| 
						 | 
					@ -403,25 +373,16 @@ static void nfs_async_rename_release(void *calldata)
 | 
				
			||||||
	kfree(data);
 | 
						kfree(data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
static void nfs_rename_prepare(struct rpc_task *task, void *calldata)
 | 
					static void nfs_rename_prepare(struct rpc_task *task, void *calldata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_renamedata *data = calldata;
 | 
						struct nfs_renamedata *data = calldata;
 | 
				
			||||||
	struct nfs_server *server = NFS_SERVER(data->old_dir);
 | 
						NFS_PROTO(data->old_dir)->rename_rpc_prepare(task, data);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (nfs4_setup_sequence(server, &data->args.seq_args,
 | 
					 | 
				
			||||||
				&data->res.seq_res, 1, task))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	rpc_call_start(task);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_rename_ops = {
 | 
					static const struct rpc_call_ops nfs_rename_ops = {
 | 
				
			||||||
	.rpc_call_done = nfs_async_rename_done,
 | 
						.rpc_call_done = nfs_async_rename_done,
 | 
				
			||||||
	.rpc_release = nfs_async_rename_release,
 | 
						.rpc_release = nfs_async_rename_release,
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_rename_prepare,
 | 
						.rpc_call_prepare = nfs_rename_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										215
									
								
								fs/nfs/write.c
									
										
									
									
									
								
							
							
						
						
									
										215
									
								
								fs/nfs/write.c
									
										
									
									
									
								
							| 
						 | 
					@ -100,7 +100,6 @@ void nfs_writedata_free(struct nfs_write_data *p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfs_writedata_release(struct nfs_write_data *wdata)
 | 
					void nfs_writedata_release(struct nfs_write_data *wdata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	put_lseg(wdata->lseg);
 | 
					 | 
				
			||||||
	put_nfs_open_context(wdata->args.context);
 | 
						put_nfs_open_context(wdata->args.context);
 | 
				
			||||||
	nfs_writedata_free(wdata);
 | 
						nfs_writedata_free(wdata);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -236,10 +235,10 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblo
 | 
				
			||||||
		req = nfs_page_find_request_locked(page);
 | 
							req = nfs_page_find_request_locked(page);
 | 
				
			||||||
		if (req == NULL)
 | 
							if (req == NULL)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		if (nfs_set_page_tag_locked(req))
 | 
							if (nfs_lock_request_dontget(req))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		/* Note: If we hold the page lock, as is the case in nfs_writepage,
 | 
							/* Note: If we hold the page lock, as is the case in nfs_writepage,
 | 
				
			||||||
		 *	 then the call to nfs_set_page_tag_locked() will always
 | 
							 *	 then the call to nfs_lock_request_dontget() will always
 | 
				
			||||||
		 *	 succeed provided that someone hasn't already marked the
 | 
							 *	 succeed provided that someone hasn't already marked the
 | 
				
			||||||
		 *	 request as dirty (in which case we don't care).
 | 
							 *	 request as dirty (in which case we don't care).
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
| 
						 | 
					@ -375,21 +374,14 @@ out_err:
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Insert a write request into an inode
 | 
					 * Insert a write request into an inode
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
 | 
					static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_inode *nfsi = NFS_I(inode);
 | 
						struct nfs_inode *nfsi = NFS_I(inode);
 | 
				
			||||||
	int error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	error = radix_tree_preload(GFP_NOFS);
 | 
					 | 
				
			||||||
	if (error != 0)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Lock the request! */
 | 
						/* Lock the request! */
 | 
				
			||||||
	nfs_lock_request_dontget(req);
 | 
						nfs_lock_request_dontget(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&inode->i_lock);
 | 
						spin_lock(&inode->i_lock);
 | 
				
			||||||
	error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
 | 
					 | 
				
			||||||
	BUG_ON(error);
 | 
					 | 
				
			||||||
	if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
 | 
						if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
 | 
				
			||||||
		inode->i_version++;
 | 
							inode->i_version++;
 | 
				
			||||||
	set_bit(PG_MAPPED, &req->wb_flags);
 | 
						set_bit(PG_MAPPED, &req->wb_flags);
 | 
				
			||||||
| 
						 | 
					@ -397,12 +389,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
 | 
				
			||||||
	set_page_private(req->wb_page, (unsigned long)req);
 | 
						set_page_private(req->wb_page, (unsigned long)req);
 | 
				
			||||||
	nfsi->npages++;
 | 
						nfsi->npages++;
 | 
				
			||||||
	kref_get(&req->wb_kref);
 | 
						kref_get(&req->wb_kref);
 | 
				
			||||||
	radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
 | 
					 | 
				
			||||||
				NFS_PAGE_TAG_LOCKED);
 | 
					 | 
				
			||||||
	spin_unlock(&inode->i_lock);
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
	radix_tree_preload_end();
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	return error;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -419,7 +406,6 @@ static void nfs_inode_remove_request(struct nfs_page *req)
 | 
				
			||||||
	set_page_private(req->wb_page, 0);
 | 
						set_page_private(req->wb_page, 0);
 | 
				
			||||||
	ClearPagePrivate(req->wb_page);
 | 
						ClearPagePrivate(req->wb_page);
 | 
				
			||||||
	clear_bit(PG_MAPPED, &req->wb_flags);
 | 
						clear_bit(PG_MAPPED, &req->wb_flags);
 | 
				
			||||||
	radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
 | 
					 | 
				
			||||||
	nfsi->npages--;
 | 
						nfsi->npages--;
 | 
				
			||||||
	spin_unlock(&inode->i_lock);
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
	nfs_release_request(req);
 | 
						nfs_release_request(req);
 | 
				
			||||||
| 
						 | 
					@ -432,6 +418,57 @@ nfs_mark_request_dirty(struct nfs_page *req)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 | 
					#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * nfs_request_add_commit_list - add request to a commit list
 | 
				
			||||||
 | 
					 * @req: pointer to a struct nfs_page
 | 
				
			||||||
 | 
					 * @head: commit list head
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This sets the PG_CLEAN bit, updates the inode global count of
 | 
				
			||||||
 | 
					 * number of outstanding requests requiring a commit as well as
 | 
				
			||||||
 | 
					 * the MM page stats.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The caller must _not_ hold the inode->i_lock, but must be
 | 
				
			||||||
 | 
					 * holding the nfs_page lock.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct inode *inode = req->wb_context->dentry->d_inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set_bit(PG_CLEAN, &(req)->wb_flags);
 | 
				
			||||||
 | 
						spin_lock(&inode->i_lock);
 | 
				
			||||||
 | 
						nfs_list_add_request(req, head);
 | 
				
			||||||
 | 
						NFS_I(inode)->ncommit++;
 | 
				
			||||||
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
 | 
						inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
 | 
				
			||||||
 | 
						inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
 | 
				
			||||||
 | 
						__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(nfs_request_add_commit_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * nfs_request_remove_commit_list - Remove request from a commit list
 | 
				
			||||||
 | 
					 * @req: pointer to a nfs_page
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This clears the PG_CLEAN bit, and updates the inode global count of
 | 
				
			||||||
 | 
					 * number of outstanding requests requiring a commit
 | 
				
			||||||
 | 
					 * It does not update the MM page stats.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The caller _must_ hold the inode->i_lock and the nfs_page lock.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					nfs_request_remove_commit_list(struct nfs_page *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct inode *inode = req->wb_context->dentry->d_inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						nfs_list_remove_request(req);
 | 
				
			||||||
 | 
						NFS_I(inode)->ncommit--;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Add a request to the inode's commit list.
 | 
					 * Add a request to the inode's commit list.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -439,32 +476,32 @@ static void
 | 
				
			||||||
nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 | 
					nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct inode *inode = req->wb_context->dentry->d_inode;
 | 
						struct inode *inode = req->wb_context->dentry->d_inode;
 | 
				
			||||||
	struct nfs_inode *nfsi = NFS_I(inode);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&inode->i_lock);
 | 
						if (pnfs_mark_request_commit(req, lseg))
 | 
				
			||||||
	set_bit(PG_CLEAN, &(req)->wb_flags);
 | 
							return;
 | 
				
			||||||
	radix_tree_tag_set(&nfsi->nfs_page_tree,
 | 
						nfs_request_add_commit_list(req, &NFS_I(inode)->commit_list);
 | 
				
			||||||
			req->wb_index,
 | 
					 | 
				
			||||||
			NFS_PAGE_TAG_COMMIT);
 | 
					 | 
				
			||||||
	nfsi->ncommit++;
 | 
					 | 
				
			||||||
	spin_unlock(&inode->i_lock);
 | 
					 | 
				
			||||||
	pnfs_mark_request_commit(req, lseg);
 | 
					 | 
				
			||||||
	inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
 | 
					 | 
				
			||||||
	inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
 | 
					 | 
				
			||||||
	__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static void
 | 
				
			||||||
nfs_clear_request_commit(struct nfs_page *req)
 | 
					nfs_clear_page_commit(struct page *page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct page *page = req->wb_page;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) {
 | 
					 | 
				
			||||||
	dec_zone_page_state(page, NR_UNSTABLE_NFS);
 | 
						dec_zone_page_state(page, NR_UNSTABLE_NFS);
 | 
				
			||||||
	dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
 | 
						dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
	return 0;
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					nfs_clear_request_commit(struct nfs_page *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (test_bit(PG_CLEAN, &req->wb_flags)) {
 | 
				
			||||||
 | 
							struct inode *inode = req->wb_context->dentry->d_inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!pnfs_clear_request_commit(req)) {
 | 
				
			||||||
 | 
								spin_lock(&inode->i_lock);
 | 
				
			||||||
 | 
								nfs_request_remove_commit_list(req);
 | 
				
			||||||
 | 
								spin_unlock(&inode->i_lock);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							nfs_clear_page_commit(req->wb_page);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline
 | 
					static inline
 | 
				
			||||||
| 
						 | 
					@ -491,15 +528,14 @@ int nfs_reschedule_unstable_write(struct nfs_page *req,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static inline void
 | 
					static void
 | 
				
			||||||
nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 | 
					nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int
 | 
					static void
 | 
				
			||||||
nfs_clear_request_commit(struct nfs_page *req)
 | 
					nfs_clear_request_commit(struct nfs_page *req)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline
 | 
					static inline
 | 
				
			||||||
| 
						 | 
					@ -520,46 +556,65 @@ int nfs_reschedule_unstable_write(struct nfs_page *req,
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
nfs_need_commit(struct nfs_inode *nfsi)
 | 
					nfs_need_commit(struct nfs_inode *nfsi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT);
 | 
						return nfsi->ncommit > 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* i_lock held by caller */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max,
 | 
				
			||||||
 | 
							spinlock_t *lock)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfs_page *req, *tmp;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry_safe(req, tmp, src, wb_list) {
 | 
				
			||||||
 | 
							if (!nfs_lock_request(req))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (cond_resched_lock(lock))
 | 
				
			||||||
 | 
								list_safe_reset_next(req, tmp, wb_list);
 | 
				
			||||||
 | 
							nfs_request_remove_commit_list(req);
 | 
				
			||||||
 | 
							nfs_list_add_request(req, dst);
 | 
				
			||||||
 | 
							ret++;
 | 
				
			||||||
 | 
							if (ret == max)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * nfs_scan_commit - Scan an inode for commit requests
 | 
					 * nfs_scan_commit - Scan an inode for commit requests
 | 
				
			||||||
 * @inode: NFS inode to scan
 | 
					 * @inode: NFS inode to scan
 | 
				
			||||||
 * @dst: destination list
 | 
					 * @dst: destination list
 | 
				
			||||||
 * @idx_start: lower bound of page->index to scan.
 | 
					 | 
				
			||||||
 * @npages: idx_start + npages sets the upper bound to scan.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Moves requests from the inode's 'commit' request list.
 | 
					 * Moves requests from the inode's 'commit' request list.
 | 
				
			||||||
 * The requests are *not* checked to ensure that they form a contiguous set.
 | 
					 * The requests are *not* checked to ensure that they form a contiguous set.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 | 
					nfs_scan_commit(struct inode *inode, struct list_head *dst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_inode *nfsi = NFS_I(inode);
 | 
						struct nfs_inode *nfsi = NFS_I(inode);
 | 
				
			||||||
	int ret;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!nfs_need_commit(nfsi))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&inode->i_lock);
 | 
						spin_lock(&inode->i_lock);
 | 
				
			||||||
	ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT);
 | 
						if (nfsi->ncommit > 0) {
 | 
				
			||||||
	if (ret > 0)
 | 
							const int max = INT_MAX;
 | 
				
			||||||
		nfsi->ncommit -= ret;
 | 
					
 | 
				
			||||||
 | 
							ret = nfs_scan_commit_list(&nfsi->commit_list, dst, max,
 | 
				
			||||||
 | 
									&inode->i_lock);
 | 
				
			||||||
 | 
							ret += pnfs_scan_commit_lists(inode, max - ret,
 | 
				
			||||||
 | 
									&inode->i_lock);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	spin_unlock(&inode->i_lock);
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (nfs_need_commit(NFS_I(inode)))
 | 
					 | 
				
			||||||
		__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static inline int nfs_need_commit(struct nfs_inode *nfsi)
 | 
					static inline int nfs_need_commit(struct nfs_inode *nfsi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 | 
					static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -604,7 +659,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
 | 
				
			||||||
		    || end < req->wb_offset)
 | 
							    || end < req->wb_offset)
 | 
				
			||||||
			goto out_flushme;
 | 
								goto out_flushme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (nfs_set_page_tag_locked(req))
 | 
							if (nfs_lock_request_dontget(req))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* The request is locked, so wait and then retry */
 | 
							/* The request is locked, so wait and then retry */
 | 
				
			||||||
| 
						 | 
					@ -616,13 +671,6 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
 | 
				
			||||||
		spin_lock(&inode->i_lock);
 | 
							spin_lock(&inode->i_lock);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nfs_clear_request_commit(req) &&
 | 
					 | 
				
			||||||
	    radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
 | 
					 | 
				
			||||||
				 req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) {
 | 
					 | 
				
			||||||
		NFS_I(inode)->ncommit--;
 | 
					 | 
				
			||||||
		pnfs_clear_request_commit(req);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Okay, the request matches. Update the region */
 | 
						/* Okay, the request matches. Update the region */
 | 
				
			||||||
	if (offset < req->wb_offset) {
 | 
						if (offset < req->wb_offset) {
 | 
				
			||||||
		req->wb_offset = offset;
 | 
							req->wb_offset = offset;
 | 
				
			||||||
| 
						 | 
					@ -634,6 +682,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
 | 
				
			||||||
		req->wb_bytes = rqend - req->wb_offset;
 | 
							req->wb_bytes = rqend - req->wb_offset;
 | 
				
			||||||
out_unlock:
 | 
					out_unlock:
 | 
				
			||||||
	spin_unlock(&inode->i_lock);
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
 | 
						nfs_clear_request_commit(req);
 | 
				
			||||||
	return req;
 | 
						return req;
 | 
				
			||||||
out_flushme:
 | 
					out_flushme:
 | 
				
			||||||
	spin_unlock(&inode->i_lock);
 | 
						spin_unlock(&inode->i_lock);
 | 
				
			||||||
| 
						 | 
					@ -655,7 +704,6 @@ static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct inode *inode = page->mapping->host;
 | 
						struct inode *inode = page->mapping->host;
 | 
				
			||||||
	struct nfs_page	*req;
 | 
						struct nfs_page	*req;
 | 
				
			||||||
	int error;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req = nfs_try_to_update_request(inode, page, offset, bytes);
 | 
						req = nfs_try_to_update_request(inode, page, offset, bytes);
 | 
				
			||||||
	if (req != NULL)
 | 
						if (req != NULL)
 | 
				
			||||||
| 
						 | 
					@ -663,11 +711,7 @@ static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
 | 
				
			||||||
	req = nfs_create_request(ctx, inode, page, offset, bytes);
 | 
						req = nfs_create_request(ctx, inode, page, offset, bytes);
 | 
				
			||||||
	if (IS_ERR(req))
 | 
						if (IS_ERR(req))
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	error = nfs_inode_add_request(inode, req);
 | 
						nfs_inode_add_request(inode, req);
 | 
				
			||||||
	if (error != 0) {
 | 
					 | 
				
			||||||
		nfs_release_request(req);
 | 
					 | 
				
			||||||
		req = ERR_PTR(error);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return req;
 | 
						return req;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -684,7 +728,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
 | 
				
			||||||
	nfs_grow_file(page, offset, count);
 | 
						nfs_grow_file(page, offset, count);
 | 
				
			||||||
	nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
 | 
						nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
 | 
				
			||||||
	nfs_mark_request_dirty(req);
 | 
						nfs_mark_request_dirty(req);
 | 
				
			||||||
	nfs_clear_page_tag_locked(req);
 | 
						nfs_unlock_request(req);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -777,7 +821,7 @@ static void nfs_writepage_release(struct nfs_page *req,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data))
 | 
						if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data))
 | 
				
			||||||
		nfs_inode_remove_request(req);
 | 
							nfs_inode_remove_request(req);
 | 
				
			||||||
	nfs_clear_page_tag_locked(req);
 | 
						nfs_unlock_request(req);
 | 
				
			||||||
	nfs_end_page_writeback(page);
 | 
						nfs_end_page_writeback(page);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -925,7 +969,7 @@ static void nfs_redirty_request(struct nfs_page *req)
 | 
				
			||||||
	struct page *page = req->wb_page;
 | 
						struct page *page = req->wb_page;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nfs_mark_request_dirty(req);
 | 
						nfs_mark_request_dirty(req);
 | 
				
			||||||
	nfs_clear_page_tag_locked(req);
 | 
						nfs_unlock_request(req);
 | 
				
			||||||
	nfs_end_page_writeback(page);
 | 
						nfs_end_page_writeback(page);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1128,23 +1172,14 @@ out:
 | 
				
			||||||
	nfs_writedata_release(calldata);
 | 
						nfs_writedata_release(calldata);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
void nfs_write_prepare(struct rpc_task *task, void *calldata)
 | 
					void nfs_write_prepare(struct rpc_task *task, void *calldata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_write_data *data = calldata;
 | 
						struct nfs_write_data *data = calldata;
 | 
				
			||||||
 | 
						NFS_PROTO(data->inode)->write_rpc_prepare(task, data);
 | 
				
			||||||
	if (nfs4_setup_sequence(NFS_SERVER(data->inode),
 | 
					 | 
				
			||||||
				&data->args.seq_args,
 | 
					 | 
				
			||||||
				&data->res.seq_res, 1, task))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	rpc_call_start(task);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_write_partial_ops = {
 | 
					static const struct rpc_call_ops nfs_write_partial_ops = {
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_write_prepare,
 | 
						.rpc_call_prepare = nfs_write_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
	.rpc_call_done = nfs_writeback_done_partial,
 | 
						.rpc_call_done = nfs_writeback_done_partial,
 | 
				
			||||||
	.rpc_release = nfs_writeback_release_partial,
 | 
						.rpc_release = nfs_writeback_release_partial,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1199,16 +1234,14 @@ static void nfs_writeback_release_full(void *calldata)
 | 
				
			||||||
remove_request:
 | 
					remove_request:
 | 
				
			||||||
		nfs_inode_remove_request(req);
 | 
							nfs_inode_remove_request(req);
 | 
				
			||||||
	next:
 | 
						next:
 | 
				
			||||||
		nfs_clear_page_tag_locked(req);
 | 
							nfs_unlock_request(req);
 | 
				
			||||||
		nfs_end_page_writeback(page);
 | 
							nfs_end_page_writeback(page);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	nfs_writedata_release(calldata);
 | 
						nfs_writedata_release(calldata);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_write_full_ops = {
 | 
					static const struct rpc_call_ops nfs_write_full_ops = {
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_write_prepare,
 | 
						.rpc_call_prepare = nfs_write_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
	.rpc_call_done = nfs_writeback_done_full,
 | 
						.rpc_call_done = nfs_writeback_done_full,
 | 
				
			||||||
	.rpc_release = nfs_writeback_release_full,
 | 
						.rpc_release = nfs_writeback_release_full,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1325,7 +1358,6 @@ void nfs_commitdata_release(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct nfs_write_data *wdata = data;
 | 
						struct nfs_write_data *wdata = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	put_lseg(wdata->lseg);
 | 
					 | 
				
			||||||
	put_nfs_open_context(wdata->args.context);
 | 
						put_nfs_open_context(wdata->args.context);
 | 
				
			||||||
	nfs_commit_free(wdata);
 | 
						nfs_commit_free(wdata);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1411,7 +1443,7 @@ void nfs_retry_commit(struct list_head *page_list,
 | 
				
			||||||
		dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
 | 
							dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
 | 
				
			||||||
		dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
 | 
							dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
 | 
				
			||||||
			     BDI_RECLAIMABLE);
 | 
								     BDI_RECLAIMABLE);
 | 
				
			||||||
		nfs_clear_page_tag_locked(req);
 | 
							nfs_unlock_request(req);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(nfs_retry_commit);
 | 
					EXPORT_SYMBOL_GPL(nfs_retry_commit);
 | 
				
			||||||
| 
						 | 
					@ -1460,7 +1492,7 @@ void nfs_commit_release_pages(struct nfs_write_data *data)
 | 
				
			||||||
	while (!list_empty(&data->pages)) {
 | 
						while (!list_empty(&data->pages)) {
 | 
				
			||||||
		req = nfs_list_entry(data->pages.next);
 | 
							req = nfs_list_entry(data->pages.next);
 | 
				
			||||||
		nfs_list_remove_request(req);
 | 
							nfs_list_remove_request(req);
 | 
				
			||||||
		nfs_clear_request_commit(req);
 | 
							nfs_clear_page_commit(req->wb_page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dprintk("NFS:       commit (%s/%lld %d@%lld)",
 | 
							dprintk("NFS:       commit (%s/%lld %d@%lld)",
 | 
				
			||||||
			req->wb_context->dentry->d_sb->s_id,
 | 
								req->wb_context->dentry->d_sb->s_id,
 | 
				
			||||||
| 
						 | 
					@ -1486,7 +1518,7 @@ void nfs_commit_release_pages(struct nfs_write_data *data)
 | 
				
			||||||
		dprintk(" mismatch\n");
 | 
							dprintk(" mismatch\n");
 | 
				
			||||||
		nfs_mark_request_dirty(req);
 | 
							nfs_mark_request_dirty(req);
 | 
				
			||||||
	next:
 | 
						next:
 | 
				
			||||||
		nfs_clear_page_tag_locked(req);
 | 
							nfs_unlock_request(req);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(nfs_commit_release_pages);
 | 
					EXPORT_SYMBOL_GPL(nfs_commit_release_pages);
 | 
				
			||||||
| 
						 | 
					@ -1501,9 +1533,7 @@ static void nfs_commit_release(void *calldata)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rpc_call_ops nfs_commit_ops = {
 | 
					static const struct rpc_call_ops nfs_commit_ops = {
 | 
				
			||||||
#if defined(CONFIG_NFS_V4_1)
 | 
					 | 
				
			||||||
	.rpc_call_prepare = nfs_write_prepare,
 | 
						.rpc_call_prepare = nfs_write_prepare,
 | 
				
			||||||
#endif /* CONFIG_NFS_V4_1 */
 | 
					 | 
				
			||||||
	.rpc_call_done = nfs_commit_done,
 | 
						.rpc_call_done = nfs_commit_done,
 | 
				
			||||||
	.rpc_release = nfs_commit_release,
 | 
						.rpc_release = nfs_commit_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1517,7 +1547,7 @@ int nfs_commit_inode(struct inode *inode, int how)
 | 
				
			||||||
	res = nfs_commit_set_lock(NFS_I(inode), may_wait);
 | 
						res = nfs_commit_set_lock(NFS_I(inode), may_wait);
 | 
				
			||||||
	if (res <= 0)
 | 
						if (res <= 0)
 | 
				
			||||||
		goto out_mark_dirty;
 | 
							goto out_mark_dirty;
 | 
				
			||||||
	res = nfs_scan_commit(inode, &head, 0, 0);
 | 
						res = nfs_scan_commit(inode, &head);
 | 
				
			||||||
	if (res) {
 | 
						if (res) {
 | 
				
			||||||
		int error;
 | 
							int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1635,6 +1665,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
 | 
				
			||||||
		if (req == NULL)
 | 
							if (req == NULL)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		if (nfs_lock_request_dontget(req)) {
 | 
							if (nfs_lock_request_dontget(req)) {
 | 
				
			||||||
 | 
								nfs_clear_request_commit(req);
 | 
				
			||||||
			nfs_inode_remove_request(req);
 | 
								nfs_inode_remove_request(req);
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * In case nfs_inode_remove_request has marked the
 | 
								 * In case nfs_inode_remove_request has marked the
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -605,24 +605,24 @@ static struct rpc_version nfs_cb_version4 = {
 | 
				
			||||||
	.procs			= nfs4_cb_procedures
 | 
						.procs			= nfs4_cb_procedures
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_version *nfs_cb_version[] = {
 | 
					static const struct rpc_version *nfs_cb_version[] = {
 | 
				
			||||||
	&nfs_cb_version4,
 | 
						&nfs_cb_version4,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_program cb_program;
 | 
					static const struct rpc_program cb_program;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct rpc_stat cb_stats = {
 | 
					static struct rpc_stat cb_stats = {
 | 
				
			||||||
	.program		= &cb_program
 | 
						.program		= &cb_program
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFS4_CALLBACK 0x40000000
 | 
					#define NFS4_CALLBACK 0x40000000
 | 
				
			||||||
static struct rpc_program cb_program = {
 | 
					static const struct rpc_program cb_program = {
 | 
				
			||||||
	.name			= "nfs4_cb",
 | 
						.name			= "nfs4_cb",
 | 
				
			||||||
	.number			= NFS4_CALLBACK,
 | 
						.number			= NFS4_CALLBACK,
 | 
				
			||||||
	.nrvers			= ARRAY_SIZE(nfs_cb_version),
 | 
						.nrvers			= ARRAY_SIZE(nfs_cb_version),
 | 
				
			||||||
	.version		= nfs_cb_version,
 | 
						.version		= nfs_cb_version,
 | 
				
			||||||
	.stats			= &cb_stats,
 | 
						.stats			= &cb_stats,
 | 
				
			||||||
	.pipe_dir_name		= "/nfsd4_cb",
 | 
						.pipe_dir_name		= "nfsd4_cb",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int max_cb_time(void)
 | 
					static int max_cb_time(void)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1308,7 +1308,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		goto out_err;
 | 
							goto out_err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
 | 
						conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val,
 | 
				
			||||||
					    se->se_callback_addr_len,
 | 
										    se->se_callback_addr_len,
 | 
				
			||||||
					    (struct sockaddr *)&conn->cb_addr,
 | 
										    (struct sockaddr *)&conn->cb_addr,
 | 
				
			||||||
					    sizeof(conn->cb_addr));
 | 
										    sizeof(conn->cb_addr));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,7 +223,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
 | 
				
			||||||
	if (qword_get(&buf, fo_path, size) < 0)
 | 
						if (qword_get(&buf, fo_path, size) < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rpc_pton(fo_path, size, sap, salen) == 0)
 | 
						if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nlmsvc_unlock_all_by_ip(sap);
 | 
						return nlmsvc_unlock_all_by_ip(sap);
 | 
				
			||||||
| 
						 | 
					@ -722,7 +722,7 @@ static ssize_t __write_ports_addxprt(char *buf)
 | 
				
			||||||
	nfsd_serv->sv_nrthreads--;
 | 
						nfsd_serv->sv_nrthreads--;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
out_close:
 | 
					out_close:
 | 
				
			||||||
	xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
 | 
						xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port);
 | 
				
			||||||
	if (xprt != NULL) {
 | 
						if (xprt != NULL) {
 | 
				
			||||||
		svc_close_xprt(xprt);
 | 
							svc_close_xprt(xprt);
 | 
				
			||||||
		svc_xprt_put(xprt);
 | 
							svc_xprt_put(xprt);
 | 
				
			||||||
| 
						 | 
					@ -748,7 +748,7 @@ static ssize_t __write_ports_delxprt(char *buf)
 | 
				
			||||||
	if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
 | 
						if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
 | 
						xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port);
 | 
				
			||||||
	if (xprt == NULL)
 | 
						if (xprt == NULL)
 | 
				
			||||||
		return -ENOTCONN;
 | 
							return -ENOTCONN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -251,13 +251,13 @@ static void nfsd_shutdown(void)
 | 
				
			||||||
	nfsd_up = false;
 | 
						nfsd_up = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nfsd_last_thread(struct svc_serv *serv)
 | 
					static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* When last nfsd thread exits we need to do some clean-up */
 | 
						/* When last nfsd thread exits we need to do some clean-up */
 | 
				
			||||||
	nfsd_serv = NULL;
 | 
						nfsd_serv = NULL;
 | 
				
			||||||
	nfsd_shutdown();
 | 
						nfsd_shutdown();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	svc_rpcb_cleanup(serv);
 | 
						svc_rpcb_cleanup(serv, net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printk(KERN_WARNING "nfsd: last server has exited, flushing export "
 | 
						printk(KERN_WARNING "nfsd: last server has exited, flushing export "
 | 
				
			||||||
			    "cache\n");
 | 
								    "cache\n");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/sunrpc/stats.h>
 | 
					#include <linux/sunrpc/stats.h>
 | 
				
			||||||
#include <linux/nfsd/stats.h>
 | 
					#include <linux/nfsd/stats.h>
 | 
				
			||||||
 | 
					#include <net/net_namespace.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "nfsd.h"
 | 
					#include "nfsd.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,11 +95,11 @@ static const struct file_operations nfsd_proc_fops = {
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
nfsd_stat_init(void)
 | 
					nfsd_stat_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	svc_proc_register(&nfsd_svcstats, &nfsd_proc_fops);
 | 
						svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
nfsd_stat_shutdown(void)
 | 
					nfsd_stat_shutdown(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	svc_proc_unregister("nfsd");
 | 
						svc_proc_unregister(&init_net, "nfsd");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -277,6 +277,8 @@ static inline key_serial_t key_serial(const struct key *key)
 | 
				
			||||||
	return key ? key->serial : 0;
 | 
						return key ? key->serial : 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void key_set_timeout(struct key *, unsigned);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * key_is_instantiated - Determine if a key has been positively instantiated
 | 
					 * key_is_instantiated - Determine if a key has been positively instantiated
 | 
				
			||||||
 * @key: The key to check.
 | 
					 * @key: The key to check.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,7 @@ struct nlmclnt_initdata {
 | 
				
			||||||
	unsigned short		protocol;
 | 
						unsigned short		protocol;
 | 
				
			||||||
	u32			nfs_version;
 | 
						u32			nfs_version;
 | 
				
			||||||
	int			noresvport;
 | 
						int			noresvport;
 | 
				
			||||||
 | 
						struct net		*net;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,6 +67,7 @@ struct nlm_host {
 | 
				
			||||||
	struct list_head	h_reclaim;	/* Locks in RECLAIM state */
 | 
						struct list_head	h_reclaim;	/* Locks in RECLAIM state */
 | 
				
			||||||
	struct nsm_handle	*h_nsmhandle;	/* NSM status handle */
 | 
						struct nsm_handle	*h_nsmhandle;	/* NSM status handle */
 | 
				
			||||||
	char			*h_addrbuf;	/* address eyecatcher */
 | 
						char			*h_addrbuf;	/* address eyecatcher */
 | 
				
			||||||
 | 
						struct net		*net;		/* host net */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -188,7 +189,7 @@ struct nlm_block {
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Global variables
 | 
					 * Global variables
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
extern struct rpc_program	nlm_program;
 | 
					extern const struct rpc_program	nlm_program;
 | 
				
			||||||
extern struct svc_procedure	nlmsvc_procedures[];
 | 
					extern struct svc_procedure	nlmsvc_procedures[];
 | 
				
			||||||
#ifdef CONFIG_LOCKD_V4
 | 
					#ifdef CONFIG_LOCKD_V4
 | 
				
			||||||
extern struct svc_procedure	nlmsvc_procedures4[];
 | 
					extern struct svc_procedure	nlmsvc_procedures4[];
 | 
				
			||||||
| 
						 | 
					@ -222,7 +223,8 @@ struct nlm_host  *nlmclnt_lookup_host(const struct sockaddr *sap,
 | 
				
			||||||
					const unsigned short protocol,
 | 
										const unsigned short protocol,
 | 
				
			||||||
					const u32 version,
 | 
										const u32 version,
 | 
				
			||||||
					const char *hostname,
 | 
										const char *hostname,
 | 
				
			||||||
					int noresvport);
 | 
										int noresvport,
 | 
				
			||||||
 | 
										struct net *net);
 | 
				
			||||||
void		  nlmclnt_release_host(struct nlm_host *);
 | 
					void		  nlmclnt_release_host(struct nlm_host *);
 | 
				
			||||||
struct nlm_host  *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 | 
					struct nlm_host  *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 | 
				
			||||||
					const char *hostname,
 | 
										const char *hostname,
 | 
				
			||||||
| 
						 | 
					@ -232,6 +234,7 @@ struct rpc_clnt * nlm_bind_host(struct nlm_host *);
 | 
				
			||||||
void		  nlm_rebind_host(struct nlm_host *);
 | 
					void		  nlm_rebind_host(struct nlm_host *);
 | 
				
			||||||
struct nlm_host * nlm_get_host(struct nlm_host *);
 | 
					struct nlm_host * nlm_get_host(struct nlm_host *);
 | 
				
			||||||
void		  nlm_shutdown_hosts(void);
 | 
					void		  nlm_shutdown_hosts(void);
 | 
				
			||||||
 | 
					void		  nlm_shutdown_hosts_net(struct net *net);
 | 
				
			||||||
void		  nlm_host_rebooted(const struct nlm_reboot *);
 | 
					void		  nlm_host_rebooted(const struct nlm_reboot *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,6 @@ int	nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 | 
				
			||||||
int	nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 | 
					int	nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 | 
				
			||||||
int	nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 | 
					int	nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
extern struct rpc_version nlm_version4;
 | 
					extern const struct rpc_version nlm_version4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* LOCKD_XDR4_H */
 | 
					#endif /* LOCKD_XDR4_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@
 | 
				
			||||||
#define NFS_MNT_VERSION		1
 | 
					#define NFS_MNT_VERSION		1
 | 
				
			||||||
#define NFS_MNT3_VERSION	3
 | 
					#define NFS_MNT3_VERSION	3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFS_PIPE_DIRNAME "/nfs"
 | 
					#define NFS_PIPE_DIRNAME "nfs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * NFS stats. The good thing with these values is that NFSv3 errors are
 | 
					 * NFS stats. The good thing with these values is that NFSv3 errors are
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,15 +183,12 @@ struct nfs4_acl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
 | 
					typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs41_stateid {
 | 
					struct nfs_stateid4 {
 | 
				
			||||||
	__be32 seqid;
 | 
						__be32 seqid;
 | 
				
			||||||
	char other[NFS4_STATEID_OTHER_SIZE];
 | 
						char other[NFS4_STATEID_OTHER_SIZE];
 | 
				
			||||||
} __attribute__ ((packed));
 | 
					} __attribute__ ((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef union {
 | 
					typedef struct nfs_stateid4 nfs4_stateid;
 | 
				
			||||||
	char data[NFS4_STATEID_SIZE];
 | 
					 | 
				
			||||||
	struct nfs41_stateid stateid;
 | 
					 | 
				
			||||||
} nfs4_stateid;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum nfs_opnum4 {
 | 
					enum nfs_opnum4 {
 | 
				
			||||||
	OP_ACCESS = 3,
 | 
						OP_ACCESS = 3,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __KERNEL__
 | 
					#ifdef __KERNEL__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Enable dprintk() debugging support for nfs client.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifdef CONFIG_NFS_DEBUG
 | 
				
			||||||
 | 
					# define NFS_DEBUG
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/in.h>
 | 
					#include <linux/in.h>
 | 
				
			||||||
#include <linux/mm.h>
 | 
					#include <linux/mm.h>
 | 
				
			||||||
#include <linux/pagemap.h>
 | 
					#include <linux/pagemap.h>
 | 
				
			||||||
| 
						 | 
					@ -171,13 +178,9 @@ struct nfs_inode {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	__be32			cookieverf[2];
 | 
						__be32			cookieverf[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * This is the list of dirty unwritten pages.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	struct radix_tree_root	nfs_page_tree;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	unsigned long		npages;
 | 
						unsigned long		npages;
 | 
				
			||||||
	unsigned long		ncommit;
 | 
						unsigned long		ncommit;
 | 
				
			||||||
 | 
						struct list_head	commit_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Open contexts for shared mmap writes */
 | 
						/* Open contexts for shared mmap writes */
 | 
				
			||||||
	struct list_head	open_files;
 | 
						struct list_head	open_files;
 | 
				
			||||||
| 
						 | 
					@ -395,6 +398,29 @@ static inline void nfs_free_fhandle(const struct nfs_fh *fh)
 | 
				
			||||||
	kfree(fh);
 | 
						kfree(fh);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef NFS_DEBUG
 | 
				
			||||||
 | 
					extern u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh);
 | 
				
			||||||
 | 
					static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return _nfs_display_fhandle_hash(fh);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					extern void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption);
 | 
				
			||||||
 | 
					#define nfs_display_fhandle(fh, caption)			\
 | 
				
			||||||
 | 
						do {							\
 | 
				
			||||||
 | 
							if (unlikely(nfs_debug & NFSDBG_FACILITY))	\
 | 
				
			||||||
 | 
								_nfs_display_fhandle(fh, caption);	\
 | 
				
			||||||
 | 
						} while (0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static inline void nfs_display_fhandle(const struct nfs_fh *fh,
 | 
				
			||||||
 | 
									       const char *caption)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * linux/fs/nfs/nfsroot.c
 | 
					 * linux/fs/nfs/nfsroot.c
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -632,19 +658,13 @@ nfs_fileid_to_ino_t(u64 fileid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __KERNEL__
 | 
					#ifdef __KERNEL__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Enable debugging support for nfs client.
 | 
					 | 
				
			||||||
 * Requires RPC_DEBUG.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#ifdef RPC_DEBUG
 | 
					 | 
				
			||||||
# define NFS_DEBUG
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# undef ifdebug
 | 
					# undef ifdebug
 | 
				
			||||||
# ifdef NFS_DEBUG
 | 
					# ifdef NFS_DEBUG
 | 
				
			||||||
#  define ifdebug(fac)		if (unlikely(nfs_debug & NFSDBG_##fac))
 | 
					#  define ifdebug(fac)		if (unlikely(nfs_debug & NFSDBG_##fac))
 | 
				
			||||||
 | 
					#  define NFS_IFDEBUG(x)	x
 | 
				
			||||||
# else
 | 
					# else
 | 
				
			||||||
#  define ifdebug(fac)		if (0)
 | 
					#  define ifdebug(fac)		if (0)
 | 
				
			||||||
 | 
					#  define NFS_IFDEBUG(x)
 | 
				
			||||||
# endif
 | 
					# endif
 | 
				
			||||||
#endif /* __KERNEL */
 | 
					#endif /* __KERNEL */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,6 @@
 | 
				
			||||||
#ifndef _NFS_FS_I
 | 
					#ifndef _NFS_FS_I
 | 
				
			||||||
#define _NFS_FS_I
 | 
					#define _NFS_FS_I
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/types.h>
 | 
					 | 
				
			||||||
#include <linux/list.h>
 | 
					 | 
				
			||||||
#include <linux/nfs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct nlm_lockowner;
 | 
					struct nlm_lockowner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/list.h>
 | 
					#include <linux/list.h>
 | 
				
			||||||
#include <linux/backing-dev.h>
 | 
					#include <linux/backing-dev.h>
 | 
				
			||||||
 | 
					#include <linux/idr.h>
 | 
				
			||||||
#include <linux/wait.h>
 | 
					#include <linux/wait.h>
 | 
				
			||||||
#include <linux/nfs_xdr.h>
 | 
					#include <linux/nfs_xdr.h>
 | 
				
			||||||
#include <linux/sunrpc/xprt.h>
 | 
					#include <linux/sunrpc/xprt.h>
 | 
				
			||||||
| 
						 | 
					@ -17,6 +18,7 @@ struct nfs4_sequence_res;
 | 
				
			||||||
struct nfs_server;
 | 
					struct nfs_server;
 | 
				
			||||||
struct nfs4_minor_version_ops;
 | 
					struct nfs4_minor_version_ops;
 | 
				
			||||||
struct server_scope;
 | 
					struct server_scope;
 | 
				
			||||||
 | 
					struct nfs41_impl_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The nfs_client identifies our client state to the server.
 | 
					 * The nfs_client identifies our client state to the server.
 | 
				
			||||||
| 
						 | 
					@ -85,6 +87,8 @@ struct nfs_client {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct server_scope	*server_scope;	/* from exchange_id */
 | 
						struct server_scope	*server_scope;	/* from exchange_id */
 | 
				
			||||||
 | 
						struct nfs41_impl_id	*impl_id;	/* from exchange_id */
 | 
				
			||||||
 | 
						struct net		*net;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -144,15 +148,18 @@ struct nfs_server {
 | 
				
			||||||
	u32			acl_bitmask;	/* V4 bitmask representing the ACEs
 | 
						u32			acl_bitmask;	/* V4 bitmask representing the ACEs
 | 
				
			||||||
						   that are supported on this
 | 
											   that are supported on this
 | 
				
			||||||
						   filesystem */
 | 
											   filesystem */
 | 
				
			||||||
 | 
						u32			fh_expire_type;	/* V4 bitmask representing file
 | 
				
			||||||
 | 
											   handle volatility type for
 | 
				
			||||||
 | 
											   this filesystem */
 | 
				
			||||||
	struct pnfs_layoutdriver_type  *pnfs_curr_ld; /* Active layout driver */
 | 
						struct pnfs_layoutdriver_type  *pnfs_curr_ld; /* Active layout driver */
 | 
				
			||||||
	struct rpc_wait_queue	roc_rpcwaitq;
 | 
						struct rpc_wait_queue	roc_rpcwaitq;
 | 
				
			||||||
	void			*pnfs_ld_data;	/* per mount point data */
 | 
						void			*pnfs_ld_data;	/* per mount point data */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* the following fields are protected by nfs_client->cl_lock */
 | 
						/* the following fields are protected by nfs_client->cl_lock */
 | 
				
			||||||
	struct rb_root		state_owners;
 | 
						struct rb_root		state_owners;
 | 
				
			||||||
	struct rb_root		openowner_id;
 | 
					 | 
				
			||||||
	struct rb_root		lockowner_id;
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						struct ida		openowner_id;
 | 
				
			||||||
 | 
						struct ida		lockowner_id;
 | 
				
			||||||
	struct list_head	state_owners_lru;
 | 
						struct list_head	state_owners_lru;
 | 
				
			||||||
	struct list_head	layouts;
 | 
						struct list_head	layouts;
 | 
				
			||||||
	struct list_head	delegations;
 | 
						struct list_head	delegations;
 | 
				
			||||||
| 
						 | 
					@ -188,21 +195,23 @@ struct nfs_server {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* maximum number of slots to use */
 | 
					/* maximum number of slots to use */
 | 
				
			||||||
#define NFS4_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE
 | 
					#define NFS4_DEF_SLOT_TABLE_SIZE (16U)
 | 
				
			||||||
 | 
					#define NFS4_MAX_SLOT_TABLE (256U)
 | 
				
			||||||
 | 
					#define NFS4_NO_SLOT ((u32)-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_NFS_V4)
 | 
					#if defined(CONFIG_NFS_V4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Sessions */
 | 
					/* Sessions */
 | 
				
			||||||
#define SLOT_TABLE_SZ (NFS4_MAX_SLOT_TABLE/(8*sizeof(long)))
 | 
					#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long))
 | 
				
			||||||
struct nfs4_slot_table {
 | 
					struct nfs4_slot_table {
 | 
				
			||||||
	struct nfs4_slot *slots;		/* seqid per slot */
 | 
						struct nfs4_slot *slots;		/* seqid per slot */
 | 
				
			||||||
	unsigned long   used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
 | 
						unsigned long   used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
 | 
				
			||||||
	spinlock_t	slot_tbl_lock;
 | 
						spinlock_t	slot_tbl_lock;
 | 
				
			||||||
	struct rpc_wait_queue	slot_tbl_waitq;	/* allocators may wait here */
 | 
						struct rpc_wait_queue	slot_tbl_waitq;	/* allocators may wait here */
 | 
				
			||||||
	int		max_slots;		/* # slots in table */
 | 
						u32		max_slots;		/* # slots in table */
 | 
				
			||||||
	int		highest_used_slotid;	/* sent to server on each SEQ.
 | 
						u32		highest_used_slotid;	/* sent to server on each SEQ.
 | 
				
			||||||
						 * op for dynamic resizing */
 | 
											 * op for dynamic resizing */
 | 
				
			||||||
	int		target_max_slots;	/* Set by CB_RECALL_SLOT as
 | 
						u32		target_max_slots;	/* Set by CB_RECALL_SLOT as
 | 
				
			||||||
						 * the new max_slots */
 | 
											 * the new max_slots */
 | 
				
			||||||
	struct completion complete;
 | 
						struct completion complete;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,36 +69,22 @@ struct nfs_server;
 | 
				
			||||||
struct nfs_fattr;
 | 
					struct nfs_fattr;
 | 
				
			||||||
struct nfs4_string;
 | 
					struct nfs4_string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
 | 
					#ifdef CONFIG_NFS_V4
 | 
				
			||||||
 | 
					 | 
				
			||||||
int nfs_idmap_init(void);
 | 
					int nfs_idmap_init(void);
 | 
				
			||||||
void nfs_idmap_quit(void);
 | 
					void nfs_idmap_quit(void);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
static inline int nfs_idmap_new(struct nfs_client *clp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void nfs_idmap_delete(struct nfs_client *clp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int nfs_idmap_init(void)
 | 
					static inline int nfs_idmap_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void nfs_idmap_quit(void)
 | 
					static inline void nfs_idmap_quit(void)
 | 
				
			||||||
{
 | 
					{}
 | 
				
			||||||
}
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfs_idmap_new(struct nfs_client *);
 | 
					int nfs_idmap_new(struct nfs_client *);
 | 
				
			||||||
void nfs_idmap_delete(struct nfs_client *);
 | 
					void nfs_idmap_delete(struct nfs_client *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void nfs_fattr_init_names(struct nfs_fattr *fattr,
 | 
					void nfs_fattr_init_names(struct nfs_fattr *fattr,
 | 
				
			||||||
		struct nfs4_string *owner_name,
 | 
							struct nfs4_string *owner_name,
 | 
				
			||||||
		struct nfs4_string *group_name);
 | 
							struct nfs4_string *group_name);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@
 | 
				
			||||||
#ifndef _LINUX_NFS_IOSTAT
 | 
					#ifndef _LINUX_NFS_IOSTAT
 | 
				
			||||||
#define _LINUX_NFS_IOSTAT
 | 
					#define _LINUX_NFS_IOSTAT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFS_IOSTAT_VERS		"1.0"
 | 
					#define NFS_IOSTAT_VERS		"1.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * NFS byte counters
 | 
					 * NFS byte counters
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,12 +18,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/kref.h>
 | 
					#include <linux/kref.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Valid flags for the radix tree
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define NFS_PAGE_TAG_LOCKED	0
 | 
					 | 
				
			||||||
#define NFS_PAGE_TAG_COMMIT	1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Valid flags for a dirty buffer
 | 
					 * Valid flags for a dirty buffer
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -33,16 +27,13 @@ enum {
 | 
				
			||||||
	PG_CLEAN,
 | 
						PG_CLEAN,
 | 
				
			||||||
	PG_NEED_COMMIT,
 | 
						PG_NEED_COMMIT,
 | 
				
			||||||
	PG_NEED_RESCHED,
 | 
						PG_NEED_RESCHED,
 | 
				
			||||||
	PG_PNFS_COMMIT,
 | 
					 | 
				
			||||||
	PG_PARTIAL_READ_FAILED,
 | 
						PG_PARTIAL_READ_FAILED,
 | 
				
			||||||
 | 
						PG_COMMIT_TO_DS,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs_inode;
 | 
					struct nfs_inode;
 | 
				
			||||||
struct nfs_page {
 | 
					struct nfs_page {
 | 
				
			||||||
	union {
 | 
					 | 
				
			||||||
	struct list_head	wb_list;	/* Defines state of page: */
 | 
						struct list_head	wb_list;	/* Defines state of page: */
 | 
				
			||||||
		struct pnfs_layout_segment *wb_commit_lseg; /* Used when PG_PNFS_COMMIT set */
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	struct page		*wb_page;	/* page to read in/write out */
 | 
						struct page		*wb_page;	/* page to read in/write out */
 | 
				
			||||||
	struct nfs_open_context	*wb_context;	/* File state context info */
 | 
						struct nfs_open_context	*wb_context;	/* File state context info */
 | 
				
			||||||
	struct nfs_lock_context	*wb_lock_context;	/* lock context info */
 | 
						struct nfs_lock_context	*wb_lock_context;	/* lock context info */
 | 
				
			||||||
| 
						 | 
					@ -90,8 +81,6 @@ extern	struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
 | 
				
			||||||
extern	void nfs_release_request(struct nfs_page *req);
 | 
					extern	void nfs_release_request(struct nfs_page *req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern	int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst,
 | 
					 | 
				
			||||||
			  pgoff_t idx_start, unsigned int npages, int tag);
 | 
					 | 
				
			||||||
extern	void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
 | 
					extern	void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
 | 
				
			||||||
			     struct inode *inode,
 | 
								     struct inode *inode,
 | 
				
			||||||
			     const struct nfs_pageio_ops *pg_ops,
 | 
								     const struct nfs_pageio_ops *pg_ops,
 | 
				
			||||||
| 
						 | 
					@ -106,8 +95,6 @@ extern bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
 | 
				
			||||||
				struct nfs_page *req);
 | 
									struct nfs_page *req);
 | 
				
			||||||
extern  int nfs_wait_on_request(struct nfs_page *);
 | 
					extern  int nfs_wait_on_request(struct nfs_page *);
 | 
				
			||||||
extern	void nfs_unlock_request(struct nfs_page *req);
 | 
					extern	void nfs_unlock_request(struct nfs_page *req);
 | 
				
			||||||
extern	int nfs_set_page_tag_locked(struct nfs_page *req);
 | 
					 | 
				
			||||||
extern  void nfs_clear_page_tag_locked(struct nfs_page *req);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Lock the page of an asynchronous request without getting a new reference
 | 
					 * Lock the page of an asynchronous request without getting a new reference
 | 
				
			||||||
| 
						 | 
					@ -118,6 +105,16 @@ nfs_lock_request_dontget(struct nfs_page *req)
 | 
				
			||||||
	return !test_and_set_bit(PG_BUSY, &req->wb_flags);
 | 
						return !test_and_set_bit(PG_BUSY, &req->wb_flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int
 | 
				
			||||||
 | 
					nfs_lock_request(struct nfs_page *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (test_and_set_bit(PG_BUSY, &req->wb_flags))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						kref_get(&req->wb_kref);
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * nfs_list_add_request - Insert a request into a list
 | 
					 * nfs_list_add_request - Insert a request into a list
 | 
				
			||||||
 * @req: request
 | 
					 * @req: request
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@
 | 
				
			||||||
#define _LINUX_NFS_XDR_H
 | 
					#define _LINUX_NFS_XDR_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/nfsacl.h>
 | 
					#include <linux/nfsacl.h>
 | 
				
			||||||
#include <linux/nfs3.h>
 | 
					 | 
				
			||||||
#include <linux/sunrpc/gss_api.h>
 | 
					#include <linux/sunrpc/gss_api.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -89,11 +88,12 @@ struct nfs_fattr {
 | 
				
			||||||
#define NFS_ATTR_FATTR_PRECTIME		(1U << 16)
 | 
					#define NFS_ATTR_FATTR_PRECTIME		(1U << 16)
 | 
				
			||||||
#define NFS_ATTR_FATTR_CHANGE		(1U << 17)
 | 
					#define NFS_ATTR_FATTR_CHANGE		(1U << 17)
 | 
				
			||||||
#define NFS_ATTR_FATTR_PRECHANGE	(1U << 18)
 | 
					#define NFS_ATTR_FATTR_PRECHANGE	(1U << 18)
 | 
				
			||||||
#define NFS_ATTR_FATTR_V4_REFERRAL	(1U << 19)	/* NFSv4 referral */
 | 
					#define NFS_ATTR_FATTR_V4_LOCATIONS	(1U << 19)
 | 
				
			||||||
#define NFS_ATTR_FATTR_MOUNTPOINT	(1U << 20)	/* Treat as mountpoint */
 | 
					#define NFS_ATTR_FATTR_V4_REFERRAL	(1U << 20)
 | 
				
			||||||
#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID		(1U << 21)
 | 
					#define NFS_ATTR_FATTR_MOUNTPOINT	(1U << 21)
 | 
				
			||||||
#define NFS_ATTR_FATTR_OWNER_NAME	(1U << 22)
 | 
					#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22)
 | 
				
			||||||
#define NFS_ATTR_FATTR_GROUP_NAME	(1U << 23)
 | 
					#define NFS_ATTR_FATTR_OWNER_NAME	(1U << 23)
 | 
				
			||||||
 | 
					#define NFS_ATTR_FATTR_GROUP_NAME	(1U << 24)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
 | 
					#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
 | 
				
			||||||
		| NFS_ATTR_FATTR_MODE \
 | 
							| NFS_ATTR_FATTR_MODE \
 | 
				
			||||||
| 
						 | 
					@ -182,7 +182,7 @@ struct nfs4_slot {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs4_sequence_args {
 | 
					struct nfs4_sequence_args {
 | 
				
			||||||
	struct nfs4_session	*sa_session;
 | 
						struct nfs4_session	*sa_session;
 | 
				
			||||||
	u8			sa_slotid;
 | 
						u32			sa_slotid;
 | 
				
			||||||
	u8			sa_cache_this;
 | 
						u8			sa_cache_this;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -977,6 +977,7 @@ struct nfs4_server_caps_res {
 | 
				
			||||||
	u32				acl_bitmask;
 | 
						u32				acl_bitmask;
 | 
				
			||||||
	u32				has_links;
 | 
						u32				has_links;
 | 
				
			||||||
	u32				has_symlinks;
 | 
						u32				has_symlinks;
 | 
				
			||||||
 | 
						u32				fh_expire_type;
 | 
				
			||||||
	struct nfs4_sequence_res	seq_res;
 | 
						struct nfs4_sequence_res	seq_res;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1055,14 +1056,6 @@ struct nfstime4 {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_NFS_V4_1
 | 
					#ifdef CONFIG_NFS_V4_1
 | 
				
			||||||
struct nfs_impl_id4 {
 | 
					 | 
				
			||||||
	u32		domain_len;
 | 
					 | 
				
			||||||
	char		*domain;
 | 
					 | 
				
			||||||
	u32		name_len;
 | 
					 | 
				
			||||||
	char		*name;
 | 
					 | 
				
			||||||
	struct nfstime4	date;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define NFS4_EXCHANGE_ID_LEN	(48)
 | 
					#define NFS4_EXCHANGE_ID_LEN	(48)
 | 
				
			||||||
struct nfs41_exchange_id_args {
 | 
					struct nfs41_exchange_id_args {
 | 
				
			||||||
	struct nfs_client		*client;
 | 
						struct nfs_client		*client;
 | 
				
			||||||
| 
						 | 
					@ -1083,10 +1076,17 @@ struct server_scope {
 | 
				
			||||||
	char 				server_scope[NFS4_OPAQUE_LIMIT];
 | 
						char 				server_scope[NFS4_OPAQUE_LIMIT];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct nfs41_impl_id {
 | 
				
			||||||
 | 
						char				domain[NFS4_OPAQUE_LIMIT + 1];
 | 
				
			||||||
 | 
						char				name[NFS4_OPAQUE_LIMIT + 1];
 | 
				
			||||||
 | 
						struct nfstime4			date;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs41_exchange_id_res {
 | 
					struct nfs41_exchange_id_res {
 | 
				
			||||||
	struct nfs_client		*client;
 | 
						struct nfs_client		*client;
 | 
				
			||||||
	u32				flags;
 | 
						u32				flags;
 | 
				
			||||||
	struct server_scope		*server_scope;
 | 
						struct server_scope		*server_scope;
 | 
				
			||||||
 | 
						struct nfs41_impl_id		*impl_id;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs41_create_session_args {
 | 
					struct nfs41_create_session_args {
 | 
				
			||||||
| 
						 | 
					@ -1192,6 +1192,27 @@ struct nfs_write_data {
 | 
				
			||||||
	struct page		*page_array[NFS_PAGEVEC_SIZE];
 | 
						struct page		*page_array[NFS_PAGEVEC_SIZE];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct nfs_unlinkdata {
 | 
				
			||||||
 | 
						struct hlist_node list;
 | 
				
			||||||
 | 
						struct nfs_removeargs args;
 | 
				
			||||||
 | 
						struct nfs_removeres res;
 | 
				
			||||||
 | 
						struct inode *dir;
 | 
				
			||||||
 | 
						struct rpc_cred	*cred;
 | 
				
			||||||
 | 
						struct nfs_fattr dir_attr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct nfs_renamedata {
 | 
				
			||||||
 | 
						struct nfs_renameargs	args;
 | 
				
			||||||
 | 
						struct nfs_renameres	res;
 | 
				
			||||||
 | 
						struct rpc_cred		*cred;
 | 
				
			||||||
 | 
						struct inode		*old_dir;
 | 
				
			||||||
 | 
						struct dentry		*old_dentry;
 | 
				
			||||||
 | 
						struct nfs_fattr	old_fattr;
 | 
				
			||||||
 | 
						struct inode		*new_dir;
 | 
				
			||||||
 | 
						struct dentry		*new_dentry;
 | 
				
			||||||
 | 
						struct nfs_fattr	new_fattr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct nfs_access_entry;
 | 
					struct nfs_access_entry;
 | 
				
			||||||
struct nfs_client;
 | 
					struct nfs_client;
 | 
				
			||||||
struct rpc_timeout;
 | 
					struct rpc_timeout;
 | 
				
			||||||
| 
						 | 
					@ -1221,10 +1242,12 @@ struct nfs_rpc_ops {
 | 
				
			||||||
			    struct iattr *, int, struct nfs_open_context *);
 | 
								    struct iattr *, int, struct nfs_open_context *);
 | 
				
			||||||
	int	(*remove)  (struct inode *, struct qstr *);
 | 
						int	(*remove)  (struct inode *, struct qstr *);
 | 
				
			||||||
	void	(*unlink_setup)  (struct rpc_message *, struct inode *dir);
 | 
						void	(*unlink_setup)  (struct rpc_message *, struct inode *dir);
 | 
				
			||||||
 | 
						void	(*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
 | 
				
			||||||
	int	(*unlink_done) (struct rpc_task *, struct inode *);
 | 
						int	(*unlink_done) (struct rpc_task *, struct inode *);
 | 
				
			||||||
	int	(*rename)  (struct inode *, struct qstr *,
 | 
						int	(*rename)  (struct inode *, struct qstr *,
 | 
				
			||||||
			    struct inode *, struct qstr *);
 | 
								    struct inode *, struct qstr *);
 | 
				
			||||||
	void	(*rename_setup)  (struct rpc_message *msg, struct inode *dir);
 | 
						void	(*rename_setup)  (struct rpc_message *msg, struct inode *dir);
 | 
				
			||||||
 | 
						void	(*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
 | 
				
			||||||
	int	(*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
 | 
						int	(*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
 | 
				
			||||||
	int	(*link)    (struct inode *, struct inode *, struct qstr *);
 | 
						int	(*link)    (struct inode *, struct inode *, struct qstr *);
 | 
				
			||||||
	int	(*symlink) (struct inode *, struct dentry *, struct page *,
 | 
						int	(*symlink) (struct inode *, struct dentry *, struct page *,
 | 
				
			||||||
| 
						 | 
					@ -1244,8 +1267,10 @@ struct nfs_rpc_ops {
 | 
				
			||||||
	int	(*set_capabilities)(struct nfs_server *, struct nfs_fh *);
 | 
						int	(*set_capabilities)(struct nfs_server *, struct nfs_fh *);
 | 
				
			||||||
	int	(*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int);
 | 
						int	(*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int);
 | 
				
			||||||
	void	(*read_setup)   (struct nfs_read_data *, struct rpc_message *);
 | 
						void	(*read_setup)   (struct nfs_read_data *, struct rpc_message *);
 | 
				
			||||||
 | 
						void	(*read_rpc_prepare)(struct rpc_task *, struct nfs_read_data *);
 | 
				
			||||||
	int	(*read_done)  (struct rpc_task *, struct nfs_read_data *);
 | 
						int	(*read_done)  (struct rpc_task *, struct nfs_read_data *);
 | 
				
			||||||
	void	(*write_setup)  (struct nfs_write_data *, struct rpc_message *);
 | 
						void	(*write_setup)  (struct nfs_write_data *, struct rpc_message *);
 | 
				
			||||||
 | 
						void	(*write_rpc_prepare)(struct rpc_task *, struct nfs_write_data *);
 | 
				
			||||||
	int	(*write_done)  (struct rpc_task *, struct nfs_write_data *);
 | 
						int	(*write_done)  (struct rpc_task *, struct nfs_write_data *);
 | 
				
			||||||
	void	(*commit_setup) (struct nfs_write_data *, struct rpc_message *);
 | 
						void	(*commit_setup) (struct nfs_write_data *, struct rpc_message *);
 | 
				
			||||||
	int	(*commit_done) (struct rpc_task *, struct nfs_write_data *);
 | 
						int	(*commit_done) (struct rpc_task *, struct nfs_write_data *);
 | 
				
			||||||
| 
						 | 
					@ -1275,11 +1300,11 @@ struct nfs_rpc_ops {
 | 
				
			||||||
extern const struct nfs_rpc_ops	nfs_v2_clientops;
 | 
					extern const struct nfs_rpc_ops	nfs_v2_clientops;
 | 
				
			||||||
extern const struct nfs_rpc_ops	nfs_v3_clientops;
 | 
					extern const struct nfs_rpc_ops	nfs_v3_clientops;
 | 
				
			||||||
extern const struct nfs_rpc_ops	nfs_v4_clientops;
 | 
					extern const struct nfs_rpc_ops	nfs_v4_clientops;
 | 
				
			||||||
extern struct rpc_version	nfs_version2;
 | 
					extern const struct rpc_version nfs_version2;
 | 
				
			||||||
extern struct rpc_version	nfs_version3;
 | 
					extern const struct rpc_version nfs_version3;
 | 
				
			||||||
extern struct rpc_version	nfs_version4;
 | 
					extern const struct rpc_version nfs_version4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct rpc_version	nfsacl_version3;
 | 
					extern const struct rpc_version nfsacl_version3;
 | 
				
			||||||
extern struct rpc_program	nfsacl_program;
 | 
					extern const struct rpc_program nfsacl_program;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -99,6 +99,8 @@ struct rpc_authops {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rpc_cred *	(*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
 | 
						struct rpc_cred *	(*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
 | 
				
			||||||
	struct rpc_cred *	(*crcreate)(struct rpc_auth*, struct auth_cred *, int);
 | 
						struct rpc_cred *	(*crcreate)(struct rpc_auth*, struct auth_cred *, int);
 | 
				
			||||||
 | 
						int			(*pipes_create)(struct rpc_auth *);
 | 
				
			||||||
 | 
						void			(*pipes_destroy)(struct rpc_auth *);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_credops {
 | 
					struct rpc_credops {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt);
 | 
					struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt);
 | 
				
			||||||
void xprt_free_bc_request(struct rpc_rqst *req);
 | 
					void xprt_free_bc_request(struct rpc_rqst *req);
 | 
				
			||||||
int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
 | 
					int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
 | 
				
			||||||
void xprt_destroy_backchannel(struct rpc_xprt *, int max_reqs);
 | 
					void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs);
 | 
				
			||||||
int bc_send(struct rpc_rqst *req);
 | 
					int bc_send(struct rpc_rqst *req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,6 +117,7 @@ struct cache_detail {
 | 
				
			||||||
		struct cache_detail_procfs procfs;
 | 
							struct cache_detail_procfs procfs;
 | 
				
			||||||
		struct cache_detail_pipefs pipefs;
 | 
							struct cache_detail_pipefs pipefs;
 | 
				
			||||||
	} u;
 | 
						} u;
 | 
				
			||||||
 | 
						struct net		*net;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -197,11 +198,14 @@ extern void cache_flush(void);
 | 
				
			||||||
extern void cache_purge(struct cache_detail *detail);
 | 
					extern void cache_purge(struct cache_detail *detail);
 | 
				
			||||||
#define NEVER (0x7FFFFFFF)
 | 
					#define NEVER (0x7FFFFFFF)
 | 
				
			||||||
extern void __init cache_initialize(void);
 | 
					extern void __init cache_initialize(void);
 | 
				
			||||||
extern int cache_register(struct cache_detail *cd);
 | 
					 | 
				
			||||||
extern int cache_register_net(struct cache_detail *cd, struct net *net);
 | 
					extern int cache_register_net(struct cache_detail *cd, struct net *net);
 | 
				
			||||||
extern void cache_unregister(struct cache_detail *cd);
 | 
					 | 
				
			||||||
extern void cache_unregister_net(struct cache_detail *cd, struct net *net);
 | 
					extern void cache_unregister_net(struct cache_detail *cd, struct net *net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net);
 | 
				
			||||||
 | 
					extern void cache_destroy_net(struct cache_detail *cd, struct net *net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void sunrpc_init_cache_detail(struct cache_detail *cd);
 | 
				
			||||||
 | 
					extern void sunrpc_destroy_cache_detail(struct cache_detail *cd);
 | 
				
			||||||
extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
 | 
					extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
 | 
				
			||||||
					umode_t, struct cache_detail *);
 | 
										umode_t, struct cache_detail *);
 | 
				
			||||||
extern void sunrpc_cache_unregister_pipefs(struct cache_detail *);
 | 
					extern void sunrpc_cache_unregister_pipefs(struct cache_detail *);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,14 +35,13 @@ struct rpc_clnt {
 | 
				
			||||||
	struct list_head	cl_clients;	/* Global list of clients */
 | 
						struct list_head	cl_clients;	/* Global list of clients */
 | 
				
			||||||
	struct list_head	cl_tasks;	/* List of tasks */
 | 
						struct list_head	cl_tasks;	/* List of tasks */
 | 
				
			||||||
	spinlock_t		cl_lock;	/* spinlock */
 | 
						spinlock_t		cl_lock;	/* spinlock */
 | 
				
			||||||
	struct rpc_xprt *	cl_xprt;	/* transport */
 | 
						struct rpc_xprt __rcu *	cl_xprt;	/* transport */
 | 
				
			||||||
	struct rpc_procinfo *	cl_procinfo;	/* procedure info */
 | 
						struct rpc_procinfo *	cl_procinfo;	/* procedure info */
 | 
				
			||||||
	u32			cl_prog,	/* RPC program number */
 | 
						u32			cl_prog,	/* RPC program number */
 | 
				
			||||||
				cl_vers,	/* RPC version number */
 | 
									cl_vers,	/* RPC version number */
 | 
				
			||||||
				cl_maxproc;	/* max procedure number */
 | 
									cl_maxproc;	/* max procedure number */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *			cl_server;	/* server machine name */
 | 
						const char *		cl_protname;	/* protocol name */
 | 
				
			||||||
	char *			cl_protname;	/* protocol name */
 | 
					 | 
				
			||||||
	struct rpc_auth *	cl_auth;	/* authenticator */
 | 
						struct rpc_auth *	cl_auth;	/* authenticator */
 | 
				
			||||||
	struct rpc_stat *	cl_stats;	/* per-program statistics */
 | 
						struct rpc_stat *	cl_stats;	/* per-program statistics */
 | 
				
			||||||
	struct rpc_iostats *	cl_metrics;	/* per-client statistics */
 | 
						struct rpc_iostats *	cl_metrics;	/* per-client statistics */
 | 
				
			||||||
| 
						 | 
					@ -57,12 +56,11 @@ struct rpc_clnt {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int			cl_nodelen;	/* nodename length */
 | 
						int			cl_nodelen;	/* nodename length */
 | 
				
			||||||
	char 			cl_nodename[UNX_MAXNODENAME];
 | 
						char 			cl_nodename[UNX_MAXNODENAME];
 | 
				
			||||||
	struct path		cl_path;
 | 
						struct dentry *		cl_dentry;
 | 
				
			||||||
	struct rpc_clnt *	cl_parent;	/* Points to parent of clones */
 | 
						struct rpc_clnt *	cl_parent;	/* Points to parent of clones */
 | 
				
			||||||
	struct rpc_rtt		cl_rtt_default;
 | 
						struct rpc_rtt		cl_rtt_default;
 | 
				
			||||||
	struct rpc_timeout	cl_timeout_default;
 | 
						struct rpc_timeout	cl_timeout_default;
 | 
				
			||||||
	struct rpc_program *	cl_program;
 | 
						const struct rpc_program *cl_program;
 | 
				
			||||||
	char			cl_inline_name[32];
 | 
					 | 
				
			||||||
	char			*cl_principal;	/* target to authenticate to */
 | 
						char			*cl_principal;	/* target to authenticate to */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,12 +69,12 @@ struct rpc_clnt {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define RPC_MAXVERSION		4
 | 
					#define RPC_MAXVERSION		4
 | 
				
			||||||
struct rpc_program {
 | 
					struct rpc_program {
 | 
				
			||||||
	char *			name;		/* protocol name */
 | 
						const char *		name;		/* protocol name */
 | 
				
			||||||
	u32			number;		/* program number */
 | 
						u32			number;		/* program number */
 | 
				
			||||||
	unsigned int		nrvers;		/* number of versions */
 | 
						unsigned int		nrvers;		/* number of versions */
 | 
				
			||||||
	struct rpc_version **	version;	/* version array */
 | 
						const struct rpc_version **	version;	/* version array */
 | 
				
			||||||
	struct rpc_stat *	stats;		/* statistics */
 | 
						struct rpc_stat *	stats;		/* statistics */
 | 
				
			||||||
	char *			pipe_dir_name;	/* path to rpc_pipefs dir */
 | 
						const char *		pipe_dir_name;	/* path to rpc_pipefs dir */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_version {
 | 
					struct rpc_version {
 | 
				
			||||||
| 
						 | 
					@ -97,7 +95,7 @@ struct rpc_procinfo {
 | 
				
			||||||
	unsigned int		p_count;	/* call count */
 | 
						unsigned int		p_count;	/* call count */
 | 
				
			||||||
	unsigned int		p_timer;	/* Which RTT timer to use */
 | 
						unsigned int		p_timer;	/* Which RTT timer to use */
 | 
				
			||||||
	u32			p_statidx;	/* Which procedure to account */
 | 
						u32			p_statidx;	/* Which procedure to account */
 | 
				
			||||||
	char *			p_name;		/* name of procedure */
 | 
						const char *		p_name;		/* name of procedure */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __KERNEL__
 | 
					#ifdef __KERNEL__
 | 
				
			||||||
| 
						 | 
					@ -109,8 +107,8 @@ struct rpc_create_args {
 | 
				
			||||||
	size_t			addrsize;
 | 
						size_t			addrsize;
 | 
				
			||||||
	struct sockaddr		*saddress;
 | 
						struct sockaddr		*saddress;
 | 
				
			||||||
	const struct rpc_timeout *timeout;
 | 
						const struct rpc_timeout *timeout;
 | 
				
			||||||
	char			*servername;
 | 
						const char		*servername;
 | 
				
			||||||
	struct rpc_program	*program;
 | 
						const struct rpc_program *program;
 | 
				
			||||||
	u32			prognumber;	/* overrides program->number */
 | 
						u32			prognumber;	/* overrides program->number */
 | 
				
			||||||
	u32			version;
 | 
						u32			version;
 | 
				
			||||||
	rpc_authflavor_t	authflavor;
 | 
						rpc_authflavor_t	authflavor;
 | 
				
			||||||
| 
						 | 
					@ -129,17 +127,18 @@ struct rpc_create_args {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
 | 
					struct rpc_clnt *rpc_create(struct rpc_create_args *args);
 | 
				
			||||||
struct rpc_clnt	*rpc_bind_new_program(struct rpc_clnt *,
 | 
					struct rpc_clnt	*rpc_bind_new_program(struct rpc_clnt *,
 | 
				
			||||||
				struct rpc_program *, u32);
 | 
									const struct rpc_program *, u32);
 | 
				
			||||||
void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
 | 
					void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
 | 
				
			||||||
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
 | 
					struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
 | 
				
			||||||
void		rpc_shutdown_client(struct rpc_clnt *);
 | 
					void		rpc_shutdown_client(struct rpc_clnt *);
 | 
				
			||||||
void		rpc_release_client(struct rpc_clnt *);
 | 
					void		rpc_release_client(struct rpc_clnt *);
 | 
				
			||||||
void		rpc_task_release_client(struct rpc_task *);
 | 
					void		rpc_task_release_client(struct rpc_task *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int		rpcb_create_local(void);
 | 
					int		rpcb_create_local(struct net *);
 | 
				
			||||||
void		rpcb_put_local(void);
 | 
					void		rpcb_put_local(struct net *);
 | 
				
			||||||
int		rpcb_register(u32, u32, int, unsigned short);
 | 
					int		rpcb_register(struct net *, u32, u32, int, unsigned short);
 | 
				
			||||||
int		rpcb_v4_register(const u32 program, const u32 version,
 | 
					int		rpcb_v4_register(struct net *net, const u32 program,
 | 
				
			||||||
 | 
									 const u32 version,
 | 
				
			||||||
				 const struct sockaddr *address,
 | 
									 const struct sockaddr *address,
 | 
				
			||||||
				 const char *netid);
 | 
									 const char *netid);
 | 
				
			||||||
void		rpcb_getport_async(struct rpc_task *);
 | 
					void		rpcb_getport_async(struct rpc_task *);
 | 
				
			||||||
| 
						 | 
					@ -156,16 +155,19 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred,
 | 
				
			||||||
int		rpc_restart_call_prepare(struct rpc_task *);
 | 
					int		rpc_restart_call_prepare(struct rpc_task *);
 | 
				
			||||||
int		rpc_restart_call(struct rpc_task *);
 | 
					int		rpc_restart_call(struct rpc_task *);
 | 
				
			||||||
void		rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
 | 
					void		rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
 | 
				
			||||||
 | 
					int		rpc_protocol(struct rpc_clnt *);
 | 
				
			||||||
 | 
					struct net *	rpc_net_ns(struct rpc_clnt *);
 | 
				
			||||||
size_t		rpc_max_payload(struct rpc_clnt *);
 | 
					size_t		rpc_max_payload(struct rpc_clnt *);
 | 
				
			||||||
void		rpc_force_rebind(struct rpc_clnt *);
 | 
					void		rpc_force_rebind(struct rpc_clnt *);
 | 
				
			||||||
size_t		rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
 | 
					size_t		rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
 | 
				
			||||||
const char	*rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
 | 
					const char	*rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
 | 
				
			||||||
 | 
					int		rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t		rpc_ntop(const struct sockaddr *, char *, const size_t);
 | 
					size_t		rpc_ntop(const struct sockaddr *, char *, const size_t);
 | 
				
			||||||
size_t		rpc_pton(const char *, const size_t,
 | 
					size_t		rpc_pton(struct net *, const char *, const size_t,
 | 
				
			||||||
			 struct sockaddr *, const size_t);
 | 
								 struct sockaddr *, const size_t);
 | 
				
			||||||
char *		rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t);
 | 
					char *		rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t);
 | 
				
			||||||
size_t		rpc_uaddr2sockaddr(const char *, const size_t,
 | 
					size_t		rpc_uaddr2sockaddr(struct net *, const char *, const size_t,
 | 
				
			||||||
				   struct sockaddr *, const size_t);
 | 
									   struct sockaddr *, const size_t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline unsigned short rpc_get_port(const struct sockaddr *sap)
 | 
					static inline unsigned short rpc_get_port(const struct sockaddr *sap)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,9 +31,12 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Enable RPC debugging/profiling.
 | 
					 * Enable RPC debugging/profiling.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifdef CONFIG_SYSCTL
 | 
					#ifdef CONFIG_SUNRPC_DEBUG
 | 
				
			||||||
#define  RPC_DEBUG
 | 
					#define  RPC_DEBUG
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_TRACEPOINTS
 | 
				
			||||||
 | 
					#define RPC_TRACEPOINTS
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
/* #define  RPC_PROFILE */
 | 
					/* #define  RPC_PROFILE */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -47,15 +50,32 @@ extern unsigned int		nlm_debug;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define dprintk(args...)	dfprintk(FACILITY, ## args)
 | 
					#define dprintk(args...)	dfprintk(FACILITY, ## args)
 | 
				
			||||||
 | 
					#define dprintk_rcu(args...)	dfprintk_rcu(FACILITY, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef ifdebug
 | 
					#undef ifdebug
 | 
				
			||||||
#ifdef RPC_DEBUG			
 | 
					#ifdef RPC_DEBUG			
 | 
				
			||||||
# define ifdebug(fac)		if (unlikely(rpc_debug & RPCDBG_##fac))
 | 
					# define ifdebug(fac)		if (unlikely(rpc_debug & RPCDBG_##fac))
 | 
				
			||||||
# define dfprintk(fac, args...)	do { ifdebug(fac) printk(args); } while(0)
 | 
					
 | 
				
			||||||
 | 
					# define dfprintk(fac, args...)	\
 | 
				
			||||||
 | 
						do { \
 | 
				
			||||||
 | 
							ifdebug(fac) \
 | 
				
			||||||
 | 
								printk(KERN_DEFAULT args); \
 | 
				
			||||||
 | 
						} while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define dfprintk_rcu(fac, args...)	\
 | 
				
			||||||
 | 
						do { \
 | 
				
			||||||
 | 
							ifdebug(fac) { \
 | 
				
			||||||
 | 
								rcu_read_lock(); \
 | 
				
			||||||
 | 
								printk(KERN_DEFAULT args); \
 | 
				
			||||||
 | 
								rcu_read_unlock(); \
 | 
				
			||||||
 | 
							} \
 | 
				
			||||||
 | 
						} while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# define RPC_IFDEBUG(x)		x
 | 
					# define RPC_IFDEBUG(x)		x
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
# define ifdebug(fac)		if (0)
 | 
					# define ifdebug(fac)		if (0)
 | 
				
			||||||
# define dfprintk(fac, args...)	do ; while (0)
 | 
					# define dfprintk(fac, args...)	do {} while (0)
 | 
				
			||||||
 | 
					# define dfprintk_rcu(fac, args...)	do {} while (0)
 | 
				
			||||||
# define RPC_IFDEBUG(x)
 | 
					# define RPC_IFDEBUG(x)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,14 +74,16 @@ struct rpc_clnt;
 | 
				
			||||||
#ifdef CONFIG_PROC_FS
 | 
					#ifdef CONFIG_PROC_FS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_iostats *	rpc_alloc_iostats(struct rpc_clnt *);
 | 
					struct rpc_iostats *	rpc_alloc_iostats(struct rpc_clnt *);
 | 
				
			||||||
void			rpc_count_iostats(struct rpc_task *);
 | 
					void			rpc_count_iostats(const struct rpc_task *,
 | 
				
			||||||
 | 
										  struct rpc_iostats *);
 | 
				
			||||||
void			rpc_print_iostats(struct seq_file *, struct rpc_clnt *);
 | 
					void			rpc_print_iostats(struct seq_file *, struct rpc_clnt *);
 | 
				
			||||||
void			rpc_free_iostats(struct rpc_iostats *);
 | 
					void			rpc_free_iostats(struct rpc_iostats *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else  /*  CONFIG_PROC_FS  */
 | 
					#else  /*  CONFIG_PROC_FS  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) { return NULL; }
 | 
					static inline struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) { return NULL; }
 | 
				
			||||||
static inline void rpc_count_iostats(struct rpc_task *task) {}
 | 
					static inline void rpc_count_iostats(const struct rpc_task *task,
 | 
				
			||||||
 | 
									     struct rpc_iostats *stats) {}
 | 
				
			||||||
static inline void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) {}
 | 
					static inline void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) {}
 | 
				
			||||||
static inline void rpc_free_iostats(struct rpc_iostats *stats) {}
 | 
					static inline void rpc_free_iostats(struct rpc_iostats *stats) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,21 +21,26 @@ struct rpc_pipe_ops {
 | 
				
			||||||
	void (*destroy_msg)(struct rpc_pipe_msg *);
 | 
						void (*destroy_msg)(struct rpc_pipe_msg *);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_inode {
 | 
					struct rpc_pipe {
 | 
				
			||||||
	struct inode vfs_inode;
 | 
					 | 
				
			||||||
	void *private;
 | 
					 | 
				
			||||||
	struct list_head pipe;
 | 
						struct list_head pipe;
 | 
				
			||||||
	struct list_head in_upcall;
 | 
						struct list_head in_upcall;
 | 
				
			||||||
	struct list_head in_downcall;
 | 
						struct list_head in_downcall;
 | 
				
			||||||
	int pipelen;
 | 
						int pipelen;
 | 
				
			||||||
	int nreaders;
 | 
						int nreaders;
 | 
				
			||||||
	int nwriters;
 | 
						int nwriters;
 | 
				
			||||||
	int nkern_readwriters;
 | 
					 | 
				
			||||||
	wait_queue_head_t waitq;
 | 
					 | 
				
			||||||
#define RPC_PIPE_WAIT_FOR_OPEN	1
 | 
					#define RPC_PIPE_WAIT_FOR_OPEN	1
 | 
				
			||||||
	int flags;
 | 
						int flags;
 | 
				
			||||||
	struct delayed_work queue_timeout;
 | 
						struct delayed_work queue_timeout;
 | 
				
			||||||
	const struct rpc_pipe_ops *ops;
 | 
						const struct rpc_pipe_ops *ops;
 | 
				
			||||||
 | 
						spinlock_t lock;
 | 
				
			||||||
 | 
						struct dentry *dentry;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rpc_inode {
 | 
				
			||||||
 | 
						struct inode vfs_inode;
 | 
				
			||||||
 | 
						void *private;
 | 
				
			||||||
 | 
						struct rpc_pipe *pipe;
 | 
				
			||||||
 | 
						wait_queue_head_t waitq;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct rpc_inode *
 | 
					static inline struct rpc_inode *
 | 
				
			||||||
| 
						 | 
					@ -44,9 +49,28 @@ RPC_I(struct inode *inode)
 | 
				
			||||||
	return container_of(inode, struct rpc_inode, vfs_inode);
 | 
						return container_of(inode, struct rpc_inode, vfs_inode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						SUNRPC_PIPEFS_NFS_PRIO,
 | 
				
			||||||
 | 
						SUNRPC_PIPEFS_RPC_PRIO,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int rpc_pipefs_notifier_register(struct notifier_block *);
 | 
				
			||||||
 | 
					extern void rpc_pipefs_notifier_unregister(struct notifier_block *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						RPC_PIPEFS_MOUNT,
 | 
				
			||||||
 | 
						RPC_PIPEFS_UMOUNT,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
 | 
				
			||||||
 | 
									      const unsigned char *dir_name);
 | 
				
			||||||
 | 
					extern void rpc_pipefs_init_net(struct net *net);
 | 
				
			||||||
 | 
					extern struct super_block *rpc_get_sb_net(const struct net *net);
 | 
				
			||||||
 | 
					extern void rpc_put_sb_net(const struct net *net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *,
 | 
					extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *,
 | 
				
			||||||
				       char __user *, size_t);
 | 
									       char __user *, size_t);
 | 
				
			||||||
extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
 | 
					extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_clnt;
 | 
					struct rpc_clnt;
 | 
				
			||||||
extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *);
 | 
					extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *);
 | 
				
			||||||
| 
						 | 
					@ -59,11 +83,13 @@ extern struct dentry *rpc_create_cache_dir(struct dentry *,
 | 
				
			||||||
					   struct cache_detail *);
 | 
										   struct cache_detail *);
 | 
				
			||||||
extern void rpc_remove_cache_dir(struct dentry *);
 | 
					extern void rpc_remove_cache_dir(struct dentry *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *,
 | 
					extern int rpc_rmdir(struct dentry *dentry);
 | 
				
			||||||
				 const struct rpc_pipe_ops *, int flags);
 | 
					
 | 
				
			||||||
 | 
					struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags);
 | 
				
			||||||
 | 
					void rpc_destroy_pipe_data(struct rpc_pipe *pipe);
 | 
				
			||||||
 | 
					extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *,
 | 
				
			||||||
 | 
										struct rpc_pipe *);
 | 
				
			||||||
extern int rpc_unlink(struct dentry *);
 | 
					extern int rpc_unlink(struct dentry *);
 | 
				
			||||||
extern struct vfsmount *rpc_get_mount(void);
 | 
					 | 
				
			||||||
extern void rpc_put_mount(void);
 | 
					 | 
				
			||||||
extern int register_rpc_pipefs(void);
 | 
					extern int register_rpc_pipefs(void);
 | 
				
			||||||
extern void unregister_rpc_pipefs(void);
 | 
					extern void unregister_rpc_pipefs(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,6 +103,7 @@ typedef void			(*rpc_action)(struct rpc_task *);
 | 
				
			||||||
struct rpc_call_ops {
 | 
					struct rpc_call_ops {
 | 
				
			||||||
	void (*rpc_call_prepare)(struct rpc_task *, void *);
 | 
						void (*rpc_call_prepare)(struct rpc_task *, void *);
 | 
				
			||||||
	void (*rpc_call_done)(struct rpc_task *, void *);
 | 
						void (*rpc_call_done)(struct rpc_task *, void *);
 | 
				
			||||||
 | 
						void (*rpc_count_stats)(struct rpc_task *, void *);
 | 
				
			||||||
	void (*rpc_release)(void *);
 | 
						void (*rpc_release)(void *);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -195,7 +196,7 @@ struct rpc_wait_queue {
 | 
				
			||||||
	unsigned char		nr;			/* # tasks remaining for cookie */
 | 
						unsigned char		nr;			/* # tasks remaining for cookie */
 | 
				
			||||||
	unsigned short		qlen;			/* total # tasks waiting in queue */
 | 
						unsigned short		qlen;			/* total # tasks waiting in queue */
 | 
				
			||||||
	struct rpc_timer	timer_list;
 | 
						struct rpc_timer	timer_list;
 | 
				
			||||||
#ifdef RPC_DEBUG
 | 
					#if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS)
 | 
				
			||||||
	const char *		name;
 | 
						const char *		name;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -235,6 +236,9 @@ void		rpc_wake_up_queued_task(struct rpc_wait_queue *,
 | 
				
			||||||
					struct rpc_task *);
 | 
										struct rpc_task *);
 | 
				
			||||||
void		rpc_wake_up(struct rpc_wait_queue *);
 | 
					void		rpc_wake_up(struct rpc_wait_queue *);
 | 
				
			||||||
struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
 | 
					struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
 | 
				
			||||||
 | 
					struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *,
 | 
				
			||||||
 | 
										bool (*)(struct rpc_task *, void *),
 | 
				
			||||||
 | 
										void *);
 | 
				
			||||||
void		rpc_wake_up_status(struct rpc_wait_queue *, int);
 | 
					void		rpc_wake_up_status(struct rpc_wait_queue *, int);
 | 
				
			||||||
int		rpc_queue_empty(struct rpc_wait_queue *);
 | 
					int		rpc_queue_empty(struct rpc_wait_queue *);
 | 
				
			||||||
void		rpc_delay(struct rpc_task *, unsigned long);
 | 
					void		rpc_delay(struct rpc_task *, unsigned long);
 | 
				
			||||||
| 
						 | 
					@ -244,7 +248,8 @@ int		rpciod_up(void);
 | 
				
			||||||
void		rpciod_down(void);
 | 
					void		rpciod_down(void);
 | 
				
			||||||
int		__rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *));
 | 
					int		__rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *));
 | 
				
			||||||
#ifdef RPC_DEBUG
 | 
					#ifdef RPC_DEBUG
 | 
				
			||||||
void		rpc_show_tasks(void);
 | 
					struct net;
 | 
				
			||||||
 | 
					void		rpc_show_tasks(struct net *);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
int		rpc_init_mempool(void);
 | 
					int		rpc_init_mempool(void);
 | 
				
			||||||
void		rpc_destroy_mempool(void);
 | 
					void		rpc_destroy_mempool(void);
 | 
				
			||||||
| 
						 | 
					@ -266,11 +271,22 @@ static inline int rpc_task_has_priority(struct rpc_task *task, unsigned char pri
 | 
				
			||||||
	return (task->tk_priority + RPC_PRIORITY_LOW == prio);
 | 
						return (task->tk_priority + RPC_PRIORITY_LOW == prio);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef RPC_DEBUG
 | 
					#if defined(RPC_DEBUG) || defined (RPC_TRACEPOINTS)
 | 
				
			||||||
static inline const char * rpc_qname(struct rpc_wait_queue *q)
 | 
					static inline const char * rpc_qname(const struct rpc_wait_queue *q)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return ((q && q->name) ? q->name : "unknown");
 | 
						return ((q && q->name) ? q->name : "unknown");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q,
 | 
				
			||||||
 | 
							const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						q->name = name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q,
 | 
				
			||||||
 | 
							const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _LINUX_SUNRPC_SCHED_H_ */
 | 
					#endif /* _LINUX_SUNRPC_SCHED_H_ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@
 | 
				
			||||||
#include <linux/proc_fs.h>
 | 
					#include <linux/proc_fs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpc_stat {
 | 
					struct rpc_stat {
 | 
				
			||||||
	struct rpc_program *	program;
 | 
						const struct rpc_program *program;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int		netcnt,
 | 
						unsigned int		netcnt,
 | 
				
			||||||
				netudpcnt,
 | 
									netudpcnt,
 | 
				
			||||||
| 
						 | 
					@ -58,24 +58,24 @@ void			rpc_modcount(struct inode *, int);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PROC_FS
 | 
					#ifdef CONFIG_PROC_FS
 | 
				
			||||||
struct proc_dir_entry *	rpc_proc_register(struct rpc_stat *);
 | 
					struct proc_dir_entry *	rpc_proc_register(struct net *,struct rpc_stat *);
 | 
				
			||||||
void			rpc_proc_unregister(const char *);
 | 
					void			rpc_proc_unregister(struct net *,const char *);
 | 
				
			||||||
void			rpc_proc_zero(struct rpc_program *);
 | 
					void			rpc_proc_zero(const struct rpc_program *);
 | 
				
			||||||
struct proc_dir_entry *	svc_proc_register(struct svc_stat *,
 | 
					struct proc_dir_entry *	svc_proc_register(struct net *, struct svc_stat *,
 | 
				
			||||||
					  const struct file_operations *);
 | 
										  const struct file_operations *);
 | 
				
			||||||
void			svc_proc_unregister(const char *);
 | 
					void			svc_proc_unregister(struct net *, const char *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void			svc_seq_show(struct seq_file *,
 | 
					void			svc_seq_show(struct seq_file *,
 | 
				
			||||||
				     const struct svc_stat *);
 | 
									     const struct svc_stat *);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; }
 | 
					static inline struct proc_dir_entry *rpc_proc_register(struct net *net, struct rpc_stat *s) { return NULL; }
 | 
				
			||||||
static inline void rpc_proc_unregister(const char *p) {}
 | 
					static inline void rpc_proc_unregister(struct net *net, const char *p) {}
 | 
				
			||||||
static inline void rpc_proc_zero(struct rpc_program *p) {}
 | 
					static inline void rpc_proc_zero(const struct rpc_program *p) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s,
 | 
					static inline struct proc_dir_entry *svc_proc_register(struct net *net, struct svc_stat *s,
 | 
				
			||||||
						       const struct file_operations *f) { return NULL; }
 | 
											       const struct file_operations *f) { return NULL; }
 | 
				
			||||||
static inline void svc_proc_unregister(const char *p) {}
 | 
					static inline void svc_proc_unregister(struct net *net, const char *p) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void svc_seq_show(struct seq_file *seq,
 | 
					static inline void svc_seq_show(struct seq_file *seq,
 | 
				
			||||||
				const struct svc_stat *st) {}
 | 
									const struct svc_stat *st) {}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,7 +84,8 @@ struct svc_serv {
 | 
				
			||||||
	unsigned int		sv_nrpools;	/* number of thread pools */
 | 
						unsigned int		sv_nrpools;	/* number of thread pools */
 | 
				
			||||||
	struct svc_pool *	sv_pools;	/* array of thread pools */
 | 
						struct svc_pool *	sv_pools;	/* array of thread pools */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void			(*sv_shutdown)(struct svc_serv *serv);
 | 
						void			(*sv_shutdown)(struct svc_serv *serv,
 | 
				
			||||||
 | 
										       struct net *net);
 | 
				
			||||||
						/* Callback to use when last thread
 | 
											/* Callback to use when last thread
 | 
				
			||||||
						 * exits.
 | 
											 * exits.
 | 
				
			||||||
						 */
 | 
											 */
 | 
				
			||||||
| 
						 | 
					@ -413,22 +414,24 @@ struct svc_procedure {
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Function prototypes.
 | 
					 * Function prototypes.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void svc_rpcb_cleanup(struct svc_serv *serv);
 | 
					int svc_rpcb_setup(struct svc_serv *serv, struct net *net);
 | 
				
			||||||
 | 
					void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
 | 
				
			||||||
struct svc_serv *svc_create(struct svc_program *, unsigned int,
 | 
					struct svc_serv *svc_create(struct svc_program *, unsigned int,
 | 
				
			||||||
			    void (*shutdown)(struct svc_serv *));
 | 
								    void (*shutdown)(struct svc_serv *, struct net *net));
 | 
				
			||||||
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
 | 
					struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
 | 
				
			||||||
					struct svc_pool *pool, int node);
 | 
										struct svc_pool *pool, int node);
 | 
				
			||||||
void		   svc_exit_thread(struct svc_rqst *);
 | 
					void		   svc_exit_thread(struct svc_rqst *);
 | 
				
			||||||
struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
 | 
					struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
 | 
				
			||||||
			void (*shutdown)(struct svc_serv *),
 | 
								void (*shutdown)(struct svc_serv *, struct net *net),
 | 
				
			||||||
			svc_thread_fn, struct module *);
 | 
								svc_thread_fn, struct module *);
 | 
				
			||||||
int		   svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 | 
					int		   svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 | 
				
			||||||
int		   svc_pool_stats_open(struct svc_serv *serv, struct file *file);
 | 
					int		   svc_pool_stats_open(struct svc_serv *serv, struct file *file);
 | 
				
			||||||
void		   svc_destroy(struct svc_serv *);
 | 
					void		   svc_destroy(struct svc_serv *);
 | 
				
			||||||
 | 
					void		   svc_shutdown_net(struct svc_serv *, struct net *);
 | 
				
			||||||
int		   svc_process(struct svc_rqst *);
 | 
					int		   svc_process(struct svc_rqst *);
 | 
				
			||||||
int		   bc_svc_process(struct svc_serv *, struct rpc_rqst *,
 | 
					int		   bc_svc_process(struct svc_serv *, struct rpc_rqst *,
 | 
				
			||||||
			struct svc_rqst *);
 | 
								struct svc_rqst *);
 | 
				
			||||||
int		   svc_register(const struct svc_serv *, const int,
 | 
					int		   svc_register(const struct svc_serv *, struct net *, const int,
 | 
				
			||||||
				const unsigned short, const unsigned short);
 | 
									const unsigned short, const unsigned short);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void		   svc_wake_up(struct svc_serv *);
 | 
					void		   svc_wake_up(struct svc_serv *);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,7 +121,8 @@ void	svc_close_xprt(struct svc_xprt *xprt);
 | 
				
			||||||
int	svc_port_is_privileged(struct sockaddr *sin);
 | 
					int	svc_port_is_privileged(struct sockaddr *sin);
 | 
				
			||||||
int	svc_print_xprts(char *buf, int maxlen);
 | 
					int	svc_print_xprts(char *buf, int maxlen);
 | 
				
			||||||
struct	svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
 | 
					struct	svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
 | 
				
			||||||
			const sa_family_t af, const unsigned short port);
 | 
								struct net *net, const sa_family_t af,
 | 
				
			||||||
 | 
								const unsigned short port);
 | 
				
			||||||
int	svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
 | 
					int	svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void svc_xprt_get(struct svc_xprt *xprt)
 | 
					static inline void svc_xprt_get(struct svc_xprt *xprt)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,6 +135,9 @@ extern void svcauth_unix_purge(void);
 | 
				
			||||||
extern void svcauth_unix_info_release(struct svc_xprt *xpt);
 | 
					extern void svcauth_unix_info_release(struct svc_xprt *xpt);
 | 
				
			||||||
extern int svcauth_unix_set_client(struct svc_rqst *rqstp);
 | 
					extern int svcauth_unix_set_client(struct svc_rqst *rqstp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int unix_gid_cache_create(struct net *net);
 | 
				
			||||||
 | 
					extern void unix_gid_cache_destroy(struct net *net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline unsigned long hash_str(char *name, int bits)
 | 
					static inline unsigned long hash_str(char *name, int bits)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long hash = 0;
 | 
						unsigned long hash = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gss_svc_init(void);
 | 
					int gss_svc_init(void);
 | 
				
			||||||
void gss_svc_shutdown(void);
 | 
					void gss_svc_shutdown(void);
 | 
				
			||||||
 | 
					int gss_svc_init_net(struct net *net);
 | 
				
			||||||
 | 
					void gss_svc_shutdown_net(struct net *net);
 | 
				
			||||||
int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
 | 
					int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
 | 
				
			||||||
u32 svcauth_gss_flavor(struct auth_domain *dom);
 | 
					u32 svcauth_gss_flavor(struct auth_domain *dom);
 | 
				
			||||||
char *svc_gss_principal(struct svc_rqst *);
 | 
					char *svc_gss_principal(struct svc_rqst *);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,7 @@ struct svc_sock {
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Function prototypes.
 | 
					 * Function prototypes.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void		svc_close_all(struct svc_serv *);
 | 
					void		svc_close_net(struct svc_serv *, struct net *);
 | 
				
			||||||
int		svc_recv(struct svc_rqst *, long);
 | 
					int		svc_recv(struct svc_rqst *, long);
 | 
				
			||||||
int		svc_send(struct svc_rqst *);
 | 
					int		svc_send(struct svc_rqst *);
 | 
				
			||||||
void		svc_drop(struct svc_rqst *);
 | 
					void		svc_drop(struct svc_rqst *);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,8 +21,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RPC_MIN_SLOT_TABLE	(2U)
 | 
					#define RPC_MIN_SLOT_TABLE	(2U)
 | 
				
			||||||
#define RPC_DEF_SLOT_TABLE	(16U)
 | 
					#define RPC_DEF_SLOT_TABLE	(16U)
 | 
				
			||||||
#define RPC_MAX_SLOT_TABLE	(128U)
 | 
					 | 
				
			||||||
#define RPC_MAX_SLOT_TABLE_LIMIT	(65536U)
 | 
					#define RPC_MAX_SLOT_TABLE_LIMIT	(65536U)
 | 
				
			||||||
 | 
					#define RPC_MAX_SLOT_TABLE	RPC_MAX_SLOT_TABLE_LIMIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This describes a timeout strategy
 | 
					 * This describes a timeout strategy
 | 
				
			||||||
| 
						 | 
					@ -219,13 +219,17 @@ struct rpc_xprt {
 | 
				
			||||||
					connect_time,	/* jiffies waiting for connect */
 | 
										connect_time,	/* jiffies waiting for connect */
 | 
				
			||||||
					sends,		/* how many complete requests */
 | 
										sends,		/* how many complete requests */
 | 
				
			||||||
					recvs,		/* how many complete requests */
 | 
										recvs,		/* how many complete requests */
 | 
				
			||||||
					bad_xids;	/* lookup_rqst didn't find XID */
 | 
										bad_xids,	/* lookup_rqst didn't find XID */
 | 
				
			||||||
 | 
										max_slots;	/* max rpc_slots used */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unsigned long long	req_u,		/* average requests on the wire */
 | 
							unsigned long long	req_u,		/* average requests on the wire */
 | 
				
			||||||
					bklog_u;	/* backlog queue utilization */
 | 
										bklog_u,	/* backlog queue utilization */
 | 
				
			||||||
 | 
										sending_u,	/* send q utilization */
 | 
				
			||||||
 | 
										pending_u;	/* pend q utilization */
 | 
				
			||||||
	} stat;
 | 
						} stat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct net		*xprt_net;
 | 
						struct net		*xprt_net;
 | 
				
			||||||
 | 
						const char		*servername;
 | 
				
			||||||
	const char		*address_strings[RPC_DISPLAY_MAX];
 | 
						const char		*address_strings[RPC_DISPLAY_MAX];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -255,6 +259,7 @@ struct xprt_create {
 | 
				
			||||||
	struct sockaddr *	srcaddr;	/* optional local address */
 | 
						struct sockaddr *	srcaddr;	/* optional local address */
 | 
				
			||||||
	struct sockaddr *	dstaddr;	/* remote peer address */
 | 
						struct sockaddr *	dstaddr;	/* remote peer address */
 | 
				
			||||||
	size_t			addrlen;
 | 
						size_t			addrlen;
 | 
				
			||||||
 | 
						const char		*servername;
 | 
				
			||||||
	struct svc_xprt		*bc_xprt;	/* NFSv4.1 backchannel */
 | 
						struct svc_xprt		*bc_xprt;	/* NFSv4.1 backchannel */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,18 +12,6 @@
 | 
				
			||||||
int		init_socket_xprt(void);
 | 
					int		init_socket_xprt(void);
 | 
				
			||||||
void		cleanup_socket_xprt(void);
 | 
					void		cleanup_socket_xprt(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * RPC slot table sizes for UDP, TCP transports
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
extern unsigned int xprt_udp_slot_table_entries;
 | 
					 | 
				
			||||||
extern unsigned int xprt_tcp_slot_table_entries;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Parameters for choosing a free port
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
extern unsigned int xprt_min_resvport;
 | 
					 | 
				
			||||||
extern unsigned int xprt_max_resvport;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define RPC_MIN_RESVPORT	(1U)
 | 
					#define RPC_MIN_RESVPORT	(1U)
 | 
				
			||||||
#define RPC_MAX_RESVPORT	(65535U)
 | 
					#define RPC_MAX_RESVPORT	(65535U)
 | 
				
			||||||
#define RPC_DEF_MIN_RESVPORT	(665U)
 | 
					#define RPC_DEF_MIN_RESVPORT	(665U)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										177
									
								
								include/trace/events/sunrpc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								include/trace/events/sunrpc.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,177 @@
 | 
				
			||||||
 | 
					#undef TRACE_SYSTEM
 | 
				
			||||||
 | 
					#define TRACE_SYSTEM sunrpc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(_TRACE_SUNRPC_H) || defined(TRACE_HEADER_MULTI_READ)
 | 
				
			||||||
 | 
					#define _TRACE_SUNRPC_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/sunrpc/sched.h>
 | 
				
			||||||
 | 
					#include <linux/sunrpc/clnt.h>
 | 
				
			||||||
 | 
					#include <linux/tracepoint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DECLARE_EVENT_CLASS(rpc_task_status,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_PROTO(struct rpc_task *task),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(task),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_STRUCT__entry(
 | 
				
			||||||
 | 
							__field(const struct rpc_task *, task)
 | 
				
			||||||
 | 
							__field(const struct rpc_clnt *, clnt)
 | 
				
			||||||
 | 
							__field(int, status)
 | 
				
			||||||
 | 
						),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_fast_assign(
 | 
				
			||||||
 | 
							__entry->task = task;
 | 
				
			||||||
 | 
							__entry->clnt = task->tk_client;
 | 
				
			||||||
 | 
							__entry->status = task->tk_status;
 | 
				
			||||||
 | 
						),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_EVENT(rpc_task_status, rpc_call_status,
 | 
				
			||||||
 | 
						TP_PROTO(struct rpc_task *task),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(task)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_EVENT(rpc_task_status, rpc_bind_status,
 | 
				
			||||||
 | 
						TP_PROTO(struct rpc_task *task),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(task)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TRACE_EVENT(rpc_connect_status,
 | 
				
			||||||
 | 
						TP_PROTO(struct rpc_task *task, int status),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(task, status),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_STRUCT__entry(
 | 
				
			||||||
 | 
							__field(const struct rpc_task *, task)
 | 
				
			||||||
 | 
							__field(const struct rpc_clnt *, clnt)
 | 
				
			||||||
 | 
							__field(int, status)
 | 
				
			||||||
 | 
						),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_fast_assign(
 | 
				
			||||||
 | 
							__entry->task = task;
 | 
				
			||||||
 | 
							__entry->clnt = task->tk_client;
 | 
				
			||||||
 | 
							__entry->status = status;
 | 
				
			||||||
 | 
						),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DECLARE_EVENT_CLASS(rpc_task_running,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(clnt, task, action),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_STRUCT__entry(
 | 
				
			||||||
 | 
							__field(const struct rpc_clnt *, clnt)
 | 
				
			||||||
 | 
							__field(const struct rpc_task *, task)
 | 
				
			||||||
 | 
							__field(const void *, action)
 | 
				
			||||||
 | 
							__field(unsigned long, runstate)
 | 
				
			||||||
 | 
							__field(int, status)
 | 
				
			||||||
 | 
							__field(unsigned short, flags)
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_fast_assign(
 | 
				
			||||||
 | 
							__entry->clnt = clnt;
 | 
				
			||||||
 | 
							__entry->task = task;
 | 
				
			||||||
 | 
							__entry->action = action;
 | 
				
			||||||
 | 
							__entry->runstate = task->tk_runstate;
 | 
				
			||||||
 | 
							__entry->status = task->tk_status;
 | 
				
			||||||
 | 
							__entry->flags = task->tk_flags;
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d action=%pf",
 | 
				
			||||||
 | 
							__entry->task,
 | 
				
			||||||
 | 
							__entry->clnt,
 | 
				
			||||||
 | 
							__entry->flags,
 | 
				
			||||||
 | 
							__entry->runstate,
 | 
				
			||||||
 | 
							__entry->status,
 | 
				
			||||||
 | 
							__entry->action
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_EVENT(rpc_task_running, rpc_task_begin,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(clnt, task, action)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_EVENT(rpc_task_running, rpc_task_run_action,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(clnt, task, action)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_EVENT(rpc_task_running, rpc_task_complete,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(clnt, task, action)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DECLARE_EVENT_CLASS(rpc_task_queued,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(clnt, task, q),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_STRUCT__entry(
 | 
				
			||||||
 | 
							__field(const struct rpc_clnt *, clnt)
 | 
				
			||||||
 | 
							__field(const struct rpc_task *, task)
 | 
				
			||||||
 | 
							__field(unsigned long, timeout)
 | 
				
			||||||
 | 
							__field(unsigned long, runstate)
 | 
				
			||||||
 | 
							__field(int, status)
 | 
				
			||||||
 | 
							__field(unsigned short, flags)
 | 
				
			||||||
 | 
							__string(q_name, rpc_qname(q))
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_fast_assign(
 | 
				
			||||||
 | 
							__entry->clnt = clnt;
 | 
				
			||||||
 | 
							__entry->task = task;
 | 
				
			||||||
 | 
							__entry->timeout = task->tk_timeout;
 | 
				
			||||||
 | 
							__entry->runstate = task->tk_runstate;
 | 
				
			||||||
 | 
							__entry->status = task->tk_status;
 | 
				
			||||||
 | 
							__entry->flags = task->tk_flags;
 | 
				
			||||||
 | 
							__assign_str(q_name, rpc_qname(q));
 | 
				
			||||||
 | 
							),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d timeout=%lu queue=%s",
 | 
				
			||||||
 | 
							__entry->task,
 | 
				
			||||||
 | 
							__entry->clnt,
 | 
				
			||||||
 | 
							__entry->flags,
 | 
				
			||||||
 | 
							__entry->runstate,
 | 
				
			||||||
 | 
							__entry->status,
 | 
				
			||||||
 | 
							__entry->timeout,
 | 
				
			||||||
 | 
							__get_str(q_name)
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_EVENT(rpc_task_queued, rpc_task_sleep,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(clnt, task, q)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_EVENT(rpc_task_queued, rpc_task_wakeup,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TP_ARGS(clnt, task, q)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _TRACE_SUNRPC_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <trace/define_trace.h>
 | 
				
			||||||
| 
						 | 
					@ -39,3 +39,16 @@ config RPCSEC_GSS_KRB5
 | 
				
			||||||
	  Kerberos support should be installed.
 | 
						  Kerberos support should be installed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  If unsure, say Y.
 | 
						  If unsure, say Y.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SUNRPC_DEBUG
 | 
				
			||||||
 | 
						bool "RPC: Enable dprintk debugging"
 | 
				
			||||||
 | 
						depends on SUNRPC && SYSCTL
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  This option enables a sysctl-based debugging interface
 | 
				
			||||||
 | 
						  that is be used by the 'rpcdebug' utility to turn on or off
 | 
				
			||||||
 | 
						  logging of different aspects of the kernel RPC activity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  Disabling this option will make your kernel slightly smaller,
 | 
				
			||||||
 | 
						  but makes troubleshooting NFS issues significantly harder.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  If unsure, say Y.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue