diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-23 11:53:47 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-23 11:53:47 -0400 |
| commit | f63d395d47f37a4fe771e6d4b1db9d2cdae5ffc5 (patch) | |
| tree | 3448a14ae965802adb963762cadeb9989ce4caa2 | |
| parent | 643ac9fc5429e85b8b7f534544b80bcc4f34c367 (diff) | |
| parent | 5a7c9eec9fde1da0e3adf0a4ddb64ff2a324a492 (diff) | |
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
...
127 files changed, 5217 insertions, 2987 deletions
diff --git a/Documentation/filesystems/nfs/idmapper.txt b/Documentation/filesystems/nfs/idmapper.txt index 120fd3cf7fd9..fe03d10bb79a 100644 --- a/Documentation/filesystems/nfs/idmapper.txt +++ b/Documentation/filesystems/nfs/idmapper.txt | |||
| @@ -4,13 +4,21 @@ ID Mapper | |||
| 4 | ========= | 4 | ========= |
| 5 | Id mapper is used by NFS to translate user and group ids into names, and to | 5 | Id mapper is used by NFS to translate user and group ids into names, and to |
| 6 | translate user and group names into ids. Part of this translation involves | 6 | translate user and group names into ids. Part of this translation involves |
| 7 | performing an upcall to userspace to request the information. Id mapper will | 7 | performing an upcall to userspace to request the information. There are two |
| 8 | user request-key to perform this upcall and cache the result. The program | 8 | ways NFS could obtain this information: placing a call to /sbin/request-key |
| 9 | /usr/sbin/nfs.idmap should be called by request-key, and will perform the | 9 | or by placing a call to the rpc.idmap daemon. |
| 10 | translation and initialize a key with the resulting information. | 10 | |
| 11 | NFS will attempt to call /sbin/request-key first. If this succeeds, the | ||
| 12 | result will be cached using the generic request-key cache. This call should | ||
| 13 | only fail if /etc/request-key.conf is not configured for the id_resolver key | ||
| 14 | type, see the "Configuring" section below if you wish to use the request-key | ||
| 15 | method. | ||
| 16 | |||
| 17 | If the call to /sbin/request-key fails (if /etc/request-key.conf is not | ||
| 18 | configured with the id_resolver key type), then the idmapper will ask the | ||
| 19 | legacy rpc.idmap daemon for the id mapping. This result will be stored | ||
| 20 | in a custom NFS idmap cache. | ||
| 11 | 21 | ||
| 12 | NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this | ||
| 13 | feature. | ||
| 14 | 22 | ||
| 15 | =========== | 23 | =========== |
| 16 | Configuring | 24 | Configuring |
diff --git a/Documentation/filesystems/nfs/pnfs.txt b/Documentation/filesystems/nfs/pnfs.txt index 983e14abe7e9..c7919c6e3bea 100644 --- a/Documentation/filesystems/nfs/pnfs.txt +++ b/Documentation/filesystems/nfs/pnfs.txt | |||
| @@ -53,3 +53,57 @@ lseg maintains an extra reference corresponding to the NFS_LSEG_VALID | |||
| 53 | bit which holds it in the pnfs_layout_hdr's list. When the final lseg | 53 | bit which holds it in the pnfs_layout_hdr's list. When the final lseg |
| 54 | is removed from the pnfs_layout_hdr's list, the NFS_LAYOUT_DESTROYED | 54 | is removed from the pnfs_layout_hdr's list, the NFS_LAYOUT_DESTROYED |
| 55 | bit is set, preventing any new lsegs from being added. | 55 | bit is set, preventing any new lsegs from being added. |
| 56 | |||
| 57 | layout drivers | ||
| 58 | -------------- | ||
| 59 | |||
| 60 | PNFS utilizes what is called layout drivers. The STD defines 3 basic | ||
| 61 | layout types: "files" "objects" and "blocks". For each of these types | ||
| 62 | there is a layout-driver with a common function-vectors table which | ||
| 63 | are called by the nfs-client pnfs-core to implement the different layout | ||
| 64 | types. | ||
| 65 | |||
| 66 | Files-layout-driver code is in: fs/nfs/nfs4filelayout.c && nfs4filelayoutdev.c | ||
| 67 | Objects-layout-deriver code is in: fs/nfs/objlayout/.. directory | ||
| 68 | Blocks-layout-deriver code is in: fs/nfs/blocklayout/.. directory | ||
| 69 | |||
| 70 | objects-layout setup | ||
| 71 | -------------------- | ||
| 72 | |||
| 73 | As part of the full STD implementation the objlayoutdriver.ko needs, at times, | ||
| 74 | to automatically login to yet undiscovered iscsi/osd devices. For this the | ||
| 75 | driver makes up-calles to a user-mode script called *osd_login* | ||
| 76 | |||
| 77 | The path_name of the script to use is by default: | ||
| 78 | /sbin/osd_login. | ||
| 79 | This name can be overridden by the Kernel module parameter: | ||
| 80 | objlayoutdriver.osd_login_prog | ||
| 81 | |||
| 82 | If Kernel does not find the osd_login_prog path it will zero it out | ||
| 83 | and will not attempt farther logins. An admin can then write new value | ||
| 84 | to the objlayoutdriver.osd_login_prog Kernel parameter to re-enable it. | ||
| 85 | |||
| 86 | The /sbin/osd_login is part of the nfs-utils package, and should usually | ||
| 87 | be installed on distributions that support this Kernel version. | ||
| 88 | |||
| 89 | The API to the login script is as follows: | ||
| 90 | Usage: $0 -u <URI> -o <OSDNAME> -s <SYSTEMID> | ||
| 91 | Options: | ||
| 92 | -u target uri e.g. iscsi://<ip>:<port> | ||
| 93 | (allways exists) | ||
| 94 | (More protocols can be defined in the future. | ||
| 95 | The client does not interpret this string it is | ||
| 96 | passed unchanged as recieved from the Server) | ||
| 97 | -o osdname of the requested target OSD | ||
| 98 | (Might be empty) | ||
| 99 | (A string which denotes the OSD name, there is a | ||
| 100 | limit of 64 chars on this string) | ||
| 101 | -s systemid of the requested target OSD | ||
| 102 | (Might be empty) | ||
| 103 | (This string, if not empty is always an hex | ||
| 104 | representation of the 20 bytes osd_system_id) | ||
| 105 | |||
| 106 | blocks-layout setup | ||
| 107 | ------------------- | ||
| 108 | |||
| 109 | TODO: Document the setup needs of the blocks layout driver | ||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 247dcfd62034..7c33ef8a1ba9 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -1672,6 +1672,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 1672 | of returning the full 64-bit number. | 1672 | of returning the full 64-bit number. |
| 1673 | The default is to return 64-bit inode numbers. | 1673 | The default is to return 64-bit inode numbers. |
| 1674 | 1674 | ||
| 1675 | nfs.max_session_slots= | ||
| 1676 | [NFSv4.1] Sets the maximum number of session slots | ||
| 1677 | the client will attempt to negotiate with the server. | ||
| 1678 | This limits the number of simultaneous RPC requests | ||
| 1679 | that the client can send to the NFSv4.1 server. | ||
| 1680 | Note that there is little point in setting this | ||
| 1681 | value higher than the max_tcp_slot_table_limit. | ||
| 1682 | |||
| 1675 | nfs.nfs4_disable_idmapping= | 1683 | nfs.nfs4_disable_idmapping= |
| 1676 | [NFSv4] When set to the default of '1', this option | 1684 | [NFSv4] When set to the default of '1', this option |
| 1677 | ensures that both the RPC level authentication | 1685 | ensures that both the RPC level authentication |
| @@ -1685,6 +1693,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 1685 | back to using the idmapper. | 1693 | back to using the idmapper. |
| 1686 | To turn off this behaviour, set the value to '0'. | 1694 | To turn off this behaviour, set the value to '0'. |
| 1687 | 1695 | ||
| 1696 | nfs.send_implementation_id = | ||
| 1697 | [NFSv4.1] Send client implementation identification | ||
| 1698 | information in exchange_id requests. | ||
| 1699 | If zero, no implementation identification information | ||
| 1700 | will be sent. | ||
| 1701 | The default is to send the implementation identification | ||
| 1702 | information. | ||
| 1703 | |||
| 1704 | |||
| 1705 | objlayoutdriver.osd_login_prog= | ||
| 1706 | [NFS] [OBJLAYOUT] sets the pathname to the program which | ||
| 1707 | is used to automatically discover and login into new | ||
| 1708 | osd-targets. Please see: | ||
| 1709 | Documentation/filesystems/pnfs.txt for more explanations | ||
| 1710 | |||
| 1688 | nmi_debug= [KNL,AVR32,SH] Specify one or more actions to take | 1711 | nmi_debug= [KNL,AVR32,SH] Specify one or more actions to take |
| 1689 | when a NMI is triggered. | 1712 | when a NMI is triggered. |
| 1690 | Format: [state][,regs][,debounce][,die] | 1713 | Format: [state][,regs][,debounce][,die] |
diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c index f848b52c67b1..3ddcbb1c0a43 100644 --- a/fs/lockd/clnt4xdr.c +++ b/fs/lockd/clnt4xdr.c | |||
| @@ -598,7 +598,7 @@ static struct rpc_procinfo nlm4_procedures[] = { | |||
| 598 | PROC(GRANTED_RES, res, norep), | 598 | PROC(GRANTED_RES, res, norep), |
| 599 | }; | 599 | }; |
| 600 | 600 | ||
| 601 | struct rpc_version nlm_version4 = { | 601 | const struct rpc_version nlm_version4 = { |
| 602 | .number = 4, | 602 | .number = 4, |
| 603 | .nrprocs = ARRAY_SIZE(nlm4_procedures), | 603 | .nrprocs = ARRAY_SIZE(nlm4_procedures), |
| 604 | .procs = nlm4_procedures, | 604 | .procs = nlm4_procedures, |
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 8d4ea8351e3d..ba1dc2eebd1e 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
| @@ -62,7 +62,8 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) | |||
| 62 | 62 | ||
| 63 | host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen, | 63 | host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen, |
| 64 | nlm_init->protocol, nlm_version, | 64 | nlm_init->protocol, nlm_version, |
| 65 | nlm_init->hostname, nlm_init->noresvport); | 65 | nlm_init->hostname, nlm_init->noresvport, |
| 66 | nlm_init->net); | ||
| 66 | if (host == NULL) { | 67 | if (host == NULL) { |
| 67 | lockd_down(); | 68 | lockd_down(); |
| 68 | return ERR_PTR(-ENOLCK); | 69 | return ERR_PTR(-ENOLCK); |
diff --git a/fs/lockd/clntxdr.c b/fs/lockd/clntxdr.c index 180ac34feb9a..3d35e3e80c1c 100644 --- a/fs/lockd/clntxdr.c +++ b/fs/lockd/clntxdr.c | |||
| @@ -596,19 +596,19 @@ static struct rpc_procinfo nlm_procedures[] = { | |||
| 596 | PROC(GRANTED_RES, res, norep), | 596 | PROC(GRANTED_RES, res, norep), |
| 597 | }; | 597 | }; |
| 598 | 598 | ||
| 599 | static struct rpc_version nlm_version1 = { | 599 | static const struct rpc_version nlm_version1 = { |
| 600 | .number = 1, | 600 | .number = 1, |
| 601 | .nrprocs = ARRAY_SIZE(nlm_procedures), | 601 | .nrprocs = ARRAY_SIZE(nlm_procedures), |
| 602 | .procs = nlm_procedures, | 602 | .procs = nlm_procedures, |
| 603 | }; | 603 | }; |
| 604 | 604 | ||
| 605 | static struct rpc_version nlm_version3 = { | 605 | static const struct rpc_version nlm_version3 = { |
| 606 | .number = 3, | 606 | .number = 3, |
| 607 | .nrprocs = ARRAY_SIZE(nlm_procedures), | 607 | .nrprocs = ARRAY_SIZE(nlm_procedures), |
| 608 | .procs = nlm_procedures, | 608 | .procs = nlm_procedures, |
| 609 | }; | 609 | }; |
| 610 | 610 | ||
| 611 | static struct rpc_version *nlm_versions[] = { | 611 | static const struct rpc_version *nlm_versions[] = { |
| 612 | [1] = &nlm_version1, | 612 | [1] = &nlm_version1, |
| 613 | [3] = &nlm_version3, | 613 | [3] = &nlm_version3, |
| 614 | #ifdef CONFIG_LOCKD_V4 | 614 | #ifdef CONFIG_LOCKD_V4 |
| @@ -618,7 +618,7 @@ static struct rpc_version *nlm_versions[] = { | |||
| 618 | 618 | ||
| 619 | static struct rpc_stat nlm_rpc_stats; | 619 | static struct rpc_stat nlm_rpc_stats; |
| 620 | 620 | ||
| 621 | struct rpc_program nlm_program = { | 621 | const struct rpc_program nlm_program = { |
| 622 | .name = "lockd", | 622 | .name = "lockd", |
| 623 | .number = NLM_PROGRAM, | 623 | .number = NLM_PROGRAM, |
| 624 | .nrvers = ARRAY_SIZE(nlm_versions), | 624 | .nrvers = ARRAY_SIZE(nlm_versions), |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 6f29836ec0cb..eb75ca7c2d6e 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include <linux/lockd/lockd.h> | 17 | #include <linux/lockd/lockd.h> |
| 18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
| 19 | 19 | ||
| 20 | #include <linux/sunrpc/svc_xprt.h> | ||
| 21 | |||
| 20 | #include <net/ipv6.h> | 22 | #include <net/ipv6.h> |
| 21 | 23 | ||
| 22 | #define NLMDBG_FACILITY NLMDBG_HOSTCACHE | 24 | #define NLMDBG_FACILITY NLMDBG_HOSTCACHE |
| @@ -54,6 +56,7 @@ struct nlm_lookup_host_info { | |||
| 54 | const char *hostname; /* remote's hostname */ | 56 | const char *hostname; /* remote's hostname */ |
| 55 | const size_t hostname_len; /* it's length */ | 57 | const size_t hostname_len; /* it's length */ |
| 56 | const int noresvport; /* use non-priv port */ | 58 | const int noresvport; /* use non-priv port */ |
| 59 | struct net *net; /* network namespace to bind */ | ||
| 57 | }; | 60 | }; |
| 58 | 61 | ||
| 59 | /* | 62 | /* |
| @@ -155,6 +158,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, | |||
| 155 | INIT_LIST_HEAD(&host->h_reclaim); | 158 | INIT_LIST_HEAD(&host->h_reclaim); |
| 156 | host->h_nsmhandle = nsm; | 159 | host->h_nsmhandle = nsm; |
| 157 | host->h_addrbuf = nsm->sm_addrbuf; | 160 | host->h_addrbuf = nsm->sm_addrbuf; |
| 161 | host->net = ni->net; | ||
| 158 | 162 | ||
| 159 | out: | 163 | out: |
| 160 | return host; | 164 | return host; |
| @@ -206,7 +210,8 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
| 206 | const unsigned short protocol, | 210 | const unsigned short protocol, |
| 207 | const u32 version, | 211 | const u32 version, |
| 208 | const char *hostname, | 212 | const char *hostname, |
| 209 | int noresvport) | 213 | int noresvport, |
| 214 | struct net *net) | ||
| 210 | { | 215 | { |
| 211 | struct nlm_lookup_host_info ni = { | 216 | struct nlm_lookup_host_info ni = { |
| 212 | .server = 0, | 217 | .server = 0, |
| @@ -217,6 +222,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
| 217 | .hostname = hostname, | 222 | .hostname = hostname, |
| 218 | .hostname_len = strlen(hostname), | 223 | .hostname_len = strlen(hostname), |
| 219 | .noresvport = noresvport, | 224 | .noresvport = noresvport, |
| 225 | .net = net, | ||
| 220 | }; | 226 | }; |
| 221 | struct hlist_head *chain; | 227 | struct hlist_head *chain; |
| 222 | struct hlist_node *pos; | 228 | struct hlist_node *pos; |
| @@ -231,6 +237,8 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
| 231 | 237 | ||
| 232 | chain = &nlm_client_hosts[nlm_hash_address(sap)]; | 238 | chain = &nlm_client_hosts[nlm_hash_address(sap)]; |
| 233 | hlist_for_each_entry(host, pos, chain, h_hash) { | 239 | hlist_for_each_entry(host, pos, chain, h_hash) { |
| 240 | if (host->net != net) | ||
| 241 | continue; | ||
| 234 | if (!rpc_cmp_addr(nlm_addr(host), sap)) | 242 | if (!rpc_cmp_addr(nlm_addr(host), sap)) |
| 235 | continue; | 243 | continue; |
| 236 | 244 | ||
| @@ -318,6 +326,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | |||
| 318 | struct nsm_handle *nsm = NULL; | 326 | struct nsm_handle *nsm = NULL; |
| 319 | struct sockaddr *src_sap = svc_daddr(rqstp); | 327 | struct sockaddr *src_sap = svc_daddr(rqstp); |
| 320 | size_t src_len = rqstp->rq_daddrlen; | 328 | size_t src_len = rqstp->rq_daddrlen; |
| 329 | struct net *net = rqstp->rq_xprt->xpt_net; | ||
| 321 | struct nlm_lookup_host_info ni = { | 330 | struct nlm_lookup_host_info ni = { |
| 322 | .server = 1, | 331 | .server = 1, |
| 323 | .sap = svc_addr(rqstp), | 332 | .sap = svc_addr(rqstp), |
| @@ -326,6 +335,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | |||
| 326 | .version = rqstp->rq_vers, | 335 | .version = rqstp->rq_vers, |
| 327 | .hostname = hostname, | 336 | .hostname = hostname, |
| 328 | .hostname_len = hostname_len, | 337 | .hostname_len = hostname_len, |
| 338 | .net = net, | ||
| 329 | }; | 339 | }; |
| 330 | 340 | ||
| 331 | dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__, | 341 | 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, | |||
| 339 | 349 | ||
| 340 | chain = &nlm_server_hosts[nlm_hash_address(ni.sap)]; | 350 | chain = &nlm_server_hosts[nlm_hash_address(ni.sap)]; |
| 341 | hlist_for_each_entry(host, pos, chain, h_hash) { | 351 | hlist_for_each_entry(host, pos, chain, h_hash) { |
| 352 | if (host->net != net) | ||
| 353 | continue; | ||
| 342 | if (!rpc_cmp_addr(nlm_addr(host), ni.sap)) | 354 | if (!rpc_cmp_addr(nlm_addr(host), ni.sap)) |
| 343 | continue; | 355 | continue; |
| 344 | 356 | ||
| @@ -431,7 +443,7 @@ nlm_bind_host(struct nlm_host *host) | |||
| 431 | .to_retries = 5U, | 443 | .to_retries = 5U, |
| 432 | }; | 444 | }; |
| 433 | struct rpc_create_args args = { | 445 | struct rpc_create_args args = { |
| 434 | .net = &init_net, | 446 | .net = host->net, |
| 435 | .protocol = host->h_proto, | 447 | .protocol = host->h_proto, |
| 436 | .address = nlm_addr(host), | 448 | .address = nlm_addr(host), |
| 437 | .addrsize = host->h_addrlen, | 449 | .addrsize = host->h_addrlen, |
| @@ -553,12 +565,8 @@ void nlm_host_rebooted(const struct nlm_reboot *info) | |||
| 553 | nsm_release(nsm); | 565 | nsm_release(nsm); |
| 554 | } | 566 | } |
| 555 | 567 | ||
| 556 | /* | ||
| 557 | * Shut down the hosts module. | ||
| 558 | * Note that this routine is called only at server shutdown time. | ||
| 559 | */ | ||
| 560 | void | 568 | void |
| 561 | nlm_shutdown_hosts(void) | 569 | nlm_shutdown_hosts_net(struct net *net) |
| 562 | { | 570 | { |
| 563 | struct hlist_head *chain; | 571 | struct hlist_head *chain; |
| 564 | struct hlist_node *pos; | 572 | struct hlist_node *pos; |
| @@ -570,6 +578,8 @@ nlm_shutdown_hosts(void) | |||
| 570 | /* First, make all hosts eligible for gc */ | 578 | /* First, make all hosts eligible for gc */ |
| 571 | dprintk("lockd: nuking all hosts...\n"); | 579 | dprintk("lockd: nuking all hosts...\n"); |
| 572 | for_each_host(host, pos, chain, nlm_server_hosts) { | 580 | for_each_host(host, pos, chain, nlm_server_hosts) { |
| 581 | if (net && host->net != net) | ||
| 582 | continue; | ||
| 573 | host->h_expires = jiffies - 1; | 583 | host->h_expires = jiffies - 1; |
| 574 | if (host->h_rpcclnt) { | 584 | if (host->h_rpcclnt) { |
| 575 | rpc_shutdown_client(host->h_rpcclnt); | 585 | rpc_shutdown_client(host->h_rpcclnt); |
| @@ -580,15 +590,29 @@ nlm_shutdown_hosts(void) | |||
| 580 | /* Then, perform a garbage collection pass */ | 590 | /* Then, perform a garbage collection pass */ |
| 581 | nlm_gc_hosts(); | 591 | nlm_gc_hosts(); |
| 582 | mutex_unlock(&nlm_host_mutex); | 592 | mutex_unlock(&nlm_host_mutex); |
| 593 | } | ||
| 594 | |||
| 595 | /* | ||
| 596 | * Shut down the hosts module. | ||
| 597 | * Note that this routine is called only at server shutdown time. | ||
| 598 | */ | ||
| 599 | void | ||
| 600 | nlm_shutdown_hosts(void) | ||
| 601 | { | ||
| 602 | struct hlist_head *chain; | ||
| 603 | struct hlist_node *pos; | ||
| 604 | struct nlm_host *host; | ||
| 605 | |||
| 606 | nlm_shutdown_hosts_net(NULL); | ||
| 583 | 607 | ||
| 584 | /* complain if any hosts are left */ | 608 | /* complain if any hosts are left */ |
| 585 | if (nrhosts != 0) { | 609 | if (nrhosts != 0) { |
| 586 | printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); | 610 | printk(KERN_WARNING "lockd: couldn't shutdown host module!\n"); |
| 587 | dprintk("lockd: %lu hosts left:\n", nrhosts); | 611 | dprintk("lockd: %lu hosts left:\n", nrhosts); |
| 588 | for_each_host(host, pos, chain, nlm_server_hosts) { | 612 | for_each_host(host, pos, chain, nlm_server_hosts) { |
| 589 | dprintk(" %s (cnt %d use %d exp %ld)\n", | 613 | dprintk(" %s (cnt %d use %d exp %ld net %p)\n", |
| 590 | host->h_name, atomic_read(&host->h_count), | 614 | host->h_name, atomic_read(&host->h_count), |
| 591 | host->h_inuse, host->h_expires); | 615 | host->h_inuse, host->h_expires, host->net); |
| 592 | } | 616 | } |
| 593 | } | 617 | } |
| 594 | } | 618 | } |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 65ba36b80a9e..7ef14b3c5bee 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
| @@ -47,7 +47,7 @@ struct nsm_res { | |||
| 47 | u32 state; | 47 | u32 state; |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| 50 | static struct rpc_program nsm_program; | 50 | static const struct rpc_program nsm_program; |
| 51 | static LIST_HEAD(nsm_handles); | 51 | static LIST_HEAD(nsm_handles); |
| 52 | static DEFINE_SPINLOCK(nsm_lock); | 52 | static DEFINE_SPINLOCK(nsm_lock); |
| 53 | 53 | ||
| @@ -62,14 +62,14 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) | |||
| 62 | return (struct sockaddr *)&nsm->sm_addr; | 62 | return (struct sockaddr *)&nsm->sm_addr; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static struct rpc_clnt *nsm_create(void) | 65 | static struct rpc_clnt *nsm_create(struct net *net) |
| 66 | { | 66 | { |
| 67 | struct sockaddr_in sin = { | 67 | struct sockaddr_in sin = { |
| 68 | .sin_family = AF_INET, | 68 | .sin_family = AF_INET, |
| 69 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), | 69 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), |
| 70 | }; | 70 | }; |
| 71 | struct rpc_create_args args = { | 71 | struct rpc_create_args args = { |
| 72 | .net = &init_net, | 72 | .net = net, |
| 73 | .protocol = XPRT_TRANSPORT_UDP, | 73 | .protocol = XPRT_TRANSPORT_UDP, |
| 74 | .address = (struct sockaddr *)&sin, | 74 | .address = (struct sockaddr *)&sin, |
| 75 | .addrsize = sizeof(sin), | 75 | .addrsize = sizeof(sin), |
| @@ -83,7 +83,8 @@ static struct rpc_clnt *nsm_create(void) | |||
| 83 | return rpc_create(&args); | 83 | return rpc_create(&args); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) | 86 | static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, |
| 87 | struct net *net) | ||
| 87 | { | 88 | { |
| 88 | struct rpc_clnt *clnt; | 89 | struct rpc_clnt *clnt; |
| 89 | int status; | 90 | int status; |
| @@ -99,7 +100,7 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) | |||
| 99 | .rpc_resp = res, | 100 | .rpc_resp = res, |
| 100 | }; | 101 | }; |
| 101 | 102 | ||
| 102 | clnt = nsm_create(); | 103 | clnt = nsm_create(net); |
| 103 | if (IS_ERR(clnt)) { | 104 | if (IS_ERR(clnt)) { |
| 104 | status = PTR_ERR(clnt); | 105 | status = PTR_ERR(clnt); |
| 105 | dprintk("lockd: failed to create NSM upcall transport, " | 106 | dprintk("lockd: failed to create NSM upcall transport, " |
| @@ -149,7 +150,7 @@ int nsm_monitor(const struct nlm_host *host) | |||
| 149 | */ | 150 | */ |
| 150 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; | 151 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; |
| 151 | 152 | ||
| 152 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res); | 153 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host->net); |
| 153 | if (unlikely(res.status != 0)) | 154 | if (unlikely(res.status != 0)) |
| 154 | status = -EIO; | 155 | status = -EIO; |
| 155 | if (unlikely(status < 0)) { | 156 | if (unlikely(status < 0)) { |
| @@ -183,7 +184,7 @@ void nsm_unmonitor(const struct nlm_host *host) | |||
| 183 | && nsm->sm_monitored && !nsm->sm_sticky) { | 184 | && nsm->sm_monitored && !nsm->sm_sticky) { |
| 184 | dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); | 185 | dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); |
| 185 | 186 | ||
| 186 | status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res); | 187 | status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host->net); |
| 187 | if (res.status != 0) | 188 | if (res.status != 0) |
| 188 | status = -EIO; | 189 | status = -EIO; |
| 189 | if (status < 0) | 190 | if (status < 0) |
| @@ -534,19 +535,19 @@ static struct rpc_procinfo nsm_procedures[] = { | |||
| 534 | }, | 535 | }, |
| 535 | }; | 536 | }; |
| 536 | 537 | ||
| 537 | static struct rpc_version nsm_version1 = { | 538 | static const struct rpc_version nsm_version1 = { |
| 538 | .number = 1, | 539 | .number = 1, |
| 539 | .nrprocs = ARRAY_SIZE(nsm_procedures), | 540 | .nrprocs = ARRAY_SIZE(nsm_procedures), |
| 540 | .procs = nsm_procedures | 541 | .procs = nsm_procedures |
| 541 | }; | 542 | }; |
| 542 | 543 | ||
| 543 | static struct rpc_version * nsm_version[] = { | 544 | static const struct rpc_version *nsm_version[] = { |
| 544 | [1] = &nsm_version1, | 545 | [1] = &nsm_version1, |
| 545 | }; | 546 | }; |
| 546 | 547 | ||
| 547 | static struct rpc_stat nsm_stats; | 548 | static struct rpc_stat nsm_stats; |
| 548 | 549 | ||
| 549 | static struct rpc_program nsm_program = { | 550 | static const struct rpc_program nsm_program = { |
| 550 | .name = "statd", | 551 | .name = "statd", |
| 551 | .number = NSM_PROGRAM, | 552 | .number = NSM_PROGRAM, |
| 552 | .nrvers = ARRAY_SIZE(nsm_version), | 553 | .nrvers = ARRAY_SIZE(nsm_version), |
diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h new file mode 100644 index 000000000000..ce227e0fbc5c --- /dev/null +++ b/fs/lockd/netns.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef __LOCKD_NETNS_H__ | ||
| 2 | #define __LOCKD_NETNS_H__ | ||
| 3 | |||
| 4 | #include <net/netns/generic.h> | ||
| 5 | |||
| 6 | struct lockd_net { | ||
| 7 | unsigned int nlmsvc_users; | ||
| 8 | }; | ||
| 9 | |||
| 10 | extern int lockd_net_id; | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index c061b9aa7ddb..2774e1013b34 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
| @@ -35,6 +35,8 @@ | |||
| 35 | #include <linux/lockd/lockd.h> | 35 | #include <linux/lockd/lockd.h> |
| 36 | #include <linux/nfs.h> | 36 | #include <linux/nfs.h> |
| 37 | 37 | ||
| 38 | #include "netns.h" | ||
| 39 | |||
| 38 | #define NLMDBG_FACILITY NLMDBG_SVC | 40 | #define NLMDBG_FACILITY NLMDBG_SVC |
| 39 | #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) | 41 | #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) |
| 40 | #define ALLOWED_SIGS (sigmask(SIGKILL)) | 42 | #define ALLOWED_SIGS (sigmask(SIGKILL)) |
| @@ -50,6 +52,8 @@ static struct task_struct *nlmsvc_task; | |||
| 50 | static struct svc_rqst *nlmsvc_rqst; | 52 | static struct svc_rqst *nlmsvc_rqst; |
| 51 | unsigned long nlmsvc_timeout; | 53 | unsigned long nlmsvc_timeout; |
| 52 | 54 | ||
| 55 | int lockd_net_id; | ||
| 56 | |||
| 53 | /* | 57 | /* |
| 54 | * These can be set at insmod time (useful for NFS as root filesystem), | 58 | * These can be set at insmod time (useful for NFS as root filesystem), |
| 55 | * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 | 59 | * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 |
| @@ -189,27 +193,29 @@ lockd(void *vrqstp) | |||
| 189 | } | 193 | } |
| 190 | 194 | ||
| 191 | static int create_lockd_listener(struct svc_serv *serv, const char *name, | 195 | static int create_lockd_listener(struct svc_serv *serv, const char *name, |
| 192 | const int family, const unsigned short port) | 196 | struct net *net, const int family, |
| 197 | const unsigned short port) | ||
| 193 | { | 198 | { |
| 194 | struct svc_xprt *xprt; | 199 | struct svc_xprt *xprt; |
| 195 | 200 | ||
| 196 | xprt = svc_find_xprt(serv, name, family, 0); | 201 | xprt = svc_find_xprt(serv, name, net, family, 0); |
| 197 | if (xprt == NULL) | 202 | if (xprt == NULL) |
| 198 | return svc_create_xprt(serv, name, &init_net, family, port, | 203 | return svc_create_xprt(serv, name, net, family, port, |
| 199 | SVC_SOCK_DEFAULTS); | 204 | SVC_SOCK_DEFAULTS); |
| 200 | svc_xprt_put(xprt); | 205 | svc_xprt_put(xprt); |
| 201 | return 0; | 206 | return 0; |
| 202 | } | 207 | } |
| 203 | 208 | ||
| 204 | static int create_lockd_family(struct svc_serv *serv, const int family) | 209 | static int create_lockd_family(struct svc_serv *serv, struct net *net, |
| 210 | const int family) | ||
| 205 | { | 211 | { |
| 206 | int err; | 212 | int err; |
| 207 | 213 | ||
| 208 | err = create_lockd_listener(serv, "udp", family, nlm_udpport); | 214 | err = create_lockd_listener(serv, "udp", net, family, nlm_udpport); |
| 209 | if (err < 0) | 215 | if (err < 0) |
| 210 | return err; | 216 | return err; |
| 211 | 217 | ||
| 212 | return create_lockd_listener(serv, "tcp", family, nlm_tcpport); | 218 | return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport); |
| 213 | } | 219 | } |
| 214 | 220 | ||
| 215 | /* | 221 | /* |
| @@ -222,16 +228,16 @@ static int create_lockd_family(struct svc_serv *serv, const int family) | |||
| 222 | * Returns zero if all listeners are available; otherwise a | 228 | * Returns zero if all listeners are available; otherwise a |
| 223 | * negative errno value is returned. | 229 | * negative errno value is returned. |
| 224 | */ | 230 | */ |
| 225 | static int make_socks(struct svc_serv *serv) | 231 | static int make_socks(struct svc_serv *serv, struct net *net) |
| 226 | { | 232 | { |
| 227 | static int warned; | 233 | static int warned; |
| 228 | int err; | 234 | int err; |
| 229 | 235 | ||
| 230 | err = create_lockd_family(serv, PF_INET); | 236 | err = create_lockd_family(serv, net, PF_INET); |
| 231 | if (err < 0) | 237 | if (err < 0) |
| 232 | goto out_err; | 238 | goto out_err; |
| 233 | 239 | ||
| 234 | err = create_lockd_family(serv, PF_INET6); | 240 | err = create_lockd_family(serv, net, PF_INET6); |
| 235 | if (err < 0 && err != -EAFNOSUPPORT) | 241 | if (err < 0 && err != -EAFNOSUPPORT) |
| 236 | goto out_err; | 242 | goto out_err; |
| 237 | 243 | ||
| @@ -245,6 +251,47 @@ out_err: | |||
| 245 | return err; | 251 | return err; |
| 246 | } | 252 | } |
| 247 | 253 | ||
| 254 | static int lockd_up_net(struct net *net) | ||
| 255 | { | ||
| 256 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
| 257 | struct svc_serv *serv = nlmsvc_rqst->rq_server; | ||
| 258 | int error; | ||
| 259 | |||
| 260 | if (ln->nlmsvc_users) | ||
| 261 | return 0; | ||
| 262 | |||
| 263 | error = svc_rpcb_setup(serv, net); | ||
| 264 | if (error) | ||
| 265 | goto err_rpcb; | ||
| 266 | |||
| 267 | error = make_socks(serv, net); | ||
| 268 | if (error < 0) | ||
| 269 | goto err_socks; | ||
| 270 | return 0; | ||
| 271 | |||
| 272 | err_socks: | ||
| 273 | svc_rpcb_cleanup(serv, net); | ||
| 274 | err_rpcb: | ||
| 275 | return error; | ||
| 276 | } | ||
| 277 | |||
| 278 | static void lockd_down_net(struct net *net) | ||
| 279 | { | ||
| 280 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
| 281 | struct svc_serv *serv = nlmsvc_rqst->rq_server; | ||
| 282 | |||
| 283 | if (ln->nlmsvc_users) { | ||
| 284 | if (--ln->nlmsvc_users == 0) { | ||
| 285 | nlm_shutdown_hosts_net(net); | ||
| 286 | svc_shutdown_net(serv, net); | ||
| 287 | } | ||
| 288 | } else { | ||
| 289 | printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n", | ||
| 290 | nlmsvc_task, net); | ||
| 291 | BUG(); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 248 | /* | 295 | /* |
| 249 | * Bring up the lockd process if it's not already up. | 296 | * Bring up the lockd process if it's not already up. |
| 250 | */ | 297 | */ |
| @@ -252,13 +299,16 @@ int lockd_up(void) | |||
| 252 | { | 299 | { |
| 253 | struct svc_serv *serv; | 300 | struct svc_serv *serv; |
| 254 | int error = 0; | 301 | int error = 0; |
| 302 | struct net *net = current->nsproxy->net_ns; | ||
| 255 | 303 | ||
| 256 | mutex_lock(&nlmsvc_mutex); | 304 | mutex_lock(&nlmsvc_mutex); |
| 257 | /* | 305 | /* |
| 258 | * Check whether we're already up and running. | 306 | * Check whether we're already up and running. |
| 259 | */ | 307 | */ |
| 260 | if (nlmsvc_rqst) | 308 | if (nlmsvc_rqst) { |
| 309 | error = lockd_up_net(net); | ||
| 261 | goto out; | 310 | goto out; |
| 311 | } | ||
| 262 | 312 | ||
| 263 | /* | 313 | /* |
| 264 | * Sanity check: if there's no pid, | 314 | * Sanity check: if there's no pid, |
| @@ -275,7 +325,7 @@ int lockd_up(void) | |||
| 275 | goto out; | 325 | goto out; |
| 276 | } | 326 | } |
| 277 | 327 | ||
| 278 | error = make_socks(serv); | 328 | error = make_socks(serv, net); |
| 279 | if (error < 0) | 329 | if (error < 0) |
| 280 | goto destroy_and_out; | 330 | goto destroy_and_out; |
| 281 | 331 | ||
| @@ -313,8 +363,12 @@ int lockd_up(void) | |||
| 313 | destroy_and_out: | 363 | destroy_and_out: |
| 314 | svc_destroy(serv); | 364 | svc_destroy(serv); |
| 315 | out: | 365 | out: |
| 316 | if (!error) | 366 | if (!error) { |
| 367 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
| 368 | |||
| 369 | ln->nlmsvc_users++; | ||
| 317 | nlmsvc_users++; | 370 | nlmsvc_users++; |
| 371 | } | ||
| 318 | mutex_unlock(&nlmsvc_mutex); | 372 | mutex_unlock(&nlmsvc_mutex); |
| 319 | return error; | 373 | return error; |
| 320 | } | 374 | } |
| @@ -328,8 +382,10 @@ lockd_down(void) | |||
| 328 | { | 382 | { |
| 329 | mutex_lock(&nlmsvc_mutex); | 383 | mutex_lock(&nlmsvc_mutex); |
| 330 | if (nlmsvc_users) { | 384 | if (nlmsvc_users) { |
| 331 | if (--nlmsvc_users) | 385 | if (--nlmsvc_users) { |
| 386 | lockd_down_net(current->nsproxy->net_ns); | ||
| 332 | goto out; | 387 | goto out; |
| 388 | } | ||
| 333 | } else { | 389 | } else { |
| 334 | printk(KERN_ERR "lockd_down: no users! task=%p\n", | 390 | printk(KERN_ERR "lockd_down: no users! task=%p\n", |
| 335 | nlmsvc_task); | 391 | nlmsvc_task); |
| @@ -497,24 +553,55 @@ module_param_call(nlm_tcpport, param_set_port, param_get_int, | |||
| 497 | module_param(nsm_use_hostnames, bool, 0644); | 553 | module_param(nsm_use_hostnames, bool, 0644); |
| 498 | module_param(nlm_max_connections, uint, 0644); | 554 | module_param(nlm_max_connections, uint, 0644); |
| 499 | 555 | ||
| 556 | static int lockd_init_net(struct net *net) | ||
| 557 | { | ||
| 558 | return 0; | ||
| 559 | } | ||
| 560 | |||
| 561 | static void lockd_exit_net(struct net *net) | ||
| 562 | { | ||
| 563 | } | ||
| 564 | |||
| 565 | static struct pernet_operations lockd_net_ops = { | ||
| 566 | .init = lockd_init_net, | ||
| 567 | .exit = lockd_exit_net, | ||
| 568 | .id = &lockd_net_id, | ||
| 569 | .size = sizeof(struct lockd_net), | ||
| 570 | }; | ||
| 571 | |||
| 572 | |||
| 500 | /* | 573 | /* |
| 501 | * Initialising and terminating the module. | 574 | * Initialising and terminating the module. |
| 502 | */ | 575 | */ |
| 503 | 576 | ||
| 504 | static int __init init_nlm(void) | 577 | static int __init init_nlm(void) |
| 505 | { | 578 | { |
| 579 | int err; | ||
| 580 | |||
| 506 | #ifdef CONFIG_SYSCTL | 581 | #ifdef CONFIG_SYSCTL |
| 582 | err = -ENOMEM; | ||
| 507 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); | 583 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); |
| 508 | return nlm_sysctl_table ? 0 : -ENOMEM; | 584 | if (nlm_sysctl_table == NULL) |
| 509 | #else | 585 | goto err_sysctl; |
| 586 | #endif | ||
| 587 | err = register_pernet_subsys(&lockd_net_ops); | ||
| 588 | if (err) | ||
| 589 | goto err_pernet; | ||
| 510 | return 0; | 590 | return 0; |
| 591 | |||
| 592 | err_pernet: | ||
| 593 | #ifdef CONFIG_SYSCTL | ||
| 594 | unregister_sysctl_table(nlm_sysctl_table); | ||
| 511 | #endif | 595 | #endif |
| 596 | err_sysctl: | ||
| 597 | return err; | ||
| 512 | } | 598 | } |
| 513 | 599 | ||
| 514 | static void __exit exit_nlm(void) | 600 | static void __exit exit_nlm(void) |
| 515 | { | 601 | { |
| 516 | /* FIXME: delete all NLM clients */ | 602 | /* FIXME: delete all NLM clients */ |
| 517 | nlm_shutdown_hosts(); | 603 | nlm_shutdown_hosts(); |
| 604 | unregister_pernet_subsys(&lockd_net_ops); | ||
| 518 | #ifdef CONFIG_SYSCTL | 605 | #ifdef CONFIG_SYSCTL |
| 519 | unregister_sysctl_table(nlm_sysctl_table); | 606 | unregister_sysctl_table(nlm_sysctl_table); |
| 520 | #endif | 607 | #endif |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index f0179c3745d2..e46353f41a42 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
| @@ -46,7 +46,6 @@ static void nlmsvc_remove_block(struct nlm_block *block); | |||
| 46 | static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); | 46 | static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); |
| 47 | static void nlmsvc_freegrantargs(struct nlm_rqst *call); | 47 | static void nlmsvc_freegrantargs(struct nlm_rqst *call); |
| 48 | static const struct rpc_call_ops nlmsvc_grant_ops; | 48 | static const struct rpc_call_ops nlmsvc_grant_ops; |
| 49 | static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie); | ||
| 50 | 49 | ||
| 51 | /* | 50 | /* |
| 52 | * The list of blocked locks to retry | 51 | * The list of blocked locks to retry |
| @@ -54,6 +53,35 @@ static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie); | |||
| 54 | static LIST_HEAD(nlm_blocked); | 53 | static LIST_HEAD(nlm_blocked); |
| 55 | static DEFINE_SPINLOCK(nlm_blocked_lock); | 54 | static DEFINE_SPINLOCK(nlm_blocked_lock); |
| 56 | 55 | ||
| 56 | #ifdef LOCKD_DEBUG | ||
| 57 | static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) | ||
| 58 | { | ||
| 59 | /* | ||
| 60 | * We can get away with a static buffer because we're only | ||
| 61 | * called with BKL held. | ||
| 62 | */ | ||
| 63 | static char buf[2*NLM_MAXCOOKIELEN+1]; | ||
| 64 | unsigned int i, len = sizeof(buf); | ||
| 65 | char *p = buf; | ||
| 66 | |||
| 67 | len--; /* allow for trailing \0 */ | ||
| 68 | if (len < 3) | ||
| 69 | return "???"; | ||
| 70 | for (i = 0 ; i < cookie->len ; i++) { | ||
| 71 | if (len < 2) { | ||
| 72 | strcpy(p-3, "..."); | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | sprintf(p, "%02x", cookie->data[i]); | ||
| 76 | p += 2; | ||
| 77 | len -= 2; | ||
| 78 | } | ||
| 79 | *p = '\0'; | ||
| 80 | |||
| 81 | return buf; | ||
| 82 | } | ||
| 83 | #endif | ||
| 84 | |||
| 57 | /* | 85 | /* |
| 58 | * Insert a blocked lock into the global list | 86 | * Insert a blocked lock into the global list |
| 59 | */ | 87 | */ |
| @@ -935,32 +963,3 @@ nlmsvc_retry_blocked(void) | |||
| 935 | 963 | ||
| 936 | return timeout; | 964 | return timeout; |
| 937 | } | 965 | } |
| 938 | |||
| 939 | #ifdef RPC_DEBUG | ||
| 940 | static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) | ||
| 941 | { | ||
| 942 | /* | ||
| 943 | * We can get away with a static buffer because we're only | ||
| 944 | * called with BKL held. | ||
| 945 | */ | ||
| 946 | static char buf[2*NLM_MAXCOOKIELEN+1]; | ||
| 947 | unsigned int i, len = sizeof(buf); | ||
| 948 | char *p = buf; | ||
| 949 | |||
| 950 | len--; /* allow for trailing \0 */ | ||
| 951 | if (len < 3) | ||
| 952 | return "???"; | ||
| 953 | for (i = 0 ; i < cookie->len ; i++) { | ||
| 954 | if (len < 2) { | ||
| 955 | strcpy(p-3, "..."); | ||
| 956 | break; | ||
| 957 | } | ||
| 958 | sprintf(p, "%02x", cookie->data[i]); | ||
| 959 | p += 2; | ||
| 960 | len -= 2; | ||
| 961 | } | ||
| 962 | *p = '\0'; | ||
| 963 | |||
| 964 | return buf; | ||
| 965 | } | ||
| 966 | #endif | ||
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index dbcd82126aed..2a0e6c599147 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
| @@ -64,6 +64,7 @@ config NFS_V4 | |||
| 64 | bool "NFS client support for NFS version 4" | 64 | bool "NFS client support for NFS version 4" |
| 65 | depends on NFS_FS | 65 | depends on NFS_FS |
| 66 | select SUNRPC_GSS | 66 | select SUNRPC_GSS |
| 67 | select KEYS | ||
| 67 | help | 68 | help |
| 68 | This option enables support for version 4 of the NFS protocol | 69 | This option enables support for version 4 of the NFS protocol |
| 69 | (RFC 3530) in the kernel's NFS client. | 70 | (RFC 3530) in the kernel's NFS client. |
| @@ -98,6 +99,18 @@ config PNFS_OBJLAYOUT | |||
| 98 | depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD | 99 | depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD |
| 99 | default m | 100 | default m |
| 100 | 101 | ||
| 102 | config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN | ||
| 103 | string "NFSv4.1 Implementation ID Domain" | ||
| 104 | depends on NFS_V4_1 | ||
| 105 | default "kernel.org" | ||
| 106 | help | ||
| 107 | This option defines the domain portion of the implementation ID that | ||
| 108 | may be sent in the NFS exchange_id operation. The value must be in | ||
| 109 | the format of a DNS domain name and should be set to the DNS domain | ||
| 110 | name of the distribution. | ||
| 111 | If the NFS client is unchanged from the upstream kernel, this | ||
| 112 | option should be set to the default "kernel.org". | ||
| 113 | |||
| 101 | config ROOT_NFS | 114 | config ROOT_NFS |
| 102 | bool "Root file system on NFS" | 115 | bool "Root file system on NFS" |
| 103 | depends on NFS_FS=y && IP_PNP | 116 | depends on NFS_FS=y && IP_PNP |
| @@ -130,16 +143,10 @@ config NFS_USE_KERNEL_DNS | |||
| 130 | bool | 143 | bool |
| 131 | depends on NFS_V4 && !NFS_USE_LEGACY_DNS | 144 | depends on NFS_V4 && !NFS_USE_LEGACY_DNS |
| 132 | select DNS_RESOLVER | 145 | select DNS_RESOLVER |
| 133 | select KEYS | ||
| 134 | default y | 146 | default y |
| 135 | 147 | ||
| 136 | config NFS_USE_NEW_IDMAPPER | 148 | config NFS_DEBUG |
| 137 | bool "Use the new idmapper upcall routine" | 149 | bool |
| 138 | depends on NFS_V4 && KEYS | 150 | depends on NFS_FS && SUNRPC_DEBUG |
| 139 | help | 151 | select CRC32 |
| 140 | Say Y here if you want NFS to use the new idmapper upcall functions. | 152 | default y |
| 141 | You will need /sbin/request-key (usually provided by the keyutils | ||
| 142 | package). For details, read | ||
| 143 | <file:Documentation/filesystems/nfs/idmapper.txt>. | ||
| 144 | |||
| 145 | If you are unsure, say N. | ||
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 48cfac31f64c..9c94297bb70e 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
| @@ -46,9 +46,6 @@ MODULE_LICENSE("GPL"); | |||
| 46 | MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>"); | 46 | MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>"); |
| 47 | MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver"); | 47 | MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver"); |
| 48 | 48 | ||
| 49 | struct dentry *bl_device_pipe; | ||
| 50 | wait_queue_head_t bl_wq; | ||
| 51 | |||
| 52 | static void print_page(struct page *page) | 49 | static void print_page(struct page *page) |
| 53 | { | 50 | { |
| 54 | dprintk("PRINTPAGE page %p\n", page); | 51 | dprintk("PRINTPAGE page %p\n", page); |
| @@ -236,12 +233,11 @@ bl_read_pagelist(struct nfs_read_data *rdata) | |||
| 236 | sector_t isect, extent_length = 0; | 233 | sector_t isect, extent_length = 0; |
| 237 | struct parallel_io *par; | 234 | struct parallel_io *par; |
| 238 | loff_t f_offset = rdata->args.offset; | 235 | loff_t f_offset = rdata->args.offset; |
| 239 | size_t count = rdata->args.count; | ||
| 240 | struct page **pages = rdata->args.pages; | 236 | struct page **pages = rdata->args.pages; |
| 241 | int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT; | 237 | int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT; |
| 242 | 238 | ||
| 243 | dprintk("%s enter nr_pages %u offset %lld count %Zd\n", __func__, | 239 | dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__, |
| 244 | rdata->npages, f_offset, count); | 240 | rdata->npages, f_offset, (unsigned int)rdata->args.count); |
| 245 | 241 | ||
| 246 | par = alloc_parallel(rdata); | 242 | par = alloc_parallel(rdata); |
| 247 | if (!par) | 243 | if (!par) |
| @@ -1025,10 +1021,128 @@ static const struct rpc_pipe_ops bl_upcall_ops = { | |||
| 1025 | .destroy_msg = bl_pipe_destroy_msg, | 1021 | .destroy_msg = bl_pipe_destroy_msg, |
| 1026 | }; | 1022 | }; |
| 1027 | 1023 | ||
| 1024 | static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb, | ||
| 1025 | struct rpc_pipe *pipe) | ||
| 1026 | { | ||
| 1027 | struct dentry *dir, *dentry; | ||
| 1028 | |||
| 1029 | dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME); | ||
| 1030 | if (dir == NULL) | ||
| 1031 | return ERR_PTR(-ENOENT); | ||
| 1032 | dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe); | ||
| 1033 | dput(dir); | ||
| 1034 | return dentry; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | static void nfs4blocklayout_unregister_sb(struct super_block *sb, | ||
| 1038 | struct rpc_pipe *pipe) | ||
| 1039 | { | ||
| 1040 | if (pipe->dentry) | ||
| 1041 | rpc_unlink(pipe->dentry); | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, | ||
| 1045 | void *ptr) | ||
| 1046 | { | ||
| 1047 | struct super_block *sb = ptr; | ||
| 1048 | struct net *net = sb->s_fs_info; | ||
| 1049 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 1050 | struct dentry *dentry; | ||
| 1051 | int ret = 0; | ||
| 1052 | |||
| 1053 | if (!try_module_get(THIS_MODULE)) | ||
| 1054 | return 0; | ||
| 1055 | |||
| 1056 | if (nn->bl_device_pipe == NULL) { | ||
| 1057 | module_put(THIS_MODULE); | ||
| 1058 | return 0; | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | switch (event) { | ||
| 1062 | case RPC_PIPEFS_MOUNT: | ||
| 1063 | dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe); | ||
| 1064 | if (IS_ERR(dentry)) { | ||
| 1065 | ret = PTR_ERR(dentry); | ||
| 1066 | break; | ||
| 1067 | } | ||
| 1068 | nn->bl_device_pipe->dentry = dentry; | ||
| 1069 | break; | ||
| 1070 | case RPC_PIPEFS_UMOUNT: | ||
| 1071 | if (nn->bl_device_pipe->dentry) | ||
| 1072 | nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe); | ||
| 1073 | break; | ||
| 1074 | default: | ||
| 1075 | ret = -ENOTSUPP; | ||
| 1076 | break; | ||
| 1077 | } | ||
| 1078 | module_put(THIS_MODULE); | ||
| 1079 | return ret; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | static struct notifier_block nfs4blocklayout_block = { | ||
| 1083 | .notifier_call = rpc_pipefs_event, | ||
| 1084 | }; | ||
| 1085 | |||
| 1086 | static struct dentry *nfs4blocklayout_register_net(struct net *net, | ||
| 1087 | struct rpc_pipe *pipe) | ||
| 1088 | { | ||
| 1089 | struct super_block *pipefs_sb; | ||
| 1090 | struct dentry *dentry; | ||
| 1091 | |||
| 1092 | pipefs_sb = rpc_get_sb_net(net); | ||
| 1093 | if (!pipefs_sb) | ||
| 1094 | return NULL; | ||
| 1095 | dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe); | ||
| 1096 | rpc_put_sb_net(net); | ||
| 1097 | return dentry; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | static void nfs4blocklayout_unregister_net(struct net *net, | ||
| 1101 | struct rpc_pipe *pipe) | ||
| 1102 | { | ||
| 1103 | struct super_block *pipefs_sb; | ||
| 1104 | |||
| 1105 | pipefs_sb = rpc_get_sb_net(net); | ||
| 1106 | if (pipefs_sb) { | ||
| 1107 | nfs4blocklayout_unregister_sb(pipefs_sb, pipe); | ||
| 1108 | rpc_put_sb_net(net); | ||
| 1109 | } | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | static int nfs4blocklayout_net_init(struct net *net) | ||
| 1113 | { | ||
| 1114 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 1115 | struct dentry *dentry; | ||
| 1116 | |||
| 1117 | init_waitqueue_head(&nn->bl_wq); | ||
| 1118 | nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); | ||
| 1119 | if (IS_ERR(nn->bl_device_pipe)) | ||
| 1120 | return PTR_ERR(nn->bl_device_pipe); | ||
| 1121 | dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe); | ||
| 1122 | if (IS_ERR(dentry)) { | ||
| 1123 | rpc_destroy_pipe_data(nn->bl_device_pipe); | ||
| 1124 | return PTR_ERR(dentry); | ||
| 1125 | } | ||
| 1126 | nn->bl_device_pipe->dentry = dentry; | ||
| 1127 | return 0; | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | static void nfs4blocklayout_net_exit(struct net *net) | ||
| 1131 | { | ||
| 1132 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 1133 | |||
| 1134 | nfs4blocklayout_unregister_net(net, nn->bl_device_pipe); | ||
| 1135 | rpc_destroy_pipe_data(nn->bl_device_pipe); | ||
| 1136 | nn->bl_device_pipe = NULL; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | static struct pernet_operations nfs4blocklayout_net_ops = { | ||
| 1140 | .init = nfs4blocklayout_net_init, | ||
| 1141 | .exit = nfs4blocklayout_net_exit, | ||
| 1142 | }; | ||
| 1143 | |||
| 1028 | static int __init nfs4blocklayout_init(void) | 1144 | static int __init nfs4blocklayout_init(void) |
| 1029 | { | 1145 | { |
| 1030 | struct vfsmount *mnt; | ||
| 1031 | struct path path; | ||
| 1032 | int ret; | 1146 | int ret; |
| 1033 | 1147 | ||
| 1034 | dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__); | 1148 | dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__); |
| @@ -1037,32 +1151,17 @@ static int __init nfs4blocklayout_init(void) | |||
| 1037 | if (ret) | 1151 | if (ret) |
| 1038 | goto out; | 1152 | goto out; |
| 1039 | 1153 | ||
| 1040 | init_waitqueue_head(&bl_wq); | 1154 | ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block); |
| 1041 | 1155 | if (ret) | |
| 1042 | mnt = rpc_get_mount(); | ||
| 1043 | if (IS_ERR(mnt)) { | ||
| 1044 | ret = PTR_ERR(mnt); | ||
| 1045 | goto out_remove; | 1156 | goto out_remove; |
| 1046 | } | 1157 | ret = register_pernet_subsys(&nfs4blocklayout_net_ops); |
| 1047 | |||
| 1048 | ret = vfs_path_lookup(mnt->mnt_root, | ||
| 1049 | mnt, | ||
| 1050 | NFS_PIPE_DIRNAME, 0, &path); | ||
| 1051 | if (ret) | 1158 | if (ret) |
| 1052 | goto out_putrpc; | 1159 | goto out_notifier; |
| 1053 | |||
| 1054 | bl_device_pipe = rpc_mkpipe(path.dentry, "blocklayout", NULL, | ||
| 1055 | &bl_upcall_ops, 0); | ||
| 1056 | path_put(&path); | ||
| 1057 | if (IS_ERR(bl_device_pipe)) { | ||
| 1058 | ret = PTR_ERR(bl_device_pipe); | ||
| 1059 | goto out_putrpc; | ||
| 1060 | } | ||
| 1061 | out: | 1160 | out: |
| 1062 | return ret; | 1161 | return ret; |
| 1063 | 1162 | ||
| 1064 | out_putrpc: | 1163 | out_notifier: |
| 1065 | rpc_put_mount(); | 1164 | rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); |
| 1066 | out_remove: | 1165 | out_remove: |
| 1067 | pnfs_unregister_layoutdriver(&blocklayout_type); | 1166 | pnfs_unregister_layoutdriver(&blocklayout_type); |
| 1068 | return ret; | 1167 | return ret; |
| @@ -1073,9 +1172,9 @@ static void __exit nfs4blocklayout_exit(void) | |||
| 1073 | dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n", | 1172 | dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n", |
| 1074 | __func__); | 1173 | __func__); |
| 1075 | 1174 | ||
| 1175 | rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); | ||
| 1176 | unregister_pernet_subsys(&nfs4blocklayout_net_ops); | ||
| 1076 | pnfs_unregister_layoutdriver(&blocklayout_type); | 1177 | pnfs_unregister_layoutdriver(&blocklayout_type); |
| 1077 | rpc_unlink(bl_device_pipe); | ||
| 1078 | rpc_put_mount(); | ||
| 1079 | } | 1178 | } |
| 1080 | 1179 | ||
| 1081 | MODULE_ALIAS("nfs-layouttype4-3"); | 1180 | MODULE_ALIAS("nfs-layouttype4-3"); |
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index e31a2df28e70..03350690118e 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/sunrpc/rpc_pipe_fs.h> | 37 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 38 | 38 | ||
| 39 | #include "../pnfs.h" | 39 | #include "../pnfs.h" |
| 40 | #include "../netns.h" | ||
| 40 | 41 | ||
| 41 | #define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT) | 42 | #define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT) |
| 42 | #define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT) | 43 | #define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT) |
| @@ -50,6 +51,7 @@ struct pnfs_block_dev { | |||
| 50 | struct list_head bm_node; | 51 | struct list_head bm_node; |
| 51 | struct nfs4_deviceid bm_mdevid; /* associated devid */ | 52 | struct nfs4_deviceid bm_mdevid; /* associated devid */ |
| 52 | struct block_device *bm_mdev; /* meta device itself */ | 53 | struct block_device *bm_mdev; /* meta device itself */ |
| 54 | struct net *net; | ||
| 53 | }; | 55 | }; |
| 54 | 56 | ||
| 55 | enum exstate4 { | 57 | enum exstate4 { |
| @@ -151,9 +153,9 @@ BLK_LSEG2EXT(struct pnfs_layout_segment *lseg) | |||
| 151 | return BLK_LO2EXT(lseg->pls_layout); | 153 | return BLK_LO2EXT(lseg->pls_layout); |
| 152 | } | 154 | } |
| 153 | 155 | ||
| 154 | struct bl_dev_msg { | 156 | struct bl_pipe_msg { |
| 155 | int32_t status; | 157 | struct rpc_pipe_msg msg; |
| 156 | uint32_t major, minor; | 158 | wait_queue_head_t *bl_wq; |
| 157 | }; | 159 | }; |
| 158 | 160 | ||
| 159 | struct bl_msg_hdr { | 161 | struct bl_msg_hdr { |
| @@ -161,9 +163,6 @@ struct bl_msg_hdr { | |||
| 161 | u16 totallen; /* length of entire message, including hdr itself */ | 163 | u16 totallen; /* length of entire message, including hdr itself */ |
| 162 | }; | 164 | }; |
| 163 | 165 | ||
| 164 | extern struct dentry *bl_device_pipe; | ||
| 165 | extern wait_queue_head_t bl_wq; | ||
| 166 | |||
| 167 | #define BL_DEVICE_UMOUNT 0x0 /* Umount--delete devices */ | 166 | #define BL_DEVICE_UMOUNT 0x0 /* Umount--delete devices */ |
| 168 | #define BL_DEVICE_MOUNT 0x1 /* Mount--create devices*/ | 167 | #define BL_DEVICE_MOUNT 0x1 /* Mount--create devices*/ |
| 169 | #define BL_DEVICE_REQUEST_INIT 0x0 /* Start request */ | 168 | #define BL_DEVICE_REQUEST_INIT 0x0 /* Start request */ |
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c index d08ba9107fde..a5c88a554d92 100644 --- a/fs/nfs/blocklayout/blocklayoutdev.c +++ b/fs/nfs/blocklayout/blocklayoutdev.c | |||
| @@ -46,7 +46,7 @@ static int decode_sector_number(__be32 **rp, sector_t *sp) | |||
| 46 | 46 | ||
| 47 | *rp = xdr_decode_hyper(*rp, &s); | 47 | *rp = xdr_decode_hyper(*rp, &s); |
| 48 | if (s & 0x1ff) { | 48 | if (s & 0x1ff) { |
| 49 | printk(KERN_WARNING "%s: sector not aligned\n", __func__); | 49 | printk(KERN_WARNING "NFS: %s: sector not aligned\n", __func__); |
| 50 | return -1; | 50 | return -1; |
| 51 | } | 51 | } |
| 52 | *sp = s >> SECTOR_SHIFT; | 52 | *sp = s >> SECTOR_SHIFT; |
| @@ -79,27 +79,30 @@ int nfs4_blkdev_put(struct block_device *bdev) | |||
| 79 | return blkdev_put(bdev, FMODE_READ); | 79 | return blkdev_put(bdev, FMODE_READ); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static struct bl_dev_msg bl_mount_reply; | ||
| 83 | |||
| 84 | ssize_t bl_pipe_downcall(struct file *filp, const char __user *src, | 82 | ssize_t bl_pipe_downcall(struct file *filp, const char __user *src, |
| 85 | size_t mlen) | 83 | size_t mlen) |
| 86 | { | 84 | { |
| 85 | struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, | ||
| 86 | nfs_net_id); | ||
| 87 | |||
| 87 | if (mlen != sizeof (struct bl_dev_msg)) | 88 | if (mlen != sizeof (struct bl_dev_msg)) |
| 88 | return -EINVAL; | 89 | return -EINVAL; |
| 89 | 90 | ||
| 90 | if (copy_from_user(&bl_mount_reply, src, mlen) != 0) | 91 | if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0) |
| 91 | return -EFAULT; | 92 | return -EFAULT; |
| 92 | 93 | ||
| 93 | wake_up(&bl_wq); | 94 | wake_up(&nn->bl_wq); |
| 94 | 95 | ||
| 95 | return mlen; | 96 | return mlen; |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg) | 99 | void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg) |
| 99 | { | 100 | { |
| 101 | struct bl_pipe_msg *bl_pipe_msg = container_of(msg, struct bl_pipe_msg, msg); | ||
| 102 | |||
| 100 | if (msg->errno >= 0) | 103 | if (msg->errno >= 0) |
| 101 | return; | 104 | return; |
| 102 | wake_up(&bl_wq); | 105 | wake_up(bl_pipe_msg->bl_wq); |
| 103 | } | 106 | } |
| 104 | 107 | ||
| 105 | /* | 108 | /* |
| @@ -111,29 +114,33 @@ nfs4_blk_decode_device(struct nfs_server *server, | |||
| 111 | { | 114 | { |
| 112 | struct pnfs_block_dev *rv; | 115 | struct pnfs_block_dev *rv; |
| 113 | struct block_device *bd = NULL; | 116 | struct block_device *bd = NULL; |
| 114 | struct rpc_pipe_msg msg; | 117 | struct bl_pipe_msg bl_pipe_msg; |
| 118 | struct rpc_pipe_msg *msg = &bl_pipe_msg.msg; | ||
| 115 | struct bl_msg_hdr bl_msg = { | 119 | struct bl_msg_hdr bl_msg = { |
| 116 | .type = BL_DEVICE_MOUNT, | 120 | .type = BL_DEVICE_MOUNT, |
| 117 | .totallen = dev->mincount, | 121 | .totallen = dev->mincount, |
| 118 | }; | 122 | }; |
| 119 | uint8_t *dataptr; | 123 | uint8_t *dataptr; |
| 120 | DECLARE_WAITQUEUE(wq, current); | 124 | DECLARE_WAITQUEUE(wq, current); |
| 121 | struct bl_dev_msg *reply = &bl_mount_reply; | ||
| 122 | int offset, len, i, rc; | 125 | int offset, len, i, rc; |
| 126 | struct net *net = server->nfs_client->net; | ||
| 127 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 128 | struct bl_dev_msg *reply = &nn->bl_mount_reply; | ||
| 123 | 129 | ||
| 124 | dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); | 130 | dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); |
| 125 | dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data, | 131 | dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data, |
| 126 | dev->mincount); | 132 | dev->mincount); |
| 127 | 133 | ||
| 128 | memset(&msg, 0, sizeof(msg)); | 134 | bl_pipe_msg.bl_wq = &nn->bl_wq; |
| 129 | msg.data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS); | 135 | memset(msg, 0, sizeof(*msg)); |
| 130 | if (!msg.data) { | 136 | msg->data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS); |
| 137 | if (!msg->data) { | ||
| 131 | rv = ERR_PTR(-ENOMEM); | 138 | rv = ERR_PTR(-ENOMEM); |
| 132 | goto out; | 139 | goto out; |
| 133 | } | 140 | } |
| 134 | 141 | ||
| 135 | memcpy(msg.data, &bl_msg, sizeof(bl_msg)); | 142 | memcpy(msg->data, &bl_msg, sizeof(bl_msg)); |
| 136 | dataptr = (uint8_t *) msg.data; | 143 | dataptr = (uint8_t *) msg->data; |
| 137 | len = dev->mincount; | 144 | len = dev->mincount; |
| 138 | offset = sizeof(bl_msg); | 145 | offset = sizeof(bl_msg); |
| 139 | for (i = 0; len > 0; i++) { | 146 | for (i = 0; len > 0; i++) { |
| @@ -142,13 +149,13 @@ nfs4_blk_decode_device(struct nfs_server *server, | |||
| 142 | len -= PAGE_CACHE_SIZE; | 149 | len -= PAGE_CACHE_SIZE; |
| 143 | offset += PAGE_CACHE_SIZE; | 150 | offset += PAGE_CACHE_SIZE; |
| 144 | } | 151 | } |
| 145 | msg.len = sizeof(bl_msg) + dev->mincount; | 152 | msg->len = sizeof(bl_msg) + dev->mincount; |
| 146 | 153 | ||
| 147 | dprintk("%s CALLING USERSPACE DAEMON\n", __func__); | 154 | dprintk("%s CALLING USERSPACE DAEMON\n", __func__); |
| 148 | add_wait_queue(&bl_wq, &wq); | 155 | add_wait_queue(&nn->bl_wq, &wq); |
| 149 | rc = rpc_queue_upcall(bl_device_pipe->d_inode, &msg); | 156 | rc = rpc_queue_upcall(nn->bl_device_pipe, msg); |
| 150 | if (rc < 0) { | 157 | if (rc < 0) { |
| 151 | remove_wait_queue(&bl_wq, &wq); | 158 | remove_wait_queue(&nn->bl_wq, &wq); |
| 152 | rv = ERR_PTR(rc); | 159 | rv = ERR_PTR(rc); |
| 153 | goto out; | 160 | goto out; |
| 154 | } | 161 | } |
| @@ -156,7 +163,7 @@ nfs4_blk_decode_device(struct nfs_server *server, | |||
| 156 | set_current_state(TASK_UNINTERRUPTIBLE); | 163 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 157 | schedule(); | 164 | schedule(); |
| 158 | __set_current_state(TASK_RUNNING); | 165 | __set_current_state(TASK_RUNNING); |
| 159 | remove_wait_queue(&bl_wq, &wq); | 166 | remove_wait_queue(&nn->bl_wq, &wq); |
| 160 | 167 | ||
| 161 | if (reply->status != BL_DEVICE_REQUEST_PROC) { | 168 | if (reply->status != BL_DEVICE_REQUEST_PROC) { |
| 162 | dprintk("%s failed to open device: %d\n", | 169 | dprintk("%s failed to open device: %d\n", |
| @@ -181,13 +188,14 @@ nfs4_blk_decode_device(struct nfs_server *server, | |||
| 181 | 188 | ||
| 182 | rv->bm_mdev = bd; | 189 | rv->bm_mdev = bd; |
| 183 | memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid)); | 190 | memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid)); |
| 191 | rv->net = net; | ||
| 184 | dprintk("%s Created device %s with bd_block_size %u\n", | 192 | dprintk("%s Created device %s with bd_block_size %u\n", |
| 185 | __func__, | 193 | __func__, |
| 186 | bd->bd_disk->disk_name, | 194 | bd->bd_disk->disk_name, |
| 187 | bd->bd_block_size); | 195 | bd->bd_block_size); |
| 188 | 196 | ||
| 189 | out: | 197 | out: |
| 190 | kfree(msg.data); | 198 | kfree(msg->data); |
| 191 | return rv; | 199 | return rv; |
| 192 | } | 200 | } |
| 193 | 201 | ||
diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c index d055c7558073..737d839bc17b 100644 --- a/fs/nfs/blocklayout/blocklayoutdm.c +++ b/fs/nfs/blocklayout/blocklayoutdm.c | |||
| @@ -38,9 +38,10 @@ | |||
| 38 | 38 | ||
| 39 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD | 39 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD |
| 40 | 40 | ||
| 41 | static void dev_remove(dev_t dev) | 41 | static void dev_remove(struct net *net, dev_t dev) |
| 42 | { | 42 | { |
| 43 | struct rpc_pipe_msg msg; | 43 | struct bl_pipe_msg bl_pipe_msg; |
| 44 | struct rpc_pipe_msg *msg = &bl_pipe_msg.msg; | ||
| 44 | struct bl_dev_msg bl_umount_request; | 45 | struct bl_dev_msg bl_umount_request; |
| 45 | struct bl_msg_hdr bl_msg = { | 46 | struct bl_msg_hdr bl_msg = { |
| 46 | .type = BL_DEVICE_UMOUNT, | 47 | .type = BL_DEVICE_UMOUNT, |
| @@ -48,36 +49,38 @@ static void dev_remove(dev_t dev) | |||
| 48 | }; | 49 | }; |
| 49 | uint8_t *dataptr; | 50 | uint8_t *dataptr; |
| 50 | DECLARE_WAITQUEUE(wq, current); | 51 | DECLARE_WAITQUEUE(wq, current); |
| 52 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 51 | 53 | ||
| 52 | dprintk("Entering %s\n", __func__); | 54 | dprintk("Entering %s\n", __func__); |
| 53 | 55 | ||
| 54 | memset(&msg, 0, sizeof(msg)); | 56 | bl_pipe_msg.bl_wq = &nn->bl_wq; |
| 55 | msg.data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS); | 57 | memset(msg, 0, sizeof(*msg)); |
| 56 | if (!msg.data) | 58 | msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS); |
| 59 | if (!msg->data) | ||
| 57 | goto out; | 60 | goto out; |
| 58 | 61 | ||
| 59 | memset(&bl_umount_request, 0, sizeof(bl_umount_request)); | 62 | memset(&bl_umount_request, 0, sizeof(bl_umount_request)); |
| 60 | bl_umount_request.major = MAJOR(dev); | 63 | bl_umount_request.major = MAJOR(dev); |
| 61 | bl_umount_request.minor = MINOR(dev); | 64 | bl_umount_request.minor = MINOR(dev); |
| 62 | 65 | ||
| 63 | memcpy(msg.data, &bl_msg, sizeof(bl_msg)); | 66 | memcpy(msg->data, &bl_msg, sizeof(bl_msg)); |
| 64 | dataptr = (uint8_t *) msg.data; | 67 | dataptr = (uint8_t *) msg->data; |
| 65 | memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request)); | 68 | memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request)); |
| 66 | msg.len = sizeof(bl_msg) + bl_msg.totallen; | 69 | msg->len = sizeof(bl_msg) + bl_msg.totallen; |
| 67 | 70 | ||
| 68 | add_wait_queue(&bl_wq, &wq); | 71 | add_wait_queue(&nn->bl_wq, &wq); |
| 69 | if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) { | 72 | if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) { |
| 70 | remove_wait_queue(&bl_wq, &wq); | 73 | remove_wait_queue(&nn->bl_wq, &wq); |
| 71 | goto out; | 74 | goto out; |
| 72 | } | 75 | } |
| 73 | 76 | ||
| 74 | set_current_state(TASK_UNINTERRUPTIBLE); | 77 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 75 | schedule(); | 78 | schedule(); |
| 76 | __set_current_state(TASK_RUNNING); | 79 | __set_current_state(TASK_RUNNING); |
| 77 | remove_wait_queue(&bl_wq, &wq); | 80 | remove_wait_queue(&nn->bl_wq, &wq); |
| 78 | 81 | ||
| 79 | out: | 82 | out: |
| 80 | kfree(msg.data); | 83 | kfree(msg->data); |
| 81 | } | 84 | } |
| 82 | 85 | ||
| 83 | /* | 86 | /* |
| @@ -90,10 +93,10 @@ static void nfs4_blk_metadev_release(struct pnfs_block_dev *bdev) | |||
| 90 | dprintk("%s Releasing\n", __func__); | 93 | dprintk("%s Releasing\n", __func__); |
| 91 | rv = nfs4_blkdev_put(bdev->bm_mdev); | 94 | rv = nfs4_blkdev_put(bdev->bm_mdev); |
| 92 | if (rv) | 95 | if (rv) |
| 93 | printk(KERN_ERR "%s nfs4_blkdev_put returns %d\n", | 96 | printk(KERN_ERR "NFS: %s nfs4_blkdev_put returns %d\n", |
| 94 | __func__, rv); | 97 | __func__, rv); |
| 95 | 98 | ||
| 96 | dev_remove(bdev->bm_mdev->bd_dev); | 99 | dev_remove(bdev->net, bdev->bm_mdev->bd_dev); |
| 97 | } | 100 | } |
| 98 | 101 | ||
| 99 | void bl_free_block_dev(struct pnfs_block_dev *bdev) | 102 | void bl_free_block_dev(struct pnfs_block_dev *bdev) |
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c index 1abac09f7cd5..1f9a6032796b 100644 --- a/fs/nfs/blocklayout/extents.c +++ b/fs/nfs/blocklayout/extents.c | |||
| @@ -147,7 +147,7 @@ static int _preload_range(struct pnfs_inval_markings *marks, | |||
| 147 | count = (int)(end - start) / (int)tree->mtt_step_size; | 147 | count = (int)(end - start) / (int)tree->mtt_step_size; |
| 148 | 148 | ||
| 149 | /* Pre-malloc what memory we might need */ | 149 | /* Pre-malloc what memory we might need */ |
| 150 | storage = kmalloc(sizeof(*storage) * count, GFP_NOFS); | 150 | storage = kcalloc(count, sizeof(*storage), GFP_NOFS); |
| 151 | if (!storage) | 151 | if (!storage) |
| 152 | return -ENOMEM; | 152 | return -ENOMEM; |
| 153 | for (i = 0; i < count; i++) { | 153 | for (i = 0; i < count; i++) { |
diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c index c98b439332fc..dded26368111 100644 --- a/fs/nfs/cache_lib.c +++ b/fs/nfs/cache_lib.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 14 | #include <linux/sunrpc/cache.h> | 14 | #include <linux/sunrpc/cache.h> |
| 15 | #include <linux/sunrpc/rpc_pipe_fs.h> | 15 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 16 | #include <net/net_namespace.h> | ||
| 16 | 17 | ||
| 17 | #include "cache_lib.h" | 18 | #include "cache_lib.h" |
| 18 | 19 | ||
| @@ -111,30 +112,54 @@ int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq) | |||
| 111 | return 0; | 112 | return 0; |
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | int nfs_cache_register(struct cache_detail *cd) | 115 | int nfs_cache_register_sb(struct super_block *sb, struct cache_detail *cd) |
| 115 | { | 116 | { |
| 116 | struct vfsmount *mnt; | ||
| 117 | struct path path; | ||
| 118 | int ret; | 117 | int ret; |
| 118 | struct dentry *dir; | ||
| 119 | 119 | ||
| 120 | mnt = rpc_get_mount(); | 120 | dir = rpc_d_lookup_sb(sb, "cache"); |
| 121 | if (IS_ERR(mnt)) | 121 | BUG_ON(dir == NULL); |
| 122 | return PTR_ERR(mnt); | 122 | ret = sunrpc_cache_register_pipefs(dir, cd->name, 0600, cd); |
| 123 | ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &path); | 123 | dput(dir); |
| 124 | if (ret) | ||
| 125 | goto err; | ||
| 126 | ret = sunrpc_cache_register_pipefs(path.dentry, cd->name, 0600, cd); | ||
| 127 | path_put(&path); | ||
| 128 | if (!ret) | ||
| 129 | return ret; | ||
| 130 | err: | ||
| 131 | rpc_put_mount(); | ||
| 132 | return ret; | 124 | return ret; |
| 133 | } | 125 | } |
| 134 | 126 | ||
| 135 | void nfs_cache_unregister(struct cache_detail *cd) | 127 | int nfs_cache_register_net(struct net *net, struct cache_detail *cd) |
| 136 | { | 128 | { |
| 137 | sunrpc_cache_unregister_pipefs(cd); | 129 | struct super_block *pipefs_sb; |
| 138 | rpc_put_mount(); | 130 | int ret = 0; |
| 131 | |||
| 132 | pipefs_sb = rpc_get_sb_net(net); | ||
| 133 | if (pipefs_sb) { | ||
| 134 | ret = nfs_cache_register_sb(pipefs_sb, cd); | ||
| 135 | rpc_put_sb_net(net); | ||
| 136 | } | ||
| 137 | return ret; | ||
| 138 | } | ||
| 139 | |||
| 140 | void nfs_cache_unregister_sb(struct super_block *sb, struct cache_detail *cd) | ||
| 141 | { | ||
| 142 | if (cd->u.pipefs.dir) | ||
| 143 | sunrpc_cache_unregister_pipefs(cd); | ||
| 144 | } | ||
| 145 | |||
| 146 | void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd) | ||
| 147 | { | ||
| 148 | struct super_block *pipefs_sb; | ||
| 149 | |||
| 150 | pipefs_sb = rpc_get_sb_net(net); | ||
| 151 | if (pipefs_sb) { | ||
| 152 | nfs_cache_unregister_sb(pipefs_sb, cd); | ||
| 153 | rpc_put_sb_net(net); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | void nfs_cache_init(struct cache_detail *cd) | ||
| 158 | { | ||
| 159 | sunrpc_init_cache_detail(cd); | ||
| 139 | } | 160 | } |
| 140 | 161 | ||
| 162 | void nfs_cache_destroy(struct cache_detail *cd) | ||
| 163 | { | ||
| 164 | sunrpc_destroy_cache_detail(cd); | ||
| 165 | } | ||
diff --git a/fs/nfs/cache_lib.h b/fs/nfs/cache_lib.h index 7cf6cafcc007..317db95e37f8 100644 --- a/fs/nfs/cache_lib.h +++ b/fs/nfs/cache_lib.h | |||
| @@ -23,5 +23,11 @@ extern struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void); | |||
| 23 | extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq); | 23 | extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq); |
| 24 | extern int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq); | 24 | extern int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq); |
| 25 | 25 | ||
| 26 | extern int nfs_cache_register(struct cache_detail *cd); | 26 | extern void nfs_cache_init(struct cache_detail *cd); |
| 27 | extern void nfs_cache_unregister(struct cache_detail *cd); | 27 | extern void nfs_cache_destroy(struct cache_detail *cd); |
| 28 | extern int nfs_cache_register_net(struct net *net, struct cache_detail *cd); | ||
| 29 | extern void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd); | ||
| 30 | extern int nfs_cache_register_sb(struct super_block *sb, | ||
| 31 | struct cache_detail *cd); | ||
| 32 | extern void nfs_cache_unregister_sb(struct super_block *sb, | ||
| 33 | struct cache_detail *cd); | ||
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 516f3375e067..eb95f5091c1a 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
| @@ -85,7 +85,7 @@ nfs4_callback_svc(void *vrqstp) | |||
| 85 | } | 85 | } |
| 86 | if (err < 0) { | 86 | if (err < 0) { |
| 87 | if (err != preverr) { | 87 | if (err != preverr) { |
| 88 | printk(KERN_WARNING "%s: unexpected error " | 88 | printk(KERN_WARNING "NFS: %s: unexpected error " |
| 89 | "from svc_recv (%d)\n", __func__, err); | 89 | "from svc_recv (%d)\n", __func__, err); |
| 90 | preverr = err; | 90 | preverr = err; |
| 91 | } | 91 | } |
| @@ -101,12 +101,12 @@ nfs4_callback_svc(void *vrqstp) | |||
| 101 | /* | 101 | /* |
| 102 | * Prepare to bring up the NFSv4 callback service | 102 | * Prepare to bring up the NFSv4 callback service |
| 103 | */ | 103 | */ |
| 104 | struct svc_rqst * | 104 | static struct svc_rqst * |
| 105 | nfs4_callback_up(struct svc_serv *serv) | 105 | nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) |
| 106 | { | 106 | { |
| 107 | int ret; | 107 | int ret; |
| 108 | 108 | ||
| 109 | ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET, | 109 | ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET, |
| 110 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 110 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
| 111 | if (ret <= 0) | 111 | if (ret <= 0) |
| 112 | goto out_err; | 112 | goto out_err; |
| @@ -114,7 +114,7 @@ nfs4_callback_up(struct svc_serv *serv) | |||
| 114 | dprintk("NFS: Callback listener port = %u (af %u)\n", | 114 | dprintk("NFS: Callback listener port = %u (af %u)\n", |
| 115 | nfs_callback_tcpport, PF_INET); | 115 | nfs_callback_tcpport, PF_INET); |
| 116 | 116 | ||
| 117 | ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6, | 117 | ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET6, |
| 118 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 118 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
| 119 | if (ret > 0) { | 119 | if (ret > 0) { |
| 120 | nfs_callback_tcpport6 = ret; | 120 | nfs_callback_tcpport6 = ret; |
| @@ -172,7 +172,7 @@ nfs41_callback_svc(void *vrqstp) | |||
| 172 | /* | 172 | /* |
| 173 | * Bring up the NFSv4.1 callback service | 173 | * Bring up the NFSv4.1 callback service |
| 174 | */ | 174 | */ |
| 175 | struct svc_rqst * | 175 | static struct svc_rqst * |
| 176 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | 176 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) |
| 177 | { | 177 | { |
| 178 | struct svc_rqst *rqstp; | 178 | struct svc_rqst *rqstp; |
| @@ -183,7 +183,7 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | |||
| 183 | * fore channel connection. | 183 | * fore channel connection. |
| 184 | * Returns the input port (0) and sets the svc_serv bc_xprt on success | 184 | * Returns the input port (0) and sets the svc_serv bc_xprt on success |
| 185 | */ | 185 | */ |
| 186 | ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0, | 186 | ret = svc_create_xprt(serv, "tcp-bc", xprt->xprt_net, PF_INET, 0, |
| 187 | SVC_SOCK_ANONYMOUS); | 187 | SVC_SOCK_ANONYMOUS); |
| 188 | if (ret < 0) { | 188 | if (ret < 0) { |
| 189 | rqstp = ERR_PTR(ret); | 189 | rqstp = ERR_PTR(ret); |
| @@ -269,7 +269,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) | |||
| 269 | serv, xprt, &rqstp, &callback_svc); | 269 | serv, xprt, &rqstp, &callback_svc); |
| 270 | if (!minorversion_setup) { | 270 | if (!minorversion_setup) { |
| 271 | /* v4.0 callback setup */ | 271 | /* v4.0 callback setup */ |
| 272 | rqstp = nfs4_callback_up(serv); | 272 | rqstp = nfs4_callback_up(serv, xprt); |
| 273 | callback_svc = nfs4_callback_svc; | 273 | callback_svc = nfs4_callback_svc; |
| 274 | } | 274 | } |
| 275 | 275 | ||
| @@ -332,7 +332,6 @@ void nfs_callback_down(int minorversion) | |||
| 332 | int | 332 | int |
| 333 | check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) | 333 | check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) |
| 334 | { | 334 | { |
| 335 | struct rpc_clnt *r = clp->cl_rpcclient; | ||
| 336 | char *p = svc_gss_principal(rqstp); | 335 | char *p = svc_gss_principal(rqstp); |
| 337 | 336 | ||
| 338 | if (rqstp->rq_authop->flavour != RPC_AUTH_GSS) | 337 | if (rqstp->rq_authop->flavour != RPC_AUTH_GSS) |
| @@ -353,7 +352,7 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) | |||
| 353 | if (memcmp(p, "nfs@", 4) != 0) | 352 | if (memcmp(p, "nfs@", 4) != 0) |
| 354 | return 0; | 353 | return 0; |
| 355 | p += 4; | 354 | p += 4; |
| 356 | if (strcmp(p, r->cl_server) != 0) | 355 | if (strcmp(p, clp->cl_hostname) != 0) |
| 357 | return 0; | 356 | return 0; |
| 358 | return 1; | 357 | return 1; |
| 359 | } | 358 | } |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index c89d3b9e483c..a5527c90a5aa 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
| @@ -38,7 +38,8 @@ enum nfs4_callback_opnum { | |||
| 38 | struct cb_process_state { | 38 | struct cb_process_state { |
| 39 | __be32 drc_status; | 39 | __be32 drc_status; |
| 40 | struct nfs_client *clp; | 40 | struct nfs_client *clp; |
| 41 | int slotid; | 41 | u32 slotid; |
| 42 | struct net *net; | ||
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | struct cb_compound_hdr_arg { | 45 | struct cb_compound_hdr_arg { |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 54cea8ad5a76..1b5d809a105e 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/nfs4.h> | 8 | #include <linux/nfs4.h> |
| 9 | #include <linux/nfs_fs.h> | 9 | #include <linux/nfs_fs.h> |
| 10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
| 11 | #include <linux/rcupdate.h> | ||
| 11 | #include "nfs4_fs.h" | 12 | #include "nfs4_fs.h" |
| 12 | #include "callback.h" | 13 | #include "callback.h" |
| 13 | #include "delegation.h" | 14 | #include "delegation.h" |
| @@ -33,7 +34,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, | |||
| 33 | res->bitmap[0] = res->bitmap[1] = 0; | 34 | res->bitmap[0] = res->bitmap[1] = 0; |
| 34 | res->status = htonl(NFS4ERR_BADHANDLE); | 35 | res->status = htonl(NFS4ERR_BADHANDLE); |
| 35 | 36 | ||
| 36 | dprintk("NFS: GETATTR callback request from %s\n", | 37 | dprintk_rcu("NFS: GETATTR callback request from %s\n", |
| 37 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | 38 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
| 38 | 39 | ||
| 39 | inode = nfs_delegation_find_inode(cps->clp, &args->fh); | 40 | inode = nfs_delegation_find_inode(cps->clp, &args->fh); |
| @@ -73,7 +74,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, | |||
| 73 | if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ | 74 | if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ |
| 74 | goto out; | 75 | goto out; |
| 75 | 76 | ||
| 76 | dprintk("NFS: RECALL callback request from %s\n", | 77 | dprintk_rcu("NFS: RECALL callback request from %s\n", |
| 77 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | 78 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
| 78 | 79 | ||
| 79 | res = htonl(NFS4ERR_BADHANDLE); | 80 | res = htonl(NFS4ERR_BADHANDLE); |
| @@ -86,8 +87,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, | |||
| 86 | res = 0; | 87 | res = 0; |
| 87 | break; | 88 | break; |
| 88 | case -ENOENT: | 89 | case -ENOENT: |
| 89 | if (res != 0) | 90 | res = htonl(NFS4ERR_BAD_STATEID); |
| 90 | res = htonl(NFS4ERR_BAD_STATEID); | ||
| 91 | break; | 91 | break; |
| 92 | default: | 92 | default: |
| 93 | res = htonl(NFS4ERR_RESOURCE); | 93 | res = htonl(NFS4ERR_RESOURCE); |
| @@ -98,52 +98,64 @@ out: | |||
| 98 | return res; | 98 | return res; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) | ||
| 102 | { | ||
| 103 | if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, | ||
| 104 | sizeof(delegation->stateid.data)) != 0) | ||
| 105 | return 0; | ||
| 106 | return 1; | ||
| 107 | } | ||
| 108 | |||
| 109 | #if defined(CONFIG_NFS_V4_1) | 101 | #if defined(CONFIG_NFS_V4_1) |
| 110 | 102 | ||
| 111 | static u32 initiate_file_draining(struct nfs_client *clp, | 103 | /* |
| 112 | struct cb_layoutrecallargs *args) | 104 | * Lookup a layout by filehandle. |
| 105 | * | ||
| 106 | * Note: gets a refcount on the layout hdr and on its respective inode. | ||
| 107 | * Caller must put the layout hdr and the inode. | ||
| 108 | * | ||
| 109 | * TODO: keep track of all layouts (and delegations) in a hash table | ||
| 110 | * hashed by filehandle. | ||
| 111 | */ | ||
| 112 | static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh) | ||
| 113 | { | 113 | { |
| 114 | struct nfs_server *server; | 114 | struct nfs_server *server; |
| 115 | struct pnfs_layout_hdr *lo; | ||
| 116 | struct inode *ino; | 115 | struct inode *ino; |
| 117 | bool found = false; | 116 | struct pnfs_layout_hdr *lo; |
| 118 | u32 rv = NFS4ERR_NOMATCHING_LAYOUT; | ||
| 119 | LIST_HEAD(free_me_list); | ||
| 120 | 117 | ||
| 121 | spin_lock(&clp->cl_lock); | ||
| 122 | rcu_read_lock(); | ||
| 123 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | 118 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
| 124 | list_for_each_entry(lo, &server->layouts, plh_layouts) { | 119 | list_for_each_entry(lo, &server->layouts, plh_layouts) { |
| 125 | if (nfs_compare_fh(&args->cbl_fh, | 120 | if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh)) |
| 126 | &NFS_I(lo->plh_inode)->fh)) | ||
| 127 | continue; | 121 | continue; |
| 128 | ino = igrab(lo->plh_inode); | 122 | ino = igrab(lo->plh_inode); |
| 129 | if (!ino) | 123 | if (!ino) |
| 130 | continue; | 124 | continue; |
| 131 | found = true; | ||
| 132 | /* Without this, layout can be freed as soon | ||
| 133 | * as we release cl_lock. | ||
| 134 | */ | ||
| 135 | get_layout_hdr(lo); | 125 | get_layout_hdr(lo); |
| 136 | break; | 126 | return lo; |
| 137 | } | 127 | } |
| 138 | if (found) | ||
| 139 | break; | ||
| 140 | } | 128 | } |
| 129 | |||
| 130 | return NULL; | ||
| 131 | } | ||
| 132 | |||
| 133 | static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh) | ||
| 134 | { | ||
| 135 | struct pnfs_layout_hdr *lo; | ||
| 136 | |||
| 137 | spin_lock(&clp->cl_lock); | ||
| 138 | rcu_read_lock(); | ||
| 139 | lo = get_layout_by_fh_locked(clp, fh); | ||
| 141 | rcu_read_unlock(); | 140 | rcu_read_unlock(); |
| 142 | spin_unlock(&clp->cl_lock); | 141 | spin_unlock(&clp->cl_lock); |
| 143 | 142 | ||
| 144 | if (!found) | 143 | return lo; |
| 144 | } | ||
| 145 | |||
| 146 | static u32 initiate_file_draining(struct nfs_client *clp, | ||
| 147 | struct cb_layoutrecallargs *args) | ||
| 148 | { | ||
| 149 | struct inode *ino; | ||
| 150 | struct pnfs_layout_hdr *lo; | ||
| 151 | u32 rv = NFS4ERR_NOMATCHING_LAYOUT; | ||
| 152 | LIST_HEAD(free_me_list); | ||
| 153 | |||
| 154 | lo = get_layout_by_fh(clp, &args->cbl_fh); | ||
| 155 | if (!lo) | ||
| 145 | return NFS4ERR_NOMATCHING_LAYOUT; | 156 | return NFS4ERR_NOMATCHING_LAYOUT; |
| 146 | 157 | ||
| 158 | ino = lo->plh_inode; | ||
| 147 | spin_lock(&ino->i_lock); | 159 | spin_lock(&ino->i_lock); |
| 148 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || | 160 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || |
| 149 | mark_matching_lsegs_invalid(lo, &free_me_list, | 161 | mark_matching_lsegs_invalid(lo, &free_me_list, |
| @@ -213,17 +225,13 @@ static u32 initiate_bulk_draining(struct nfs_client *clp, | |||
| 213 | static u32 do_callback_layoutrecall(struct nfs_client *clp, | 225 | static u32 do_callback_layoutrecall(struct nfs_client *clp, |
| 214 | struct cb_layoutrecallargs *args) | 226 | struct cb_layoutrecallargs *args) |
| 215 | { | 227 | { |
| 216 | u32 res = NFS4ERR_DELAY; | 228 | u32 res; |
| 217 | 229 | ||
| 218 | dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type); | 230 | dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type); |
| 219 | if (test_and_set_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state)) | ||
| 220 | goto out; | ||
| 221 | if (args->cbl_recall_type == RETURN_FILE) | 231 | if (args->cbl_recall_type == RETURN_FILE) |
| 222 | res = initiate_file_draining(clp, args); | 232 | res = initiate_file_draining(clp, args); |
| 223 | else | 233 | else |
| 224 | res = initiate_bulk_draining(clp, args); | 234 | res = initiate_bulk_draining(clp, args); |
| 225 | clear_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state); | ||
| 226 | out: | ||
| 227 | dprintk("%s returning %i\n", __func__, res); | 235 | dprintk("%s returning %i\n", __func__, res); |
| 228 | return res; | 236 | return res; |
| 229 | 237 | ||
| @@ -303,21 +311,6 @@ out: | |||
| 303 | return res; | 311 | return res; |
| 304 | } | 312 | } |
| 305 | 313 | ||
| 306 | int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) | ||
| 307 | { | ||
| 308 | if (delegation == NULL) | ||
| 309 | return 0; | ||
| 310 | |||
| 311 | if (stateid->stateid.seqid != 0) | ||
| 312 | return 0; | ||
| 313 | if (memcmp(&delegation->stateid.stateid.other, | ||
| 314 | &stateid->stateid.other, | ||
| 315 | NFS4_STATEID_OTHER_SIZE)) | ||
| 316 | return 0; | ||
| 317 | |||
| 318 | return 1; | ||
| 319 | } | ||
| 320 | |||
| 321 | /* | 314 | /* |
| 322 | * Validate the sequenceID sent by the server. | 315 | * Validate the sequenceID sent by the server. |
| 323 | * Return success if the sequenceID is one more than what we last saw on | 316 | * 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, | |||
| 441 | int i; | 434 | int i; |
| 442 | __be32 status = htonl(NFS4ERR_BADSESSION); | 435 | __be32 status = htonl(NFS4ERR_BADSESSION); |
| 443 | 436 | ||
| 444 | clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid); | 437 | clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, &args->csa_sessionid); |
| 445 | if (clp == NULL) | 438 | if (clp == NULL) |
| 446 | goto out; | 439 | goto out; |
| 447 | 440 | ||
| @@ -517,7 +510,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy, | |||
| 517 | if (!cps->clp) /* set in cb_sequence */ | 510 | if (!cps->clp) /* set in cb_sequence */ |
| 518 | goto out; | 511 | goto out; |
| 519 | 512 | ||
| 520 | dprintk("NFS: RECALL_ANY callback request from %s\n", | 513 | dprintk_rcu("NFS: RECALL_ANY callback request from %s\n", |
| 521 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | 514 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
| 522 | 515 | ||
| 523 | status = cpu_to_be32(NFS4ERR_INVAL); | 516 | status = cpu_to_be32(NFS4ERR_INVAL); |
| @@ -552,7 +545,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, | |||
| 552 | if (!cps->clp) /* set in cb_sequence */ | 545 | if (!cps->clp) /* set in cb_sequence */ |
| 553 | goto out; | 546 | goto out; |
| 554 | 547 | ||
| 555 | dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", | 548 | dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", |
| 556 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR), | 549 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR), |
| 557 | args->crsa_target_max_slots); | 550 | args->crsa_target_max_slots); |
| 558 | 551 | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index d50b2742f23b..95bfc243992c 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | #include <linux/sunrpc/svc.h> | 9 | #include <linux/sunrpc/svc.h> |
| 10 | #include <linux/nfs4.h> | 10 | #include <linux/nfs4.h> |
| 11 | #include <linux/nfs_fs.h> | 11 | #include <linux/nfs_fs.h> |
| 12 | #include <linux/ratelimit.h> | ||
| 13 | #include <linux/printk.h> | ||
| 12 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 13 | #include <linux/sunrpc/bc_xprt.h> | 15 | #include <linux/sunrpc/bc_xprt.h> |
| 14 | #include "nfs4_fs.h" | 16 | #include "nfs4_fs.h" |
| @@ -73,7 +75,7 @@ static __be32 *read_buf(struct xdr_stream *xdr, int nbytes) | |||
| 73 | 75 | ||
| 74 | p = xdr_inline_decode(xdr, nbytes); | 76 | p = xdr_inline_decode(xdr, nbytes); |
| 75 | if (unlikely(p == NULL)) | 77 | if (unlikely(p == NULL)) |
| 76 | printk(KERN_WARNING "NFSv4 callback reply buffer overflowed!\n"); | 78 | printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n"); |
| 77 | return p; | 79 | return p; |
| 78 | } | 80 | } |
| 79 | 81 | ||
| @@ -138,10 +140,10 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) | |||
| 138 | { | 140 | { |
| 139 | __be32 *p; | 141 | __be32 *p; |
| 140 | 142 | ||
| 141 | p = read_buf(xdr, 16); | 143 | p = read_buf(xdr, NFS4_STATEID_SIZE); |
| 142 | if (unlikely(p == NULL)) | 144 | if (unlikely(p == NULL)) |
| 143 | return htonl(NFS4ERR_RESOURCE); | 145 | return htonl(NFS4ERR_RESOURCE); |
| 144 | memcpy(stateid->data, p, 16); | 146 | memcpy(stateid, p, NFS4_STATEID_SIZE); |
| 145 | return 0; | 147 | return 0; |
| 146 | } | 148 | } |
| 147 | 149 | ||
| @@ -155,7 +157,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
| 155 | return status; | 157 | return status; |
| 156 | /* We do not like overly long tags! */ | 158 | /* We do not like overly long tags! */ |
| 157 | if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) { | 159 | if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) { |
| 158 | printk("NFSv4 CALLBACK %s: client sent tag of length %u\n", | 160 | printk("NFS: NFSv4 CALLBACK %s: client sent tag of length %u\n", |
| 159 | __func__, hdr->taglen); | 161 | __func__, hdr->taglen); |
| 160 | return htonl(NFS4ERR_RESOURCE); | 162 | return htonl(NFS4ERR_RESOURCE); |
| 161 | } | 163 | } |
| @@ -167,7 +169,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
| 167 | if (hdr->minorversion <= 1) { | 169 | if (hdr->minorversion <= 1) { |
| 168 | hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */ | 170 | hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */ |
| 169 | } else { | 171 | } else { |
| 170 | printk(KERN_WARNING "%s: NFSv4 server callback with " | 172 | pr_warn_ratelimited("NFS: %s: NFSv4 server callback with " |
| 171 | "illegal minor version %u!\n", | 173 | "illegal minor version %u!\n", |
| 172 | __func__, hdr->minorversion); | 174 | __func__, hdr->minorversion); |
| 173 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | 175 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); |
| @@ -759,14 +761,14 @@ static void nfs4_callback_free_slot(struct nfs4_session *session) | |||
| 759 | * Let the state manager know callback processing done. | 761 | * Let the state manager know callback processing done. |
| 760 | * A single slot, so highest used slotid is either 0 or -1 | 762 | * A single slot, so highest used slotid is either 0 or -1 |
| 761 | */ | 763 | */ |
| 762 | tbl->highest_used_slotid = -1; | 764 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
| 763 | nfs4_check_drain_bc_complete(session); | 765 | nfs4_check_drain_bc_complete(session); |
| 764 | spin_unlock(&tbl->slot_tbl_lock); | 766 | spin_unlock(&tbl->slot_tbl_lock); |
| 765 | } | 767 | } |
| 766 | 768 | ||
| 767 | static void nfs4_cb_free_slot(struct cb_process_state *cps) | 769 | static void nfs4_cb_free_slot(struct cb_process_state *cps) |
| 768 | { | 770 | { |
| 769 | if (cps->slotid != -1) | 771 | if (cps->slotid != NFS4_NO_SLOT) |
| 770 | nfs4_callback_free_slot(cps->clp->cl_session); | 772 | nfs4_callback_free_slot(cps->clp->cl_session); |
| 771 | } | 773 | } |
| 772 | 774 | ||
| @@ -860,7 +862,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
| 860 | struct cb_process_state cps = { | 862 | struct cb_process_state cps = { |
| 861 | .drc_status = 0, | 863 | .drc_status = 0, |
| 862 | .clp = NULL, | 864 | .clp = NULL, |
| 863 | .slotid = -1, | 865 | .slotid = NFS4_NO_SLOT, |
| 866 | .net = rqstp->rq_xprt->xpt_net, | ||
| 864 | }; | 867 | }; |
| 865 | unsigned int nops = 0; | 868 | unsigned int nops = 0; |
| 866 | 869 | ||
| @@ -876,7 +879,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
| 876 | return rpc_garbage_args; | 879 | return rpc_garbage_args; |
| 877 | 880 | ||
| 878 | if (hdr_arg.minorversion == 0) { | 881 | if (hdr_arg.minorversion == 0) { |
| 879 | cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident); | 882 | cps.clp = nfs4_find_client_ident(rqstp->rq_xprt->xpt_net, hdr_arg.cb_ident); |
| 880 | if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) | 883 | if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) |
| 881 | return rpc_drop_reply; | 884 | return rpc_drop_reply; |
| 882 | } | 885 | } |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index d4f772ebd1ef..4a108a0a2a60 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -40,6 +40,8 @@ | |||
| 40 | #include <net/ipv6.h> | 40 | #include <net/ipv6.h> |
| 41 | #include <linux/nfs_xdr.h> | 41 | #include <linux/nfs_xdr.h> |
| 42 | #include <linux/sunrpc/bc_xprt.h> | 42 | #include <linux/sunrpc/bc_xprt.h> |
| 43 | #include <linux/nsproxy.h> | ||
| 44 | #include <linux/pid_namespace.h> | ||
| 43 | 45 | ||
| 44 | #include <asm/system.h> | 46 | #include <asm/system.h> |
| 45 | 47 | ||
| @@ -50,15 +52,12 @@ | |||
| 50 | #include "internal.h" | 52 | #include "internal.h" |
| 51 | #include "fscache.h" | 53 | #include "fscache.h" |
| 52 | #include "pnfs.h" | 54 | #include "pnfs.h" |
| 55 | #include "netns.h" | ||
| 53 | 56 | ||
| 54 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 57 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
| 55 | 58 | ||
| 56 | static DEFINE_SPINLOCK(nfs_client_lock); | ||
| 57 | static LIST_HEAD(nfs_client_list); | ||
| 58 | static LIST_HEAD(nfs_volume_list); | ||
| 59 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | 59 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); |
| 60 | #ifdef CONFIG_NFS_V4 | 60 | #ifdef CONFIG_NFS_V4 |
| 61 | static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */ | ||
| 62 | 61 | ||
| 63 | /* | 62 | /* |
| 64 | * Get a unique NFSv4.0 callback identifier which will be used | 63 | * 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 */ | |||
| 67 | static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) | 66 | static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) |
| 68 | { | 67 | { |
| 69 | int ret = 0; | 68 | int ret = 0; |
| 69 | struct nfs_net *nn = net_generic(clp->net, nfs_net_id); | ||
| 70 | 70 | ||
| 71 | if (clp->rpc_ops->version != 4 || minorversion != 0) | 71 | if (clp->rpc_ops->version != 4 || minorversion != 0) |
| 72 | return ret; | 72 | return ret; |
| 73 | retry: | 73 | retry: |
| 74 | if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL)) | 74 | if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL)) |
| 75 | return -ENOMEM; | 75 | return -ENOMEM; |
| 76 | spin_lock(&nfs_client_lock); | 76 | spin_lock(&nn->nfs_client_lock); |
| 77 | ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident); | 77 | ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident); |
| 78 | spin_unlock(&nfs_client_lock); | 78 | spin_unlock(&nn->nfs_client_lock); |
| 79 | if (ret == -EAGAIN) | 79 | if (ret == -EAGAIN) |
| 80 | goto retry; | 80 | goto retry; |
| 81 | return ret; | 81 | return ret; |
| @@ -90,7 +90,7 @@ static bool nfs4_disable_idmapping = true; | |||
| 90 | /* | 90 | /* |
| 91 | * RPC cruft for NFS | 91 | * RPC cruft for NFS |
| 92 | */ | 92 | */ |
| 93 | static struct rpc_version *nfs_version[5] = { | 93 | static const struct rpc_version *nfs_version[5] = { |
| 94 | [2] = &nfs_version2, | 94 | [2] = &nfs_version2, |
| 95 | #ifdef CONFIG_NFS_V3 | 95 | #ifdef CONFIG_NFS_V3 |
| 96 | [3] = &nfs_version3, | 96 | [3] = &nfs_version3, |
| @@ -100,7 +100,7 @@ static struct rpc_version *nfs_version[5] = { | |||
| 100 | #endif | 100 | #endif |
| 101 | }; | 101 | }; |
| 102 | 102 | ||
| 103 | struct rpc_program nfs_program = { | 103 | const struct rpc_program nfs_program = { |
| 104 | .name = "nfs", | 104 | .name = "nfs", |
| 105 | .number = NFS_PROGRAM, | 105 | .number = NFS_PROGRAM, |
| 106 | .nrvers = ARRAY_SIZE(nfs_version), | 106 | .nrvers = ARRAY_SIZE(nfs_version), |
| @@ -116,11 +116,11 @@ struct rpc_stat nfs_rpcstat = { | |||
| 116 | 116 | ||
| 117 | #ifdef CONFIG_NFS_V3_ACL | 117 | #ifdef CONFIG_NFS_V3_ACL |
| 118 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; | 118 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; |
| 119 | static struct rpc_version * nfsacl_version[] = { | 119 | static const struct rpc_version *nfsacl_version[] = { |
| 120 | [3] = &nfsacl_version3, | 120 | [3] = &nfsacl_version3, |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | struct rpc_program nfsacl_program = { | 123 | const struct rpc_program nfsacl_program = { |
| 124 | .name = "nfsacl", | 124 | .name = "nfsacl", |
| 125 | .number = NFS_ACL_PROGRAM, | 125 | .number = NFS_ACL_PROGRAM, |
| 126 | .nrvers = ARRAY_SIZE(nfsacl_version), | 126 | .nrvers = ARRAY_SIZE(nfsacl_version), |
| @@ -136,6 +136,7 @@ struct nfs_client_initdata { | |||
| 136 | const struct nfs_rpc_ops *rpc_ops; | 136 | const struct nfs_rpc_ops *rpc_ops; |
| 137 | int proto; | 137 | int proto; |
| 138 | u32 minorversion; | 138 | u32 minorversion; |
| 139 | struct net *net; | ||
| 139 | }; | 140 | }; |
| 140 | 141 | ||
| 141 | /* | 142 | /* |
| @@ -172,6 +173,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
| 172 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | 173 | clp->cl_rpcclient = ERR_PTR(-EINVAL); |
| 173 | 174 | ||
| 174 | clp->cl_proto = cl_init->proto; | 175 | clp->cl_proto = cl_init->proto; |
| 176 | clp->net = get_net(cl_init->net); | ||
| 175 | 177 | ||
| 176 | #ifdef CONFIG_NFS_V4 | 178 | #ifdef CONFIG_NFS_V4 |
| 177 | err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); | 179 | err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); |
| @@ -203,8 +205,11 @@ error_0: | |||
| 203 | #ifdef CONFIG_NFS_V4_1 | 205 | #ifdef CONFIG_NFS_V4_1 |
| 204 | static void nfs4_shutdown_session(struct nfs_client *clp) | 206 | static void nfs4_shutdown_session(struct nfs_client *clp) |
| 205 | { | 207 | { |
| 206 | if (nfs4_has_session(clp)) | 208 | if (nfs4_has_session(clp)) { |
| 209 | nfs4_deviceid_purge_client(clp); | ||
| 207 | nfs4_destroy_session(clp->cl_session); | 210 | nfs4_destroy_session(clp->cl_session); |
| 211 | } | ||
| 212 | |||
| 208 | } | 213 | } |
| 209 | #else /* CONFIG_NFS_V4_1 */ | 214 | #else /* CONFIG_NFS_V4_1 */ |
| 210 | static void nfs4_shutdown_session(struct nfs_client *clp) | 215 | static void nfs4_shutdown_session(struct nfs_client *clp) |
| @@ -234,16 +239,20 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
| 234 | } | 239 | } |
| 235 | 240 | ||
| 236 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ | 241 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ |
| 237 | void nfs_cleanup_cb_ident_idr(void) | 242 | void nfs_cleanup_cb_ident_idr(struct net *net) |
| 238 | { | 243 | { |
| 239 | idr_destroy(&cb_ident_idr); | 244 | struct nfs_net *nn = net_generic(net, nfs_net_id); |
| 245 | |||
| 246 | idr_destroy(&nn->cb_ident_idr); | ||
| 240 | } | 247 | } |
| 241 | 248 | ||
| 242 | /* nfs_client_lock held */ | 249 | /* nfs_client_lock held */ |
| 243 | static void nfs_cb_idr_remove_locked(struct nfs_client *clp) | 250 | static void nfs_cb_idr_remove_locked(struct nfs_client *clp) |
| 244 | { | 251 | { |
| 252 | struct nfs_net *nn = net_generic(clp->net, nfs_net_id); | ||
| 253 | |||
| 245 | if (clp->cl_cb_ident) | 254 | if (clp->cl_cb_ident) |
| 246 | idr_remove(&cb_ident_idr, clp->cl_cb_ident); | 255 | idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident); |
| 247 | } | 256 | } |
| 248 | 257 | ||
| 249 | static void pnfs_init_server(struct nfs_server *server) | 258 | static void pnfs_init_server(struct nfs_server *server) |
| @@ -261,7 +270,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
| 261 | { | 270 | { |
| 262 | } | 271 | } |
| 263 | 272 | ||
| 264 | void nfs_cleanup_cb_ident_idr(void) | 273 | void nfs_cleanup_cb_ident_idr(struct net *net) |
| 265 | { | 274 | { |
| 266 | } | 275 | } |
| 267 | 276 | ||
| @@ -293,10 +302,10 @@ static void nfs_free_client(struct nfs_client *clp) | |||
| 293 | if (clp->cl_machine_cred != NULL) | 302 | if (clp->cl_machine_cred != NULL) |
| 294 | put_rpccred(clp->cl_machine_cred); | 303 | put_rpccred(clp->cl_machine_cred); |
| 295 | 304 | ||
| 296 | nfs4_deviceid_purge_client(clp); | 305 | put_net(clp->net); |
| 297 | |||
| 298 | kfree(clp->cl_hostname); | 306 | kfree(clp->cl_hostname); |
| 299 | kfree(clp->server_scope); | 307 | kfree(clp->server_scope); |
| 308 | kfree(clp->impl_id); | ||
| 300 | kfree(clp); | 309 | kfree(clp); |
| 301 | 310 | ||
| 302 | dprintk("<-- nfs_free_client()\n"); | 311 | dprintk("<-- nfs_free_client()\n"); |
| @@ -307,15 +316,18 @@ static void nfs_free_client(struct nfs_client *clp) | |||
| 307 | */ | 316 | */ |
| 308 | void nfs_put_client(struct nfs_client *clp) | 317 | void nfs_put_client(struct nfs_client *clp) |
| 309 | { | 318 | { |
| 319 | struct nfs_net *nn; | ||
| 320 | |||
| 310 | if (!clp) | 321 | if (!clp) |
| 311 | return; | 322 | return; |
| 312 | 323 | ||
| 313 | dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); | 324 | dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); |
| 325 | nn = net_generic(clp->net, nfs_net_id); | ||
| 314 | 326 | ||
| 315 | if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) { | 327 | if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) { |
| 316 | list_del(&clp->cl_share_link); | 328 | list_del(&clp->cl_share_link); |
| 317 | nfs_cb_idr_remove_locked(clp); | 329 | nfs_cb_idr_remove_locked(clp); |
| 318 | spin_unlock(&nfs_client_lock); | 330 | spin_unlock(&nn->nfs_client_lock); |
| 319 | 331 | ||
| 320 | BUG_ON(!list_empty(&clp->cl_superblocks)); | 332 | BUG_ON(!list_empty(&clp->cl_superblocks)); |
| 321 | 333 | ||
| @@ -393,6 +405,7 @@ static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, | |||
| 393 | (sin1->sin_port == sin2->sin_port); | 405 | (sin1->sin_port == sin2->sin_port); |
| 394 | } | 406 | } |
| 395 | 407 | ||
| 408 | #if defined(CONFIG_NFS_V4_1) | ||
| 396 | /* | 409 | /* |
| 397 | * Test if two socket addresses represent the same actual socket, | 410 | * Test if two socket addresses represent the same actual socket, |
| 398 | * by comparing (only) relevant fields, excluding the port number. | 411 | * by comparing (only) relevant fields, excluding the port number. |
| @@ -411,6 +424,7 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | |||
| 411 | } | 424 | } |
| 412 | return 0; | 425 | return 0; |
| 413 | } | 426 | } |
| 427 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 414 | 428 | ||
| 415 | /* | 429 | /* |
| 416 | * Test if two socket addresses represent the same actual socket, | 430 | * Test if two socket addresses represent the same actual socket, |
| @@ -431,10 +445,10 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1, | |||
| 431 | return 0; | 445 | return 0; |
| 432 | } | 446 | } |
| 433 | 447 | ||
| 448 | #if defined(CONFIG_NFS_V4_1) | ||
| 434 | /* Common match routine for v4.0 and v4.1 callback services */ | 449 | /* Common match routine for v4.0 and v4.1 callback services */ |
| 435 | bool | 450 | static bool nfs4_cb_match_client(const struct sockaddr *addr, |
| 436 | nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp, | 451 | struct nfs_client *clp, u32 minorversion) |
| 437 | u32 minorversion) | ||
| 438 | { | 452 | { |
| 439 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 453 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
| 440 | 454 | ||
| @@ -454,6 +468,7 @@ nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp, | |||
| 454 | 468 | ||
| 455 | return true; | 469 | return true; |
| 456 | } | 470 | } |
| 471 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 457 | 472 | ||
| 458 | /* | 473 | /* |
| 459 | * Find an nfs_client on the list that matches the initialisation data | 474 | * 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 | |||
| 463 | { | 478 | { |
| 464 | struct nfs_client *clp; | 479 | struct nfs_client *clp; |
| 465 | const struct sockaddr *sap = data->addr; | 480 | const struct sockaddr *sap = data->addr; |
| 481 | struct nfs_net *nn = net_generic(data->net, nfs_net_id); | ||
| 466 | 482 | ||
| 467 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | 483 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { |
| 468 | const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 484 | const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
| 469 | /* Don't match clients that failed to initialise properly */ | 485 | /* Don't match clients that failed to initialise properly */ |
| 470 | if (clp->cl_cons_state < 0) | 486 | if (clp->cl_cons_state < 0) |
| @@ -502,13 +518,14 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
| 502 | { | 518 | { |
| 503 | struct nfs_client *clp, *new = NULL; | 519 | struct nfs_client *clp, *new = NULL; |
| 504 | int error; | 520 | int error; |
| 521 | struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id); | ||
| 505 | 522 | ||
| 506 | dprintk("--> nfs_get_client(%s,v%u)\n", | 523 | dprintk("--> nfs_get_client(%s,v%u)\n", |
| 507 | cl_init->hostname ?: "", cl_init->rpc_ops->version); | 524 | cl_init->hostname ?: "", cl_init->rpc_ops->version); |
| 508 | 525 | ||
| 509 | /* see if the client already exists */ | 526 | /* see if the client already exists */ |
| 510 | do { | 527 | do { |
| 511 | spin_lock(&nfs_client_lock); | 528 | spin_lock(&nn->nfs_client_lock); |
| 512 | 529 | ||
| 513 | clp = nfs_match_client(cl_init); | 530 | clp = nfs_match_client(cl_init); |
| 514 | if (clp) | 531 | if (clp) |
| @@ -516,7 +533,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
| 516 | if (new) | 533 | if (new) |
| 517 | goto install_client; | 534 | goto install_client; |
| 518 | 535 | ||
| 519 | spin_unlock(&nfs_client_lock); | 536 | spin_unlock(&nn->nfs_client_lock); |
| 520 | 537 | ||
| 521 | new = nfs_alloc_client(cl_init); | 538 | new = nfs_alloc_client(cl_init); |
| 522 | } while (!IS_ERR(new)); | 539 | } while (!IS_ERR(new)); |
| @@ -527,8 +544,8 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
| 527 | /* install a new client and return with it unready */ | 544 | /* install a new client and return with it unready */ |
| 528 | install_client: | 545 | install_client: |
| 529 | clp = new; | 546 | clp = new; |
| 530 | list_add(&clp->cl_share_link, &nfs_client_list); | 547 | list_add(&clp->cl_share_link, &nn->nfs_client_list); |
| 531 | spin_unlock(&nfs_client_lock); | 548 | spin_unlock(&nn->nfs_client_lock); |
| 532 | 549 | ||
| 533 | error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr, | 550 | error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr, |
| 534 | authflavour, noresvport); | 551 | authflavour, noresvport); |
| @@ -543,7 +560,7 @@ install_client: | |||
| 543 | * - make sure it's ready before returning | 560 | * - make sure it's ready before returning |
| 544 | */ | 561 | */ |
| 545 | found_client: | 562 | found_client: |
| 546 | spin_unlock(&nfs_client_lock); | 563 | spin_unlock(&nn->nfs_client_lock); |
| 547 | 564 | ||
| 548 | if (new) | 565 | if (new) |
| 549 | nfs_free_client(new); | 566 | nfs_free_client(new); |
| @@ -643,7 +660,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp, | |||
| 643 | { | 660 | { |
| 644 | struct rpc_clnt *clnt = NULL; | 661 | struct rpc_clnt *clnt = NULL; |
| 645 | struct rpc_create_args args = { | 662 | struct rpc_create_args args = { |
| 646 | .net = &init_net, | 663 | .net = clp->net, |
| 647 | .protocol = clp->cl_proto, | 664 | .protocol = clp->cl_proto, |
| 648 | .address = (struct sockaddr *)&clp->cl_addr, | 665 | .address = (struct sockaddr *)&clp->cl_addr, |
| 649 | .addrsize = clp->cl_addrlen, | 666 | .addrsize = clp->cl_addrlen, |
| @@ -697,6 +714,7 @@ static int nfs_start_lockd(struct nfs_server *server) | |||
| 697 | .nfs_version = clp->rpc_ops->version, | 714 | .nfs_version = clp->rpc_ops->version, |
| 698 | .noresvport = server->flags & NFS_MOUNT_NORESVPORT ? | 715 | .noresvport = server->flags & NFS_MOUNT_NORESVPORT ? |
| 699 | 1 : 0, | 716 | 1 : 0, |
| 717 | .net = clp->net, | ||
| 700 | }; | 718 | }; |
| 701 | 719 | ||
| 702 | if (nlm_init.nfs_version > 3) | 720 | if (nlm_init.nfs_version > 3) |
| @@ -832,6 +850,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
| 832 | .addrlen = data->nfs_server.addrlen, | 850 | .addrlen = data->nfs_server.addrlen, |
| 833 | .rpc_ops = &nfs_v2_clientops, | 851 | .rpc_ops = &nfs_v2_clientops, |
| 834 | .proto = data->nfs_server.protocol, | 852 | .proto = data->nfs_server.protocol, |
| 853 | .net = data->net, | ||
| 835 | }; | 854 | }; |
| 836 | struct rpc_timeout timeparms; | 855 | struct rpc_timeout timeparms; |
| 837 | struct nfs_client *clp; | 856 | struct nfs_client *clp; |
| @@ -1030,25 +1049,30 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve | |||
| 1030 | static void nfs_server_insert_lists(struct nfs_server *server) | 1049 | static void nfs_server_insert_lists(struct nfs_server *server) |
| 1031 | { | 1050 | { |
| 1032 | struct nfs_client *clp = server->nfs_client; | 1051 | struct nfs_client *clp = server->nfs_client; |
| 1052 | struct nfs_net *nn = net_generic(clp->net, nfs_net_id); | ||
| 1033 | 1053 | ||
| 1034 | spin_lock(&nfs_client_lock); | 1054 | spin_lock(&nn->nfs_client_lock); |
| 1035 | list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); | 1055 | list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); |
| 1036 | list_add_tail(&server->master_link, &nfs_volume_list); | 1056 | list_add_tail(&server->master_link, &nn->nfs_volume_list); |
| 1037 | clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); | 1057 | clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); |
| 1038 | spin_unlock(&nfs_client_lock); | 1058 | spin_unlock(&nn->nfs_client_lock); |
| 1039 | 1059 | ||
| 1040 | } | 1060 | } |
| 1041 | 1061 | ||
| 1042 | static void nfs_server_remove_lists(struct nfs_server *server) | 1062 | static void nfs_server_remove_lists(struct nfs_server *server) |
| 1043 | { | 1063 | { |
| 1044 | struct nfs_client *clp = server->nfs_client; | 1064 | struct nfs_client *clp = server->nfs_client; |
| 1065 | struct nfs_net *nn; | ||
| 1045 | 1066 | ||
| 1046 | spin_lock(&nfs_client_lock); | 1067 | if (clp == NULL) |
| 1068 | return; | ||
| 1069 | nn = net_generic(clp->net, nfs_net_id); | ||
| 1070 | spin_lock(&nn->nfs_client_lock); | ||
| 1047 | list_del_rcu(&server->client_link); | 1071 | list_del_rcu(&server->client_link); |
| 1048 | if (clp && list_empty(&clp->cl_superblocks)) | 1072 | if (list_empty(&clp->cl_superblocks)) |
| 1049 | set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); | 1073 | set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); |
| 1050 | list_del(&server->master_link); | 1074 | list_del(&server->master_link); |
| 1051 | spin_unlock(&nfs_client_lock); | 1075 | spin_unlock(&nn->nfs_client_lock); |
| 1052 | 1076 | ||
| 1053 | synchronize_rcu(); | 1077 | synchronize_rcu(); |
| 1054 | } | 1078 | } |
| @@ -1087,6 +1111,8 @@ static struct nfs_server *nfs_alloc_server(void) | |||
| 1087 | return NULL; | 1111 | return NULL; |
| 1088 | } | 1112 | } |
| 1089 | 1113 | ||
| 1114 | ida_init(&server->openowner_id); | ||
| 1115 | ida_init(&server->lockowner_id); | ||
| 1090 | pnfs_init_server(server); | 1116 | pnfs_init_server(server); |
| 1091 | 1117 | ||
| 1092 | return server; | 1118 | return server; |
| @@ -1112,6 +1138,8 @@ void nfs_free_server(struct nfs_server *server) | |||
| 1112 | 1138 | ||
| 1113 | nfs_put_client(server->nfs_client); | 1139 | nfs_put_client(server->nfs_client); |
| 1114 | 1140 | ||
| 1141 | ida_destroy(&server->lockowner_id); | ||
| 1142 | ida_destroy(&server->openowner_id); | ||
| 1115 | nfs_free_iostats(server->io_stats); | 1143 | nfs_free_iostats(server->io_stats); |
| 1116 | bdi_destroy(&server->backing_dev_info); | 1144 | bdi_destroy(&server->backing_dev_info); |
| 1117 | kfree(server); | 1145 | kfree(server); |
| @@ -1190,45 +1218,19 @@ error: | |||
| 1190 | /* | 1218 | /* |
| 1191 | * NFSv4.0 callback thread helper | 1219 | * NFSv4.0 callback thread helper |
| 1192 | * | 1220 | * |
| 1193 | * Find a client by IP address, protocol version, and minorversion | ||
| 1194 | * | ||
| 1195 | * Called from the pg_authenticate method. The callback identifier | ||
| 1196 | * is not used as it has not been decoded. | ||
| 1197 | * | ||
| 1198 | * Returns NULL if no such client | ||
| 1199 | */ | ||
| 1200 | struct nfs_client * | ||
| 1201 | nfs4_find_client_no_ident(const struct sockaddr *addr) | ||
| 1202 | { | ||
| 1203 | struct nfs_client *clp; | ||
| 1204 | |||
| 1205 | spin_lock(&nfs_client_lock); | ||
| 1206 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | ||
| 1207 | if (nfs4_cb_match_client(addr, clp, 0) == false) | ||
| 1208 | continue; | ||
| 1209 | atomic_inc(&clp->cl_count); | ||
| 1210 | spin_unlock(&nfs_client_lock); | ||
| 1211 | return clp; | ||
| 1212 | } | ||
| 1213 | spin_unlock(&nfs_client_lock); | ||
| 1214 | return NULL; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | /* | ||
| 1218 | * NFSv4.0 callback thread helper | ||
| 1219 | * | ||
| 1220 | * Find a client by callback identifier | 1221 | * Find a client by callback identifier |
| 1221 | */ | 1222 | */ |
| 1222 | struct nfs_client * | 1223 | struct nfs_client * |
| 1223 | nfs4_find_client_ident(int cb_ident) | 1224 | nfs4_find_client_ident(struct net *net, int cb_ident) |
| 1224 | { | 1225 | { |
| 1225 | struct nfs_client *clp; | 1226 | struct nfs_client *clp; |
| 1227 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 1226 | 1228 | ||
| 1227 | spin_lock(&nfs_client_lock); | 1229 | spin_lock(&nn->nfs_client_lock); |
| 1228 | clp = idr_find(&cb_ident_idr, cb_ident); | 1230 | clp = idr_find(&nn->cb_ident_idr, cb_ident); |
| 1229 | if (clp) | 1231 | if (clp) |
| 1230 | atomic_inc(&clp->cl_count); | 1232 | atomic_inc(&clp->cl_count); |
| 1231 | spin_unlock(&nfs_client_lock); | 1233 | spin_unlock(&nn->nfs_client_lock); |
| 1232 | return clp; | 1234 | return clp; |
| 1233 | } | 1235 | } |
| 1234 | 1236 | ||
| @@ -1241,13 +1243,14 @@ nfs4_find_client_ident(int cb_ident) | |||
| 1241 | * Returns NULL if no such client | 1243 | * Returns NULL if no such client |
| 1242 | */ | 1244 | */ |
| 1243 | struct nfs_client * | 1245 | struct nfs_client * |
| 1244 | nfs4_find_client_sessionid(const struct sockaddr *addr, | 1246 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, |
| 1245 | struct nfs4_sessionid *sid) | 1247 | struct nfs4_sessionid *sid) |
| 1246 | { | 1248 | { |
| 1247 | struct nfs_client *clp; | 1249 | struct nfs_client *clp; |
| 1250 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 1248 | 1251 | ||
| 1249 | spin_lock(&nfs_client_lock); | 1252 | spin_lock(&nn->nfs_client_lock); |
| 1250 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | 1253 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { |
| 1251 | if (nfs4_cb_match_client(addr, clp, 1) == false) | 1254 | if (nfs4_cb_match_client(addr, clp, 1) == false) |
| 1252 | continue; | 1255 | continue; |
| 1253 | 1256 | ||
| @@ -1260,17 +1263,17 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, | |||
| 1260 | continue; | 1263 | continue; |
| 1261 | 1264 | ||
| 1262 | atomic_inc(&clp->cl_count); | 1265 | atomic_inc(&clp->cl_count); |
| 1263 | spin_unlock(&nfs_client_lock); | 1266 | spin_unlock(&nn->nfs_client_lock); |
| 1264 | return clp; | 1267 | return clp; |
| 1265 | } | 1268 | } |
| 1266 | spin_unlock(&nfs_client_lock); | 1269 | spin_unlock(&nn->nfs_client_lock); |
| 1267 | return NULL; | 1270 | return NULL; |
| 1268 | } | 1271 | } |
| 1269 | 1272 | ||
| 1270 | #else /* CONFIG_NFS_V4_1 */ | 1273 | #else /* CONFIG_NFS_V4_1 */ |
| 1271 | 1274 | ||
| 1272 | struct nfs_client * | 1275 | struct nfs_client * |
| 1273 | nfs4_find_client_sessionid(const struct sockaddr *addr, | 1276 | nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, |
| 1274 | struct nfs4_sessionid *sid) | 1277 | struct nfs4_sessionid *sid) |
| 1275 | { | 1278 | { |
| 1276 | return NULL; | 1279 | return NULL; |
| @@ -1285,16 +1288,18 @@ static int nfs4_init_callback(struct nfs_client *clp) | |||
| 1285 | int error; | 1288 | int error; |
| 1286 | 1289 | ||
| 1287 | if (clp->rpc_ops->version == 4) { | 1290 | if (clp->rpc_ops->version == 4) { |
| 1291 | struct rpc_xprt *xprt; | ||
| 1292 | |||
| 1293 | xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); | ||
| 1294 | |||
| 1288 | if (nfs4_has_session(clp)) { | 1295 | if (nfs4_has_session(clp)) { |
| 1289 | error = xprt_setup_backchannel( | 1296 | error = xprt_setup_backchannel(xprt, |
| 1290 | clp->cl_rpcclient->cl_xprt, | ||
| 1291 | NFS41_BC_MIN_CALLBACKS); | 1297 | NFS41_BC_MIN_CALLBACKS); |
| 1292 | if (error < 0) | 1298 | if (error < 0) |
| 1293 | return error; | 1299 | return error; |
| 1294 | } | 1300 | } |
| 1295 | 1301 | ||
| 1296 | error = nfs_callback_up(clp->cl_mvops->minor_version, | 1302 | error = nfs_callback_up(clp->cl_mvops->minor_version, xprt); |
| 1297 | clp->cl_rpcclient->cl_xprt); | ||
| 1298 | if (error < 0) { | 1303 | if (error < 0) { |
| 1299 | dprintk("%s: failed to start callback. Error = %d\n", | 1304 | dprintk("%s: failed to start callback. Error = %d\n", |
| 1300 | __func__, error); | 1305 | __func__, error); |
| @@ -1345,6 +1350,7 @@ int nfs4_init_client(struct nfs_client *clp, | |||
| 1345 | rpc_authflavor_t authflavour, | 1350 | rpc_authflavor_t authflavour, |
| 1346 | int noresvport) | 1351 | int noresvport) |
| 1347 | { | 1352 | { |
| 1353 | char buf[INET6_ADDRSTRLEN + 1]; | ||
| 1348 | int error; | 1354 | int error; |
| 1349 | 1355 | ||
| 1350 | if (clp->cl_cons_state == NFS_CS_READY) { | 1356 | if (clp->cl_cons_state == NFS_CS_READY) { |
| @@ -1360,6 +1366,20 @@ int nfs4_init_client(struct nfs_client *clp, | |||
| 1360 | 1, noresvport); | 1366 | 1, noresvport); |
| 1361 | if (error < 0) | 1367 | if (error < 0) |
| 1362 | goto error; | 1368 | goto error; |
| 1369 | |||
| 1370 | /* If no clientaddr= option was specified, find a usable cb address */ | ||
| 1371 | if (ip_addr == NULL) { | ||
| 1372 | struct sockaddr_storage cb_addr; | ||
| 1373 | struct sockaddr *sap = (struct sockaddr *)&cb_addr; | ||
| 1374 | |||
| 1375 | error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr)); | ||
| 1376 | if (error < 0) | ||
| 1377 | goto error; | ||
| 1378 | error = rpc_ntop(sap, buf, sizeof(buf)); | ||
| 1379 | if (error < 0) | ||
| 1380 | goto error; | ||
| 1381 | ip_addr = (const char *)buf; | ||
| 1382 | } | ||
| 1363 | strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); | 1383 | strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); |
| 1364 | 1384 | ||
| 1365 | error = nfs_idmap_new(clp); | 1385 | error = nfs_idmap_new(clp); |
| @@ -1394,7 +1414,7 @@ static int nfs4_set_client(struct nfs_server *server, | |||
| 1394 | const char *ip_addr, | 1414 | const char *ip_addr, |
| 1395 | rpc_authflavor_t authflavour, | 1415 | rpc_authflavor_t authflavour, |
| 1396 | int proto, const struct rpc_timeout *timeparms, | 1416 | int proto, const struct rpc_timeout *timeparms, |
| 1397 | u32 minorversion) | 1417 | u32 minorversion, struct net *net) |
| 1398 | { | 1418 | { |
| 1399 | struct nfs_client_initdata cl_init = { | 1419 | struct nfs_client_initdata cl_init = { |
| 1400 | .hostname = hostname, | 1420 | .hostname = hostname, |
| @@ -1403,6 +1423,7 @@ static int nfs4_set_client(struct nfs_server *server, | |||
| 1403 | .rpc_ops = &nfs_v4_clientops, | 1423 | .rpc_ops = &nfs_v4_clientops, |
| 1404 | .proto = proto, | 1424 | .proto = proto, |
| 1405 | .minorversion = minorversion, | 1425 | .minorversion = minorversion, |
| 1426 | .net = net, | ||
| 1406 | }; | 1427 | }; |
| 1407 | struct nfs_client *clp; | 1428 | struct nfs_client *clp; |
| 1408 | int error; | 1429 | int error; |
| @@ -1454,6 +1475,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | |||
| 1454 | .rpc_ops = &nfs_v4_clientops, | 1475 | .rpc_ops = &nfs_v4_clientops, |
| 1455 | .proto = ds_proto, | 1476 | .proto = ds_proto, |
| 1456 | .minorversion = mds_clp->cl_minorversion, | 1477 | .minorversion = mds_clp->cl_minorversion, |
| 1478 | .net = mds_clp->net, | ||
| 1457 | }; | 1479 | }; |
| 1458 | struct rpc_timeout ds_timeout = { | 1480 | struct rpc_timeout ds_timeout = { |
| 1459 | .to_initval = 15 * HZ, | 1481 | .to_initval = 15 * HZ, |
| @@ -1581,7 +1603,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
| 1581 | data->auth_flavors[0], | 1603 | data->auth_flavors[0], |
| 1582 | data->nfs_server.protocol, | 1604 | data->nfs_server.protocol, |
| 1583 | &timeparms, | 1605 | &timeparms, |
| 1584 | data->minorversion); | 1606 | data->minorversion, |
| 1607 | data->net); | ||
| 1585 | if (error < 0) | 1608 | if (error < 0) |
| 1586 | goto error; | 1609 | goto error; |
| 1587 | 1610 | ||
| @@ -1676,9 +1699,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1676 | data->addrlen, | 1699 | data->addrlen, |
| 1677 | parent_client->cl_ipaddr, | 1700 | parent_client->cl_ipaddr, |
| 1678 | data->authflavor, | 1701 | data->authflavor, |
| 1679 | parent_server->client->cl_xprt->prot, | 1702 | rpc_protocol(parent_server->client), |
| 1680 | parent_server->client->cl_timeout, | 1703 | parent_server->client->cl_timeout, |
| 1681 | parent_client->cl_mvops->minor_version); | 1704 | parent_client->cl_mvops->minor_version, |
| 1705 | parent_client->net); | ||
| 1682 | if (error < 0) | 1706 | if (error < 0) |
| 1683 | goto error; | 1707 | goto error; |
| 1684 | 1708 | ||
| @@ -1771,6 +1795,18 @@ out_free_server: | |||
| 1771 | return ERR_PTR(error); | 1795 | return ERR_PTR(error); |
| 1772 | } | 1796 | } |
| 1773 | 1797 | ||
| 1798 | void nfs_clients_init(struct net *net) | ||
| 1799 | { | ||
| 1800 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 1801 | |||
| 1802 | INIT_LIST_HEAD(&nn->nfs_client_list); | ||
| 1803 | INIT_LIST_HEAD(&nn->nfs_volume_list); | ||
| 1804 | #ifdef CONFIG_NFS_V4 | ||
| 1805 | idr_init(&nn->cb_ident_idr); | ||
| 1806 | #endif | ||
| 1807 | spin_lock_init(&nn->nfs_client_lock); | ||
| 1808 | } | ||
| 1809 | |||
| 1774 | #ifdef CONFIG_PROC_FS | 1810 | #ifdef CONFIG_PROC_FS |
| 1775 | static struct proc_dir_entry *proc_fs_nfs; | 1811 | static struct proc_dir_entry *proc_fs_nfs; |
| 1776 | 1812 | ||
| @@ -1824,13 +1860,15 @@ static int nfs_server_list_open(struct inode *inode, struct file *file) | |||
| 1824 | { | 1860 | { |
| 1825 | struct seq_file *m; | 1861 | struct seq_file *m; |
| 1826 | int ret; | 1862 | int ret; |
| 1863 | struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info; | ||
| 1864 | struct net *net = pid_ns->child_reaper->nsproxy->net_ns; | ||
| 1827 | 1865 | ||
| 1828 | ret = seq_open(file, &nfs_server_list_ops); | 1866 | ret = seq_open(file, &nfs_server_list_ops); |
| 1829 | if (ret < 0) | 1867 | if (ret < 0) |
| 1830 | return ret; | 1868 | return ret; |
| 1831 | 1869 | ||
| 1832 | m = file->private_data; | 1870 | m = file->private_data; |
| 1833 | m->private = PDE(inode)->data; | 1871 | m->private = net; |
| 1834 | 1872 | ||
| 1835 | return 0; | 1873 | return 0; |
| 1836 | } | 1874 | } |
| @@ -1840,9 +1878,11 @@ static int nfs_server_list_open(struct inode *inode, struct file *file) | |||
| 1840 | */ | 1878 | */ |
| 1841 | static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) | 1879 | static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) |
| 1842 | { | 1880 | { |
| 1881 | struct nfs_net *nn = net_generic(m->private, nfs_net_id); | ||
| 1882 | |||
| 1843 | /* lock the list against modification */ | 1883 | /* lock the list against modification */ |
| 1844 | spin_lock(&nfs_client_lock); | 1884 | spin_lock(&nn->nfs_client_lock); |
| 1845 | return seq_list_start_head(&nfs_client_list, *_pos); | 1885 | return seq_list_start_head(&nn->nfs_client_list, *_pos); |
| 1846 | } | 1886 | } |
| 1847 | 1887 | ||
| 1848 | /* | 1888 | /* |
| @@ -1850,7 +1890,9 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) | |||
| 1850 | */ | 1890 | */ |
| 1851 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) | 1891 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) |
| 1852 | { | 1892 | { |
| 1853 | return seq_list_next(v, &nfs_client_list, pos); | 1893 | struct nfs_net *nn = net_generic(p->private, nfs_net_id); |
| 1894 | |||
| 1895 | return seq_list_next(v, &nn->nfs_client_list, pos); | ||
| 1854 | } | 1896 | } |
| 1855 | 1897 | ||
| 1856 | /* | 1898 | /* |
| @@ -1858,7 +1900,9 @@ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) | |||
| 1858 | */ | 1900 | */ |
| 1859 | static void nfs_server_list_stop(struct seq_file *p, void *v) | 1901 | static void nfs_server_list_stop(struct seq_file *p, void *v) |
| 1860 | { | 1902 | { |
| 1861 | spin_unlock(&nfs_client_lock); | 1903 | struct nfs_net *nn = net_generic(p->private, nfs_net_id); |
| 1904 | |||
| 1905 | spin_unlock(&nn->nfs_client_lock); | ||
| 1862 | } | 1906 | } |
| 1863 | 1907 | ||
| 1864 | /* | 1908 | /* |
| @@ -1867,9 +1911,10 @@ static void nfs_server_list_stop(struct seq_file *p, void *v) | |||
| 1867 | static int nfs_server_list_show(struct seq_file *m, void *v) | 1911 | static int nfs_server_list_show(struct seq_file *m, void *v) |
| 1868 | { | 1912 | { |
| 1869 | struct nfs_client *clp; | 1913 | struct nfs_client *clp; |
| 1914 | struct nfs_net *nn = net_generic(m->private, nfs_net_id); | ||
| 1870 | 1915 | ||
| 1871 | /* display header on line 1 */ | 1916 | /* display header on line 1 */ |
| 1872 | if (v == &nfs_client_list) { | 1917 | if (v == &nn->nfs_client_list) { |
| 1873 | seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); | 1918 | seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); |
| 1874 | return 0; | 1919 | return 0; |
| 1875 | } | 1920 | } |
| @@ -1881,12 +1926,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v) | |||
| 1881 | if (clp->cl_cons_state != NFS_CS_READY) | 1926 | if (clp->cl_cons_state != NFS_CS_READY) |
| 1882 | return 0; | 1927 | return 0; |
| 1883 | 1928 | ||
| 1929 | rcu_read_lock(); | ||
| 1884 | seq_printf(m, "v%u %s %s %3d %s\n", | 1930 | seq_printf(m, "v%u %s %s %3d %s\n", |
| 1885 | clp->rpc_ops->version, | 1931 | clp->rpc_ops->version, |
| 1886 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), | 1932 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
| 1887 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), | 1933 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
| 1888 | atomic_read(&clp->cl_count), | 1934 | atomic_read(&clp->cl_count), |
| 1889 | clp->cl_hostname); | 1935 | clp->cl_hostname); |
| 1936 | rcu_read_unlock(); | ||
| 1890 | 1937 | ||
| 1891 | return 0; | 1938 | return 0; |
| 1892 | } | 1939 | } |
| @@ -1898,13 +1945,15 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file) | |||
| 1898 | { | 1945 | { |
| 1899 | struct seq_file *m; | 1946 | struct seq_file *m; |
| 1900 | int ret; | 1947 | int ret; |
| 1948 | struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info; | ||
| 1949 | struct net *net = pid_ns->child_reaper->nsproxy->net_ns; | ||
| 1901 | 1950 | ||
| 1902 | ret = seq_open(file, &nfs_volume_list_ops); | 1951 | ret = seq_open(file, &nfs_volume_list_ops); |
| 1903 | if (ret < 0) | 1952 | if (ret < 0) |
| 1904 | return ret; | 1953 | return ret; |
| 1905 | 1954 | ||
| 1906 | m = file->private_data; | 1955 | m = file->private_data; |
| 1907 | m->private = PDE(inode)->data; | 1956 | m->private = net; |
| 1908 | 1957 | ||
| 1909 | return 0; | 1958 | return 0; |
| 1910 | } | 1959 | } |
| @@ -1914,9 +1963,11 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file) | |||
| 1914 | */ | 1963 | */ |
| 1915 | static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) | 1964 | static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) |
| 1916 | { | 1965 | { |
| 1966 | struct nfs_net *nn = net_generic(m->private, nfs_net_id); | ||
| 1967 | |||
| 1917 | /* lock the list against modification */ | 1968 | /* lock the list against modification */ |
| 1918 | spin_lock(&nfs_client_lock); | 1969 | spin_lock(&nn->nfs_client_lock); |
| 1919 | return seq_list_start_head(&nfs_volume_list, *_pos); | 1970 | return seq_list_start_head(&nn->nfs_volume_list, *_pos); |
| 1920 | } | 1971 | } |
| 1921 | 1972 | ||
| 1922 | /* | 1973 | /* |
| @@ -1924,7 +1975,9 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) | |||
| 1924 | */ | 1975 | */ |
| 1925 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) | 1976 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) |
| 1926 | { | 1977 | { |
| 1927 | return seq_list_next(v, &nfs_volume_list, pos); | 1978 | struct nfs_net *nn = net_generic(p->private, nfs_net_id); |
| 1979 | |||
| 1980 | return seq_list_next(v, &nn->nfs_volume_list, pos); | ||
| 1928 | } | 1981 | } |
| 1929 | 1982 | ||
| 1930 | /* | 1983 | /* |
| @@ -1932,7 +1985,9 @@ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) | |||
| 1932 | */ | 1985 | */ |
| 1933 | static void nfs_volume_list_stop(struct seq_file *p, void *v) | 1986 | static void nfs_volume_list_stop(struct seq_file *p, void *v) |
| 1934 | { | 1987 | { |
| 1935 | spin_unlock(&nfs_client_lock); | 1988 | struct nfs_net *nn = net_generic(p->private, nfs_net_id); |
| 1989 | |||
| 1990 | spin_unlock(&nn->nfs_client_lock); | ||
| 1936 | } | 1991 | } |
| 1937 | 1992 | ||
| 1938 | /* | 1993 | /* |
| @@ -1943,9 +1998,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
| 1943 | struct nfs_server *server; | 1998 | struct nfs_server *server; |
| 1944 | struct nfs_client *clp; | 1999 | struct nfs_client *clp; |
| 1945 | char dev[8], fsid[17]; | 2000 | char dev[8], fsid[17]; |
| 2001 | struct nfs_net *nn = net_generic(m->private, nfs_net_id); | ||
| 1946 | 2002 | ||
| 1947 | /* display header on line 1 */ | 2003 | /* display header on line 1 */ |
| 1948 | if (v == &nfs_volume_list) { | 2004 | if (v == &nn->nfs_volume_list) { |
| 1949 | seq_puts(m, "NV SERVER PORT DEV FSID FSC\n"); | 2005 | seq_puts(m, "NV SERVER PORT DEV FSID FSC\n"); |
| 1950 | return 0; | 2006 | return 0; |
| 1951 | } | 2007 | } |
| @@ -1960,6 +2016,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
| 1960 | (unsigned long long) server->fsid.major, | 2016 | (unsigned long long) server->fsid.major, |
| 1961 | (unsigned long long) server->fsid.minor); | 2017 | (unsigned long long) server->fsid.minor); |
| 1962 | 2018 | ||
| 2019 | rcu_read_lock(); | ||
| 1963 | seq_printf(m, "v%u %s %s %-7s %-17s %s\n", | 2020 | seq_printf(m, "v%u %s %s %-7s %-17s %s\n", |
| 1964 | clp->rpc_ops->version, | 2021 | clp->rpc_ops->version, |
| 1965 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), | 2022 | 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) | |||
| 1967 | dev, | 2024 | dev, |
| 1968 | fsid, | 2025 | fsid, |
| 1969 | nfs_server_fscache_state(server)); | 2026 | nfs_server_fscache_state(server)); |
| 2027 | rcu_read_unlock(); | ||
| 1970 | 2028 | ||
| 1971 | return 0; | 2029 | return 0; |
| 1972 | } | 2030 | } |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 7f2654069806..89af1d269274 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -105,7 +105,7 @@ again: | |||
| 105 | continue; | 105 | continue; |
| 106 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 106 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
| 107 | continue; | 107 | continue; |
| 108 | if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0) | 108 | if (!nfs4_stateid_match(&state->stateid, stateid)) |
| 109 | continue; | 109 | continue; |
| 110 | get_nfs_open_context(ctx); | 110 | get_nfs_open_context(ctx); |
| 111 | spin_unlock(&inode->i_lock); | 111 | spin_unlock(&inode->i_lock); |
| @@ -139,8 +139,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, | |||
| 139 | if (delegation != NULL) { | 139 | if (delegation != NULL) { |
| 140 | spin_lock(&delegation->lock); | 140 | spin_lock(&delegation->lock); |
| 141 | if (delegation->inode != NULL) { | 141 | if (delegation->inode != NULL) { |
| 142 | memcpy(delegation->stateid.data, res->delegation.data, | 142 | nfs4_stateid_copy(&delegation->stateid, &res->delegation); |
| 143 | sizeof(delegation->stateid.data)); | ||
| 144 | delegation->type = res->delegation_type; | 143 | delegation->type = res->delegation_type; |
| 145 | delegation->maxsize = res->maxsize; | 144 | delegation->maxsize = res->maxsize; |
| 146 | oldcred = delegation->cred; | 145 | oldcred = delegation->cred; |
| @@ -236,8 +235,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 236 | delegation = kmalloc(sizeof(*delegation), GFP_NOFS); | 235 | delegation = kmalloc(sizeof(*delegation), GFP_NOFS); |
| 237 | if (delegation == NULL) | 236 | if (delegation == NULL) |
| 238 | return -ENOMEM; | 237 | return -ENOMEM; |
| 239 | memcpy(delegation->stateid.data, res->delegation.data, | 238 | nfs4_stateid_copy(&delegation->stateid, &res->delegation); |
| 240 | sizeof(delegation->stateid.data)); | ||
| 241 | delegation->type = res->delegation_type; | 239 | delegation->type = res->delegation_type; |
| 242 | delegation->maxsize = res->maxsize; | 240 | delegation->maxsize = res->maxsize; |
| 243 | delegation->change_attr = inode->i_version; | 241 | delegation->change_attr = inode->i_version; |
| @@ -250,19 +248,22 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 250 | old_delegation = rcu_dereference_protected(nfsi->delegation, | 248 | old_delegation = rcu_dereference_protected(nfsi->delegation, |
| 251 | lockdep_is_held(&clp->cl_lock)); | 249 | lockdep_is_held(&clp->cl_lock)); |
| 252 | if (old_delegation != NULL) { | 250 | if (old_delegation != NULL) { |
| 253 | if (memcmp(&delegation->stateid, &old_delegation->stateid, | 251 | if (nfs4_stateid_match(&delegation->stateid, |
| 254 | sizeof(old_delegation->stateid)) == 0 && | 252 | &old_delegation->stateid) && |
| 255 | delegation->type == old_delegation->type) { | 253 | delegation->type == old_delegation->type) { |
| 256 | goto out; | 254 | goto out; |
| 257 | } | 255 | } |
| 258 | /* | 256 | /* |
| 259 | * Deal with broken servers that hand out two | 257 | * Deal with broken servers that hand out two |
| 260 | * delegations for the same file. | 258 | * delegations for the same file. |
| 259 | * Allow for upgrades to a WRITE delegation, but | ||
| 260 | * nothing else. | ||
| 261 | */ | 261 | */ |
| 262 | dfprintk(FILE, "%s: server %s handed out " | 262 | dfprintk(FILE, "%s: server %s handed out " |
| 263 | "a duplicate delegation!\n", | 263 | "a duplicate delegation!\n", |
| 264 | __func__, clp->cl_hostname); | 264 | __func__, clp->cl_hostname); |
| 265 | if (delegation->type <= old_delegation->type) { | 265 | if (delegation->type == old_delegation->type || |
| 266 | !(delegation->type & FMODE_WRITE)) { | ||
| 266 | freeme = delegation; | 267 | freeme = delegation; |
| 267 | delegation = NULL; | 268 | delegation = NULL; |
| 268 | goto out; | 269 | goto out; |
| @@ -455,17 +456,24 @@ static void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp, | |||
| 455 | rcu_read_unlock(); | 456 | rcu_read_unlock(); |
| 456 | } | 457 | } |
| 457 | 458 | ||
| 458 | static void nfs_client_mark_return_all_delegations(struct nfs_client *clp) | ||
| 459 | { | ||
| 460 | nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE); | ||
| 461 | } | ||
| 462 | |||
| 463 | static void nfs_delegation_run_state_manager(struct nfs_client *clp) | 459 | static void nfs_delegation_run_state_manager(struct nfs_client *clp) |
| 464 | { | 460 | { |
| 465 | if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) | 461 | if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) |
| 466 | nfs4_schedule_state_manager(clp); | 462 | nfs4_schedule_state_manager(clp); |
| 467 | } | 463 | } |
| 468 | 464 | ||
| 465 | void nfs_remove_bad_delegation(struct inode *inode) | ||
| 466 | { | ||
| 467 | struct nfs_delegation *delegation; | ||
| 468 | |||
| 469 | delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode)); | ||
| 470 | if (delegation) { | ||
| 471 | nfs_inode_find_state_and_recover(inode, &delegation->stateid); | ||
| 472 | nfs_free_delegation(delegation); | ||
| 473 | } | ||
| 474 | } | ||
| 475 | EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation); | ||
| 476 | |||
| 469 | /** | 477 | /** |
| 470 | * nfs_expire_all_delegation_types | 478 | * nfs_expire_all_delegation_types |
| 471 | * @clp: client to process | 479 | * @clp: client to process |
| @@ -488,18 +496,6 @@ void nfs_expire_all_delegations(struct nfs_client *clp) | |||
| 488 | nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE); | 496 | nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE); |
| 489 | } | 497 | } |
| 490 | 498 | ||
| 491 | /** | ||
| 492 | * nfs_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN | ||
| 493 | * @clp: client to process | ||
| 494 | * | ||
| 495 | */ | ||
| 496 | void nfs_handle_cb_pathdown(struct nfs_client *clp) | ||
| 497 | { | ||
| 498 | if (clp == NULL) | ||
| 499 | return; | ||
| 500 | nfs_client_mark_return_all_delegations(clp); | ||
| 501 | } | ||
| 502 | |||
| 503 | static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server) | 499 | static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server) |
| 504 | { | 500 | { |
| 505 | struct nfs_delegation *delegation; | 501 | struct nfs_delegation *delegation; |
| @@ -531,7 +527,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp) | |||
| 531 | /** | 527 | /** |
| 532 | * nfs_async_inode_return_delegation - asynchronously return a delegation | 528 | * nfs_async_inode_return_delegation - asynchronously return a delegation |
| 533 | * @inode: inode to process | 529 | * @inode: inode to process |
| 534 | * @stateid: state ID information from CB_RECALL arguments | 530 | * @stateid: state ID information |
| 535 | * | 531 | * |
| 536 | * Returns zero on success, or a negative errno value. | 532 | * Returns zero on success, or a negative errno value. |
| 537 | */ | 533 | */ |
| @@ -545,7 +541,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, | |||
| 545 | rcu_read_lock(); | 541 | rcu_read_lock(); |
| 546 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 542 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
| 547 | 543 | ||
| 548 | if (!clp->cl_mvops->validate_stateid(delegation, stateid)) { | 544 | if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) { |
| 549 | rcu_read_unlock(); | 545 | rcu_read_unlock(); |
| 550 | return -ENOENT; | 546 | return -ENOENT; |
| 551 | } | 547 | } |
| @@ -684,21 +680,25 @@ int nfs_delegations_present(struct nfs_client *clp) | |||
| 684 | * nfs4_copy_delegation_stateid - Copy inode's state ID information | 680 | * nfs4_copy_delegation_stateid - Copy inode's state ID information |
| 685 | * @dst: stateid data structure to fill in | 681 | * @dst: stateid data structure to fill in |
| 686 | * @inode: inode to check | 682 | * @inode: inode to check |
| 683 | * @flags: delegation type requirement | ||
| 687 | * | 684 | * |
| 688 | * Returns one and fills in "dst->data" * if inode had a delegation, | 685 | * Returns "true" and fills in "dst->data" * if inode had a delegation, |
| 689 | * otherwise zero is returned. | 686 | * otherwise "false" is returned. |
| 690 | */ | 687 | */ |
| 691 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) | 688 | bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, |
| 689 | fmode_t flags) | ||
| 692 | { | 690 | { |
| 693 | struct nfs_inode *nfsi = NFS_I(inode); | 691 | struct nfs_inode *nfsi = NFS_I(inode); |
| 694 | struct nfs_delegation *delegation; | 692 | struct nfs_delegation *delegation; |
| 695 | int ret = 0; | 693 | bool ret; |
| 696 | 694 | ||
| 695 | flags &= FMODE_READ|FMODE_WRITE; | ||
| 697 | rcu_read_lock(); | 696 | rcu_read_lock(); |
| 698 | delegation = rcu_dereference(nfsi->delegation); | 697 | delegation = rcu_dereference(nfsi->delegation); |
| 699 | if (delegation != NULL) { | 698 | ret = (delegation != NULL && (delegation->type & flags) == flags); |
| 700 | memcpy(dst->data, delegation->stateid.data, sizeof(dst->data)); | 699 | if (ret) { |
| 701 | ret = 1; | 700 | nfs4_stateid_copy(dst, &delegation->stateid); |
| 701 | nfs_mark_delegation_referenced(delegation); | ||
| 702 | } | 702 | } |
| 703 | rcu_read_unlock(); | 703 | rcu_read_unlock(); |
| 704 | return ret; | 704 | return ret; |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index d9322e490c56..cd6a7a8dadae 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
| @@ -42,9 +42,9 @@ void nfs_super_return_all_delegations(struct super_block *sb); | |||
| 42 | void nfs_expire_all_delegations(struct nfs_client *clp); | 42 | void nfs_expire_all_delegations(struct nfs_client *clp); |
| 43 | void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags); | 43 | void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags); |
| 44 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp); | 44 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp); |
| 45 | void nfs_handle_cb_pathdown(struct nfs_client *clp); | ||
| 46 | int nfs_client_return_marked_delegations(struct nfs_client *clp); | 45 | int nfs_client_return_marked_delegations(struct nfs_client *clp); |
| 47 | int nfs_delegations_present(struct nfs_client *clp); | 46 | int nfs_delegations_present(struct nfs_client *clp); |
| 47 | void nfs_remove_bad_delegation(struct inode *inode); | ||
| 48 | 48 | ||
| 49 | void nfs_delegation_mark_reclaim(struct nfs_client *clp); | 49 | void nfs_delegation_mark_reclaim(struct nfs_client *clp); |
| 50 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); | 50 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); |
| @@ -53,7 +53,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp); | |||
| 53 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); | 53 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); |
| 54 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); | 54 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); |
| 55 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); | 55 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); |
| 56 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); | 56 | bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags); |
| 57 | 57 | ||
| 58 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); | 58 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); |
| 59 | int nfs_have_delegation(struct inode *inode, fmode_t flags); | 59 | int nfs_have_delegation(struct inode *inode, fmode_t flags); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 32aa6917265a..4aaf0316d76a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -207,7 +207,7 @@ struct nfs_cache_array_entry { | |||
| 207 | }; | 207 | }; |
| 208 | 208 | ||
| 209 | struct nfs_cache_array { | 209 | struct nfs_cache_array { |
| 210 | unsigned int size; | 210 | int size; |
| 211 | int eof_index; | 211 | int eof_index; |
| 212 | u64 last_cookie; | 212 | u64 last_cookie; |
| 213 | struct nfs_cache_array_entry array[0]; | 213 | struct nfs_cache_array_entry array[0]; |
| @@ -1429,6 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
| 1429 | } | 1429 | } |
| 1430 | 1430 | ||
| 1431 | open_flags = nd->intent.open.flags; | 1431 | open_flags = nd->intent.open.flags; |
| 1432 | attr.ia_valid = 0; | ||
| 1432 | 1433 | ||
| 1433 | ctx = create_nfs_open_context(dentry, open_flags); | 1434 | ctx = create_nfs_open_context(dentry, open_flags); |
| 1434 | res = ERR_CAST(ctx); | 1435 | res = ERR_CAST(ctx); |
| @@ -1437,11 +1438,14 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
| 1437 | 1438 | ||
| 1438 | if (nd->flags & LOOKUP_CREATE) { | 1439 | if (nd->flags & LOOKUP_CREATE) { |
| 1439 | attr.ia_mode = nd->intent.open.create_mode; | 1440 | attr.ia_mode = nd->intent.open.create_mode; |
| 1440 | attr.ia_valid = ATTR_MODE; | 1441 | attr.ia_valid |= ATTR_MODE; |
| 1441 | attr.ia_mode &= ~current_umask(); | 1442 | attr.ia_mode &= ~current_umask(); |
| 1442 | } else { | 1443 | } else |
| 1443 | open_flags &= ~(O_EXCL | O_CREAT); | 1444 | open_flags &= ~(O_EXCL | O_CREAT); |
| 1444 | attr.ia_valid = 0; | 1445 | |
| 1446 | if (open_flags & O_TRUNC) { | ||
| 1447 | attr.ia_valid |= ATTR_SIZE; | ||
| 1448 | attr.ia_size = 0; | ||
| 1445 | } | 1449 | } |
| 1446 | 1450 | ||
| 1447 | /* Open the file on the server */ | 1451 | /* Open the file on the server */ |
| @@ -1495,6 +1499,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1495 | struct inode *inode; | 1499 | struct inode *inode; |
| 1496 | struct inode *dir; | 1500 | struct inode *dir; |
| 1497 | struct nfs_open_context *ctx; | 1501 | struct nfs_open_context *ctx; |
| 1502 | struct iattr attr; | ||
| 1498 | int openflags, ret = 0; | 1503 | int openflags, ret = 0; |
| 1499 | 1504 | ||
| 1500 | if (nd->flags & LOOKUP_RCU) | 1505 | if (nd->flags & LOOKUP_RCU) |
| @@ -1523,19 +1528,27 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1523 | /* We cannot do exclusive creation on a positive dentry */ | 1528 | /* We cannot do exclusive creation on a positive dentry */ |
| 1524 | if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) | 1529 | if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) |
| 1525 | goto no_open_dput; | 1530 | goto no_open_dput; |
| 1526 | /* We can't create new files, or truncate existing ones here */ | 1531 | /* We can't create new files here */ |
| 1527 | openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); | 1532 | openflags &= ~(O_CREAT|O_EXCL); |
| 1528 | 1533 | ||
| 1529 | ctx = create_nfs_open_context(dentry, openflags); | 1534 | ctx = create_nfs_open_context(dentry, openflags); |
| 1530 | ret = PTR_ERR(ctx); | 1535 | ret = PTR_ERR(ctx); |
| 1531 | if (IS_ERR(ctx)) | 1536 | if (IS_ERR(ctx)) |
| 1532 | goto out; | 1537 | goto out; |
| 1538 | |||
| 1539 | attr.ia_valid = 0; | ||
| 1540 | if (openflags & O_TRUNC) { | ||
| 1541 | attr.ia_valid |= ATTR_SIZE; | ||
| 1542 | attr.ia_size = 0; | ||
| 1543 | nfs_wb_all(inode); | ||
| 1544 | } | ||
| 1545 | |||
| 1533 | /* | 1546 | /* |
| 1534 | * Note: we're not holding inode->i_mutex and so may be racing with | 1547 | * Note: we're not holding inode->i_mutex and so may be racing with |
| 1535 | * operations that change the directory. We therefore save the | 1548 | * operations that change the directory. We therefore save the |
| 1536 | * change attribute *before* we do the RPC call. | 1549 | * change attribute *before* we do the RPC call. |
| 1537 | */ | 1550 | */ |
| 1538 | inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL); | 1551 | inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr); |
| 1539 | if (IS_ERR(inode)) { | 1552 | if (IS_ERR(inode)) { |
| 1540 | ret = PTR_ERR(inode); | 1553 | ret = PTR_ERR(inode); |
| 1541 | switch (ret) { | 1554 | switch (ret) { |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 1940f1a56a5f..9c7f66ac6cc2 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -265,9 +265,7 @@ static void nfs_direct_read_release(void *calldata) | |||
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | static const struct rpc_call_ops nfs_read_direct_ops = { | 267 | static const struct rpc_call_ops nfs_read_direct_ops = { |
| 268 | #if defined(CONFIG_NFS_V4_1) | ||
| 269 | .rpc_call_prepare = nfs_read_prepare, | 268 | .rpc_call_prepare = nfs_read_prepare, |
| 270 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 271 | .rpc_call_done = nfs_direct_read_result, | 269 | .rpc_call_done = nfs_direct_read_result, |
| 272 | .rpc_release = nfs_direct_read_release, | 270 | .rpc_release = nfs_direct_read_release, |
| 273 | }; | 271 | }; |
| @@ -554,9 +552,7 @@ static void nfs_direct_commit_release(void *calldata) | |||
| 554 | } | 552 | } |
| 555 | 553 | ||
| 556 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 554 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
| 557 | #if defined(CONFIG_NFS_V4_1) | ||
| 558 | .rpc_call_prepare = nfs_write_prepare, | 555 | .rpc_call_prepare = nfs_write_prepare, |
| 559 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 560 | .rpc_call_done = nfs_direct_commit_result, | 556 | .rpc_call_done = nfs_direct_commit_result, |
| 561 | .rpc_release = nfs_direct_commit_release, | 557 | .rpc_release = nfs_direct_commit_release, |
| 562 | }; | 558 | }; |
| @@ -696,9 +692,7 @@ out_unlock: | |||
| 696 | } | 692 | } |
| 697 | 693 | ||
| 698 | static const struct rpc_call_ops nfs_write_direct_ops = { | 694 | static const struct rpc_call_ops nfs_write_direct_ops = { |
| 699 | #if defined(CONFIG_NFS_V4_1) | ||
| 700 | .rpc_call_prepare = nfs_write_prepare, | 695 | .rpc_call_prepare = nfs_write_prepare, |
| 701 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 702 | .rpc_call_done = nfs_direct_write_result, | 696 | .rpc_call_done = nfs_direct_write_result, |
| 703 | .rpc_release = nfs_direct_write_release, | 697 | .rpc_release = nfs_direct_write_release, |
| 704 | }; | 698 | }; |
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index a6e711ad130f..b3924b8a6000 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c | |||
| @@ -10,8 +10,9 @@ | |||
| 10 | 10 | ||
| 11 | #include <linux/sunrpc/clnt.h> | 11 | #include <linux/sunrpc/clnt.h> |
| 12 | #include <linux/dns_resolver.h> | 12 | #include <linux/dns_resolver.h> |
| 13 | #include "dns_resolve.h" | ||
| 13 | 14 | ||
| 14 | ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | 15 | ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen, |
| 15 | struct sockaddr *sa, size_t salen) | 16 | struct sockaddr *sa, size_t salen) |
| 16 | { | 17 | { |
| 17 | ssize_t ret; | 18 | ssize_t ret; |
| @@ -20,7 +21,7 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | |||
| 20 | 21 | ||
| 21 | ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL); | 22 | ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL); |
| 22 | if (ip_len > 0) | 23 | if (ip_len > 0) |
| 23 | ret = rpc_pton(ip_addr, ip_len, sa, salen); | 24 | ret = rpc_pton(net, ip_addr, ip_len, sa, salen); |
| 24 | else | 25 | else |
| 25 | ret = -ESRCH; | 26 | ret = -ESRCH; |
| 26 | kfree(ip_addr); | 27 | kfree(ip_addr); |
| @@ -40,15 +41,15 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | |||
| 40 | #include <linux/sunrpc/clnt.h> | 41 | #include <linux/sunrpc/clnt.h> |
| 41 | #include <linux/sunrpc/cache.h> | 42 | #include <linux/sunrpc/cache.h> |
| 42 | #include <linux/sunrpc/svcauth.h> | 43 | #include <linux/sunrpc/svcauth.h> |
| 44 | #include <linux/sunrpc/rpc_pipe_fs.h> | ||
| 43 | 45 | ||
| 44 | #include "dns_resolve.h" | 46 | #include "dns_resolve.h" |
| 45 | #include "cache_lib.h" | 47 | #include "cache_lib.h" |
| 48 | #include "netns.h" | ||
| 46 | 49 | ||
| 47 | #define NFS_DNS_HASHBITS 4 | 50 | #define NFS_DNS_HASHBITS 4 |
| 48 | #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS) | 51 | #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS) |
| 49 | 52 | ||
| 50 | static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE]; | ||
| 51 | |||
| 52 | struct nfs_dns_ent { | 53 | struct nfs_dns_ent { |
| 53 | struct cache_head h; | 54 | struct cache_head h; |
| 54 | 55 | ||
| @@ -224,7 +225,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) | |||
| 224 | len = qword_get(&buf, buf1, sizeof(buf1)); | 225 | len = qword_get(&buf, buf1, sizeof(buf1)); |
| 225 | if (len <= 0) | 226 | if (len <= 0) |
| 226 | goto out; | 227 | goto out; |
| 227 | key.addrlen = rpc_pton(buf1, len, | 228 | key.addrlen = rpc_pton(cd->net, buf1, len, |
| 228 | (struct sockaddr *)&key.addr, | 229 | (struct sockaddr *)&key.addr, |
| 229 | sizeof(key.addr)); | 230 | sizeof(key.addr)); |
| 230 | 231 | ||
| @@ -259,21 +260,6 @@ out: | |||
| 259 | return ret; | 260 | return ret; |
| 260 | } | 261 | } |
| 261 | 262 | ||
| 262 | static struct cache_detail nfs_dns_resolve = { | ||
| 263 | .owner = THIS_MODULE, | ||
| 264 | .hash_size = NFS_DNS_HASHTBL_SIZE, | ||
| 265 | .hash_table = nfs_dns_table, | ||
| 266 | .name = "dns_resolve", | ||
| 267 | .cache_put = nfs_dns_ent_put, | ||
| 268 | .cache_upcall = nfs_dns_upcall, | ||
| 269 | .cache_parse = nfs_dns_parse, | ||
| 270 | .cache_show = nfs_dns_show, | ||
| 271 | .match = nfs_dns_match, | ||
| 272 | .init = nfs_dns_ent_init, | ||
| 273 | .update = nfs_dns_ent_update, | ||
| 274 | .alloc = nfs_dns_ent_alloc, | ||
| 275 | }; | ||
| 276 | |||
| 277 | static int do_cache_lookup(struct cache_detail *cd, | 263 | static int do_cache_lookup(struct cache_detail *cd, |
| 278 | struct nfs_dns_ent *key, | 264 | struct nfs_dns_ent *key, |
| 279 | struct nfs_dns_ent **item, | 265 | struct nfs_dns_ent **item, |
| @@ -336,8 +322,8 @@ out: | |||
| 336 | return ret; | 322 | return ret; |
| 337 | } | 323 | } |
| 338 | 324 | ||
| 339 | ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | 325 | ssize_t nfs_dns_resolve_name(struct net *net, char *name, |
| 340 | struct sockaddr *sa, size_t salen) | 326 | size_t namelen, struct sockaddr *sa, size_t salen) |
| 341 | { | 327 | { |
| 342 | struct nfs_dns_ent key = { | 328 | struct nfs_dns_ent key = { |
| 343 | .hostname = name, | 329 | .hostname = name, |
| @@ -345,28 +331,118 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | |||
| 345 | }; | 331 | }; |
| 346 | struct nfs_dns_ent *item = NULL; | 332 | struct nfs_dns_ent *item = NULL; |
| 347 | ssize_t ret; | 333 | ssize_t ret; |
| 334 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 348 | 335 | ||
| 349 | ret = do_cache_lookup_wait(&nfs_dns_resolve, &key, &item); | 336 | ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item); |
| 350 | if (ret == 0) { | 337 | if (ret == 0) { |
| 351 | if (salen >= item->addrlen) { | 338 | if (salen >= item->addrlen) { |
| 352 | memcpy(sa, &item->addr, item->addrlen); | 339 | memcpy(sa, &item->addr, item->addrlen); |
| 353 | ret = item->addrlen; | 340 | ret = item->addrlen; |
| 354 | } else | 341 | } else |
| 355 | ret = -EOVERFLOW; | 342 | ret = -EOVERFLOW; |
| 356 | cache_put(&item->h, &nfs_dns_resolve); | 343 | cache_put(&item->h, nn->nfs_dns_resolve); |
| 357 | } else if (ret == -ENOENT) | 344 | } else if (ret == -ENOENT) |
| 358 | ret = -ESRCH; | 345 | ret = -ESRCH; |
| 359 | return ret; | 346 | return ret; |
| 360 | } | 347 | } |
| 361 | 348 | ||
| 349 | int nfs_dns_resolver_cache_init(struct net *net) | ||
| 350 | { | ||
| 351 | int err = -ENOMEM; | ||
| 352 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 353 | struct cache_detail *cd; | ||
| 354 | struct cache_head **tbl; | ||
| 355 | |||
| 356 | cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL); | ||
| 357 | if (cd == NULL) | ||
| 358 | goto err_cd; | ||
| 359 | |||
| 360 | tbl = kzalloc(NFS_DNS_HASHTBL_SIZE * sizeof(struct cache_head *), | ||
| 361 | GFP_KERNEL); | ||
| 362 | if (tbl == NULL) | ||
| 363 | goto err_tbl; | ||
| 364 | |||
| 365 | cd->owner = THIS_MODULE, | ||
| 366 | cd->hash_size = NFS_DNS_HASHTBL_SIZE, | ||
| 367 | cd->hash_table = tbl, | ||
| 368 | cd->name = "dns_resolve", | ||
| 369 | cd->cache_put = nfs_dns_ent_put, | ||
| 370 | cd->cache_upcall = nfs_dns_upcall, | ||
| 371 | cd->cache_parse = nfs_dns_parse, | ||
| 372 | cd->cache_show = nfs_dns_show, | ||
| 373 | cd->match = nfs_dns_match, | ||
| 374 | cd->init = nfs_dns_ent_init, | ||
| 375 | cd->update = nfs_dns_ent_update, | ||
| 376 | cd->alloc = nfs_dns_ent_alloc, | ||
| 377 | |||
| 378 | nfs_cache_init(cd); | ||
| 379 | err = nfs_cache_register_net(net, cd); | ||
| 380 | if (err) | ||
| 381 | goto err_reg; | ||
| 382 | nn->nfs_dns_resolve = cd; | ||
| 383 | return 0; | ||
| 384 | |||
| 385 | err_reg: | ||
| 386 | nfs_cache_destroy(cd); | ||
| 387 | kfree(cd->hash_table); | ||
| 388 | err_tbl: | ||
| 389 | kfree(cd); | ||
| 390 | err_cd: | ||
| 391 | return err; | ||
| 392 | } | ||
| 393 | |||
| 394 | void nfs_dns_resolver_cache_destroy(struct net *net) | ||
| 395 | { | ||
| 396 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 397 | struct cache_detail *cd = nn->nfs_dns_resolve; | ||
| 398 | |||
| 399 | nfs_cache_unregister_net(net, cd); | ||
| 400 | nfs_cache_destroy(cd); | ||
| 401 | kfree(cd->hash_table); | ||
| 402 | kfree(cd); | ||
| 403 | } | ||
| 404 | |||
| 405 | static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, | ||
| 406 | void *ptr) | ||
| 407 | { | ||
| 408 | struct super_block *sb = ptr; | ||
| 409 | struct net *net = sb->s_fs_info; | ||
| 410 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 411 | struct cache_detail *cd = nn->nfs_dns_resolve; | ||
| 412 | int ret = 0; | ||
| 413 | |||
| 414 | if (cd == NULL) | ||
| 415 | return 0; | ||
| 416 | |||
| 417 | if (!try_module_get(THIS_MODULE)) | ||
| 418 | return 0; | ||
| 419 | |||
| 420 | switch (event) { | ||
| 421 | case RPC_PIPEFS_MOUNT: | ||
| 422 | ret = nfs_cache_register_sb(sb, cd); | ||
| 423 | break; | ||
| 424 | case RPC_PIPEFS_UMOUNT: | ||
| 425 | nfs_cache_unregister_sb(sb, cd); | ||
| 426 | break; | ||
| 427 | default: | ||
| 428 | ret = -ENOTSUPP; | ||
| 429 | break; | ||
| 430 | } | ||
| 431 | module_put(THIS_MODULE); | ||
| 432 | return ret; | ||
| 433 | } | ||
| 434 | |||
| 435 | static struct notifier_block nfs_dns_resolver_block = { | ||
| 436 | .notifier_call = rpc_pipefs_event, | ||
| 437 | }; | ||
| 438 | |||
| 362 | int nfs_dns_resolver_init(void) | 439 | int nfs_dns_resolver_init(void) |
| 363 | { | 440 | { |
| 364 | return nfs_cache_register(&nfs_dns_resolve); | 441 | return rpc_pipefs_notifier_register(&nfs_dns_resolver_block); |
| 365 | } | 442 | } |
| 366 | 443 | ||
| 367 | void nfs_dns_resolver_destroy(void) | 444 | void nfs_dns_resolver_destroy(void) |
| 368 | { | 445 | { |
| 369 | nfs_cache_unregister(&nfs_dns_resolve); | 446 | rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block); |
| 370 | } | 447 | } |
| 371 | |||
| 372 | #endif | 448 | #endif |
diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h index 199bb5543a91..2e4f596d2923 100644 --- a/fs/nfs/dns_resolve.h +++ b/fs/nfs/dns_resolve.h | |||
| @@ -15,12 +15,22 @@ static inline int nfs_dns_resolver_init(void) | |||
| 15 | 15 | ||
| 16 | static inline void nfs_dns_resolver_destroy(void) | 16 | static inline void nfs_dns_resolver_destroy(void) |
| 17 | {} | 17 | {} |
| 18 | |||
| 19 | static inline int nfs_dns_resolver_cache_init(struct net *net) | ||
| 20 | { | ||
| 21 | return 0; | ||
| 22 | } | ||
| 23 | |||
| 24 | static inline void nfs_dns_resolver_cache_destroy(struct net *net) | ||
| 25 | {} | ||
| 18 | #else | 26 | #else |
| 19 | extern int nfs_dns_resolver_init(void); | 27 | extern int nfs_dns_resolver_init(void); |
| 20 | extern void nfs_dns_resolver_destroy(void); | 28 | extern void nfs_dns_resolver_destroy(void); |
| 29 | extern int nfs_dns_resolver_cache_init(struct net *net); | ||
| 30 | extern void nfs_dns_resolver_cache_destroy(struct net *net); | ||
| 21 | #endif | 31 | #endif |
| 22 | 32 | ||
| 23 | extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | 33 | extern ssize_t nfs_dns_resolve_name(struct net *net, char *name, |
| 24 | struct sockaddr *sa, size_t salen); | 34 | size_t namelen, struct sockaddr *sa, size_t salen); |
| 25 | 35 | ||
| 26 | #endif | 36 | #endif |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index c43a452f7da2..4fdaaa63cf1c 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -530,6 +530,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
| 530 | if (mapping != dentry->d_inode->i_mapping) | 530 | if (mapping != dentry->d_inode->i_mapping) |
| 531 | goto out_unlock; | 531 | goto out_unlock; |
| 532 | 532 | ||
| 533 | wait_on_page_writeback(page); | ||
| 534 | |||
| 533 | pagelen = nfs_page_length(page); | 535 | pagelen = nfs_page_length(page); |
| 534 | if (pagelen == 0) | 536 | if (pagelen == 0) |
| 535 | goto out_unlock; | 537 | goto out_unlock; |
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index 419119c371bf..ae65c16b3670 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
| @@ -327,7 +327,7 @@ void nfs_fscache_reset_inode_cookie(struct inode *inode) | |||
| 327 | { | 327 | { |
| 328 | struct nfs_inode *nfsi = NFS_I(inode); | 328 | struct nfs_inode *nfsi = NFS_I(inode); |
| 329 | struct nfs_server *nfss = NFS_SERVER(inode); | 329 | struct nfs_server *nfss = NFS_SERVER(inode); |
| 330 | struct fscache_cookie *old = nfsi->fscache; | 330 | NFS_IFDEBUG(struct fscache_cookie *old = nfsi->fscache); |
| 331 | 331 | ||
| 332 | nfs_fscache_inode_lock(inode); | 332 | nfs_fscache_inode_lock(inode); |
| 333 | if (nfsi->fscache) { | 333 | if (nfsi->fscache) { |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index a1bbf7780dfc..b7f348bb618b 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
| @@ -34,11 +34,29 @@ | |||
| 34 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 35 | */ | 35 | */ |
| 36 | #include <linux/types.h> | 36 | #include <linux/types.h> |
| 37 | #include <linux/string.h> | 37 | #include <linux/parser.h> |
| 38 | #include <linux/kernel.h> | 38 | #include <linux/fs.h> |
| 39 | #include <linux/slab.h> | ||
| 40 | #include <linux/nfs_idmap.h> | 39 | #include <linux/nfs_idmap.h> |
| 40 | #include <net/net_namespace.h> | ||
| 41 | #include <linux/sunrpc/rpc_pipe_fs.h> | ||
| 41 | #include <linux/nfs_fs.h> | 42 | #include <linux/nfs_fs.h> |
| 43 | #include <linux/nfs_fs_sb.h> | ||
| 44 | #include <linux/key.h> | ||
| 45 | #include <linux/keyctl.h> | ||
| 46 | #include <linux/key-type.h> | ||
| 47 | #include <keys/user-type.h> | ||
| 48 | #include <linux/module.h> | ||
| 49 | |||
| 50 | #include "internal.h" | ||
| 51 | #include "netns.h" | ||
| 52 | |||
| 53 | #define NFS_UINT_MAXLEN 11 | ||
| 54 | |||
| 55 | /* Default cache timeout is 10 minutes */ | ||
| 56 | unsigned int nfs_idmap_cache_timeout = 600; | ||
| 57 | static const struct cred *id_resolver_cache; | ||
| 58 | static struct key_type key_type_id_resolver_legacy; | ||
| 59 | |||
| 42 | 60 | ||
| 43 | /** | 61 | /** |
| 44 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields | 62 | * 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) | |||
| 142 | return snprintf(buf, buflen, "%u", id); | 160 | return snprintf(buf, buflen, "%u", id); |
| 143 | } | 161 | } |
| 144 | 162 | ||
| 145 | #ifdef CONFIG_NFS_USE_NEW_IDMAPPER | 163 | static struct key_type key_type_id_resolver = { |
| 146 | |||
| 147 | #include <linux/cred.h> | ||
| 148 | #include <linux/sunrpc/sched.h> | ||
| 149 | #include <linux/nfs4.h> | ||
| 150 | #include <linux/nfs_fs_sb.h> | ||
| 151 | #include <linux/keyctl.h> | ||
| 152 | #include <linux/key-type.h> | ||
| 153 | #include <linux/rcupdate.h> | ||
| 154 | #include <linux/err.h> | ||
| 155 | |||
| 156 | #include <keys/user-type.h> | ||
| 157 | |||
| 158 | #define NFS_UINT_MAXLEN 11 | ||
| 159 | |||
| 160 | const struct cred *id_resolver_cache; | ||
| 161 | |||
| 162 | struct key_type key_type_id_resolver = { | ||
| 163 | .name = "id_resolver", | 164 | .name = "id_resolver", |
| 164 | .instantiate = user_instantiate, | 165 | .instantiate = user_instantiate, |
| 165 | .match = user_match, | 166 | .match = user_match, |
| @@ -169,13 +170,14 @@ struct key_type key_type_id_resolver = { | |||
| 169 | .read = user_read, | 170 | .read = user_read, |
| 170 | }; | 171 | }; |
| 171 | 172 | ||
| 172 | int nfs_idmap_init(void) | 173 | static int nfs_idmap_init_keyring(void) |
| 173 | { | 174 | { |
| 174 | struct cred *cred; | 175 | struct cred *cred; |
| 175 | struct key *keyring; | 176 | struct key *keyring; |
| 176 | int ret = 0; | 177 | int ret = 0; |
| 177 | 178 | ||
| 178 | printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name); | 179 | printk(KERN_NOTICE "NFS: Registering the %s key type\n", |
| 180 | key_type_id_resolver.name); | ||
| 179 | 181 | ||
| 180 | cred = prepare_kernel_cred(NULL); | 182 | cred = prepare_kernel_cred(NULL); |
| 181 | if (!cred) | 183 | if (!cred) |
| @@ -211,7 +213,7 @@ failed_put_cred: | |||
| 211 | return ret; | 213 | return ret; |
| 212 | } | 214 | } |
| 213 | 215 | ||
| 214 | void nfs_idmap_quit(void) | 216 | static void nfs_idmap_quit_keyring(void) |
| 215 | { | 217 | { |
| 216 | key_revoke(id_resolver_cache->thread_keyring); | 218 | key_revoke(id_resolver_cache->thread_keyring); |
| 217 | unregister_key_type(&key_type_id_resolver); | 219 | unregister_key_type(&key_type_id_resolver); |
| @@ -246,8 +248,10 @@ static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen, | |||
| 246 | return desclen; | 248 | return desclen; |
| 247 | } | 249 | } |
| 248 | 250 | ||
| 249 | static ssize_t nfs_idmap_request_key(const char *name, size_t namelen, | 251 | static ssize_t nfs_idmap_request_key(struct key_type *key_type, |
| 250 | const char *type, void *data, size_t data_size) | 252 | const char *name, size_t namelen, |
| 253 | const char *type, void *data, | ||
| 254 | size_t data_size, struct idmap *idmap) | ||
| 251 | { | 255 | { |
| 252 | const struct cred *saved_cred; | 256 | const struct cred *saved_cred; |
| 253 | struct key *rkey; | 257 | struct key *rkey; |
| @@ -260,8 +264,12 @@ static ssize_t nfs_idmap_request_key(const char *name, size_t namelen, | |||
| 260 | goto out; | 264 | goto out; |
| 261 | 265 | ||
| 262 | saved_cred = override_creds(id_resolver_cache); | 266 | saved_cred = override_creds(id_resolver_cache); |
| 263 | rkey = request_key(&key_type_id_resolver, desc, ""); | 267 | if (idmap) |
| 268 | rkey = request_key_with_auxdata(key_type, desc, "", 0, idmap); | ||
| 269 | else | ||
| 270 | rkey = request_key(&key_type_id_resolver, desc, ""); | ||
| 264 | revert_creds(saved_cred); | 271 | revert_creds(saved_cred); |
| 272 | |||
| 265 | kfree(desc); | 273 | kfree(desc); |
| 266 | if (IS_ERR(rkey)) { | 274 | if (IS_ERR(rkey)) { |
| 267 | ret = PTR_ERR(rkey); | 275 | ret = PTR_ERR(rkey); |
| @@ -294,31 +302,46 @@ out: | |||
| 294 | return ret; | 302 | return ret; |
| 295 | } | 303 | } |
| 296 | 304 | ||
| 305 | static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, | ||
| 306 | const char *type, void *data, | ||
| 307 | size_t data_size, struct idmap *idmap) | ||
| 308 | { | ||
| 309 | ssize_t ret = nfs_idmap_request_key(&key_type_id_resolver, | ||
| 310 | name, namelen, type, data, | ||
| 311 | data_size, NULL); | ||
| 312 | if (ret < 0) { | ||
| 313 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, | ||
| 314 | name, namelen, type, data, | ||
| 315 | data_size, idmap); | ||
| 316 | } | ||
| 317 | return ret; | ||
| 318 | } | ||
| 297 | 319 | ||
| 298 | /* ID -> Name */ | 320 | /* ID -> Name */ |
| 299 | static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen) | 321 | static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, |
| 322 | size_t buflen, struct idmap *idmap) | ||
| 300 | { | 323 | { |
| 301 | char id_str[NFS_UINT_MAXLEN]; | 324 | char id_str[NFS_UINT_MAXLEN]; |
| 302 | int id_len; | 325 | int id_len; |
| 303 | ssize_t ret; | 326 | ssize_t ret; |
| 304 | 327 | ||
| 305 | id_len = snprintf(id_str, sizeof(id_str), "%u", id); | 328 | id_len = snprintf(id_str, sizeof(id_str), "%u", id); |
| 306 | ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen); | 329 | ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap); |
| 307 | if (ret < 0) | 330 | if (ret < 0) |
| 308 | return -EINVAL; | 331 | return -EINVAL; |
| 309 | return ret; | 332 | return ret; |
| 310 | } | 333 | } |
| 311 | 334 | ||
| 312 | /* Name -> ID */ | 335 | /* Name -> ID */ |
| 313 | static int nfs_idmap_lookup_id(const char *name, size_t namelen, | 336 | static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type, |
| 314 | const char *type, __u32 *id) | 337 | __u32 *id, struct idmap *idmap) |
| 315 | { | 338 | { |
| 316 | char id_str[NFS_UINT_MAXLEN]; | 339 | char id_str[NFS_UINT_MAXLEN]; |
| 317 | long id_long; | 340 | long id_long; |
| 318 | ssize_t data_size; | 341 | ssize_t data_size; |
| 319 | int ret = 0; | 342 | int ret = 0; |
| 320 | 343 | ||
| 321 | data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN); | 344 | data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap); |
| 322 | if (data_size <= 0) { | 345 | if (data_size <= 0) { |
| 323 | ret = -EINVAL; | 346 | ret = -EINVAL; |
| 324 | } else { | 347 | } else { |
| @@ -328,114 +351,103 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen, | |||
| 328 | return ret; | 351 | return ret; |
| 329 | } | 352 | } |
| 330 | 353 | ||
| 331 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 354 | /* idmap classic begins here */ |
| 332 | { | 355 | module_param(nfs_idmap_cache_timeout, int, 0644); |
| 333 | if (nfs_map_string_to_numeric(name, namelen, uid)) | ||
| 334 | return 0; | ||
| 335 | return nfs_idmap_lookup_id(name, namelen, "uid", uid); | ||
| 336 | } | ||
| 337 | |||
| 338 | int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid) | ||
| 339 | { | ||
| 340 | if (nfs_map_string_to_numeric(name, namelen, gid)) | ||
| 341 | return 0; | ||
| 342 | return nfs_idmap_lookup_id(name, namelen, "gid", gid); | ||
| 343 | } | ||
| 344 | |||
| 345 | int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) | ||
| 346 | { | ||
| 347 | int ret = -EINVAL; | ||
| 348 | |||
| 349 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | ||
| 350 | ret = nfs_idmap_lookup_name(uid, "user", buf, buflen); | ||
| 351 | if (ret < 0) | ||
| 352 | ret = nfs_map_numeric_to_string(uid, buf, buflen); | ||
| 353 | return ret; | ||
| 354 | } | ||
| 355 | int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen) | ||
| 356 | { | ||
| 357 | int ret = -EINVAL; | ||
| 358 | 356 | ||
| 359 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | 357 | struct idmap { |
| 360 | ret = nfs_idmap_lookup_name(gid, "group", buf, buflen); | 358 | struct rpc_pipe *idmap_pipe; |
| 361 | if (ret < 0) | 359 | struct key_construction *idmap_key_cons; |
| 362 | ret = nfs_map_numeric_to_string(gid, buf, buflen); | ||
| 363 | return ret; | ||
| 364 | } | ||
| 365 | |||
| 366 | #else /* CONFIG_NFS_USE_NEW_IDMAPPER not defined */ | ||
| 367 | |||
| 368 | #include <linux/module.h> | ||
| 369 | #include <linux/mutex.h> | ||
| 370 | #include <linux/init.h> | ||
| 371 | #include <linux/socket.h> | ||
| 372 | #include <linux/in.h> | ||
| 373 | #include <linux/sched.h> | ||
| 374 | #include <linux/sunrpc/clnt.h> | ||
| 375 | #include <linux/workqueue.h> | ||
| 376 | #include <linux/sunrpc/rpc_pipe_fs.h> | ||
| 377 | |||
| 378 | #include <linux/nfs_fs.h> | ||
| 379 | |||
| 380 | #include "nfs4_fs.h" | ||
| 381 | |||
| 382 | #define IDMAP_HASH_SZ 128 | ||
| 383 | |||
| 384 | /* Default cache timeout is 10 minutes */ | ||
| 385 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; | ||
| 386 | |||
| 387 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) | ||
| 388 | { | ||
| 389 | char *endp; | ||
| 390 | int num = simple_strtol(val, &endp, 0); | ||
| 391 | int jif = num * HZ; | ||
| 392 | if (endp == val || *endp || num < 0 || jif < num) | ||
| 393 | return -EINVAL; | ||
| 394 | *((int *)kp->arg) = jif; | ||
| 395 | return 0; | ||
| 396 | } | ||
| 397 | |||
| 398 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | ||
| 399 | &nfs_idmap_cache_timeout, 0644); | ||
| 400 | |||
| 401 | struct idmap_hashent { | ||
| 402 | unsigned long ih_expires; | ||
| 403 | __u32 ih_id; | ||
| 404 | size_t ih_namelen; | ||
| 405 | char ih_name[IDMAP_NAMESZ]; | ||
| 406 | }; | 360 | }; |
| 407 | 361 | ||
| 408 | struct idmap_hashtable { | 362 | enum { |
| 409 | __u8 h_type; | 363 | Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err |
| 410 | struct idmap_hashent h_entries[IDMAP_HASH_SZ]; | ||
| 411 | }; | 364 | }; |
| 412 | 365 | ||
| 413 | struct idmap { | 366 | static const match_table_t nfs_idmap_tokens = { |
| 414 | struct dentry *idmap_dentry; | 367 | { Opt_find_uid, "uid:%s" }, |
| 415 | wait_queue_head_t idmap_wq; | 368 | { Opt_find_gid, "gid:%s" }, |
| 416 | struct idmap_msg idmap_im; | 369 | { Opt_find_user, "user:%s" }, |
| 417 | struct mutex idmap_lock; /* Serializes upcalls */ | 370 | { Opt_find_group, "group:%s" }, |
| 418 | struct mutex idmap_im_lock; /* Protects the hashtable */ | 371 | { Opt_find_err, NULL } |
| 419 | struct idmap_hashtable idmap_user_hash; | ||
| 420 | struct idmap_hashtable idmap_group_hash; | ||
| 421 | }; | 372 | }; |
| 422 | 373 | ||
| 374 | static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *); | ||
| 423 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, | 375 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, |
| 424 | size_t); | 376 | size_t); |
| 425 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); | 377 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); |
| 426 | 378 | ||
| 427 | static unsigned int fnvhash32(const void *, size_t); | ||
| 428 | |||
| 429 | static const struct rpc_pipe_ops idmap_upcall_ops = { | 379 | static const struct rpc_pipe_ops idmap_upcall_ops = { |
| 430 | .upcall = rpc_pipe_generic_upcall, | 380 | .upcall = rpc_pipe_generic_upcall, |
| 431 | .downcall = idmap_pipe_downcall, | 381 | .downcall = idmap_pipe_downcall, |
| 432 | .destroy_msg = idmap_pipe_destroy_msg, | 382 | .destroy_msg = idmap_pipe_destroy_msg, |
| 433 | }; | 383 | }; |
| 434 | 384 | ||
| 385 | static struct key_type key_type_id_resolver_legacy = { | ||
| 386 | .name = "id_resolver", | ||
| 387 | .instantiate = user_instantiate, | ||
| 388 | .match = user_match, | ||
| 389 | .revoke = user_revoke, | ||
| 390 | .destroy = user_destroy, | ||
| 391 | .describe = user_describe, | ||
| 392 | .read = user_read, | ||
| 393 | .request_key = nfs_idmap_legacy_upcall, | ||
| 394 | }; | ||
| 395 | |||
| 396 | static void __nfs_idmap_unregister(struct rpc_pipe *pipe) | ||
| 397 | { | ||
| 398 | if (pipe->dentry) | ||
| 399 | rpc_unlink(pipe->dentry); | ||
| 400 | } | ||
| 401 | |||
| 402 | static int __nfs_idmap_register(struct dentry *dir, | ||
| 403 | struct idmap *idmap, | ||
| 404 | struct rpc_pipe *pipe) | ||
| 405 | { | ||
| 406 | struct dentry *dentry; | ||
| 407 | |||
| 408 | dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe); | ||
| 409 | if (IS_ERR(dentry)) | ||
| 410 | return PTR_ERR(dentry); | ||
| 411 | pipe->dentry = dentry; | ||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | static void nfs_idmap_unregister(struct nfs_client *clp, | ||
| 416 | struct rpc_pipe *pipe) | ||
| 417 | { | ||
| 418 | struct net *net = clp->net; | ||
| 419 | struct super_block *pipefs_sb; | ||
| 420 | |||
| 421 | pipefs_sb = rpc_get_sb_net(net); | ||
| 422 | if (pipefs_sb) { | ||
| 423 | __nfs_idmap_unregister(pipe); | ||
| 424 | rpc_put_sb_net(net); | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | static int nfs_idmap_register(struct nfs_client *clp, | ||
| 429 | struct idmap *idmap, | ||
| 430 | struct rpc_pipe *pipe) | ||
| 431 | { | ||
| 432 | struct net *net = clp->net; | ||
| 433 | struct super_block *pipefs_sb; | ||
| 434 | int err = 0; | ||
| 435 | |||
| 436 | pipefs_sb = rpc_get_sb_net(net); | ||
| 437 | if (pipefs_sb) { | ||
| 438 | if (clp->cl_rpcclient->cl_dentry) | ||
| 439 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, | ||
| 440 | idmap, pipe); | ||
| 441 | rpc_put_sb_net(net); | ||
| 442 | } | ||
| 443 | return err; | ||
| 444 | } | ||
| 445 | |||
| 435 | int | 446 | int |
| 436 | nfs_idmap_new(struct nfs_client *clp) | 447 | nfs_idmap_new(struct nfs_client *clp) |
| 437 | { | 448 | { |
| 438 | struct idmap *idmap; | 449 | struct idmap *idmap; |
| 450 | struct rpc_pipe *pipe; | ||
| 439 | int error; | 451 | int error; |
| 440 | 452 | ||
| 441 | BUG_ON(clp->cl_idmap != NULL); | 453 | BUG_ON(clp->cl_idmap != NULL); |
| @@ -444,19 +456,19 @@ nfs_idmap_new(struct nfs_client *clp) | |||
| 444 | if (idmap == NULL) | 456 | if (idmap == NULL) |
| 445 | return -ENOMEM; | 457 | return -ENOMEM; |
| 446 | 458 | ||
| 447 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry, | 459 | pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0); |
| 448 | "idmap", idmap, &idmap_upcall_ops, 0); | 460 | if (IS_ERR(pipe)) { |
| 449 | if (IS_ERR(idmap->idmap_dentry)) { | 461 | error = PTR_ERR(pipe); |
| 450 | error = PTR_ERR(idmap->idmap_dentry); | ||
| 451 | kfree(idmap); | 462 | kfree(idmap); |
| 452 | return error; | 463 | return error; |
| 453 | } | 464 | } |
| 454 | 465 | error = nfs_idmap_register(clp, idmap, pipe); | |
| 455 | mutex_init(&idmap->idmap_lock); | 466 | if (error) { |
| 456 | mutex_init(&idmap->idmap_im_lock); | 467 | rpc_destroy_pipe_data(pipe); |
| 457 | init_waitqueue_head(&idmap->idmap_wq); | 468 | kfree(idmap); |
| 458 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; | 469 | return error; |
| 459 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; | 470 | } |
| 471 | idmap->idmap_pipe = pipe; | ||
| 460 | 472 | ||
| 461 | clp->cl_idmap = idmap; | 473 | clp->cl_idmap = idmap; |
| 462 | return 0; | 474 | return 0; |
| @@ -469,211 +481,220 @@ nfs_idmap_delete(struct nfs_client *clp) | |||
| 469 | 481 | ||
| 470 | if (!idmap) | 482 | if (!idmap) |
| 471 | return; | 483 | return; |
| 472 | rpc_unlink(idmap->idmap_dentry); | 484 | nfs_idmap_unregister(clp, idmap->idmap_pipe); |
| 485 | rpc_destroy_pipe_data(idmap->idmap_pipe); | ||
| 473 | clp->cl_idmap = NULL; | 486 | clp->cl_idmap = NULL; |
| 474 | kfree(idmap); | 487 | kfree(idmap); |
| 475 | } | 488 | } |
| 476 | 489 | ||
| 477 | /* | 490 | static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, |
| 478 | * Helper routines for manipulating the hashtable | 491 | struct super_block *sb) |
| 479 | */ | ||
| 480 | static inline struct idmap_hashent * | ||
| 481 | idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len) | ||
| 482 | { | ||
| 483 | return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ]; | ||
| 484 | } | ||
| 485 | |||
| 486 | static struct idmap_hashent * | ||
| 487 | idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len) | ||
| 488 | { | 492 | { |
| 489 | struct idmap_hashent *he = idmap_name_hash(h, name, len); | 493 | int err = 0; |
| 490 | 494 | ||
| 491 | if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) | 495 | switch (event) { |
| 492 | return NULL; | 496 | case RPC_PIPEFS_MOUNT: |
| 493 | if (time_after(jiffies, he->ih_expires)) | 497 | BUG_ON(clp->cl_rpcclient->cl_dentry == NULL); |
| 494 | return NULL; | 498 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, |
| 495 | return he; | 499 | clp->cl_idmap, |
| 500 | clp->cl_idmap->idmap_pipe); | ||
| 501 | break; | ||
| 502 | case RPC_PIPEFS_UMOUNT: | ||
| 503 | if (clp->cl_idmap->idmap_pipe) { | ||
| 504 | struct dentry *parent; | ||
| 505 | |||
| 506 | parent = clp->cl_idmap->idmap_pipe->dentry->d_parent; | ||
| 507 | __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe); | ||
| 508 | /* | ||
| 509 | * Note: This is a dirty hack. SUNRPC hook has been | ||
| 510 | * called already but simple_rmdir() call for the | ||
| 511 | * directory returned with error because of idmap pipe | ||
| 512 | * inside. Thus now we have to remove this directory | ||
| 513 | * here. | ||
| 514 | */ | ||
| 515 | if (rpc_rmdir(parent)) | ||
| 516 | printk(KERN_ERR "NFS: %s: failed to remove " | ||
| 517 | "clnt dir!\n", __func__); | ||
| 518 | } | ||
| 519 | break; | ||
| 520 | default: | ||
| 521 | printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__, | ||
| 522 | event); | ||
| 523 | return -ENOTSUPP; | ||
| 524 | } | ||
| 525 | return err; | ||
| 526 | } | ||
| 527 | |||
| 528 | static struct nfs_client *nfs_get_client_for_event(struct net *net, int event) | ||
| 529 | { | ||
| 530 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
| 531 | struct dentry *cl_dentry; | ||
| 532 | struct nfs_client *clp; | ||
| 533 | |||
| 534 | spin_lock(&nn->nfs_client_lock); | ||
| 535 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { | ||
| 536 | if (clp->rpc_ops != &nfs_v4_clientops) | ||
| 537 | continue; | ||
| 538 | cl_dentry = clp->cl_idmap->idmap_pipe->dentry; | ||
| 539 | if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) || | ||
| 540 | ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry)) | ||
| 541 | continue; | ||
| 542 | atomic_inc(&clp->cl_count); | ||
| 543 | spin_unlock(&nn->nfs_client_lock); | ||
| 544 | return clp; | ||
| 545 | } | ||
| 546 | spin_unlock(&nn->nfs_client_lock); | ||
| 547 | return NULL; | ||
| 496 | } | 548 | } |
| 497 | 549 | ||
| 498 | static inline struct idmap_hashent * | 550 | static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, |
| 499 | idmap_id_hash(struct idmap_hashtable* h, __u32 id) | 551 | void *ptr) |
| 500 | { | 552 | { |
| 501 | return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ]; | 553 | struct super_block *sb = ptr; |
| 502 | } | 554 | struct nfs_client *clp; |
| 555 | int error = 0; | ||
| 503 | 556 | ||
| 504 | static struct idmap_hashent * | 557 | while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) { |
| 505 | idmap_lookup_id(struct idmap_hashtable *h, __u32 id) | 558 | error = __rpc_pipefs_event(clp, event, sb); |
| 506 | { | 559 | nfs_put_client(clp); |
| 507 | struct idmap_hashent *he = idmap_id_hash(h, id); | 560 | if (error) |
| 508 | if (he->ih_id != id || he->ih_namelen == 0) | 561 | break; |
| 509 | return NULL; | 562 | } |
| 510 | if (time_after(jiffies, he->ih_expires)) | 563 | return error; |
| 511 | return NULL; | ||
| 512 | return he; | ||
| 513 | } | 564 | } |
| 514 | 565 | ||
| 515 | /* | 566 | #define PIPEFS_NFS_PRIO 1 |
| 516 | * Routines for allocating new entries in the hashtable. | 567 | |
| 517 | * For now, we just have 1 entry per bucket, so it's all | 568 | static struct notifier_block nfs_idmap_block = { |
| 518 | * pretty trivial. | 569 | .notifier_call = rpc_pipefs_event, |
| 519 | */ | 570 | .priority = SUNRPC_PIPEFS_NFS_PRIO, |
| 520 | static inline struct idmap_hashent * | 571 | }; |
| 521 | idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len) | ||
| 522 | { | ||
| 523 | return idmap_name_hash(h, name, len); | ||
| 524 | } | ||
| 525 | 572 | ||
| 526 | static inline struct idmap_hashent * | 573 | int nfs_idmap_init(void) |
| 527 | idmap_alloc_id(struct idmap_hashtable *h, __u32 id) | ||
| 528 | { | 574 | { |
| 529 | return idmap_id_hash(h, id); | 575 | int ret; |
| 576 | ret = nfs_idmap_init_keyring(); | ||
| 577 | if (ret != 0) | ||
| 578 | goto out; | ||
| 579 | ret = rpc_pipefs_notifier_register(&nfs_idmap_block); | ||
| 580 | if (ret != 0) | ||
| 581 | nfs_idmap_quit_keyring(); | ||
| 582 | out: | ||
| 583 | return ret; | ||
| 530 | } | 584 | } |
| 531 | 585 | ||
| 532 | static void | 586 | void nfs_idmap_quit(void) |
| 533 | idmap_update_entry(struct idmap_hashent *he, const char *name, | ||
| 534 | size_t namelen, __u32 id) | ||
| 535 | { | 587 | { |
| 536 | he->ih_id = id; | 588 | rpc_pipefs_notifier_unregister(&nfs_idmap_block); |
| 537 | memcpy(he->ih_name, name, namelen); | 589 | nfs_idmap_quit_keyring(); |
| 538 | he->ih_name[namelen] = '\0'; | ||
| 539 | he->ih_namelen = namelen; | ||
| 540 | he->ih_expires = jiffies + nfs_idmap_cache_timeout; | ||
| 541 | } | 590 | } |
| 542 | 591 | ||
| 543 | /* | 592 | static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im, |
| 544 | * Name -> ID | 593 | struct rpc_pipe_msg *msg) |
| 545 | */ | ||
| 546 | static int | ||
| 547 | nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, | ||
| 548 | const char *name, size_t namelen, __u32 *id) | ||
| 549 | { | 594 | { |
| 550 | struct rpc_pipe_msg msg; | 595 | substring_t substr; |
| 551 | struct idmap_msg *im; | 596 | int token, ret; |
| 552 | struct idmap_hashent *he; | ||
| 553 | DECLARE_WAITQUEUE(wq, current); | ||
| 554 | int ret = -EIO; | ||
| 555 | |||
| 556 | im = &idmap->idmap_im; | ||
| 557 | |||
| 558 | /* | ||
| 559 | * String sanity checks | ||
| 560 | * Note that the userland daemon expects NUL terminated strings | ||
| 561 | */ | ||
| 562 | for (;;) { | ||
| 563 | if (namelen == 0) | ||
| 564 | return -EINVAL; | ||
| 565 | if (name[namelen-1] != '\0') | ||
| 566 | break; | ||
| 567 | namelen--; | ||
| 568 | } | ||
| 569 | if (namelen >= IDMAP_NAMESZ) | ||
| 570 | return -EINVAL; | ||
| 571 | 597 | ||
| 572 | mutex_lock(&idmap->idmap_lock); | 598 | memset(im, 0, sizeof(*im)); |
| 573 | mutex_lock(&idmap->idmap_im_lock); | 599 | memset(msg, 0, sizeof(*msg)); |
| 574 | |||
| 575 | he = idmap_lookup_name(h, name, namelen); | ||
| 576 | if (he != NULL) { | ||
| 577 | *id = he->ih_id; | ||
| 578 | ret = 0; | ||
| 579 | goto out; | ||
| 580 | } | ||
| 581 | 600 | ||
| 582 | memset(im, 0, sizeof(*im)); | 601 | im->im_type = IDMAP_TYPE_GROUP; |
| 583 | memcpy(im->im_name, name, namelen); | 602 | token = match_token(desc, nfs_idmap_tokens, &substr); |
| 584 | 603 | ||
| 585 | im->im_type = h->h_type; | 604 | switch (token) { |
| 586 | im->im_conv = IDMAP_CONV_NAMETOID; | 605 | case Opt_find_uid: |
| 606 | im->im_type = IDMAP_TYPE_USER; | ||
| 607 | case Opt_find_gid: | ||
| 608 | im->im_conv = IDMAP_CONV_NAMETOID; | ||
| 609 | ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ); | ||
| 610 | break; | ||
| 587 | 611 | ||
| 588 | memset(&msg, 0, sizeof(msg)); | 612 | case Opt_find_user: |
| 589 | msg.data = im; | 613 | im->im_type = IDMAP_TYPE_USER; |
| 590 | msg.len = sizeof(*im); | 614 | case Opt_find_group: |
| 615 | im->im_conv = IDMAP_CONV_IDTONAME; | ||
| 616 | ret = match_int(&substr, &im->im_id); | ||
| 617 | break; | ||
| 591 | 618 | ||
| 592 | add_wait_queue(&idmap->idmap_wq, &wq); | 619 | default: |
| 593 | if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { | 620 | ret = -EINVAL; |
| 594 | remove_wait_queue(&idmap->idmap_wq, &wq); | ||
| 595 | goto out; | 621 | goto out; |
| 596 | } | 622 | } |
| 597 | 623 | ||
| 598 | set_current_state(TASK_UNINTERRUPTIBLE); | 624 | msg->data = im; |
| 599 | mutex_unlock(&idmap->idmap_im_lock); | 625 | msg->len = sizeof(struct idmap_msg); |
| 600 | schedule(); | ||
| 601 | __set_current_state(TASK_RUNNING); | ||
| 602 | remove_wait_queue(&idmap->idmap_wq, &wq); | ||
| 603 | mutex_lock(&idmap->idmap_im_lock); | ||
| 604 | 626 | ||
| 605 | if (im->im_status & IDMAP_STATUS_SUCCESS) { | 627 | out: |
| 606 | *id = im->im_id; | ||
| 607 | ret = 0; | ||
| 608 | } | ||
| 609 | |||
| 610 | out: | ||
| 611 | memset(im, 0, sizeof(*im)); | ||
| 612 | mutex_unlock(&idmap->idmap_im_lock); | ||
| 613 | mutex_unlock(&idmap->idmap_lock); | ||
| 614 | return ret; | 628 | return ret; |
| 615 | } | 629 | } |
| 616 | 630 | ||
| 617 | /* | 631 | static int nfs_idmap_legacy_upcall(struct key_construction *cons, |
| 618 | * ID -> Name | 632 | const char *op, |
| 619 | */ | 633 | void *aux) |
| 620 | static int | ||
| 621 | nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, | ||
| 622 | __u32 id, char *name) | ||
| 623 | { | 634 | { |
| 624 | struct rpc_pipe_msg msg; | 635 | struct rpc_pipe_msg *msg; |
| 625 | struct idmap_msg *im; | 636 | struct idmap_msg *im; |
| 626 | struct idmap_hashent *he; | 637 | struct idmap *idmap = (struct idmap *)aux; |
| 627 | DECLARE_WAITQUEUE(wq, current); | 638 | struct key *key = cons->key; |
| 628 | int ret = -EIO; | 639 | int ret; |
| 629 | unsigned int len; | ||
| 630 | |||
| 631 | im = &idmap->idmap_im; | ||
| 632 | 640 | ||
| 633 | mutex_lock(&idmap->idmap_lock); | 641 | /* msg and im are freed in idmap_pipe_destroy_msg */ |
| 634 | mutex_lock(&idmap->idmap_im_lock); | 642 | msg = kmalloc(sizeof(*msg), GFP_KERNEL); |
| 643 | if (IS_ERR(msg)) { | ||
| 644 | ret = PTR_ERR(msg); | ||
| 645 | goto out0; | ||
| 646 | } | ||
| 635 | 647 | ||
| 636 | he = idmap_lookup_id(h, id); | 648 | im = kmalloc(sizeof(*im), GFP_KERNEL); |
| 637 | if (he) { | 649 | if (IS_ERR(im)) { |
| 638 | memcpy(name, he->ih_name, he->ih_namelen); | 650 | ret = PTR_ERR(im); |
| 639 | ret = he->ih_namelen; | 651 | goto out1; |
| 640 | goto out; | ||
| 641 | } | 652 | } |
| 642 | 653 | ||
| 643 | memset(im, 0, sizeof(*im)); | 654 | ret = nfs_idmap_prepare_message(key->description, im, msg); |
| 644 | im->im_type = h->h_type; | 655 | if (ret < 0) |
| 645 | im->im_conv = IDMAP_CONV_IDTONAME; | 656 | goto out2; |
| 646 | im->im_id = id; | ||
| 647 | 657 | ||
| 648 | memset(&msg, 0, sizeof(msg)); | 658 | idmap->idmap_key_cons = cons; |
| 649 | msg.data = im; | ||
| 650 | msg.len = sizeof(*im); | ||
| 651 | 659 | ||
| 652 | add_wait_queue(&idmap->idmap_wq, &wq); | 660 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); |
| 661 | if (ret < 0) | ||
| 662 | goto out2; | ||
| 653 | 663 | ||
| 654 | if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { | 664 | return ret; |
| 655 | remove_wait_queue(&idmap->idmap_wq, &wq); | 665 | |
| 656 | goto out; | 666 | out2: |
| 657 | } | 667 | kfree(im); |
| 668 | out1: | ||
| 669 | kfree(msg); | ||
| 670 | out0: | ||
| 671 | key_revoke(cons->key); | ||
| 672 | key_revoke(cons->authkey); | ||
| 673 | return ret; | ||
| 674 | } | ||
| 675 | |||
| 676 | static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data) | ||
| 677 | { | ||
| 678 | return key_instantiate_and_link(key, data, strlen(data) + 1, | ||
| 679 | id_resolver_cache->thread_keyring, | ||
| 680 | authkey); | ||
| 681 | } | ||
| 658 | 682 | ||
| 659 | set_current_state(TASK_UNINTERRUPTIBLE); | 683 | static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey) |
| 660 | mutex_unlock(&idmap->idmap_im_lock); | 684 | { |
| 661 | schedule(); | 685 | char id_str[NFS_UINT_MAXLEN]; |
| 662 | __set_current_state(TASK_RUNNING); | 686 | int ret = -EINVAL; |
| 663 | remove_wait_queue(&idmap->idmap_wq, &wq); | 687 | |
| 664 | mutex_lock(&idmap->idmap_im_lock); | 688 | switch (im->im_conv) { |
| 665 | 689 | case IDMAP_CONV_NAMETOID: | |
| 666 | if (im->im_status & IDMAP_STATUS_SUCCESS) { | 690 | sprintf(id_str, "%d", im->im_id); |
| 667 | if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0) | 691 | ret = nfs_idmap_instantiate(key, authkey, id_str); |
| 668 | goto out; | 692 | break; |
| 669 | memcpy(name, im->im_name, len); | 693 | case IDMAP_CONV_IDTONAME: |
| 670 | ret = len; | 694 | ret = nfs_idmap_instantiate(key, authkey, im->im_name); |
| 695 | break; | ||
| 671 | } | 696 | } |
| 672 | 697 | ||
| 673 | out: | ||
| 674 | memset(im, 0, sizeof(*im)); | ||
| 675 | mutex_unlock(&idmap->idmap_im_lock); | ||
| 676 | mutex_unlock(&idmap->idmap_lock); | ||
| 677 | return ret; | 698 | return ret; |
| 678 | } | 699 | } |
| 679 | 700 | ||
| @@ -682,115 +703,51 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
| 682 | { | 703 | { |
| 683 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); | 704 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); |
| 684 | struct idmap *idmap = (struct idmap *)rpci->private; | 705 | struct idmap *idmap = (struct idmap *)rpci->private; |
| 685 | struct idmap_msg im_in, *im = &idmap->idmap_im; | 706 | struct key_construction *cons = idmap->idmap_key_cons; |
| 686 | struct idmap_hashtable *h; | 707 | struct idmap_msg im; |
| 687 | struct idmap_hashent *he = NULL; | ||
| 688 | size_t namelen_in; | 708 | size_t namelen_in; |
| 689 | int ret; | 709 | int ret; |
| 690 | 710 | ||
| 691 | if (mlen != sizeof(im_in)) | 711 | if (mlen != sizeof(im)) { |
| 692 | return -ENOSPC; | 712 | ret = -ENOSPC; |
| 693 | |||
| 694 | if (copy_from_user(&im_in, src, mlen) != 0) | ||
| 695 | return -EFAULT; | ||
| 696 | |||
| 697 | mutex_lock(&idmap->idmap_im_lock); | ||
| 698 | |||
| 699 | ret = mlen; | ||
| 700 | im->im_status = im_in.im_status; | ||
| 701 | /* If we got an error, terminate now, and wake up pending upcalls */ | ||
| 702 | if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) { | ||
| 703 | wake_up(&idmap->idmap_wq); | ||
| 704 | goto out; | 713 | goto out; |
| 705 | } | 714 | } |
| 706 | 715 | ||
| 707 | /* Sanity checking of strings */ | 716 | if (copy_from_user(&im, src, mlen) != 0) { |
| 708 | ret = -EINVAL; | 717 | ret = -EFAULT; |
| 709 | namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ); | ||
| 710 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) | ||
| 711 | goto out; | 718 | goto out; |
| 719 | } | ||
| 712 | 720 | ||
| 713 | switch (im_in.im_type) { | 721 | if (!(im.im_status & IDMAP_STATUS_SUCCESS)) { |
| 714 | case IDMAP_TYPE_USER: | 722 | ret = mlen; |
| 715 | h = &idmap->idmap_user_hash; | 723 | complete_request_key(idmap->idmap_key_cons, -ENOKEY); |
| 716 | break; | 724 | goto out_incomplete; |
| 717 | case IDMAP_TYPE_GROUP: | ||
| 718 | h = &idmap->idmap_group_hash; | ||
| 719 | break; | ||
| 720 | default: | ||
| 721 | goto out; | ||
| 722 | } | 725 | } |
| 723 | 726 | ||
| 724 | switch (im_in.im_conv) { | 727 | namelen_in = strnlen(im.im_name, IDMAP_NAMESZ); |
| 725 | case IDMAP_CONV_IDTONAME: | 728 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) { |
| 726 | /* Did we match the current upcall? */ | 729 | ret = -EINVAL; |
| 727 | if (im->im_conv == IDMAP_CONV_IDTONAME | ||
| 728 | && im->im_type == im_in.im_type | ||
| 729 | && im->im_id == im_in.im_id) { | ||
| 730 | /* Yes: copy string, including the terminating '\0' */ | ||
| 731 | memcpy(im->im_name, im_in.im_name, namelen_in); | ||
| 732 | im->im_name[namelen_in] = '\0'; | ||
| 733 | wake_up(&idmap->idmap_wq); | ||
| 734 | } | ||
| 735 | he = idmap_alloc_id(h, im_in.im_id); | ||
| 736 | break; | ||
| 737 | case IDMAP_CONV_NAMETOID: | ||
| 738 | /* Did we match the current upcall? */ | ||
| 739 | if (im->im_conv == IDMAP_CONV_NAMETOID | ||
| 740 | && im->im_type == im_in.im_type | ||
| 741 | && strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in | ||
| 742 | && memcmp(im->im_name, im_in.im_name, namelen_in) == 0) { | ||
| 743 | im->im_id = im_in.im_id; | ||
| 744 | wake_up(&idmap->idmap_wq); | ||
| 745 | } | ||
| 746 | he = idmap_alloc_name(h, im_in.im_name, namelen_in); | ||
| 747 | break; | ||
| 748 | default: | ||
| 749 | goto out; | 730 | goto out; |
| 750 | } | 731 | } |
| 751 | 732 | ||
| 752 | /* If the entry is valid, also copy it to the cache */ | 733 | ret = nfs_idmap_read_message(&im, cons->key, cons->authkey); |
| 753 | if (he != NULL) | 734 | if (ret >= 0) { |
| 754 | idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id); | 735 | key_set_timeout(cons->key, nfs_idmap_cache_timeout); |
| 755 | ret = mlen; | 736 | ret = mlen; |
| 737 | } | ||
| 738 | |||
| 756 | out: | 739 | out: |
| 757 | mutex_unlock(&idmap->idmap_im_lock); | 740 | complete_request_key(idmap->idmap_key_cons, ret); |
| 741 | out_incomplete: | ||
| 758 | return ret; | 742 | return ret; |
| 759 | } | 743 | } |
| 760 | 744 | ||
| 761 | static void | 745 | static void |
| 762 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) | 746 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) |
| 763 | { | 747 | { |
| 764 | struct idmap_msg *im = msg->data; | 748 | /* Free memory allocated in nfs_idmap_legacy_upcall() */ |
| 765 | struct idmap *idmap = container_of(im, struct idmap, idmap_im); | 749 | kfree(msg->data); |
| 766 | 750 | kfree(msg); | |
| 767 | if (msg->errno >= 0) | ||
| 768 | return; | ||
| 769 | mutex_lock(&idmap->idmap_im_lock); | ||
| 770 | im->im_status = IDMAP_STATUS_LOOKUPFAIL; | ||
| 771 | wake_up(&idmap->idmap_wq); | ||
| 772 | mutex_unlock(&idmap->idmap_im_lock); | ||
| 773 | } | ||
| 774 | |||
| 775 | /* | ||
| 776 | * Fowler/Noll/Vo hash | ||
| 777 | * http://www.isthe.com/chongo/tech/comp/fnv/ | ||
| 778 | */ | ||
| 779 | |||
| 780 | #define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */ | ||
| 781 | #define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */ | ||
| 782 | |||
| 783 | static unsigned int fnvhash32(const void *buf, size_t buflen) | ||
| 784 | { | ||
| 785 | const unsigned char *p, *end = (const unsigned char *)buf + buflen; | ||
| 786 | unsigned int hash = FNV_1_32; | ||
| 787 | |||
| 788 | for (p = buf; p < end; p++) { | ||
| 789 | hash *= FNV_P_32; | ||
| 790 | hash ^= (unsigned int)*p; | ||
| 791 | } | ||
| 792 | |||
| 793 | return hash; | ||
| 794 | } | 751 | } |
| 795 | 752 | ||
| 796 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 753 | 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_ | |||
| 799 | 756 | ||
| 800 | if (nfs_map_string_to_numeric(name, namelen, uid)) | 757 | if (nfs_map_string_to_numeric(name, namelen, uid)) |
| 801 | return 0; | 758 | return 0; |
| 802 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); | 759 | return nfs_idmap_lookup_id(name, namelen, "uid", uid, idmap); |
| 803 | } | 760 | } |
| 804 | 761 | ||
| 805 | int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 762 | int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid) |
| 806 | { | 763 | { |
| 807 | struct idmap *idmap = server->nfs_client->cl_idmap; | 764 | struct idmap *idmap = server->nfs_client->cl_idmap; |
| 808 | 765 | ||
| 809 | if (nfs_map_string_to_numeric(name, namelen, uid)) | 766 | if (nfs_map_string_to_numeric(name, namelen, gid)) |
| 810 | return 0; | 767 | return 0; |
| 811 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); | 768 | return nfs_idmap_lookup_id(name, namelen, "gid", gid, idmap); |
| 812 | } | 769 | } |
| 813 | 770 | ||
| 814 | int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) | 771 | 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 | |||
| 817 | int ret = -EINVAL; | 774 | int ret = -EINVAL; |
| 818 | 775 | ||
| 819 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | 776 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) |
| 820 | ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); | 777 | ret = nfs_idmap_lookup_name(uid, "user", buf, buflen, idmap); |
| 821 | if (ret < 0) | 778 | if (ret < 0) |
| 822 | ret = nfs_map_numeric_to_string(uid, buf, buflen); | 779 | ret = nfs_map_numeric_to_string(uid, buf, buflen); |
| 823 | return ret; | 780 | return ret; |
| 824 | } | 781 | } |
| 825 | int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) | 782 | int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen) |
| 826 | { | 783 | { |
| 827 | struct idmap *idmap = server->nfs_client->cl_idmap; | 784 | struct idmap *idmap = server->nfs_client->cl_idmap; |
| 828 | int ret = -EINVAL; | 785 | int ret = -EINVAL; |
| 829 | 786 | ||
| 830 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | 787 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) |
| 831 | ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf); | 788 | ret = nfs_idmap_lookup_name(gid, "group", buf, buflen, idmap); |
| 832 | if (ret < 0) | 789 | if (ret < 0) |
| 833 | ret = nfs_map_numeric_to_string(uid, buf, buflen); | 790 | ret = nfs_map_numeric_to_string(gid, buf, buflen); |
| 834 | return ret; | 791 | return ret; |
| 835 | } | 792 | } |
| 836 | |||
| 837 | #endif /* CONFIG_NFS_USE_NEW_IDMAPPER */ | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f649fba8c384..7bb4d13c1cd5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
| 40 | #include <linux/compat.h> | 40 | #include <linux/compat.h> |
| 41 | #include <linux/freezer.h> | 41 | #include <linux/freezer.h> |
| 42 | #include <linux/crc32.h> | ||
| 42 | 43 | ||
| 43 | #include <asm/system.h> | 44 | #include <asm/system.h> |
| 44 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
| @@ -51,6 +52,7 @@ | |||
| 51 | #include "fscache.h" | 52 | #include "fscache.h" |
| 52 | #include "dns_resolve.h" | 53 | #include "dns_resolve.h" |
| 53 | #include "pnfs.h" | 54 | #include "pnfs.h" |
| 55 | #include "netns.h" | ||
| 54 | 56 | ||
| 55 | #define NFSDBG_FACILITY NFSDBG_VFS | 57 | #define NFSDBG_FACILITY NFSDBG_VFS |
| 56 | 58 | ||
| @@ -388,9 +390,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
| 388 | unlock_new_inode(inode); | 390 | unlock_new_inode(inode); |
| 389 | } else | 391 | } else |
| 390 | nfs_refresh_inode(inode, fattr); | 392 | nfs_refresh_inode(inode, fattr); |
| 391 | dprintk("NFS: nfs_fhget(%s/%Ld ct=%d)\n", | 393 | dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n", |
| 392 | inode->i_sb->s_id, | 394 | inode->i_sb->s_id, |
| 393 | (long long)NFS_FILEID(inode), | 395 | (long long)NFS_FILEID(inode), |
| 396 | nfs_display_fhandle_hash(fh), | ||
| 394 | atomic_read(&inode->i_count)); | 397 | atomic_read(&inode->i_count)); |
| 395 | 398 | ||
| 396 | out: | 399 | out: |
| @@ -401,7 +404,7 @@ out_no_inode: | |||
| 401 | goto out; | 404 | goto out; |
| 402 | } | 405 | } |
| 403 | 406 | ||
| 404 | #define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE) | 407 | #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) |
| 405 | 408 | ||
| 406 | int | 409 | int |
| 407 | nfs_setattr(struct dentry *dentry, struct iattr *attr) | 410 | nfs_setattr(struct dentry *dentry, struct iattr *attr) |
| @@ -423,7 +426,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 423 | 426 | ||
| 424 | /* Optimization: if the end result is no change, don't RPC */ | 427 | /* Optimization: if the end result is no change, don't RPC */ |
| 425 | attr->ia_valid &= NFS_VALID_ATTRS; | 428 | attr->ia_valid &= NFS_VALID_ATTRS; |
| 426 | if ((attr->ia_valid & ~ATTR_FILE) == 0) | 429 | if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0) |
| 427 | return 0; | 430 | return 0; |
| 428 | 431 | ||
| 429 | /* Write all dirty data */ | 432 | /* Write all dirty data */ |
| @@ -1044,6 +1047,67 @@ struct nfs_fh *nfs_alloc_fhandle(void) | |||
| 1044 | return fh; | 1047 | return fh; |
| 1045 | } | 1048 | } |
| 1046 | 1049 | ||
| 1050 | #ifdef NFS_DEBUG | ||
| 1051 | /* | ||
| 1052 | * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle | ||
| 1053 | * in the same way that wireshark does | ||
| 1054 | * | ||
| 1055 | * @fh: file handle | ||
| 1056 | * | ||
| 1057 | * For debugging only. | ||
| 1058 | */ | ||
| 1059 | u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh) | ||
| 1060 | { | ||
| 1061 | /* wireshark uses 32-bit AUTODIN crc and does a bitwise | ||
| 1062 | * not on the result */ | ||
| 1063 | return ~crc32(0xFFFFFFFF, &fh->data[0], fh->size); | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | /* | ||
| 1067 | * _nfs_display_fhandle - display an NFS file handle on the console | ||
| 1068 | * | ||
| 1069 | * @fh: file handle to display | ||
| 1070 | * @caption: display caption | ||
| 1071 | * | ||
| 1072 | * For debugging only. | ||
| 1073 | */ | ||
| 1074 | void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption) | ||
| 1075 | { | ||
| 1076 | unsigned short i; | ||
| 1077 | |||
| 1078 | if (fh == NULL || fh->size == 0) { | ||
| 1079 | printk(KERN_DEFAULT "%s at %p is empty\n", caption, fh); | ||
| 1080 | return; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | printk(KERN_DEFAULT "%s at %p is %u bytes, crc: 0x%08x:\n", | ||
| 1084 | caption, fh, fh->size, _nfs_display_fhandle_hash(fh)); | ||
| 1085 | for (i = 0; i < fh->size; i += 16) { | ||
| 1086 | __be32 *pos = (__be32 *)&fh->data[i]; | ||
| 1087 | |||
| 1088 | switch ((fh->size - i - 1) >> 2) { | ||
| 1089 | case 0: | ||
| 1090 | printk(KERN_DEFAULT " %08x\n", | ||
| 1091 | be32_to_cpup(pos)); | ||
| 1092 | break; | ||
| 1093 | case 1: | ||
| 1094 | printk(KERN_DEFAULT " %08x %08x\n", | ||
| 1095 | be32_to_cpup(pos), be32_to_cpup(pos + 1)); | ||
| 1096 | break; | ||
| 1097 | case 2: | ||
| 1098 | printk(KERN_DEFAULT " %08x %08x %08x\n", | ||
| 1099 | be32_to_cpup(pos), be32_to_cpup(pos + 1), | ||
| 1100 | be32_to_cpup(pos + 2)); | ||
| 1101 | break; | ||
| 1102 | default: | ||
| 1103 | printk(KERN_DEFAULT " %08x %08x %08x %08x\n", | ||
| 1104 | be32_to_cpup(pos), be32_to_cpup(pos + 1), | ||
| 1105 | be32_to_cpup(pos + 2), be32_to_cpup(pos + 3)); | ||
| 1106 | } | ||
| 1107 | } | ||
| 1108 | } | ||
| 1109 | #endif | ||
| 1110 | |||
| 1047 | /** | 1111 | /** |
| 1048 | * nfs_inode_attrs_need_update - check if the inode attributes need updating | 1112 | * nfs_inode_attrs_need_update - check if the inode attributes need updating |
| 1049 | * @inode - pointer to inode | 1113 | * @inode - pointer to inode |
| @@ -1211,8 +1275,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1211 | unsigned long now = jiffies; | 1275 | unsigned long now = jiffies; |
| 1212 | unsigned long save_cache_validity; | 1276 | unsigned long save_cache_validity; |
| 1213 | 1277 | ||
| 1214 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", | 1278 | dfprintk(VFS, "NFS: %s(%s/%ld fh_crc=0x%08x ct=%d info=0x%x)\n", |
| 1215 | __func__, inode->i_sb->s_id, inode->i_ino, | 1279 | __func__, inode->i_sb->s_id, inode->i_ino, |
| 1280 | nfs_display_fhandle_hash(NFS_FH(inode)), | ||
| 1216 | atomic_read(&inode->i_count), fattr->valid); | 1281 | atomic_read(&inode->i_count), fattr->valid); |
| 1217 | 1282 | ||
| 1218 | if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid) | 1283 | 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) | |||
| 1406 | /* | 1471 | /* |
| 1407 | * Big trouble! The inode has become a different object. | 1472 | * Big trouble! The inode has become a different object. |
| 1408 | */ | 1473 | */ |
| 1409 | printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", | 1474 | printk(KERN_DEBUG "NFS: %s: inode %ld mode changed, %07o to %07o\n", |
| 1410 | __func__, inode->i_ino, inode->i_mode, fattr->mode); | 1475 | __func__, inode->i_ino, inode->i_mode, fattr->mode); |
| 1411 | out_err: | 1476 | out_err: |
| 1412 | /* | 1477 | /* |
| @@ -1495,7 +1560,7 @@ static void init_once(void *foo) | |||
| 1495 | INIT_LIST_HEAD(&nfsi->open_files); | 1560 | INIT_LIST_HEAD(&nfsi->open_files); |
| 1496 | INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); | 1561 | INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); |
| 1497 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); | 1562 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); |
| 1498 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); | 1563 | INIT_LIST_HEAD(&nfsi->commit_list); |
| 1499 | nfsi->npages = 0; | 1564 | nfsi->npages = 0; |
| 1500 | nfsi->ncommit = 0; | 1565 | nfsi->ncommit = 0; |
| 1501 | atomic_set(&nfsi->silly_count, 1); | 1566 | atomic_set(&nfsi->silly_count, 1); |
| @@ -1552,6 +1617,28 @@ static void nfsiod_stop(void) | |||
| 1552 | destroy_workqueue(wq); | 1617 | destroy_workqueue(wq); |
| 1553 | } | 1618 | } |
| 1554 | 1619 | ||
| 1620 | int nfs_net_id; | ||
| 1621 | EXPORT_SYMBOL_GPL(nfs_net_id); | ||
| 1622 | |||
| 1623 | static int nfs_net_init(struct net *net) | ||
| 1624 | { | ||
| 1625 | nfs_clients_init(net); | ||
| 1626 | return nfs_dns_resolver_cache_init(net); | ||
| 1627 | } | ||
| 1628 | |||
| 1629 | static void nfs_net_exit(struct net *net) | ||
| 1630 | { | ||
| 1631 | nfs_dns_resolver_cache_destroy(net); | ||
| 1632 | nfs_cleanup_cb_ident_idr(net); | ||
| 1633 | } | ||
| 1634 | |||
| 1635 | static struct pernet_operations nfs_net_ops = { | ||
| 1636 | .init = nfs_net_init, | ||
| 1637 | .exit = nfs_net_exit, | ||
| 1638 | .id = &nfs_net_id, | ||
| 1639 | .size = sizeof(struct nfs_net), | ||
| 1640 | }; | ||
| 1641 | |||
| 1555 | /* | 1642 | /* |
| 1556 | * Initialize NFS | 1643 | * Initialize NFS |
| 1557 | */ | 1644 | */ |
| @@ -1561,10 +1648,14 @@ static int __init init_nfs_fs(void) | |||
| 1561 | 1648 | ||
| 1562 | err = nfs_idmap_init(); | 1649 | err = nfs_idmap_init(); |
| 1563 | if (err < 0) | 1650 | if (err < 0) |
| 1564 | goto out9; | 1651 | goto out10; |
| 1565 | 1652 | ||
| 1566 | err = nfs_dns_resolver_init(); | 1653 | err = nfs_dns_resolver_init(); |
| 1567 | if (err < 0) | 1654 | if (err < 0) |
| 1655 | goto out9; | ||
| 1656 | |||
| 1657 | err = register_pernet_subsys(&nfs_net_ops); | ||
| 1658 | if (err < 0) | ||
| 1568 | goto out8; | 1659 | goto out8; |
| 1569 | 1660 | ||
| 1570 | err = nfs_fscache_register(); | 1661 | err = nfs_fscache_register(); |
| @@ -1600,14 +1691,14 @@ static int __init init_nfs_fs(void) | |||
| 1600 | goto out0; | 1691 | goto out0; |
| 1601 | 1692 | ||
| 1602 | #ifdef CONFIG_PROC_FS | 1693 | #ifdef CONFIG_PROC_FS |
| 1603 | rpc_proc_register(&nfs_rpcstat); | 1694 | rpc_proc_register(&init_net, &nfs_rpcstat); |
| 1604 | #endif | 1695 | #endif |
| 1605 | if ((err = register_nfs_fs()) != 0) | 1696 | if ((err = register_nfs_fs()) != 0) |
| 1606 | goto out; | 1697 | goto out; |
| 1607 | return 0; | 1698 | return 0; |
| 1608 | out: | 1699 | out: |
| 1609 | #ifdef CONFIG_PROC_FS | 1700 | #ifdef CONFIG_PROC_FS |
| 1610 | rpc_proc_unregister("nfs"); | 1701 | rpc_proc_unregister(&init_net, "nfs"); |
| 1611 | #endif | 1702 | #endif |
| 1612 | nfs_destroy_directcache(); | 1703 | nfs_destroy_directcache(); |
| 1613 | out0: | 1704 | out0: |
| @@ -1625,10 +1716,12 @@ out5: | |||
| 1625 | out6: | 1716 | out6: |
| 1626 | nfs_fscache_unregister(); | 1717 | nfs_fscache_unregister(); |
| 1627 | out7: | 1718 | out7: |
| 1628 | nfs_dns_resolver_destroy(); | 1719 | unregister_pernet_subsys(&nfs_net_ops); |
| 1629 | out8: | 1720 | out8: |
| 1630 | nfs_idmap_quit(); | 1721 | nfs_dns_resolver_destroy(); |
| 1631 | out9: | 1722 | out9: |
| 1723 | nfs_idmap_quit(); | ||
| 1724 | out10: | ||
| 1632 | return err; | 1725 | return err; |
| 1633 | } | 1726 | } |
| 1634 | 1727 | ||
| @@ -1640,12 +1733,12 @@ static void __exit exit_nfs_fs(void) | |||
| 1640 | nfs_destroy_inodecache(); | 1733 | nfs_destroy_inodecache(); |
| 1641 | nfs_destroy_nfspagecache(); | 1734 | nfs_destroy_nfspagecache(); |
| 1642 | nfs_fscache_unregister(); | 1735 | nfs_fscache_unregister(); |
| 1736 | unregister_pernet_subsys(&nfs_net_ops); | ||
| 1643 | nfs_dns_resolver_destroy(); | 1737 | nfs_dns_resolver_destroy(); |
| 1644 | nfs_idmap_quit(); | 1738 | nfs_idmap_quit(); |
| 1645 | #ifdef CONFIG_PROC_FS | 1739 | #ifdef CONFIG_PROC_FS |
| 1646 | rpc_proc_unregister("nfs"); | 1740 | rpc_proc_unregister(&init_net, "nfs"); |
| 1647 | #endif | 1741 | #endif |
| 1648 | nfs_cleanup_cb_ident_idr(); | ||
| 1649 | unregister_nfs_fs(); | 1742 | unregister_nfs_fs(); |
| 1650 | nfs_fs_proc_exit(); | 1743 | nfs_fs_proc_exit(); |
| 1651 | nfsiod_stop(); | 1744 | nfsiod_stop(); |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 8102db9b926c..2476dc69365f 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -123,6 +123,7 @@ struct nfs_parsed_mount_data { | |||
| 123 | } nfs_server; | 123 | } nfs_server; |
| 124 | 124 | ||
| 125 | struct security_mnt_opts lsm_opts; | 125 | struct security_mnt_opts lsm_opts; |
| 126 | struct net *net; | ||
| 126 | }; | 127 | }; |
| 127 | 128 | ||
| 128 | /* mount_clnt.c */ | 129 | /* mount_clnt.c */ |
| @@ -137,20 +138,22 @@ struct nfs_mount_request { | |||
| 137 | int noresvport; | 138 | int noresvport; |
| 138 | unsigned int *auth_flav_len; | 139 | unsigned int *auth_flav_len; |
| 139 | rpc_authflavor_t *auth_flavs; | 140 | rpc_authflavor_t *auth_flavs; |
| 141 | struct net *net; | ||
| 140 | }; | 142 | }; |
| 141 | 143 | ||
| 142 | extern int nfs_mount(struct nfs_mount_request *info); | 144 | extern int nfs_mount(struct nfs_mount_request *info); |
| 143 | extern void nfs_umount(const struct nfs_mount_request *info); | 145 | extern void nfs_umount(const struct nfs_mount_request *info); |
| 144 | 146 | ||
| 145 | /* client.c */ | 147 | /* client.c */ |
| 146 | extern struct rpc_program nfs_program; | 148 | extern const struct rpc_program nfs_program; |
| 149 | extern void nfs_clients_init(struct net *net); | ||
| 147 | 150 | ||
| 148 | extern void nfs_cleanup_cb_ident_idr(void); | 151 | extern void nfs_cleanup_cb_ident_idr(struct net *); |
| 149 | extern void nfs_put_client(struct nfs_client *); | 152 | extern void nfs_put_client(struct nfs_client *); |
| 150 | extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *); | 153 | extern struct nfs_client *nfs4_find_client_ident(struct net *, int); |
| 151 | extern struct nfs_client *nfs4_find_client_ident(int); | ||
| 152 | extern struct nfs_client * | 154 | extern struct nfs_client * |
| 153 | nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *); | 155 | nfs4_find_client_sessionid(struct net *, const struct sockaddr *, |
| 156 | struct nfs4_sessionid *); | ||
| 154 | extern struct nfs_server *nfs_create_server( | 157 | extern struct nfs_server *nfs_create_server( |
| 155 | const struct nfs_parsed_mount_data *, | 158 | const struct nfs_parsed_mount_data *, |
| 156 | struct nfs_fh *); | 159 | struct nfs_fh *); |
| @@ -329,6 +332,8 @@ void nfs_retry_commit(struct list_head *page_list, | |||
| 329 | void nfs_commit_clear_lock(struct nfs_inode *nfsi); | 332 | void nfs_commit_clear_lock(struct nfs_inode *nfsi); |
| 330 | void nfs_commitdata_release(void *data); | 333 | void nfs_commitdata_release(void *data); |
| 331 | void nfs_commit_release_pages(struct nfs_write_data *data); | 334 | void nfs_commit_release_pages(struct nfs_write_data *data); |
| 335 | void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head); | ||
| 336 | void nfs_request_remove_commit_list(struct nfs_page *req); | ||
| 332 | 337 | ||
| 333 | #ifdef CONFIG_MIGRATION | 338 | #ifdef CONFIG_MIGRATION |
| 334 | extern int nfs_migrate_page(struct address_space *, | 339 | extern int nfs_migrate_page(struct address_space *, |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index d4c2d6b7507e..8e65c7f1f87c 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
| 17 | #include "internal.h" | 17 | #include "internal.h" |
| 18 | 18 | ||
| 19 | #ifdef RPC_DEBUG | 19 | #ifdef NFS_DEBUG |
| 20 | # define NFSDBG_FACILITY NFSDBG_MOUNT | 20 | # define NFSDBG_FACILITY NFSDBG_MOUNT |
| 21 | #endif | 21 | #endif |
| 22 | 22 | ||
| @@ -67,7 +67,7 @@ enum { | |||
| 67 | MOUNTPROC3_EXPORT = 5, | 67 | MOUNTPROC3_EXPORT = 5, |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | static struct rpc_program mnt_program; | 70 | static const struct rpc_program mnt_program; |
| 71 | 71 | ||
| 72 | /* | 72 | /* |
| 73 | * Defined by OpenGroup XNFS Version 3W, chapter 8 | 73 | * Defined by OpenGroup XNFS Version 3W, chapter 8 |
| @@ -153,7 +153,7 @@ int nfs_mount(struct nfs_mount_request *info) | |||
| 153 | .rpc_resp = &result, | 153 | .rpc_resp = &result, |
| 154 | }; | 154 | }; |
| 155 | struct rpc_create_args args = { | 155 | struct rpc_create_args args = { |
| 156 | .net = &init_net, | 156 | .net = info->net, |
| 157 | .protocol = info->protocol, | 157 | .protocol = info->protocol, |
| 158 | .address = info->sap, | 158 | .address = info->sap, |
| 159 | .addrsize = info->salen, | 159 | .addrsize = info->salen, |
| @@ -225,7 +225,7 @@ void nfs_umount(const struct nfs_mount_request *info) | |||
| 225 | .to_retries = 2, | 225 | .to_retries = 2, |
| 226 | }; | 226 | }; |
| 227 | struct rpc_create_args args = { | 227 | struct rpc_create_args args = { |
| 228 | .net = &init_net, | 228 | .net = info->net, |
| 229 | .protocol = IPPROTO_UDP, | 229 | .protocol = IPPROTO_UDP, |
| 230 | .address = info->sap, | 230 | .address = info->sap, |
| 231 | .addrsize = info->salen, | 231 | .addrsize = info->salen, |
| @@ -488,19 +488,19 @@ static struct rpc_procinfo mnt3_procedures[] = { | |||
| 488 | }; | 488 | }; |
| 489 | 489 | ||
| 490 | 490 | ||
| 491 | static struct rpc_version mnt_version1 = { | 491 | static const struct rpc_version mnt_version1 = { |
| 492 | .number = 1, | 492 | .number = 1, |
| 493 | .nrprocs = ARRAY_SIZE(mnt_procedures), | 493 | .nrprocs = ARRAY_SIZE(mnt_procedures), |
| 494 | .procs = mnt_procedures, | 494 | .procs = mnt_procedures, |
| 495 | }; | 495 | }; |
| 496 | 496 | ||
| 497 | static struct rpc_version mnt_version3 = { | 497 | static const struct rpc_version mnt_version3 = { |
| 498 | .number = 3, | 498 | .number = 3, |
| 499 | .nrprocs = ARRAY_SIZE(mnt3_procedures), | 499 | .nrprocs = ARRAY_SIZE(mnt3_procedures), |
| 500 | .procs = mnt3_procedures, | 500 | .procs = mnt3_procedures, |
| 501 | }; | 501 | }; |
| 502 | 502 | ||
| 503 | static struct rpc_version *mnt_version[] = { | 503 | static const struct rpc_version *mnt_version[] = { |
| 504 | NULL, | 504 | NULL, |
| 505 | &mnt_version1, | 505 | &mnt_version1, |
| 506 | NULL, | 506 | NULL, |
| @@ -509,7 +509,7 @@ static struct rpc_version *mnt_version[] = { | |||
| 509 | 509 | ||
| 510 | static struct rpc_stat mnt_stats; | 510 | static struct rpc_stat mnt_stats; |
| 511 | 511 | ||
| 512 | static struct rpc_program mnt_program = { | 512 | static const struct rpc_program mnt_program = { |
| 513 | .name = "mount", | 513 | .name = "mount", |
| 514 | .number = NFS_MNT_PROGRAM, | 514 | .number = NFS_MNT_PROGRAM, |
| 515 | .nrvers = ARRAY_SIZE(mnt_version), | 515 | .nrvers = ARRAY_SIZE(mnt_version), |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 8102391bb374..1807866bb3ab 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
| @@ -276,7 +276,10 @@ out: | |||
| 276 | nfs_free_fattr(fattr); | 276 | nfs_free_fattr(fattr); |
| 277 | nfs_free_fhandle(fh); | 277 | nfs_free_fhandle(fh); |
| 278 | out_nofree: | 278 | out_nofree: |
| 279 | dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt); | 279 | if (IS_ERR(mnt)) |
| 280 | dprintk("<-- %s(): error %ld\n", __func__, PTR_ERR(mnt)); | ||
| 281 | else | ||
| 282 | dprintk("<-- %s() = %p\n", __func__, mnt); | ||
| 280 | return mnt; | 283 | return mnt; |
| 281 | } | 284 | } |
| 282 | 285 | ||
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h new file mode 100644 index 000000000000..aa14ec303e94 --- /dev/null +++ b/fs/nfs/netns.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #ifndef __NFS_NETNS_H__ | ||
| 2 | #define __NFS_NETNS_H__ | ||
| 3 | |||
| 4 | #include <net/net_namespace.h> | ||
| 5 | #include <net/netns/generic.h> | ||
| 6 | |||
| 7 | struct bl_dev_msg { | ||
| 8 | int32_t status; | ||
| 9 | uint32_t major, minor; | ||
| 10 | }; | ||
| 11 | |||
| 12 | struct nfs_net { | ||
| 13 | struct cache_detail *nfs_dns_resolve; | ||
| 14 | struct rpc_pipe *bl_device_pipe; | ||
| 15 | struct bl_dev_msg bl_mount_reply; | ||
| 16 | wait_queue_head_t bl_wq; | ||
| 17 | struct list_head nfs_client_list; | ||
| 18 | struct list_head nfs_volume_list; | ||
| 19 | #ifdef CONFIG_NFS_V4 | ||
| 20 | struct idr cb_ident_idr; /* Protected by nfs_client_lock */ | ||
| 21 | #endif | ||
| 22 | spinlock_t nfs_client_lock; | ||
| 23 | }; | ||
| 24 | |||
| 25 | extern int nfs_net_id; | ||
| 26 | |||
| 27 | #endif | ||
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 792cb13a4304..1f56000fabbd 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
| @@ -1150,7 +1150,7 @@ struct rpc_procinfo nfs_procedures[] = { | |||
| 1150 | PROC(STATFS, fhandle, statfsres, 0), | 1150 | PROC(STATFS, fhandle, statfsres, 0), |
| 1151 | }; | 1151 | }; |
| 1152 | 1152 | ||
| 1153 | struct rpc_version nfs_version2 = { | 1153 | const struct rpc_version nfs_version2 = { |
| 1154 | .number = 2, | 1154 | .number = 2, |
| 1155 | .nrprocs = ARRAY_SIZE(nfs_procedures), | 1155 | .nrprocs = ARRAY_SIZE(nfs_procedures), |
| 1156 | .procs = nfs_procedures | 1156 | .procs = nfs_procedures |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 7ef23979896d..e4498dc351a8 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
| @@ -192,7 +192,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
| 192 | .pages = pages, | 192 | .pages = pages, |
| 193 | }; | 193 | }; |
| 194 | struct nfs3_getaclres res = { | 194 | struct nfs3_getaclres res = { |
| 195 | 0 | 195 | NULL, |
| 196 | }; | 196 | }; |
| 197 | struct rpc_message msg = { | 197 | struct rpc_message msg = { |
| 198 | .rpc_argp = &args, | 198 | .rpc_argp = &args, |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 91943953a370..5242eae6711a 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
| @@ -428,6 +428,11 @@ nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) | |||
| 428 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; | 428 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; |
| 429 | } | 429 | } |
| 430 | 430 | ||
| 431 | static void nfs3_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) | ||
| 432 | { | ||
| 433 | rpc_call_start(task); | ||
| 434 | } | ||
| 435 | |||
| 431 | static int | 436 | static int |
| 432 | nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir) | 437 | nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir) |
| 433 | { | 438 | { |
| @@ -445,6 +450,11 @@ nfs3_proc_rename_setup(struct rpc_message *msg, struct inode *dir) | |||
| 445 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME]; | 450 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME]; |
| 446 | } | 451 | } |
| 447 | 452 | ||
| 453 | static void nfs3_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data) | ||
| 454 | { | ||
| 455 | rpc_call_start(task); | ||
| 456 | } | ||
| 457 | |||
| 448 | static int | 458 | static int |
| 449 | nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir, | 459 | nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir, |
| 450 | struct inode *new_dir) | 460 | struct inode *new_dir) |
| @@ -814,6 +824,11 @@ static void nfs3_proc_read_setup(struct nfs_read_data *data, struct rpc_message | |||
| 814 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; | 824 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; |
| 815 | } | 825 | } |
| 816 | 826 | ||
| 827 | static void nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) | ||
| 828 | { | ||
| 829 | rpc_call_start(task); | ||
| 830 | } | ||
| 831 | |||
| 817 | static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) | 832 | static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) |
| 818 | { | 833 | { |
| 819 | if (nfs3_async_handle_jukebox(task, data->inode)) | 834 | 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 | |||
| 828 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE]; | 843 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE]; |
| 829 | } | 844 | } |
| 830 | 845 | ||
| 846 | static void nfs3_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data) | ||
| 847 | { | ||
| 848 | rpc_call_start(task); | ||
| 849 | } | ||
| 850 | |||
| 831 | static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) | 851 | static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) |
| 832 | { | 852 | { |
| 833 | if (nfs3_async_handle_jukebox(task, data->inode)) | 853 | if (nfs3_async_handle_jukebox(task, data->inode)) |
| @@ -864,9 +884,11 @@ const struct nfs_rpc_ops nfs_v3_clientops = { | |||
| 864 | .create = nfs3_proc_create, | 884 | .create = nfs3_proc_create, |
| 865 | .remove = nfs3_proc_remove, | 885 | .remove = nfs3_proc_remove, |
| 866 | .unlink_setup = nfs3_proc_unlink_setup, | 886 | .unlink_setup = nfs3_proc_unlink_setup, |
| 887 | .unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare, | ||
| 867 | .unlink_done = nfs3_proc_unlink_done, | 888 | .unlink_done = nfs3_proc_unlink_done, |
| 868 | .rename = nfs3_proc_rename, | 889 | .rename = nfs3_proc_rename, |
| 869 | .rename_setup = nfs3_proc_rename_setup, | 890 | .rename_setup = nfs3_proc_rename_setup, |
| 891 | .rename_rpc_prepare = nfs3_proc_rename_rpc_prepare, | ||
| 870 | .rename_done = nfs3_proc_rename_done, | 892 | .rename_done = nfs3_proc_rename_done, |
| 871 | .link = nfs3_proc_link, | 893 | .link = nfs3_proc_link, |
| 872 | .symlink = nfs3_proc_symlink, | 894 | .symlink = nfs3_proc_symlink, |
| @@ -879,8 +901,10 @@ const struct nfs_rpc_ops nfs_v3_clientops = { | |||
| 879 | .pathconf = nfs3_proc_pathconf, | 901 | .pathconf = nfs3_proc_pathconf, |
| 880 | .decode_dirent = nfs3_decode_dirent, | 902 | .decode_dirent = nfs3_decode_dirent, |
| 881 | .read_setup = nfs3_proc_read_setup, | 903 | .read_setup = nfs3_proc_read_setup, |
| 904 | .read_rpc_prepare = nfs3_proc_read_rpc_prepare, | ||
| 882 | .read_done = nfs3_read_done, | 905 | .read_done = nfs3_read_done, |
| 883 | .write_setup = nfs3_proc_write_setup, | 906 | .write_setup = nfs3_proc_write_setup, |
| 907 | .write_rpc_prepare = nfs3_proc_write_rpc_prepare, | ||
| 884 | .write_done = nfs3_write_done, | 908 | .write_done = nfs3_write_done, |
| 885 | .commit_setup = nfs3_proc_commit_setup, | 909 | .commit_setup = nfs3_proc_commit_setup, |
| 886 | .commit_done = nfs3_commit_done, | 910 | .commit_done = nfs3_commit_done, |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 183c6b123d0f..a77cc9a3ce55 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
| @@ -2461,7 +2461,7 @@ struct rpc_procinfo nfs3_procedures[] = { | |||
| 2461 | PROC(COMMIT, commit, commit, 5), | 2461 | PROC(COMMIT, commit, commit, 5), |
| 2462 | }; | 2462 | }; |
| 2463 | 2463 | ||
| 2464 | struct rpc_version nfs_version3 = { | 2464 | const struct rpc_version nfs_version3 = { |
| 2465 | .number = 3, | 2465 | .number = 3, |
| 2466 | .nrprocs = ARRAY_SIZE(nfs3_procedures), | 2466 | .nrprocs = ARRAY_SIZE(nfs3_procedures), |
| 2467 | .procs = nfs3_procedures | 2467 | .procs = nfs3_procedures |
| @@ -2489,7 +2489,7 @@ static struct rpc_procinfo nfs3_acl_procedures[] = { | |||
| 2489 | }, | 2489 | }, |
| 2490 | }; | 2490 | }; |
| 2491 | 2491 | ||
| 2492 | struct rpc_version nfsacl_version3 = { | 2492 | const struct rpc_version nfsacl_version3 = { |
| 2493 | .number = 3, | 2493 | .number = 3, |
| 2494 | .nrprocs = sizeof(nfs3_acl_procedures)/ | 2494 | .nrprocs = sizeof(nfs3_acl_procedures)/ |
| 2495 | sizeof(nfs3_acl_procedures[0]), | 2495 | sizeof(nfs3_acl_procedures[0]), |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 4d7d0aedc101..97ecc863dd76 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -20,7 +20,6 @@ enum nfs4_client_state { | |||
| 20 | NFS4CLNT_RECLAIM_REBOOT, | 20 | NFS4CLNT_RECLAIM_REBOOT, |
| 21 | NFS4CLNT_RECLAIM_NOGRACE, | 21 | NFS4CLNT_RECLAIM_NOGRACE, |
| 22 | NFS4CLNT_DELEGRETURN, | 22 | NFS4CLNT_DELEGRETURN, |
| 23 | NFS4CLNT_LAYOUTRECALL, | ||
| 24 | NFS4CLNT_SESSION_RESET, | 23 | NFS4CLNT_SESSION_RESET, |
| 25 | NFS4CLNT_RECALL_SLOT, | 24 | NFS4CLNT_RECALL_SLOT, |
| 26 | NFS4CLNT_LEASE_CONFIRM, | 25 | NFS4CLNT_LEASE_CONFIRM, |
| @@ -44,7 +43,7 @@ struct nfs4_minor_version_ops { | |||
| 44 | struct nfs4_sequence_args *args, | 43 | struct nfs4_sequence_args *args, |
| 45 | struct nfs4_sequence_res *res, | 44 | struct nfs4_sequence_res *res, |
| 46 | int cache_reply); | 45 | int cache_reply); |
| 47 | int (*validate_stateid)(struct nfs_delegation *, | 46 | bool (*match_stateid)(const nfs4_stateid *, |
| 48 | const nfs4_stateid *); | 47 | const nfs4_stateid *); |
| 49 | int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, | 48 | int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, |
| 50 | struct nfs_fsinfo *); | 49 | struct nfs_fsinfo *); |
| @@ -53,26 +52,25 @@ struct nfs4_minor_version_ops { | |||
| 53 | const struct nfs4_state_maintenance_ops *state_renewal_ops; | 52 | const struct nfs4_state_maintenance_ops *state_renewal_ops; |
| 54 | }; | 53 | }; |
| 55 | 54 | ||
| 56 | /* | 55 | struct nfs_unique_id { |
| 57 | * struct rpc_sequence ensures that RPC calls are sent in the exact | 56 | struct rb_node rb_node; |
| 58 | * order that they appear on the list. | 57 | __u64 id; |
| 59 | */ | ||
| 60 | struct rpc_sequence { | ||
| 61 | struct rpc_wait_queue wait; /* RPC call delay queue */ | ||
| 62 | spinlock_t lock; /* Protects the list */ | ||
| 63 | struct list_head list; /* Defines sequence of RPC calls */ | ||
| 64 | }; | 58 | }; |
| 65 | 59 | ||
| 66 | #define NFS_SEQID_CONFIRMED 1 | 60 | #define NFS_SEQID_CONFIRMED 1 |
| 67 | struct nfs_seqid_counter { | 61 | struct nfs_seqid_counter { |
| 68 | struct rpc_sequence *sequence; | 62 | int owner_id; |
| 69 | int flags; | 63 | int flags; |
| 70 | u32 counter; | 64 | u32 counter; |
| 65 | spinlock_t lock; /* Protects the list */ | ||
| 66 | struct list_head list; /* Defines sequence of RPC calls */ | ||
| 67 | struct rpc_wait_queue wait; /* RPC call delay queue */ | ||
| 71 | }; | 68 | }; |
| 72 | 69 | ||
| 73 | struct nfs_seqid { | 70 | struct nfs_seqid { |
| 74 | struct nfs_seqid_counter *sequence; | 71 | struct nfs_seqid_counter *sequence; |
| 75 | struct list_head list; | 72 | struct list_head list; |
| 73 | struct rpc_task *task; | ||
| 76 | }; | 74 | }; |
| 77 | 75 | ||
| 78 | static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status) | 76 | 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 | |||
| 81 | seqid->flags |= NFS_SEQID_CONFIRMED; | 79 | seqid->flags |= NFS_SEQID_CONFIRMED; |
| 82 | } | 80 | } |
| 83 | 81 | ||
| 84 | struct nfs_unique_id { | ||
| 85 | struct rb_node rb_node; | ||
| 86 | __u64 id; | ||
| 87 | }; | ||
| 88 | |||
| 89 | /* | 82 | /* |
| 90 | * NFS4 state_owners and lock_owners are simply labels for ordered | 83 | * NFS4 state_owners and lock_owners are simply labels for ordered |
| 91 | * sequences of RPC calls. Their sole purpose is to provide once-only | 84 | * sequences of RPC calls. Their sole purpose is to provide once-only |
| 92 | * semantics by allowing the server to identify replayed requests. | 85 | * semantics by allowing the server to identify replayed requests. |
| 93 | */ | 86 | */ |
| 94 | struct nfs4_state_owner { | 87 | struct nfs4_state_owner { |
| 95 | struct nfs_unique_id so_owner_id; | ||
| 96 | struct nfs_server *so_server; | 88 | struct nfs_server *so_server; |
| 97 | struct list_head so_lru; | 89 | struct list_head so_lru; |
| 98 | unsigned long so_expires; | 90 | unsigned long so_expires; |
| @@ -105,7 +97,6 @@ struct nfs4_state_owner { | |||
| 105 | unsigned long so_flags; | 97 | unsigned long so_flags; |
| 106 | struct list_head so_states; | 98 | struct list_head so_states; |
| 107 | struct nfs_seqid_counter so_seqid; | 99 | struct nfs_seqid_counter so_seqid; |
| 108 | struct rpc_sequence so_sequence; | ||
| 109 | }; | 100 | }; |
| 110 | 101 | ||
| 111 | enum { | 102 | enum { |
| @@ -146,8 +137,6 @@ struct nfs4_lock_state { | |||
| 146 | #define NFS_LOCK_INITIALIZED 1 | 137 | #define NFS_LOCK_INITIALIZED 1 |
| 147 | int ls_flags; | 138 | int ls_flags; |
| 148 | struct nfs_seqid_counter ls_seqid; | 139 | struct nfs_seqid_counter ls_seqid; |
| 149 | struct rpc_sequence ls_sequence; | ||
| 150 | struct nfs_unique_id ls_id; | ||
| 151 | nfs4_stateid ls_stateid; | 140 | nfs4_stateid ls_stateid; |
| 152 | atomic_t ls_count; | 141 | atomic_t ls_count; |
| 153 | struct nfs4_lock_owner ls_owner; | 142 | struct nfs4_lock_owner ls_owner; |
| @@ -193,6 +182,7 @@ struct nfs4_exception { | |||
| 193 | long timeout; | 182 | long timeout; |
| 194 | int retry; | 183 | int retry; |
| 195 | struct nfs4_state *state; | 184 | struct nfs4_state *state; |
| 185 | struct inode *inode; | ||
| 196 | }; | 186 | }; |
| 197 | 187 | ||
| 198 | struct nfs4_state_recovery_ops { | 188 | 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 | |||
| 224 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 214 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
| 225 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 215 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, |
| 226 | struct nfs4_fs_locations *fs_locations, struct page *page); | 216 | struct nfs4_fs_locations *fs_locations, struct page *page); |
| 227 | extern void nfs4_release_lockowner(const struct nfs4_lock_state *); | 217 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); |
| 228 | extern const struct xattr_handler *nfs4_xattr_handlers[]; | 218 | extern const struct xattr_handler *nfs4_xattr_handlers[]; |
| 229 | 219 | ||
| 230 | #if defined(CONFIG_NFS_V4_1) | 220 | #if defined(CONFIG_NFS_V4_1) |
| @@ -233,12 +223,13 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser | |||
| 233 | return server->nfs_client->cl_session; | 223 | return server->nfs_client->cl_session; |
| 234 | } | 224 | } |
| 235 | 225 | ||
| 226 | extern bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy); | ||
| 236 | extern int nfs4_setup_sequence(const struct nfs_server *server, | 227 | extern int nfs4_setup_sequence(const struct nfs_server *server, |
| 237 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 228 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
| 238 | int cache_reply, struct rpc_task *task); | 229 | struct rpc_task *task); |
| 239 | extern int nfs41_setup_sequence(struct nfs4_session *session, | 230 | extern int nfs41_setup_sequence(struct nfs4_session *session, |
| 240 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 231 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
| 241 | int cache_reply, struct rpc_task *task); | 232 | struct rpc_task *task); |
| 242 | extern void nfs4_destroy_session(struct nfs4_session *session); | 233 | extern void nfs4_destroy_session(struct nfs4_session *session); |
| 243 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | 234 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); |
| 244 | extern int nfs4_proc_create_session(struct nfs_client *); | 235 | 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 | |||
| 269 | 260 | ||
| 270 | static inline int nfs4_setup_sequence(const struct nfs_server *server, | 261 | static inline int nfs4_setup_sequence(const struct nfs_server *server, |
| 271 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 262 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
| 272 | int cache_reply, struct rpc_task *task) | 263 | struct rpc_task *task) |
| 273 | { | 264 | { |
| 274 | return 0; | 265 | return 0; |
| 275 | } | 266 | } |
| @@ -319,7 +310,7 @@ static inline void nfs4_schedule_session_recovery(struct nfs4_session *session) | |||
| 319 | } | 310 | } |
| 320 | #endif /* CONFIG_NFS_V4_1 */ | 311 | #endif /* CONFIG_NFS_V4_1 */ |
| 321 | 312 | ||
| 322 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 313 | extern struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *, gfp_t); |
| 323 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 314 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
| 324 | extern void nfs4_purge_state_owners(struct nfs_server *); | 315 | extern void nfs4_purge_state_owners(struct nfs_server *); |
| 325 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); | 316 | 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 *); | |||
| 327 | extern void nfs4_close_state(struct nfs4_state *, fmode_t); | 318 | extern void nfs4_close_state(struct nfs4_state *, fmode_t); |
| 328 | extern void nfs4_close_sync(struct nfs4_state *, fmode_t); | 319 | extern void nfs4_close_sync(struct nfs4_state *, fmode_t); |
| 329 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); | 320 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); |
| 321 | extern void nfs_inode_find_state_and_recover(struct inode *inode, | ||
| 322 | const nfs4_stateid *stateid); | ||
| 330 | extern void nfs4_schedule_lease_recovery(struct nfs_client *); | 323 | extern void nfs4_schedule_lease_recovery(struct nfs_client *); |
| 331 | extern void nfs4_schedule_state_manager(struct nfs_client *); | 324 | extern void nfs4_schedule_state_manager(struct nfs_client *); |
| 332 | extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); | 325 | extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); |
| @@ -337,7 +330,8 @@ extern void nfs41_handle_server_scope(struct nfs_client *, | |||
| 337 | struct server_scope **); | 330 | struct server_scope **); |
| 338 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 331 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
| 339 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 332 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
| 340 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t); | 333 | extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, |
| 334 | fmode_t, fl_owner_t, pid_t); | ||
| 341 | 335 | ||
| 342 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); | 336 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); |
| 343 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); | 337 | 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); | |||
| 346 | extern void nfs_release_seqid(struct nfs_seqid *seqid); | 340 | extern void nfs_release_seqid(struct nfs_seqid *seqid); |
| 347 | extern void nfs_free_seqid(struct nfs_seqid *seqid); | 341 | extern void nfs_free_seqid(struct nfs_seqid *seqid); |
| 348 | 342 | ||
| 343 | extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp); | ||
| 344 | |||
| 349 | extern const nfs4_stateid zero_stateid; | 345 | extern const nfs4_stateid zero_stateid; |
| 350 | 346 | ||
| 351 | /* nfs4xdr.c */ | 347 | /* nfs4xdr.c */ |
| @@ -357,6 +353,16 @@ struct nfs4_mount_data; | |||
| 357 | extern struct svc_version nfs4_callback_version1; | 353 | extern struct svc_version nfs4_callback_version1; |
| 358 | extern struct svc_version nfs4_callback_version4; | 354 | extern struct svc_version nfs4_callback_version4; |
| 359 | 355 | ||
| 356 | static inline void nfs4_stateid_copy(nfs4_stateid *dst, const nfs4_stateid *src) | ||
| 357 | { | ||
| 358 | memcpy(dst, src, sizeof(*dst)); | ||
| 359 | } | ||
| 360 | |||
| 361 | static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_stateid *src) | ||
| 362 | { | ||
| 363 | return memcmp(dst, src, sizeof(*dst)) == 0; | ||
| 364 | } | ||
| 365 | |||
| 360 | #else | 366 | #else |
| 361 | 367 | ||
| 362 | #define nfs4_close_state(a, b) do { } while (0) | 368 | #define nfs4_close_state(a, b) do { } while (0) |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 71ec08617e23..634c0bcb4fd6 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
| @@ -33,7 +33,10 @@ | |||
| 33 | #include <linux/nfs_page.h> | 33 | #include <linux/nfs_page.h> |
| 34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
| 35 | 35 | ||
| 36 | #include <linux/sunrpc/metrics.h> | ||
| 37 | |||
| 36 | #include "internal.h" | 38 | #include "internal.h" |
| 39 | #include "delegation.h" | ||
| 37 | #include "nfs4filelayout.h" | 40 | #include "nfs4filelayout.h" |
| 38 | 41 | ||
| 39 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD | 42 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD |
| @@ -84,12 +87,27 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
| 84 | struct nfs_client *clp, | 87 | struct nfs_client *clp, |
| 85 | int *reset) | 88 | int *reset) |
| 86 | { | 89 | { |
| 90 | struct nfs_server *mds_server = NFS_SERVER(state->inode); | ||
| 91 | struct nfs_client *mds_client = mds_server->nfs_client; | ||
| 92 | |||
| 87 | if (task->tk_status >= 0) | 93 | if (task->tk_status >= 0) |
| 88 | return 0; | 94 | return 0; |
| 89 | |||
| 90 | *reset = 0; | 95 | *reset = 0; |
| 91 | 96 | ||
| 92 | switch (task->tk_status) { | 97 | switch (task->tk_status) { |
| 98 | /* MDS state errors */ | ||
| 99 | case -NFS4ERR_DELEG_REVOKED: | ||
| 100 | case -NFS4ERR_ADMIN_REVOKED: | ||
| 101 | case -NFS4ERR_BAD_STATEID: | ||
| 102 | nfs_remove_bad_delegation(state->inode); | ||
| 103 | case -NFS4ERR_OPENMODE: | ||
| 104 | nfs4_schedule_stateid_recovery(mds_server, state); | ||
| 105 | goto wait_on_recovery; | ||
| 106 | case -NFS4ERR_EXPIRED: | ||
| 107 | nfs4_schedule_stateid_recovery(mds_server, state); | ||
| 108 | nfs4_schedule_lease_recovery(mds_client); | ||
| 109 | goto wait_on_recovery; | ||
| 110 | /* DS session errors */ | ||
| 93 | case -NFS4ERR_BADSESSION: | 111 | case -NFS4ERR_BADSESSION: |
| 94 | case -NFS4ERR_BADSLOT: | 112 | case -NFS4ERR_BADSLOT: |
| 95 | case -NFS4ERR_BAD_HIGH_SLOT: | 113 | case -NFS4ERR_BAD_HIGH_SLOT: |
| @@ -115,8 +133,14 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
| 115 | *reset = 1; | 133 | *reset = 1; |
| 116 | break; | 134 | break; |
| 117 | } | 135 | } |
| 136 | out: | ||
| 118 | task->tk_status = 0; | 137 | task->tk_status = 0; |
| 119 | return -EAGAIN; | 138 | return -EAGAIN; |
| 139 | wait_on_recovery: | ||
| 140 | rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL); | ||
| 141 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0) | ||
| 142 | rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task); | ||
| 143 | goto out; | ||
| 120 | } | 144 | } |
| 121 | 145 | ||
| 122 | /* NFS_PROTO call done callback routines */ | 146 | /* NFS_PROTO call done callback routines */ |
| @@ -173,7 +197,7 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data) | |||
| 173 | 197 | ||
| 174 | if (nfs41_setup_sequence(rdata->ds_clp->cl_session, | 198 | if (nfs41_setup_sequence(rdata->ds_clp->cl_session, |
| 175 | &rdata->args.seq_args, &rdata->res.seq_res, | 199 | &rdata->args.seq_args, &rdata->res.seq_res, |
| 176 | 0, task)) | 200 | task)) |
| 177 | return; | 201 | return; |
| 178 | 202 | ||
| 179 | rpc_call_start(task); | 203 | rpc_call_start(task); |
| @@ -189,10 +213,18 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data) | |||
| 189 | rdata->mds_ops->rpc_call_done(task, data); | 213 | rdata->mds_ops->rpc_call_done(task, data); |
| 190 | } | 214 | } |
| 191 | 215 | ||
| 216 | static void filelayout_read_count_stats(struct rpc_task *task, void *data) | ||
| 217 | { | ||
| 218 | struct nfs_read_data *rdata = (struct nfs_read_data *)data; | ||
| 219 | |||
| 220 | rpc_count_iostats(task, NFS_SERVER(rdata->inode)->client->cl_metrics); | ||
| 221 | } | ||
| 222 | |||
| 192 | static void filelayout_read_release(void *data) | 223 | static void filelayout_read_release(void *data) |
| 193 | { | 224 | { |
| 194 | struct nfs_read_data *rdata = (struct nfs_read_data *)data; | 225 | struct nfs_read_data *rdata = (struct nfs_read_data *)data; |
| 195 | 226 | ||
| 227 | put_lseg(rdata->lseg); | ||
| 196 | rdata->mds_ops->rpc_release(data); | 228 | rdata->mds_ops->rpc_release(data); |
| 197 | } | 229 | } |
| 198 | 230 | ||
| @@ -254,7 +286,7 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data) | |||
| 254 | 286 | ||
| 255 | if (nfs41_setup_sequence(wdata->ds_clp->cl_session, | 287 | if (nfs41_setup_sequence(wdata->ds_clp->cl_session, |
| 256 | &wdata->args.seq_args, &wdata->res.seq_res, | 288 | &wdata->args.seq_args, &wdata->res.seq_res, |
| 257 | 0, task)) | 289 | task)) |
| 258 | return; | 290 | return; |
| 259 | 291 | ||
| 260 | rpc_call_start(task); | 292 | rpc_call_start(task); |
| @@ -268,10 +300,18 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data) | |||
| 268 | wdata->mds_ops->rpc_call_done(task, data); | 300 | wdata->mds_ops->rpc_call_done(task, data); |
| 269 | } | 301 | } |
| 270 | 302 | ||
| 303 | static void filelayout_write_count_stats(struct rpc_task *task, void *data) | ||
| 304 | { | ||
| 305 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; | ||
| 306 | |||
| 307 | rpc_count_iostats(task, NFS_SERVER(wdata->inode)->client->cl_metrics); | ||
| 308 | } | ||
| 309 | |||
| 271 | static void filelayout_write_release(void *data) | 310 | static void filelayout_write_release(void *data) |
| 272 | { | 311 | { |
| 273 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; | 312 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; |
| 274 | 313 | ||
| 314 | put_lseg(wdata->lseg); | ||
| 275 | wdata->mds_ops->rpc_release(data); | 315 | wdata->mds_ops->rpc_release(data); |
| 276 | } | 316 | } |
| 277 | 317 | ||
| @@ -282,24 +322,28 @@ static void filelayout_commit_release(void *data) | |||
| 282 | nfs_commit_release_pages(wdata); | 322 | nfs_commit_release_pages(wdata); |
| 283 | if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding)) | 323 | if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding)) |
| 284 | nfs_commit_clear_lock(NFS_I(wdata->inode)); | 324 | nfs_commit_clear_lock(NFS_I(wdata->inode)); |
| 325 | put_lseg(wdata->lseg); | ||
| 285 | nfs_commitdata_release(wdata); | 326 | nfs_commitdata_release(wdata); |
| 286 | } | 327 | } |
| 287 | 328 | ||
| 288 | struct rpc_call_ops filelayout_read_call_ops = { | 329 | static const struct rpc_call_ops filelayout_read_call_ops = { |
| 289 | .rpc_call_prepare = filelayout_read_prepare, | 330 | .rpc_call_prepare = filelayout_read_prepare, |
| 290 | .rpc_call_done = filelayout_read_call_done, | 331 | .rpc_call_done = filelayout_read_call_done, |
| 332 | .rpc_count_stats = filelayout_read_count_stats, | ||
| 291 | .rpc_release = filelayout_read_release, | 333 | .rpc_release = filelayout_read_release, |
| 292 | }; | 334 | }; |
| 293 | 335 | ||
| 294 | struct rpc_call_ops filelayout_write_call_ops = { | 336 | static const struct rpc_call_ops filelayout_write_call_ops = { |
| 295 | .rpc_call_prepare = filelayout_write_prepare, | 337 | .rpc_call_prepare = filelayout_write_prepare, |
| 296 | .rpc_call_done = filelayout_write_call_done, | 338 | .rpc_call_done = filelayout_write_call_done, |
| 339 | .rpc_count_stats = filelayout_write_count_stats, | ||
| 297 | .rpc_release = filelayout_write_release, | 340 | .rpc_release = filelayout_write_release, |
| 298 | }; | 341 | }; |
| 299 | 342 | ||
| 300 | struct rpc_call_ops filelayout_commit_call_ops = { | 343 | static const struct rpc_call_ops filelayout_commit_call_ops = { |
| 301 | .rpc_call_prepare = filelayout_write_prepare, | 344 | .rpc_call_prepare = filelayout_write_prepare, |
| 302 | .rpc_call_done = filelayout_write_call_done, | 345 | .rpc_call_done = filelayout_write_call_done, |
| 346 | .rpc_count_stats = filelayout_write_count_stats, | ||
| 303 | .rpc_release = filelayout_commit_release, | 347 | .rpc_release = filelayout_commit_release, |
| 304 | }; | 348 | }; |
| 305 | 349 | ||
| @@ -367,7 +411,8 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) | |||
| 367 | idx = nfs4_fl_calc_ds_index(lseg, j); | 411 | idx = nfs4_fl_calc_ds_index(lseg, j); |
| 368 | ds = nfs4_fl_prepare_ds(lseg, idx); | 412 | ds = nfs4_fl_prepare_ds(lseg, idx); |
| 369 | if (!ds) { | 413 | if (!ds) { |
| 370 | printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__); | 414 | printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n", |
| 415 | __func__); | ||
| 371 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); | 416 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); |
| 372 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); | 417 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); |
| 373 | return PNFS_NOT_ATTEMPTED; | 418 | return PNFS_NOT_ATTEMPTED; |
| @@ -575,7 +620,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo, | |||
| 575 | goto out_err_free; | 620 | goto out_err_free; |
| 576 | fl->fh_array[i]->size = be32_to_cpup(p++); | 621 | fl->fh_array[i]->size = be32_to_cpup(p++); |
| 577 | if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) { | 622 | if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) { |
| 578 | printk(KERN_ERR "Too big fh %d received %d\n", | 623 | printk(KERN_ERR "NFS: Too big fh %d received %d\n", |
| 579 | i, fl->fh_array[i]->size); | 624 | i, fl->fh_array[i]->size); |
| 580 | goto out_err_free; | 625 | goto out_err_free; |
| 581 | } | 626 | } |
| @@ -640,14 +685,16 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, | |||
| 640 | int size = (fl->stripe_type == STRIPE_SPARSE) ? | 685 | int size = (fl->stripe_type == STRIPE_SPARSE) ? |
| 641 | fl->dsaddr->ds_num : fl->dsaddr->stripe_count; | 686 | fl->dsaddr->ds_num : fl->dsaddr->stripe_count; |
| 642 | 687 | ||
| 643 | fl->commit_buckets = kcalloc(size, sizeof(struct list_head), gfp_flags); | 688 | fl->commit_buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket), gfp_flags); |
| 644 | if (!fl->commit_buckets) { | 689 | if (!fl->commit_buckets) { |
| 645 | filelayout_free_lseg(&fl->generic_hdr); | 690 | filelayout_free_lseg(&fl->generic_hdr); |
| 646 | return NULL; | 691 | return NULL; |
| 647 | } | 692 | } |
| 648 | fl->number_of_buckets = size; | 693 | fl->number_of_buckets = size; |
| 649 | for (i = 0; i < size; i++) | 694 | for (i = 0; i < size; i++) { |
| 650 | INIT_LIST_HEAD(&fl->commit_buckets[i]); | 695 | INIT_LIST_HEAD(&fl->commit_buckets[i].written); |
| 696 | INIT_LIST_HEAD(&fl->commit_buckets[i].committing); | ||
| 697 | } | ||
| 651 | } | 698 | } |
| 652 | return &fl->generic_hdr; | 699 | return &fl->generic_hdr; |
| 653 | } | 700 | } |
| @@ -679,7 +726,7 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, | |||
| 679 | return (p_stripe == r_stripe); | 726 | return (p_stripe == r_stripe); |
| 680 | } | 727 | } |
| 681 | 728 | ||
| 682 | void | 729 | static void |
| 683 | filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, | 730 | filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, |
| 684 | struct nfs_page *req) | 731 | struct nfs_page *req) |
| 685 | { | 732 | { |
| @@ -696,7 +743,7 @@ filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, | |||
| 696 | nfs_pageio_reset_read_mds(pgio); | 743 | nfs_pageio_reset_read_mds(pgio); |
| 697 | } | 744 | } |
| 698 | 745 | ||
| 699 | void | 746 | static void |
| 700 | filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, | 747 | filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, |
| 701 | struct nfs_page *req) | 748 | struct nfs_page *req) |
| 702 | { | 749 | { |
| @@ -725,11 +772,6 @@ static const struct nfs_pageio_ops filelayout_pg_write_ops = { | |||
| 725 | .pg_doio = pnfs_generic_pg_writepages, | 772 | .pg_doio = pnfs_generic_pg_writepages, |
| 726 | }; | 773 | }; |
| 727 | 774 | ||
| 728 | static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg) | ||
| 729 | { | ||
| 730 | return !FILELAYOUT_LSEG(lseg)->commit_through_mds; | ||
| 731 | } | ||
| 732 | |||
| 733 | static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) | 775 | static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) |
| 734 | { | 776 | { |
| 735 | if (fl->stripe_type == STRIPE_SPARSE) | 777 | if (fl->stripe_type == STRIPE_SPARSE) |
| @@ -738,13 +780,49 @@ static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) | |||
| 738 | return j; | 780 | return j; |
| 739 | } | 781 | } |
| 740 | 782 | ||
| 741 | struct list_head *filelayout_choose_commit_list(struct nfs_page *req) | 783 | /* The generic layer is about to remove the req from the commit list. |
| 784 | * If this will make the bucket empty, it will need to put the lseg reference. | ||
| 785 | */ | ||
| 786 | static void | ||
| 787 | filelayout_clear_request_commit(struct nfs_page *req) | ||
| 788 | { | ||
| 789 | struct pnfs_layout_segment *freeme = NULL; | ||
| 790 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
| 791 | |||
| 792 | spin_lock(&inode->i_lock); | ||
| 793 | if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) | ||
| 794 | goto out; | ||
| 795 | if (list_is_singular(&req->wb_list)) { | ||
| 796 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
| 797 | struct pnfs_layout_segment *lseg; | ||
| 798 | |||
| 799 | /* From here we can find the bucket, but for the moment, | ||
| 800 | * since there is only one relevant lseg... | ||
| 801 | */ | ||
| 802 | list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { | ||
| 803 | if (lseg->pls_range.iomode == IOMODE_RW) { | ||
| 804 | freeme = lseg; | ||
| 805 | break; | ||
| 806 | } | ||
| 807 | } | ||
| 808 | } | ||
| 809 | out: | ||
| 810 | nfs_request_remove_commit_list(req); | ||
| 811 | spin_unlock(&inode->i_lock); | ||
| 812 | put_lseg(freeme); | ||
| 813 | } | ||
| 814 | |||
| 815 | static struct list_head * | ||
| 816 | filelayout_choose_commit_list(struct nfs_page *req, | ||
| 817 | struct pnfs_layout_segment *lseg) | ||
| 742 | { | 818 | { |
| 743 | struct pnfs_layout_segment *lseg = req->wb_commit_lseg; | ||
| 744 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 819 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); |
| 745 | u32 i, j; | 820 | u32 i, j; |
| 746 | struct list_head *list; | 821 | struct list_head *list; |
| 747 | 822 | ||
| 823 | if (fl->commit_through_mds) | ||
| 824 | return &NFS_I(req->wb_context->dentry->d_inode)->commit_list; | ||
| 825 | |||
| 748 | /* Note that we are calling nfs4_fl_calc_j_index on each page | 826 | /* Note that we are calling nfs4_fl_calc_j_index on each page |
| 749 | * that ends up being committed to a data server. An attractive | 827 | * that ends up being committed to a data server. An attractive |
| 750 | * alternative is to add a field to nfs_write_data and nfs_page | 828 | * 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) | |||
| 754 | j = nfs4_fl_calc_j_index(lseg, | 832 | j = nfs4_fl_calc_j_index(lseg, |
| 755 | (loff_t)req->wb_index << PAGE_CACHE_SHIFT); | 833 | (loff_t)req->wb_index << PAGE_CACHE_SHIFT); |
| 756 | i = select_bucket_index(fl, j); | 834 | i = select_bucket_index(fl, j); |
| 757 | list = &fl->commit_buckets[i]; | 835 | list = &fl->commit_buckets[i].written; |
| 758 | if (list_empty(list)) { | 836 | if (list_empty(list)) { |
| 759 | /* Non-empty buckets hold a reference on the lseg */ | 837 | /* Non-empty buckets hold a reference on the lseg. That ref |
| 838 | * is normally transferred to the COMMIT call and released | ||
| 839 | * there. It could also be released if the last req is pulled | ||
| 840 | * off due to a rewrite, in which case it will be done in | ||
| 841 | * filelayout_remove_commit_req | ||
| 842 | */ | ||
| 760 | get_lseg(lseg); | 843 | get_lseg(lseg); |
| 761 | } | 844 | } |
| 845 | set_bit(PG_COMMIT_TO_DS, &req->wb_flags); | ||
| 762 | return list; | 846 | return list; |
| 763 | } | 847 | } |
| 764 | 848 | ||
| 849 | static void | ||
| 850 | filelayout_mark_request_commit(struct nfs_page *req, | ||
| 851 | struct pnfs_layout_segment *lseg) | ||
| 852 | { | ||
| 853 | struct list_head *list; | ||
| 854 | |||
| 855 | list = filelayout_choose_commit_list(req, lseg); | ||
| 856 | nfs_request_add_commit_list(req, list); | ||
| 857 | } | ||
| 858 | |||
| 765 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) | 859 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) |
| 766 | { | 860 | { |
| 767 | struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); | 861 | struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); |
| @@ -797,11 +891,12 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how) | |||
| 797 | idx = calc_ds_index_from_commit(lseg, data->ds_commit_index); | 891 | idx = calc_ds_index_from_commit(lseg, data->ds_commit_index); |
| 798 | ds = nfs4_fl_prepare_ds(lseg, idx); | 892 | ds = nfs4_fl_prepare_ds(lseg, idx); |
| 799 | if (!ds) { | 893 | if (!ds) { |
| 800 | printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__); | 894 | printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n", |
| 895 | __func__); | ||
| 801 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); | 896 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); |
| 802 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); | 897 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); |
| 803 | prepare_to_resend_writes(data); | 898 | prepare_to_resend_writes(data); |
| 804 | data->mds_ops->rpc_release(data); | 899 | filelayout_commit_release(data); |
| 805 | return -EAGAIN; | 900 | return -EAGAIN; |
| 806 | } | 901 | } |
| 807 | dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how); | 902 | 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) | |||
| 817 | /* | 912 | /* |
| 818 | * This is only useful while we are using whole file layouts. | 913 | * This is only useful while we are using whole file layouts. |
| 819 | */ | 914 | */ |
| 820 | static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode) | 915 | static struct pnfs_layout_segment * |
| 916 | find_only_write_lseg_locked(struct inode *inode) | ||
| 821 | { | 917 | { |
| 822 | struct pnfs_layout_segment *lseg, *rv = NULL; | 918 | struct pnfs_layout_segment *lseg; |
| 823 | 919 | ||
| 824 | spin_lock(&inode->i_lock); | ||
| 825 | list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) | 920 | list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) |
| 826 | if (lseg->pls_range.iomode == IOMODE_RW) | 921 | if (lseg->pls_range.iomode == IOMODE_RW) |
| 827 | rv = get_lseg(lseg); | 922 | return lseg; |
| 923 | return NULL; | ||
| 924 | } | ||
| 925 | |||
| 926 | static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode) | ||
| 927 | { | ||
| 928 | struct pnfs_layout_segment *rv; | ||
| 929 | |||
| 930 | spin_lock(&inode->i_lock); | ||
| 931 | rv = find_only_write_lseg_locked(inode); | ||
| 932 | if (rv) | ||
| 933 | get_lseg(rv); | ||
| 828 | spin_unlock(&inode->i_lock); | 934 | spin_unlock(&inode->i_lock); |
| 829 | return rv; | 935 | return rv; |
| 830 | } | 936 | } |
| 831 | 937 | ||
| 832 | static int alloc_ds_commits(struct inode *inode, struct list_head *list) | 938 | static int |
| 939 | filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max, | ||
| 940 | spinlock_t *lock) | ||
| 941 | { | ||
| 942 | struct list_head *src = &bucket->written; | ||
| 943 | struct list_head *dst = &bucket->committing; | ||
| 944 | struct nfs_page *req, *tmp; | ||
| 945 | int ret = 0; | ||
| 946 | |||
| 947 | list_for_each_entry_safe(req, tmp, src, wb_list) { | ||
| 948 | if (!nfs_lock_request(req)) | ||
| 949 | continue; | ||
| 950 | if (cond_resched_lock(lock)) | ||
| 951 | list_safe_reset_next(req, tmp, wb_list); | ||
| 952 | nfs_request_remove_commit_list(req); | ||
| 953 | clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); | ||
| 954 | nfs_list_add_request(req, dst); | ||
| 955 | ret++; | ||
| 956 | if (ret == max) | ||
| 957 | break; | ||
| 958 | } | ||
| 959 | return ret; | ||
| 960 | } | ||
| 961 | |||
| 962 | /* Move reqs from written to committing lists, returning count of number moved. | ||
| 963 | * Note called with i_lock held. | ||
| 964 | */ | ||
| 965 | static int filelayout_scan_commit_lists(struct inode *inode, int max, | ||
| 966 | spinlock_t *lock) | ||
| 967 | { | ||
| 968 | struct pnfs_layout_segment *lseg; | ||
| 969 | struct nfs4_filelayout_segment *fl; | ||
| 970 | int i, rv = 0, cnt; | ||
| 971 | |||
| 972 | lseg = find_only_write_lseg_locked(inode); | ||
| 973 | if (!lseg) | ||
| 974 | goto out_done; | ||
| 975 | fl = FILELAYOUT_LSEG(lseg); | ||
| 976 | if (fl->commit_through_mds) | ||
| 977 | goto out_done; | ||
| 978 | for (i = 0; i < fl->number_of_buckets && max != 0; i++) { | ||
| 979 | cnt = filelayout_scan_ds_commit_list(&fl->commit_buckets[i], | ||
| 980 | max, lock); | ||
| 981 | max -= cnt; | ||
| 982 | rv += cnt; | ||
| 983 | } | ||
| 984 | out_done: | ||
| 985 | return rv; | ||
| 986 | } | ||
| 987 | |||
| 988 | static unsigned int | ||
| 989 | alloc_ds_commits(struct inode *inode, struct list_head *list) | ||
| 833 | { | 990 | { |
| 834 | struct pnfs_layout_segment *lseg; | 991 | struct pnfs_layout_segment *lseg; |
| 835 | struct nfs4_filelayout_segment *fl; | 992 | struct nfs4_filelayout_segment *fl; |
| 836 | struct nfs_write_data *data; | 993 | struct nfs_write_data *data; |
| 837 | int i, j; | 994 | int i, j; |
| 995 | unsigned int nreq = 0; | ||
| 838 | 996 | ||
| 839 | /* Won't need this when non-whole file layout segments are supported | 997 | /* Won't need this when non-whole file layout segments are supported |
| 840 | * instead we will use a pnfs_layout_hdr structure */ | 998 | * 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) | |||
| 843 | return 0; | 1001 | return 0; |
| 844 | fl = FILELAYOUT_LSEG(lseg); | 1002 | fl = FILELAYOUT_LSEG(lseg); |
| 845 | for (i = 0; i < fl->number_of_buckets; i++) { | 1003 | for (i = 0; i < fl->number_of_buckets; i++) { |
| 846 | if (list_empty(&fl->commit_buckets[i])) | 1004 | if (list_empty(&fl->commit_buckets[i].committing)) |
| 847 | continue; | 1005 | continue; |
| 848 | data = nfs_commitdata_alloc(); | 1006 | data = nfs_commitdata_alloc(); |
| 849 | if (!data) | 1007 | if (!data) |
| 850 | goto out_bad; | 1008 | break; |
| 851 | data->ds_commit_index = i; | 1009 | data->ds_commit_index = i; |
| 852 | data->lseg = lseg; | 1010 | data->lseg = lseg; |
| 853 | list_add(&data->pages, list); | 1011 | list_add(&data->pages, list); |
| 1012 | nreq++; | ||
| 854 | } | 1013 | } |
| 855 | put_lseg(lseg); | ||
| 856 | return 0; | ||
| 857 | 1014 | ||
| 858 | out_bad: | 1015 | /* Clean up on error */ |
| 859 | for (j = i; j < fl->number_of_buckets; j++) { | 1016 | for (j = i; j < fl->number_of_buckets; j++) { |
| 860 | if (list_empty(&fl->commit_buckets[i])) | 1017 | if (list_empty(&fl->commit_buckets[i].committing)) |
| 861 | continue; | 1018 | continue; |
| 862 | nfs_retry_commit(&fl->commit_buckets[i], lseg); | 1019 | nfs_retry_commit(&fl->commit_buckets[i].committing, lseg); |
| 863 | put_lseg(lseg); /* associated with emptying bucket */ | 1020 | put_lseg(lseg); /* associated with emptying bucket */ |
| 864 | } | 1021 | } |
| 865 | put_lseg(lseg); | 1022 | put_lseg(lseg); |
| 866 | /* Caller will clean up entries put on list */ | 1023 | /* Caller will clean up entries put on list */ |
| 867 | return -ENOMEM; | 1024 | return nreq; |
| 868 | } | 1025 | } |
| 869 | 1026 | ||
| 870 | /* This follows nfs_commit_list pretty closely */ | 1027 | /* This follows nfs_commit_list pretty closely */ |
| @@ -874,40 +1031,40 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, | |||
| 874 | { | 1031 | { |
| 875 | struct nfs_write_data *data, *tmp; | 1032 | struct nfs_write_data *data, *tmp; |
| 876 | LIST_HEAD(list); | 1033 | LIST_HEAD(list); |
| 1034 | unsigned int nreq = 0; | ||
| 877 | 1035 | ||
| 878 | if (!list_empty(mds_pages)) { | 1036 | if (!list_empty(mds_pages)) { |
| 879 | data = nfs_commitdata_alloc(); | 1037 | data = nfs_commitdata_alloc(); |
| 880 | if (!data) | 1038 | if (data != NULL) { |
| 881 | goto out_bad; | 1039 | data->lseg = NULL; |
| 882 | data->lseg = NULL; | 1040 | list_add(&data->pages, &list); |
| 883 | list_add(&data->pages, &list); | 1041 | nreq++; |
| 1042 | } else | ||
| 1043 | nfs_retry_commit(mds_pages, NULL); | ||
| 884 | } | 1044 | } |
| 885 | 1045 | ||
| 886 | if (alloc_ds_commits(inode, &list)) | 1046 | nreq += alloc_ds_commits(inode, &list); |
| 887 | goto out_bad; | 1047 | |
| 1048 | if (nreq == 0) { | ||
| 1049 | nfs_commit_clear_lock(NFS_I(inode)); | ||
| 1050 | goto out; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | atomic_add(nreq, &NFS_I(inode)->commits_outstanding); | ||
| 888 | 1054 | ||
| 889 | list_for_each_entry_safe(data, tmp, &list, pages) { | 1055 | list_for_each_entry_safe(data, tmp, &list, pages) { |
| 890 | list_del_init(&data->pages); | 1056 | list_del_init(&data->pages); |
| 891 | atomic_inc(&NFS_I(inode)->commits_outstanding); | ||
| 892 | if (!data->lseg) { | 1057 | if (!data->lseg) { |
| 893 | nfs_init_commit(data, mds_pages, NULL); | 1058 | nfs_init_commit(data, mds_pages, NULL); |
| 894 | nfs_initiate_commit(data, NFS_CLIENT(inode), | 1059 | nfs_initiate_commit(data, NFS_CLIENT(inode), |
| 895 | data->mds_ops, how); | 1060 | data->mds_ops, how); |
| 896 | } else { | 1061 | } else { |
| 897 | nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index], data->lseg); | 1062 | nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index].committing, data->lseg); |
| 898 | filelayout_initiate_commit(data, how); | 1063 | filelayout_initiate_commit(data, how); |
| 899 | } | 1064 | } |
| 900 | } | 1065 | } |
| 901 | return 0; | 1066 | out: |
| 902 | out_bad: | 1067 | return PNFS_ATTEMPTED; |
| 903 | list_for_each_entry_safe(data, tmp, &list, pages) { | ||
| 904 | nfs_retry_commit(&data->pages, data->lseg); | ||
| 905 | list_del_init(&data->pages); | ||
| 906 | nfs_commit_free(data); | ||
| 907 | } | ||
| 908 | nfs_retry_commit(mds_pages, NULL); | ||
| 909 | nfs_commit_clear_lock(NFS_I(inode)); | ||
| 910 | return -ENOMEM; | ||
| 911 | } | 1068 | } |
| 912 | 1069 | ||
| 913 | static void | 1070 | static void |
| @@ -924,8 +1081,9 @@ static struct pnfs_layoutdriver_type filelayout_type = { | |||
| 924 | .free_lseg = filelayout_free_lseg, | 1081 | .free_lseg = filelayout_free_lseg, |
| 925 | .pg_read_ops = &filelayout_pg_read_ops, | 1082 | .pg_read_ops = &filelayout_pg_read_ops, |
| 926 | .pg_write_ops = &filelayout_pg_write_ops, | 1083 | .pg_write_ops = &filelayout_pg_write_ops, |
| 927 | .mark_pnfs_commit = filelayout_mark_pnfs_commit, | 1084 | .mark_request_commit = filelayout_mark_request_commit, |
| 928 | .choose_commit_list = filelayout_choose_commit_list, | 1085 | .clear_request_commit = filelayout_clear_request_commit, |
| 1086 | .scan_commit_lists = filelayout_scan_commit_lists, | ||
| 929 | .commit_pagelist = filelayout_commit_pagelist, | 1087 | .commit_pagelist = filelayout_commit_pagelist, |
| 930 | .read_pagelist = filelayout_read_pagelist, | 1088 | .read_pagelist = filelayout_read_pagelist, |
| 931 | .write_pagelist = filelayout_write_pagelist, | 1089 | .write_pagelist = filelayout_write_pagelist, |
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index 2e42284253fa..21190bb1f5e3 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h | |||
| @@ -74,6 +74,11 @@ struct nfs4_file_layout_dsaddr { | |||
| 74 | struct nfs4_pnfs_ds *ds_list[1]; | 74 | struct nfs4_pnfs_ds *ds_list[1]; |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 77 | struct nfs4_fl_commit_bucket { | ||
| 78 | struct list_head written; | ||
| 79 | struct list_head committing; | ||
| 80 | }; | ||
| 81 | |||
| 77 | struct nfs4_filelayout_segment { | 82 | struct nfs4_filelayout_segment { |
| 78 | struct pnfs_layout_segment generic_hdr; | 83 | struct pnfs_layout_segment generic_hdr; |
| 79 | u32 stripe_type; | 84 | u32 stripe_type; |
| @@ -84,7 +89,7 @@ struct nfs4_filelayout_segment { | |||
| 84 | struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */ | 89 | struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */ |
| 85 | unsigned int num_fh; | 90 | unsigned int num_fh; |
| 86 | struct nfs_fh **fh_array; | 91 | struct nfs_fh **fh_array; |
| 87 | struct list_head *commit_buckets; /* Sort commits to ds */ | 92 | struct nfs4_fl_commit_bucket *commit_buckets; /* Sort commits to ds */ |
| 88 | int number_of_buckets; | 93 | int number_of_buckets; |
| 89 | }; | 94 | }; |
| 90 | 95 | ||
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 8ae91908f5aa..a866bbd2890a 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
| @@ -45,7 +45,7 @@ | |||
| 45 | * - incremented when a device id maps a data server already in the cache. | 45 | * - incremented when a device id maps a data server already in the cache. |
| 46 | * - decremented when deviceid is removed from the cache. | 46 | * - decremented when deviceid is removed from the cache. |
| 47 | */ | 47 | */ |
| 48 | DEFINE_SPINLOCK(nfs4_ds_cache_lock); | 48 | static DEFINE_SPINLOCK(nfs4_ds_cache_lock); |
| 49 | static LIST_HEAD(nfs4_data_server_cache); | 49 | static LIST_HEAD(nfs4_data_server_cache); |
| 50 | 50 | ||
| 51 | /* Debug routines */ | 51 | /* Debug routines */ |
| @@ -108,58 +108,40 @@ same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2) | |||
| 108 | return false; | 108 | return false; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | /* | 111 | static bool |
| 112 | * Lookup DS by addresses. The first matching address returns true. | 112 | _same_data_server_addrs_locked(const struct list_head *dsaddrs1, |
| 113 | * nfs4_ds_cache_lock is held | 113 | const struct list_head *dsaddrs2) |
| 114 | */ | ||
| 115 | static struct nfs4_pnfs_ds * | ||
| 116 | _data_server_lookup_locked(struct list_head *dsaddrs) | ||
| 117 | { | 114 | { |
| 118 | struct nfs4_pnfs_ds *ds; | ||
| 119 | struct nfs4_pnfs_ds_addr *da1, *da2; | 115 | struct nfs4_pnfs_ds_addr *da1, *da2; |
| 120 | 116 | ||
| 121 | list_for_each_entry(da1, dsaddrs, da_node) { | 117 | /* step through both lists, comparing as we go */ |
| 122 | list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) { | 118 | for (da1 = list_first_entry(dsaddrs1, typeof(*da1), da_node), |
| 123 | list_for_each_entry(da2, &ds->ds_addrs, da_node) { | 119 | da2 = list_first_entry(dsaddrs2, typeof(*da2), da_node); |
| 124 | if (same_sockaddr( | 120 | da1 != NULL && da2 != NULL; |
| 125 | (struct sockaddr *)&da1->da_addr, | 121 | da1 = list_entry(da1->da_node.next, typeof(*da1), da_node), |
| 126 | (struct sockaddr *)&da2->da_addr)) | 122 | da2 = list_entry(da2->da_node.next, typeof(*da2), da_node)) { |
| 127 | return ds; | 123 | if (!same_sockaddr((struct sockaddr *)&da1->da_addr, |
| 128 | } | 124 | (struct sockaddr *)&da2->da_addr)) |
| 129 | } | 125 | return false; |
| 130 | } | 126 | } |
| 131 | return NULL; | 127 | if (da1 == NULL && da2 == NULL) |
| 128 | return true; | ||
| 129 | |||
| 130 | return false; | ||
| 132 | } | 131 | } |
| 133 | 132 | ||
| 134 | /* | 133 | /* |
| 135 | * Compare two lists of addresses. | 134 | * Lookup DS by addresses. nfs4_ds_cache_lock is held |
| 136 | */ | 135 | */ |
| 137 | static bool | 136 | static struct nfs4_pnfs_ds * |
| 138 | _data_server_match_all_addrs_locked(struct list_head *dsaddrs1, | 137 | _data_server_lookup_locked(const struct list_head *dsaddrs) |
| 139 | struct list_head *dsaddrs2) | ||
| 140 | { | 138 | { |
| 141 | struct nfs4_pnfs_ds_addr *da1, *da2; | 139 | struct nfs4_pnfs_ds *ds; |
| 142 | size_t count1 = 0, | ||
| 143 | count2 = 0; | ||
| 144 | |||
| 145 | list_for_each_entry(da1, dsaddrs1, da_node) | ||
| 146 | count1++; | ||
| 147 | |||
| 148 | list_for_each_entry(da2, dsaddrs2, da_node) { | ||
| 149 | bool found = false; | ||
| 150 | count2++; | ||
| 151 | list_for_each_entry(da1, dsaddrs1, da_node) { | ||
| 152 | if (same_sockaddr((struct sockaddr *)&da1->da_addr, | ||
| 153 | (struct sockaddr *)&da2->da_addr)) { | ||
| 154 | found = true; | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | if (!found) | ||
| 159 | return false; | ||
| 160 | } | ||
| 161 | 140 | ||
| 162 | return (count1 == count2); | 141 | list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) |
| 142 | if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs)) | ||
| 143 | return ds; | ||
| 144 | return NULL; | ||
| 163 | } | 145 | } |
| 164 | 146 | ||
| 165 | /* | 147 | /* |
| @@ -356,11 +338,6 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) | |||
| 356 | dprintk("%s add new data server %s\n", __func__, | 338 | dprintk("%s add new data server %s\n", __func__, |
| 357 | ds->ds_remotestr); | 339 | ds->ds_remotestr); |
| 358 | } else { | 340 | } else { |
| 359 | if (!_data_server_match_all_addrs_locked(&tmp_ds->ds_addrs, | ||
| 360 | dsaddrs)) { | ||
| 361 | dprintk("%s: multipath address mismatch: %s != %s", | ||
| 362 | __func__, tmp_ds->ds_remotestr, remotestr); | ||
| 363 | } | ||
| 364 | kfree(remotestr); | 341 | kfree(remotestr); |
| 365 | kfree(ds); | 342 | kfree(ds); |
| 366 | atomic_inc(&tmp_ds->ds_count); | 343 | atomic_inc(&tmp_ds->ds_count); |
| @@ -378,7 +355,7 @@ out: | |||
| 378 | * Currently only supports ipv4, ipv6 and one multi-path address. | 355 | * Currently only supports ipv4, ipv6 and one multi-path address. |
| 379 | */ | 356 | */ |
| 380 | static struct nfs4_pnfs_ds_addr * | 357 | static struct nfs4_pnfs_ds_addr * |
| 381 | decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags) | 358 | decode_ds_addr(struct net *net, struct xdr_stream *streamp, gfp_t gfp_flags) |
| 382 | { | 359 | { |
| 383 | struct nfs4_pnfs_ds_addr *da = NULL; | 360 | struct nfs4_pnfs_ds_addr *da = NULL; |
| 384 | char *buf, *portstr; | 361 | char *buf, *portstr; |
| @@ -457,7 +434,7 @@ decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags) | |||
| 457 | 434 | ||
| 458 | INIT_LIST_HEAD(&da->da_node); | 435 | INIT_LIST_HEAD(&da->da_node); |
| 459 | 436 | ||
| 460 | if (!rpc_pton(buf, portstr-buf, (struct sockaddr *)&da->da_addr, | 437 | if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr, |
| 461 | sizeof(da->da_addr))) { | 438 | sizeof(da->da_addr))) { |
| 462 | dprintk("%s: error parsing address %s\n", __func__, buf); | 439 | dprintk("%s: error parsing address %s\n", __func__, buf); |
| 463 | goto out_free_da; | 440 | goto out_free_da; |
| @@ -554,7 +531,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) | |||
| 554 | cnt = be32_to_cpup(p); | 531 | cnt = be32_to_cpup(p); |
| 555 | dprintk("%s stripe count %d\n", __func__, cnt); | 532 | dprintk("%s stripe count %d\n", __func__, cnt); |
| 556 | if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) { | 533 | if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) { |
| 557 | printk(KERN_WARNING "%s: stripe count %d greater than " | 534 | printk(KERN_WARNING "NFS: %s: stripe count %d greater than " |
| 558 | "supported maximum %d\n", __func__, | 535 | "supported maximum %d\n", __func__, |
| 559 | cnt, NFS4_PNFS_MAX_STRIPE_CNT); | 536 | cnt, NFS4_PNFS_MAX_STRIPE_CNT); |
| 560 | goto out_err_free_scratch; | 537 | goto out_err_free_scratch; |
| @@ -585,7 +562,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) | |||
| 585 | num = be32_to_cpup(p); | 562 | num = be32_to_cpup(p); |
| 586 | dprintk("%s ds_num %u\n", __func__, num); | 563 | dprintk("%s ds_num %u\n", __func__, num); |
| 587 | if (num > NFS4_PNFS_MAX_MULTI_CNT) { | 564 | if (num > NFS4_PNFS_MAX_MULTI_CNT) { |
| 588 | printk(KERN_WARNING "%s: multipath count %d greater than " | 565 | printk(KERN_WARNING "NFS: %s: multipath count %d greater than " |
| 589 | "supported maximum %d\n", __func__, | 566 | "supported maximum %d\n", __func__, |
| 590 | num, NFS4_PNFS_MAX_MULTI_CNT); | 567 | num, NFS4_PNFS_MAX_MULTI_CNT); |
| 591 | goto out_err_free_stripe_indices; | 568 | goto out_err_free_stripe_indices; |
| @@ -593,7 +570,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) | |||
| 593 | 570 | ||
| 594 | /* validate stripe indices are all < num */ | 571 | /* validate stripe indices are all < num */ |
| 595 | if (max_stripe_index >= num) { | 572 | if (max_stripe_index >= num) { |
| 596 | printk(KERN_WARNING "%s: stripe index %u >= num ds %u\n", | 573 | printk(KERN_WARNING "NFS: %s: stripe index %u >= num ds %u\n", |
| 597 | __func__, max_stripe_index, num); | 574 | __func__, max_stripe_index, num); |
| 598 | goto out_err_free_stripe_indices; | 575 | goto out_err_free_stripe_indices; |
| 599 | } | 576 | } |
| @@ -625,7 +602,8 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) | |||
| 625 | 602 | ||
| 626 | mp_count = be32_to_cpup(p); /* multipath count */ | 603 | mp_count = be32_to_cpup(p); /* multipath count */ |
| 627 | for (j = 0; j < mp_count; j++) { | 604 | for (j = 0; j < mp_count; j++) { |
| 628 | da = decode_ds_addr(&stream, gfp_flags); | 605 | da = decode_ds_addr(NFS_SERVER(ino)->nfs_client->net, |
| 606 | &stream, gfp_flags); | ||
| 629 | if (da) | 607 | if (da) |
| 630 | list_add_tail(&da->da_node, &dsaddrs); | 608 | list_add_tail(&da->da_node, &dsaddrs); |
| 631 | } | 609 | } |
| @@ -686,7 +664,7 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_fl | |||
| 686 | 664 | ||
| 687 | new = decode_device(inode, dev, gfp_flags); | 665 | new = decode_device(inode, dev, gfp_flags); |
| 688 | if (!new) { | 666 | if (!new) { |
| 689 | printk(KERN_WARNING "%s: Could not decode or add device\n", | 667 | printk(KERN_WARNING "NFS: %s: Could not decode or add device\n", |
| 690 | __func__); | 668 | __func__); |
| 691 | return NULL; | 669 | return NULL; |
| 692 | } | 670 | } |
| @@ -835,7 +813,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) | |||
| 835 | struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx]; | 813 | struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx]; |
| 836 | 814 | ||
| 837 | if (ds == NULL) { | 815 | if (ds == NULL) { |
| 838 | printk(KERN_ERR "%s: No data server for offset index %d\n", | 816 | printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", |
| 839 | __func__, ds_idx); | 817 | __func__, ds_idx); |
| 840 | return NULL; | 818 | return NULL; |
| 841 | } | 819 | } |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index bb80c49b6533..9c8eca315f43 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
| @@ -94,13 +94,14 @@ static int nfs4_validate_fspath(struct dentry *dentry, | |||
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | static size_t nfs_parse_server_name(char *string, size_t len, | 96 | static size_t nfs_parse_server_name(char *string, size_t len, |
| 97 | struct sockaddr *sa, size_t salen) | 97 | struct sockaddr *sa, size_t salen, struct nfs_server *server) |
| 98 | { | 98 | { |
| 99 | struct net *net = rpc_net_ns(server->client); | ||
| 99 | ssize_t ret; | 100 | ssize_t ret; |
| 100 | 101 | ||
| 101 | ret = rpc_pton(string, len, sa, salen); | 102 | ret = rpc_pton(net, string, len, sa, salen); |
| 102 | if (ret == 0) { | 103 | if (ret == 0) { |
| 103 | ret = nfs_dns_resolve_name(string, len, sa, salen); | 104 | ret = nfs_dns_resolve_name(net, string, len, sa, salen); |
| 104 | if (ret < 0) | 105 | if (ret < 0) |
| 105 | ret = 0; | 106 | ret = 0; |
| 106 | } | 107 | } |
| @@ -137,7 +138,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
| 137 | continue; | 138 | continue; |
| 138 | 139 | ||
| 139 | mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, | 140 | mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, |
| 140 | mountdata->addr, addr_bufsize); | 141 | mountdata->addr, addr_bufsize, |
| 142 | NFS_SB(mountdata->sb)); | ||
| 141 | if (mountdata->addrlen == 0) | 143 | if (mountdata->addrlen == 0) |
| 142 | continue; | 144 | continue; |
| 143 | 145 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index caf92d05c3a9..e809d2305ebf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -72,18 +72,21 @@ | |||
| 72 | 72 | ||
| 73 | #define NFS4_MAX_LOOP_ON_RECOVER (10) | 73 | #define NFS4_MAX_LOOP_ON_RECOVER (10) |
| 74 | 74 | ||
| 75 | static unsigned short max_session_slots = NFS4_DEF_SLOT_TABLE_SIZE; | ||
| 76 | |||
| 75 | struct nfs4_opendata; | 77 | struct nfs4_opendata; |
| 76 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 78 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
| 77 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); | 79 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); |
| 78 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 80 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
| 79 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 81 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
| 82 | static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr); | ||
| 80 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 83 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
| 81 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | 84 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, |
| 82 | struct nfs_fattr *fattr, struct iattr *sattr, | 85 | struct nfs_fattr *fattr, struct iattr *sattr, |
| 83 | struct nfs4_state *state); | 86 | struct nfs4_state *state); |
| 84 | #ifdef CONFIG_NFS_V4_1 | 87 | #ifdef CONFIG_NFS_V4_1 |
| 85 | static int nfs41_test_stateid(struct nfs_server *, struct nfs4_state *); | 88 | static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *); |
| 86 | static int nfs41_free_stateid(struct nfs_server *, struct nfs4_state *); | 89 | static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *); |
| 87 | #endif | 90 | #endif |
| 88 | /* Prevent leaks of NFSv4 errors into userland */ | 91 | /* Prevent leaks of NFSv4 errors into userland */ |
| 89 | static int nfs4_map_errors(int err) | 92 | static int nfs4_map_errors(int err) |
| @@ -259,15 +262,28 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
| 259 | { | 262 | { |
| 260 | struct nfs_client *clp = server->nfs_client; | 263 | struct nfs_client *clp = server->nfs_client; |
| 261 | struct nfs4_state *state = exception->state; | 264 | struct nfs4_state *state = exception->state; |
| 265 | struct inode *inode = exception->inode; | ||
| 262 | int ret = errorcode; | 266 | int ret = errorcode; |
| 263 | 267 | ||
| 264 | exception->retry = 0; | 268 | exception->retry = 0; |
| 265 | switch(errorcode) { | 269 | switch(errorcode) { |
| 266 | case 0: | 270 | case 0: |
| 267 | return 0; | 271 | return 0; |
| 272 | case -NFS4ERR_OPENMODE: | ||
| 273 | if (nfs_have_delegation(inode, FMODE_READ)) { | ||
| 274 | nfs_inode_return_delegation(inode); | ||
| 275 | exception->retry = 1; | ||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | if (state == NULL) | ||
| 279 | break; | ||
| 280 | nfs4_schedule_stateid_recovery(server, state); | ||
| 281 | goto wait_on_recovery; | ||
| 282 | case -NFS4ERR_DELEG_REVOKED: | ||
| 268 | case -NFS4ERR_ADMIN_REVOKED: | 283 | case -NFS4ERR_ADMIN_REVOKED: |
| 269 | case -NFS4ERR_BAD_STATEID: | 284 | case -NFS4ERR_BAD_STATEID: |
| 270 | case -NFS4ERR_OPENMODE: | 285 | if (state != NULL) |
| 286 | nfs_remove_bad_delegation(state->inode); | ||
| 271 | if (state == NULL) | 287 | if (state == NULL) |
| 272 | break; | 288 | break; |
| 273 | nfs4_schedule_stateid_recovery(server, state); | 289 | nfs4_schedule_stateid_recovery(server, state); |
| @@ -360,16 +376,14 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
| 360 | * When updating highest_used_slotid there may be "holes" in the bitmap | 376 | * When updating highest_used_slotid there may be "holes" in the bitmap |
| 361 | * so we need to scan down from highest_used_slotid to 0 looking for the now | 377 | * so we need to scan down from highest_used_slotid to 0 looking for the now |
| 362 | * highest slotid in use. | 378 | * highest slotid in use. |
| 363 | * If none found, highest_used_slotid is set to -1. | 379 | * If none found, highest_used_slotid is set to NFS4_NO_SLOT. |
| 364 | * | 380 | * |
| 365 | * Must be called while holding tbl->slot_tbl_lock | 381 | * Must be called while holding tbl->slot_tbl_lock |
| 366 | */ | 382 | */ |
| 367 | static void | 383 | static void |
| 368 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | 384 | nfs4_free_slot(struct nfs4_slot_table *tbl, u32 slotid) |
| 369 | { | 385 | { |
| 370 | int slotid = free_slotid; | 386 | BUG_ON(slotid >= NFS4_MAX_SLOT_TABLE); |
| 371 | |||
| 372 | BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE); | ||
| 373 | /* clear used bit in bitmap */ | 387 | /* clear used bit in bitmap */ |
| 374 | __clear_bit(slotid, tbl->used_slots); | 388 | __clear_bit(slotid, tbl->used_slots); |
| 375 | 389 | ||
| @@ -379,10 +393,16 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | |||
| 379 | if (slotid < tbl->max_slots) | 393 | if (slotid < tbl->max_slots) |
| 380 | tbl->highest_used_slotid = slotid; | 394 | tbl->highest_used_slotid = slotid; |
| 381 | else | 395 | else |
| 382 | tbl->highest_used_slotid = -1; | 396 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
| 383 | } | 397 | } |
| 384 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | 398 | dprintk("%s: slotid %u highest_used_slotid %d\n", __func__, |
| 385 | free_slotid, tbl->highest_used_slotid); | 399 | slotid, tbl->highest_used_slotid); |
| 400 | } | ||
| 401 | |||
| 402 | bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy) | ||
| 403 | { | ||
| 404 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
| 405 | return true; | ||
| 386 | } | 406 | } |
| 387 | 407 | ||
| 388 | /* | 408 | /* |
| @@ -390,16 +410,13 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | |||
| 390 | */ | 410 | */ |
| 391 | static void nfs4_check_drain_fc_complete(struct nfs4_session *ses) | 411 | static void nfs4_check_drain_fc_complete(struct nfs4_session *ses) |
| 392 | { | 412 | { |
| 393 | struct rpc_task *task; | ||
| 394 | |||
| 395 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { | 413 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { |
| 396 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); | 414 | rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq, |
| 397 | if (task) | 415 | nfs4_set_task_privileged, NULL); |
| 398 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
| 399 | return; | 416 | return; |
| 400 | } | 417 | } |
| 401 | 418 | ||
| 402 | if (ses->fc_slot_table.highest_used_slotid != -1) | 419 | if (ses->fc_slot_table.highest_used_slotid != NFS4_NO_SLOT) |
| 403 | return; | 420 | return; |
| 404 | 421 | ||
| 405 | dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__); | 422 | dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__); |
| @@ -412,7 +429,7 @@ static void nfs4_check_drain_fc_complete(struct nfs4_session *ses) | |||
| 412 | void nfs4_check_drain_bc_complete(struct nfs4_session *ses) | 429 | void nfs4_check_drain_bc_complete(struct nfs4_session *ses) |
| 413 | { | 430 | { |
| 414 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) || | 431 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) || |
| 415 | ses->bc_slot_table.highest_used_slotid != -1) | 432 | ses->bc_slot_table.highest_used_slotid != NFS4_NO_SLOT) |
| 416 | return; | 433 | return; |
| 417 | dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__); | 434 | dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__); |
| 418 | complete(&ses->bc_slot_table.complete); | 435 | complete(&ses->bc_slot_table.complete); |
| @@ -507,25 +524,25 @@ static int nfs4_sequence_done(struct rpc_task *task, | |||
| 507 | * nfs4_find_slot looks for an unset bit in the used_slots bitmap. | 524 | * nfs4_find_slot looks for an unset bit in the used_slots bitmap. |
| 508 | * If found, we mark the slot as used, update the highest_used_slotid, | 525 | * If found, we mark the slot as used, update the highest_used_slotid, |
| 509 | * and respectively set up the sequence operation args. | 526 | * and respectively set up the sequence operation args. |
| 510 | * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise. | 527 | * The slot number is returned if found, or NFS4_NO_SLOT otherwise. |
| 511 | * | 528 | * |
| 512 | * Note: must be called with under the slot_tbl_lock. | 529 | * Note: must be called with under the slot_tbl_lock. |
| 513 | */ | 530 | */ |
| 514 | static u8 | 531 | static u32 |
| 515 | nfs4_find_slot(struct nfs4_slot_table *tbl) | 532 | nfs4_find_slot(struct nfs4_slot_table *tbl) |
| 516 | { | 533 | { |
| 517 | int slotid; | 534 | u32 slotid; |
| 518 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | 535 | u32 ret_id = NFS4_NO_SLOT; |
| 519 | BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE); | ||
| 520 | 536 | ||
| 521 | dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n", | 537 | dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", |
| 522 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | 538 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, |
| 523 | tbl->max_slots); | 539 | tbl->max_slots); |
| 524 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots); | 540 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots); |
| 525 | if (slotid >= tbl->max_slots) | 541 | if (slotid >= tbl->max_slots) |
| 526 | goto out; | 542 | goto out; |
| 527 | __set_bit(slotid, tbl->used_slots); | 543 | __set_bit(slotid, tbl->used_slots); |
| 528 | if (slotid > tbl->highest_used_slotid) | 544 | if (slotid > tbl->highest_used_slotid || |
| 545 | tbl->highest_used_slotid == NFS4_NO_SLOT) | ||
| 529 | tbl->highest_used_slotid = slotid; | 546 | tbl->highest_used_slotid = slotid; |
| 530 | ret_id = slotid; | 547 | ret_id = slotid; |
| 531 | out: | 548 | out: |
| @@ -534,15 +551,25 @@ out: | |||
| 534 | return ret_id; | 551 | return ret_id; |
| 535 | } | 552 | } |
| 536 | 553 | ||
| 554 | static void nfs41_init_sequence(struct nfs4_sequence_args *args, | ||
| 555 | struct nfs4_sequence_res *res, int cache_reply) | ||
| 556 | { | ||
| 557 | args->sa_session = NULL; | ||
| 558 | args->sa_cache_this = 0; | ||
| 559 | if (cache_reply) | ||
| 560 | args->sa_cache_this = 1; | ||
| 561 | res->sr_session = NULL; | ||
| 562 | res->sr_slot = NULL; | ||
| 563 | } | ||
| 564 | |||
| 537 | int nfs41_setup_sequence(struct nfs4_session *session, | 565 | int nfs41_setup_sequence(struct nfs4_session *session, |
| 538 | struct nfs4_sequence_args *args, | 566 | struct nfs4_sequence_args *args, |
| 539 | struct nfs4_sequence_res *res, | 567 | struct nfs4_sequence_res *res, |
| 540 | int cache_reply, | ||
| 541 | struct rpc_task *task) | 568 | struct rpc_task *task) |
| 542 | { | 569 | { |
| 543 | struct nfs4_slot *slot; | 570 | struct nfs4_slot *slot; |
| 544 | struct nfs4_slot_table *tbl; | 571 | struct nfs4_slot_table *tbl; |
| 545 | u8 slotid; | 572 | u32 slotid; |
| 546 | 573 | ||
| 547 | dprintk("--> %s\n", __func__); | 574 | dprintk("--> %s\n", __func__); |
| 548 | /* slot already allocated? */ | 575 | /* slot already allocated? */ |
| @@ -570,7 +597,7 @@ int nfs41_setup_sequence(struct nfs4_session *session, | |||
| 570 | } | 597 | } |
| 571 | 598 | ||
| 572 | slotid = nfs4_find_slot(tbl); | 599 | slotid = nfs4_find_slot(tbl); |
| 573 | if (slotid == NFS4_MAX_SLOT_TABLE) { | 600 | if (slotid == NFS4_NO_SLOT) { |
| 574 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | 601 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); |
| 575 | spin_unlock(&tbl->slot_tbl_lock); | 602 | spin_unlock(&tbl->slot_tbl_lock); |
| 576 | dprintk("<-- %s: no free slots\n", __func__); | 603 | dprintk("<-- %s: no free slots\n", __func__); |
| @@ -582,7 +609,6 @@ int nfs41_setup_sequence(struct nfs4_session *session, | |||
| 582 | slot = tbl->slots + slotid; | 609 | slot = tbl->slots + slotid; |
| 583 | args->sa_session = session; | 610 | args->sa_session = session; |
| 584 | args->sa_slotid = slotid; | 611 | args->sa_slotid = slotid; |
| 585 | args->sa_cache_this = cache_reply; | ||
| 586 | 612 | ||
| 587 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | 613 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); |
| 588 | 614 | ||
| @@ -602,24 +628,19 @@ EXPORT_SYMBOL_GPL(nfs41_setup_sequence); | |||
| 602 | int nfs4_setup_sequence(const struct nfs_server *server, | 628 | int nfs4_setup_sequence(const struct nfs_server *server, |
| 603 | struct nfs4_sequence_args *args, | 629 | struct nfs4_sequence_args *args, |
| 604 | struct nfs4_sequence_res *res, | 630 | struct nfs4_sequence_res *res, |
| 605 | int cache_reply, | ||
| 606 | struct rpc_task *task) | 631 | struct rpc_task *task) |
| 607 | { | 632 | { |
| 608 | struct nfs4_session *session = nfs4_get_session(server); | 633 | struct nfs4_session *session = nfs4_get_session(server); |
| 609 | int ret = 0; | 634 | int ret = 0; |
| 610 | 635 | ||
| 611 | if (session == NULL) { | 636 | if (session == NULL) |
| 612 | args->sa_session = NULL; | ||
| 613 | res->sr_session = NULL; | ||
| 614 | goto out; | 637 | goto out; |
| 615 | } | ||
| 616 | 638 | ||
| 617 | dprintk("--> %s clp %p session %p sr_slot %td\n", | 639 | dprintk("--> %s clp %p session %p sr_slot %td\n", |
| 618 | __func__, session->clp, session, res->sr_slot ? | 640 | __func__, session->clp, session, res->sr_slot ? |
| 619 | res->sr_slot - session->fc_slot_table.slots : -1); | 641 | res->sr_slot - session->fc_slot_table.slots : -1); |
| 620 | 642 | ||
| 621 | ret = nfs41_setup_sequence(session, args, res, cache_reply, | 643 | ret = nfs41_setup_sequence(session, args, res, task); |
| 622 | task); | ||
| 623 | out: | 644 | out: |
| 624 | dprintk("<-- %s status=%d\n", __func__, ret); | 645 | dprintk("<-- %s status=%d\n", __func__, ret); |
| 625 | return ret; | 646 | return ret; |
| @@ -629,7 +650,6 @@ struct nfs41_call_sync_data { | |||
| 629 | const struct nfs_server *seq_server; | 650 | const struct nfs_server *seq_server; |
| 630 | struct nfs4_sequence_args *seq_args; | 651 | struct nfs4_sequence_args *seq_args; |
| 631 | struct nfs4_sequence_res *seq_res; | 652 | struct nfs4_sequence_res *seq_res; |
| 632 | int cache_reply; | ||
| 633 | }; | 653 | }; |
| 634 | 654 | ||
| 635 | static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | 655 | static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) |
| @@ -639,7 +659,7 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | |||
| 639 | dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server); | 659 | dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server); |
| 640 | 660 | ||
| 641 | if (nfs4_setup_sequence(data->seq_server, data->seq_args, | 661 | if (nfs4_setup_sequence(data->seq_server, data->seq_args, |
| 642 | data->seq_res, data->cache_reply, task)) | 662 | data->seq_res, task)) |
| 643 | return; | 663 | return; |
| 644 | rpc_call_start(task); | 664 | rpc_call_start(task); |
| 645 | } | 665 | } |
| @@ -657,12 +677,12 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | |||
| 657 | nfs41_sequence_done(task, data->seq_res); | 677 | nfs41_sequence_done(task, data->seq_res); |
| 658 | } | 678 | } |
| 659 | 679 | ||
| 660 | struct rpc_call_ops nfs41_call_sync_ops = { | 680 | static const struct rpc_call_ops nfs41_call_sync_ops = { |
| 661 | .rpc_call_prepare = nfs41_call_sync_prepare, | 681 | .rpc_call_prepare = nfs41_call_sync_prepare, |
| 662 | .rpc_call_done = nfs41_call_sync_done, | 682 | .rpc_call_done = nfs41_call_sync_done, |
| 663 | }; | 683 | }; |
| 664 | 684 | ||
| 665 | struct rpc_call_ops nfs41_call_priv_sync_ops = { | 685 | static const struct rpc_call_ops nfs41_call_priv_sync_ops = { |
| 666 | .rpc_call_prepare = nfs41_call_priv_sync_prepare, | 686 | .rpc_call_prepare = nfs41_call_priv_sync_prepare, |
| 667 | .rpc_call_done = nfs41_call_sync_done, | 687 | .rpc_call_done = nfs41_call_sync_done, |
| 668 | }; | 688 | }; |
| @@ -672,7 +692,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, | |||
| 672 | struct rpc_message *msg, | 692 | struct rpc_message *msg, |
| 673 | struct nfs4_sequence_args *args, | 693 | struct nfs4_sequence_args *args, |
| 674 | struct nfs4_sequence_res *res, | 694 | struct nfs4_sequence_res *res, |
| 675 | int cache_reply, | ||
| 676 | int privileged) | 695 | int privileged) |
| 677 | { | 696 | { |
| 678 | int ret; | 697 | int ret; |
| @@ -681,7 +700,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, | |||
| 681 | .seq_server = server, | 700 | .seq_server = server, |
| 682 | .seq_args = args, | 701 | .seq_args = args, |
| 683 | .seq_res = res, | 702 | .seq_res = res, |
| 684 | .cache_reply = cache_reply, | ||
| 685 | }; | 703 | }; |
| 686 | struct rpc_task_setup task_setup = { | 704 | struct rpc_task_setup task_setup = { |
| 687 | .rpc_client = clnt, | 705 | .rpc_client = clnt, |
| @@ -690,7 +708,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, | |||
| 690 | .callback_data = &data | 708 | .callback_data = &data |
| 691 | }; | 709 | }; |
| 692 | 710 | ||
| 693 | res->sr_slot = NULL; | ||
| 694 | if (privileged) | 711 | if (privileged) |
| 695 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; | 712 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; |
| 696 | task = rpc_run_task(&task_setup); | 713 | task = rpc_run_task(&task_setup); |
| @@ -710,10 +727,17 @@ int _nfs4_call_sync_session(struct rpc_clnt *clnt, | |||
| 710 | struct nfs4_sequence_res *res, | 727 | struct nfs4_sequence_res *res, |
| 711 | int cache_reply) | 728 | int cache_reply) |
| 712 | { | 729 | { |
| 713 | return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0); | 730 | nfs41_init_sequence(args, res, cache_reply); |
| 731 | return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0); | ||
| 714 | } | 732 | } |
| 715 | 733 | ||
| 716 | #else | 734 | #else |
| 735 | static inline | ||
| 736 | void nfs41_init_sequence(struct nfs4_sequence_args *args, | ||
| 737 | struct nfs4_sequence_res *res, int cache_reply) | ||
| 738 | { | ||
| 739 | } | ||
| 740 | |||
| 717 | static int nfs4_sequence_done(struct rpc_task *task, | 741 | static int nfs4_sequence_done(struct rpc_task *task, |
| 718 | struct nfs4_sequence_res *res) | 742 | struct nfs4_sequence_res *res) |
| 719 | { | 743 | { |
| @@ -728,7 +752,7 @@ int _nfs4_call_sync(struct rpc_clnt *clnt, | |||
| 728 | struct nfs4_sequence_res *res, | 752 | struct nfs4_sequence_res *res, |
| 729 | int cache_reply) | 753 | int cache_reply) |
| 730 | { | 754 | { |
| 731 | args->sa_session = res->sr_session = NULL; | 755 | nfs41_init_sequence(args, res, cache_reply); |
| 732 | return rpc_call_sync(clnt, msg, 0); | 756 | return rpc_call_sync(clnt, msg, 0); |
| 733 | } | 757 | } |
| 734 | 758 | ||
| @@ -815,20 +839,22 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
| 815 | p->o_arg.open_flags = flags; | 839 | p->o_arg.open_flags = flags; |
| 816 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); | 840 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); |
| 817 | p->o_arg.clientid = server->nfs_client->cl_clientid; | 841 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
| 818 | p->o_arg.id = sp->so_owner_id.id; | 842 | p->o_arg.id = sp->so_seqid.owner_id; |
| 819 | p->o_arg.name = &dentry->d_name; | 843 | p->o_arg.name = &dentry->d_name; |
| 820 | p->o_arg.server = server; | 844 | p->o_arg.server = server; |
| 821 | p->o_arg.bitmask = server->attr_bitmask; | 845 | p->o_arg.bitmask = server->attr_bitmask; |
| 822 | p->o_arg.dir_bitmask = server->cache_consistency_bitmask; | 846 | p->o_arg.dir_bitmask = server->cache_consistency_bitmask; |
| 823 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 847 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
| 824 | if (flags & O_CREAT) { | 848 | if (attrs != NULL && attrs->ia_valid != 0) { |
| 825 | u32 *s; | 849 | __be32 verf[2]; |
| 826 | 850 | ||
| 827 | p->o_arg.u.attrs = &p->attrs; | 851 | p->o_arg.u.attrs = &p->attrs; |
| 828 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | 852 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); |
| 829 | s = (u32 *) p->o_arg.u.verifier.data; | 853 | |
| 830 | s[0] = jiffies; | 854 | verf[0] = jiffies; |
| 831 | s[1] = current->pid; | 855 | verf[1] = current->pid; |
| 856 | memcpy(p->o_arg.u.verifier.data, verf, | ||
| 857 | sizeof(p->o_arg.u.verifier.data)); | ||
| 832 | } | 858 | } |
| 833 | p->c_arg.fh = &p->o_res.fh; | 859 | p->c_arg.fh = &p->o_res.fh; |
| 834 | p->c_arg.stateid = &p->o_res.stateid; | 860 | p->c_arg.stateid = &p->o_res.stateid; |
| @@ -878,7 +904,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode | |||
| 878 | { | 904 | { |
| 879 | int ret = 0; | 905 | int ret = 0; |
| 880 | 906 | ||
| 881 | if (open_mode & O_EXCL) | 907 | if (open_mode & (O_EXCL|O_TRUNC)) |
| 882 | goto out; | 908 | goto out; |
| 883 | switch (mode & (FMODE_READ|FMODE_WRITE)) { | 909 | switch (mode & (FMODE_READ|FMODE_WRITE)) { |
| 884 | case FMODE_READ: | 910 | case FMODE_READ: |
| @@ -927,8 +953,8 @@ static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode) | |||
| 927 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) | 953 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) |
| 928 | { | 954 | { |
| 929 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 955 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
| 930 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); | 956 | nfs4_stateid_copy(&state->stateid, stateid); |
| 931 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); | 957 | nfs4_stateid_copy(&state->open_stateid, stateid); |
| 932 | switch (fmode) { | 958 | switch (fmode) { |
| 933 | case FMODE_READ: | 959 | case FMODE_READ: |
| 934 | set_bit(NFS_O_RDONLY_STATE, &state->flags); | 960 | set_bit(NFS_O_RDONLY_STATE, &state->flags); |
| @@ -956,7 +982,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s | |||
| 956 | */ | 982 | */ |
| 957 | write_seqlock(&state->seqlock); | 983 | write_seqlock(&state->seqlock); |
| 958 | if (deleg_stateid != NULL) { | 984 | if (deleg_stateid != NULL) { |
| 959 | memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); | 985 | nfs4_stateid_copy(&state->stateid, deleg_stateid); |
| 960 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 986 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
| 961 | } | 987 | } |
| 962 | if (open_stateid != NULL) | 988 | if (open_stateid != NULL) |
| @@ -987,7 +1013,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat | |||
| 987 | 1013 | ||
| 988 | if (delegation == NULL) | 1014 | if (delegation == NULL) |
| 989 | delegation = &deleg_cur->stateid; | 1015 | delegation = &deleg_cur->stateid; |
| 990 | else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0) | 1016 | else if (!nfs4_stateid_match(&deleg_cur->stateid, delegation)) |
| 991 | goto no_delegation_unlock; | 1017 | goto no_delegation_unlock; |
| 992 | 1018 | ||
| 993 | nfs_mark_delegation_referenced(deleg_cur); | 1019 | nfs_mark_delegation_referenced(deleg_cur); |
| @@ -1026,7 +1052,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
| 1026 | struct nfs4_state *state = opendata->state; | 1052 | struct nfs4_state *state = opendata->state; |
| 1027 | struct nfs_inode *nfsi = NFS_I(state->inode); | 1053 | struct nfs_inode *nfsi = NFS_I(state->inode); |
| 1028 | struct nfs_delegation *delegation; | 1054 | struct nfs_delegation *delegation; |
| 1029 | int open_mode = opendata->o_arg.open_flags & O_EXCL; | 1055 | int open_mode = opendata->o_arg.open_flags & (O_EXCL|O_TRUNC); |
| 1030 | fmode_t fmode = opendata->o_arg.fmode; | 1056 | fmode_t fmode = opendata->o_arg.fmode; |
| 1031 | nfs4_stateid stateid; | 1057 | nfs4_stateid stateid; |
| 1032 | int ret = -EAGAIN; | 1058 | int ret = -EAGAIN; |
| @@ -1048,7 +1074,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
| 1048 | break; | 1074 | break; |
| 1049 | } | 1075 | } |
| 1050 | /* Save the delegation */ | 1076 | /* Save the delegation */ |
| 1051 | memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); | 1077 | nfs4_stateid_copy(&stateid, &delegation->stateid); |
| 1052 | rcu_read_unlock(); | 1078 | rcu_read_unlock(); |
| 1053 | ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode); | 1079 | ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode); |
| 1054 | if (ret != 0) | 1080 | if (ret != 0) |
| @@ -1090,6 +1116,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
| 1090 | if (state == NULL) | 1116 | if (state == NULL) |
| 1091 | goto err_put_inode; | 1117 | goto err_put_inode; |
| 1092 | if (data->o_res.delegation_type != 0) { | 1118 | if (data->o_res.delegation_type != 0) { |
| 1119 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | ||
| 1093 | int delegation_flags = 0; | 1120 | int delegation_flags = 0; |
| 1094 | 1121 | ||
| 1095 | rcu_read_lock(); | 1122 | rcu_read_lock(); |
| @@ -1101,7 +1128,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
| 1101 | pr_err_ratelimited("NFS: Broken NFSv4 server %s is " | 1128 | pr_err_ratelimited("NFS: Broken NFSv4 server %s is " |
| 1102 | "returning a delegation for " | 1129 | "returning a delegation for " |
| 1103 | "OPEN(CLAIM_DELEGATE_CUR)\n", | 1130 | "OPEN(CLAIM_DELEGATE_CUR)\n", |
| 1104 | NFS_CLIENT(inode)->cl_server); | 1131 | clp->cl_hostname); |
| 1105 | } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0) | 1132 | } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0) |
| 1106 | nfs_inode_set_delegation(state->inode, | 1133 | nfs_inode_set_delegation(state->inode, |
| 1107 | data->owner->so_cred, | 1134 | data->owner->so_cred, |
| @@ -1210,10 +1237,10 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
| 1210 | * Check if we need to update the current stateid. | 1237 | * Check if we need to update the current stateid. |
| 1211 | */ | 1238 | */ |
| 1212 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && | 1239 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && |
| 1213 | memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { | 1240 | !nfs4_stateid_match(&state->stateid, &state->open_stateid)) { |
| 1214 | write_seqlock(&state->seqlock); | 1241 | write_seqlock(&state->seqlock); |
| 1215 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 1242 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
| 1216 | memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); | 1243 | nfs4_stateid_copy(&state->stateid, &state->open_stateid); |
| 1217 | write_sequnlock(&state->seqlock); | 1244 | write_sequnlock(&state->seqlock); |
| 1218 | } | 1245 | } |
| 1219 | return 0; | 1246 | return 0; |
| @@ -1282,8 +1309,7 @@ static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs | |||
| 1282 | if (IS_ERR(opendata)) | 1309 | if (IS_ERR(opendata)) |
| 1283 | return PTR_ERR(opendata); | 1310 | return PTR_ERR(opendata); |
| 1284 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; | 1311 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; |
| 1285 | memcpy(opendata->o_arg.u.delegation.data, stateid->data, | 1312 | nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid); |
| 1286 | sizeof(opendata->o_arg.u.delegation.data)); | ||
| 1287 | ret = nfs4_open_recover(opendata, state); | 1313 | ret = nfs4_open_recover(opendata, state); |
| 1288 | nfs4_opendata_put(opendata); | 1314 | nfs4_opendata_put(opendata); |
| 1289 | return ret; | 1315 | return ret; |
| @@ -1319,8 +1345,11 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
| 1319 | * The show must go on: exit, but mark the | 1345 | * The show must go on: exit, but mark the |
| 1320 | * stateid as needing recovery. | 1346 | * stateid as needing recovery. |
| 1321 | */ | 1347 | */ |
| 1348 | case -NFS4ERR_DELEG_REVOKED: | ||
| 1322 | case -NFS4ERR_ADMIN_REVOKED: | 1349 | case -NFS4ERR_ADMIN_REVOKED: |
| 1323 | case -NFS4ERR_BAD_STATEID: | 1350 | case -NFS4ERR_BAD_STATEID: |
| 1351 | nfs_inode_find_state_and_recover(state->inode, | ||
| 1352 | stateid); | ||
| 1324 | nfs4_schedule_stateid_recovery(server, state); | 1353 | nfs4_schedule_stateid_recovery(server, state); |
| 1325 | case -EKEYEXPIRED: | 1354 | case -EKEYEXPIRED: |
| 1326 | /* | 1355 | /* |
| @@ -1345,8 +1374,7 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | |||
| 1345 | 1374 | ||
| 1346 | data->rpc_status = task->tk_status; | 1375 | data->rpc_status = task->tk_status; |
| 1347 | if (data->rpc_status == 0) { | 1376 | if (data->rpc_status == 0) { |
| 1348 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, | 1377 | nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid); |
| 1349 | sizeof(data->o_res.stateid.data)); | ||
| 1350 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 1378 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
| 1351 | renew_lease(data->o_res.server, data->timestamp); | 1379 | renew_lease(data->o_res.server, data->timestamp); |
| 1352 | data->rpc_done = 1; | 1380 | data->rpc_done = 1; |
| @@ -1440,7 +1468,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
| 1440 | rcu_read_unlock(); | 1468 | rcu_read_unlock(); |
| 1441 | } | 1469 | } |
| 1442 | /* Update sequence id. */ | 1470 | /* Update sequence id. */ |
| 1443 | data->o_arg.id = sp->so_owner_id.id; | 1471 | data->o_arg.id = sp->so_seqid.owner_id; |
| 1444 | data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid; | 1472 | data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid; |
| 1445 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { | 1473 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { |
| 1446 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 1474 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; |
| @@ -1449,7 +1477,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
| 1449 | data->timestamp = jiffies; | 1477 | data->timestamp = jiffies; |
| 1450 | if (nfs4_setup_sequence(data->o_arg.server, | 1478 | if (nfs4_setup_sequence(data->o_arg.server, |
| 1451 | &data->o_arg.seq_args, | 1479 | &data->o_arg.seq_args, |
| 1452 | &data->o_res.seq_res, 1, task)) | 1480 | &data->o_res.seq_res, task)) |
| 1453 | return; | 1481 | return; |
| 1454 | rpc_call_start(task); | 1482 | rpc_call_start(task); |
| 1455 | return; | 1483 | return; |
| @@ -1551,6 +1579,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) | |||
| 1551 | }; | 1579 | }; |
| 1552 | int status; | 1580 | int status; |
| 1553 | 1581 | ||
| 1582 | nfs41_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1); | ||
| 1554 | kref_get(&data->kref); | 1583 | kref_get(&data->kref); |
| 1555 | data->rpc_done = 0; | 1584 | data->rpc_done = 0; |
| 1556 | data->rpc_status = 0; | 1585 | data->rpc_status = 0; |
| @@ -1712,15 +1741,32 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
| 1712 | } | 1741 | } |
| 1713 | 1742 | ||
| 1714 | #if defined(CONFIG_NFS_V4_1) | 1743 | #if defined(CONFIG_NFS_V4_1) |
| 1715 | static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | 1744 | static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *stateid, unsigned int flags) |
| 1716 | { | 1745 | { |
| 1717 | int status; | 1746 | int status = NFS_OK; |
| 1718 | struct nfs_server *server = NFS_SERVER(state->inode); | 1747 | struct nfs_server *server = NFS_SERVER(state->inode); |
| 1719 | 1748 | ||
| 1720 | status = nfs41_test_stateid(server, state); | 1749 | if (state->flags & flags) { |
| 1721 | if (status == NFS_OK) | 1750 | status = nfs41_test_stateid(server, stateid); |
| 1722 | return 0; | 1751 | if (status != NFS_OK) { |
| 1723 | nfs41_free_stateid(server, state); | 1752 | nfs41_free_stateid(server, stateid); |
| 1753 | state->flags &= ~flags; | ||
| 1754 | } | ||
| 1755 | } | ||
| 1756 | return status; | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | ||
| 1760 | { | ||
| 1761 | int deleg_status, open_status; | ||
| 1762 | int deleg_flags = 1 << NFS_DELEGATED_STATE; | ||
| 1763 | int open_flags = (1 << NFS_O_RDONLY_STATE) | (1 << NFS_O_WRONLY_STATE) | (1 << NFS_O_RDWR_STATE); | ||
| 1764 | |||
| 1765 | deleg_status = nfs41_check_expired_stateid(state, &state->stateid, deleg_flags); | ||
| 1766 | open_status = nfs41_check_expired_stateid(state, &state->open_stateid, open_flags); | ||
| 1767 | |||
| 1768 | if ((deleg_status == NFS_OK) && (open_status == NFS_OK)) | ||
| 1769 | return NFS_OK; | ||
| 1724 | return nfs4_open_expired(sp, state); | 1770 | return nfs4_open_expired(sp, state); |
| 1725 | } | 1771 | } |
| 1726 | #endif | 1772 | #endif |
| @@ -1754,7 +1800,8 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode | |||
| 1754 | 1800 | ||
| 1755 | /* Protect against reboot recovery conflicts */ | 1801 | /* Protect against reboot recovery conflicts */ |
| 1756 | status = -ENOMEM; | 1802 | status = -ENOMEM; |
| 1757 | if (!(sp = nfs4_get_state_owner(server, cred))) { | 1803 | sp = nfs4_get_state_owner(server, cred, GFP_KERNEL); |
| 1804 | if (sp == NULL) { | ||
| 1758 | dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); | 1805 | dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); |
| 1759 | goto out_err; | 1806 | goto out_err; |
| 1760 | } | 1807 | } |
| @@ -1829,7 +1876,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |||
| 1829 | * the user though... | 1876 | * the user though... |
| 1830 | */ | 1877 | */ |
| 1831 | if (status == -NFS4ERR_BAD_SEQID) { | 1878 | if (status == -NFS4ERR_BAD_SEQID) { |
| 1832 | printk(KERN_WARNING "NFS: v4 server %s " | 1879 | pr_warn_ratelimited("NFS: v4 server %s " |
| 1833 | " returned a bad sequence-id error!\n", | 1880 | " returned a bad sequence-id error!\n", |
| 1834 | NFS_SERVER(dir)->nfs_client->cl_hostname); | 1881 | NFS_SERVER(dir)->nfs_client->cl_hostname); |
| 1835 | exception.retry = 1; | 1882 | exception.retry = 1; |
| @@ -1882,12 +1929,14 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
| 1882 | 1929 | ||
| 1883 | nfs_fattr_init(fattr); | 1930 | nfs_fattr_init(fattr); |
| 1884 | 1931 | ||
| 1885 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { | 1932 | if (state != NULL) { |
| 1933 | nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE, | ||
| 1934 | current->files, current->tgid); | ||
| 1935 | } else if (nfs4_copy_delegation_stateid(&arg.stateid, inode, | ||
| 1936 | FMODE_WRITE)) { | ||
| 1886 | /* Use that stateid */ | 1937 | /* Use that stateid */ |
| 1887 | } else if (state != NULL) { | ||
| 1888 | nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid); | ||
| 1889 | } else | 1938 | } else |
| 1890 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1939 | nfs4_stateid_copy(&arg.stateid, &zero_stateid); |
| 1891 | 1940 | ||
| 1892 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); | 1941 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
| 1893 | if (status == 0 && state != NULL) | 1942 | if (status == 0 && state != NULL) |
| @@ -1900,7 +1949,10 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
| 1900 | struct nfs4_state *state) | 1949 | struct nfs4_state *state) |
| 1901 | { | 1950 | { |
| 1902 | struct nfs_server *server = NFS_SERVER(inode); | 1951 | struct nfs_server *server = NFS_SERVER(inode); |
| 1903 | struct nfs4_exception exception = { }; | 1952 | struct nfs4_exception exception = { |
| 1953 | .state = state, | ||
| 1954 | .inode = inode, | ||
| 1955 | }; | ||
| 1904 | int err; | 1956 | int err; |
| 1905 | do { | 1957 | do { |
| 1906 | err = nfs4_handle_exception(server, | 1958 | err = nfs4_handle_exception(server, |
| @@ -1954,6 +2006,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 1954 | struct nfs4_state *state = calldata->state; | 2006 | struct nfs4_state *state = calldata->state; |
| 1955 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 2007 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
| 1956 | 2008 | ||
| 2009 | dprintk("%s: begin!\n", __func__); | ||
| 1957 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) | 2010 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
| 1958 | return; | 2011 | return; |
| 1959 | /* hmm. we are done with the inode, and in the process of freeing | 2012 | /* hmm. we are done with the inode, and in the process of freeing |
| @@ -1981,6 +2034,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 1981 | } | 2034 | } |
| 1982 | nfs_release_seqid(calldata->arg.seqid); | 2035 | nfs_release_seqid(calldata->arg.seqid); |
| 1983 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 2036 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
| 2037 | dprintk("%s: done, ret = %d!\n", __func__, task->tk_status); | ||
| 1984 | } | 2038 | } |
| 1985 | 2039 | ||
| 1986 | static void nfs4_close_prepare(struct rpc_task *task, void *data) | 2040 | static void nfs4_close_prepare(struct rpc_task *task, void *data) |
| @@ -1989,6 +2043,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 1989 | struct nfs4_state *state = calldata->state; | 2043 | struct nfs4_state *state = calldata->state; |
| 1990 | int call_close = 0; | 2044 | int call_close = 0; |
| 1991 | 2045 | ||
| 2046 | dprintk("%s: begin!\n", __func__); | ||
| 1992 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 2047 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
| 1993 | return; | 2048 | return; |
| 1994 | 2049 | ||
| @@ -2013,7 +2068,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 2013 | if (!call_close) { | 2068 | if (!call_close) { |
| 2014 | /* Note: exit _without_ calling nfs4_close_done */ | 2069 | /* Note: exit _without_ calling nfs4_close_done */ |
| 2015 | task->tk_action = NULL; | 2070 | task->tk_action = NULL; |
| 2016 | return; | 2071 | goto out; |
| 2017 | } | 2072 | } |
| 2018 | 2073 | ||
| 2019 | if (calldata->arg.fmode == 0) { | 2074 | if (calldata->arg.fmode == 0) { |
| @@ -2022,17 +2077,20 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 2022 | pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) { | 2077 | pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) { |
| 2023 | rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq, | 2078 | rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq, |
| 2024 | task, NULL); | 2079 | task, NULL); |
| 2025 | return; | 2080 | goto out; |
| 2026 | } | 2081 | } |
| 2027 | } | 2082 | } |
| 2028 | 2083 | ||
| 2029 | nfs_fattr_init(calldata->res.fattr); | 2084 | nfs_fattr_init(calldata->res.fattr); |
| 2030 | calldata->timestamp = jiffies; | 2085 | calldata->timestamp = jiffies; |
| 2031 | if (nfs4_setup_sequence(NFS_SERVER(calldata->inode), | 2086 | if (nfs4_setup_sequence(NFS_SERVER(calldata->inode), |
| 2032 | &calldata->arg.seq_args, &calldata->res.seq_res, | 2087 | &calldata->arg.seq_args, |
| 2033 | 1, task)) | 2088 | &calldata->res.seq_res, |
| 2034 | return; | 2089 | task)) |
| 2090 | goto out; | ||
| 2035 | rpc_call_start(task); | 2091 | rpc_call_start(task); |
| 2092 | out: | ||
| 2093 | dprintk("%s: done!\n", __func__); | ||
| 2036 | } | 2094 | } |
| 2037 | 2095 | ||
| 2038 | static const struct rpc_call_ops nfs4_close_ops = { | 2096 | static const struct rpc_call_ops nfs4_close_ops = { |
| @@ -2074,6 +2132,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) | |||
| 2074 | calldata = kzalloc(sizeof(*calldata), gfp_mask); | 2132 | calldata = kzalloc(sizeof(*calldata), gfp_mask); |
| 2075 | if (calldata == NULL) | 2133 | if (calldata == NULL) |
| 2076 | goto out; | 2134 | goto out; |
| 2135 | nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1); | ||
| 2077 | calldata->inode = state->inode; | 2136 | calldata->inode = state->inode; |
| 2078 | calldata->state = state; | 2137 | calldata->state = state; |
| 2079 | calldata->arg.fh = NFS_FH(state->inode); | 2138 | calldata->arg.fh = NFS_FH(state->inode); |
| @@ -2182,6 +2241,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
| 2182 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; | 2241 | server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; |
| 2183 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 2242 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
| 2184 | server->acl_bitmask = res.acl_bitmask; | 2243 | server->acl_bitmask = res.acl_bitmask; |
| 2244 | server->fh_expire_type = res.fh_expire_type; | ||
| 2185 | } | 2245 | } |
| 2186 | 2246 | ||
| 2187 | return status; | 2247 | return status; |
| @@ -2303,7 +2363,6 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
| 2303 | return nfs4_map_errors(status); | 2363 | return nfs4_map_errors(status); |
| 2304 | } | 2364 | } |
| 2305 | 2365 | ||
| 2306 | static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr); | ||
| 2307 | /* | 2366 | /* |
| 2308 | * Get locations and (maybe) other attributes of a referral. | 2367 | * Get locations and (maybe) other attributes of a referral. |
| 2309 | * Note that we'll actually follow the referral later when | 2368 | * Note that we'll actually follow the referral later when |
| @@ -2420,6 +2479,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
| 2420 | } | 2479 | } |
| 2421 | } | 2480 | } |
| 2422 | 2481 | ||
| 2482 | /* Deal with open(O_TRUNC) */ | ||
| 2483 | if (sattr->ia_valid & ATTR_OPEN) | ||
| 2484 | sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN); | ||
| 2485 | |||
| 2423 | status = nfs4_do_setattr(inode, cred, fattr, sattr, state); | 2486 | status = nfs4_do_setattr(inode, cred, fattr, sattr, state); |
| 2424 | if (status == 0) | 2487 | if (status == 0) |
| 2425 | nfs_setattr_update_inode(inode, sattr); | 2488 | nfs_setattr_update_inode(inode, sattr); |
| @@ -2494,7 +2557,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
| 2494 | struct nfs_server *server = NFS_SERVER(inode); | 2557 | struct nfs_server *server = NFS_SERVER(inode); |
| 2495 | struct nfs4_accessargs args = { | 2558 | struct nfs4_accessargs args = { |
| 2496 | .fh = NFS_FH(inode), | 2559 | .fh = NFS_FH(inode), |
| 2497 | .bitmask = server->attr_bitmask, | 2560 | .bitmask = server->cache_consistency_bitmask, |
| 2498 | }; | 2561 | }; |
| 2499 | struct nfs4_accessres res = { | 2562 | struct nfs4_accessres res = { |
| 2500 | .server = server, | 2563 | .server = server, |
| @@ -2712,8 +2775,18 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) | |||
| 2712 | 2775 | ||
| 2713 | args->bitmask = server->cache_consistency_bitmask; | 2776 | args->bitmask = server->cache_consistency_bitmask; |
| 2714 | res->server = server; | 2777 | res->server = server; |
| 2715 | res->seq_res.sr_slot = NULL; | ||
| 2716 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; | 2778 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; |
| 2779 | nfs41_init_sequence(&args->seq_args, &res->seq_res, 1); | ||
| 2780 | } | ||
| 2781 | |||
| 2782 | static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) | ||
| 2783 | { | ||
| 2784 | if (nfs4_setup_sequence(NFS_SERVER(data->dir), | ||
| 2785 | &data->args.seq_args, | ||
| 2786 | &data->res.seq_res, | ||
| 2787 | task)) | ||
| 2788 | return; | ||
| 2789 | rpc_call_start(task); | ||
| 2717 | } | 2790 | } |
| 2718 | 2791 | ||
| 2719 | static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | 2792 | static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) |
| @@ -2738,6 +2811,17 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir) | |||
| 2738 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME]; | 2811 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME]; |
| 2739 | arg->bitmask = server->attr_bitmask; | 2812 | arg->bitmask = server->attr_bitmask; |
| 2740 | res->server = server; | 2813 | res->server = server; |
| 2814 | nfs41_init_sequence(&arg->seq_args, &res->seq_res, 1); | ||
| 2815 | } | ||
| 2816 | |||
| 2817 | static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data) | ||
| 2818 | { | ||
| 2819 | if (nfs4_setup_sequence(NFS_SERVER(data->old_dir), | ||
| 2820 | &data->args.seq_args, | ||
| 2821 | &data->res.seq_res, | ||
| 2822 | task)) | ||
| 2823 | return; | ||
| 2824 | rpc_call_start(task); | ||
| 2741 | } | 2825 | } |
| 2742 | 2826 | ||
| 2743 | static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir, | 2827 | static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir, |
| @@ -3232,6 +3316,17 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message | |||
| 3232 | data->timestamp = jiffies; | 3316 | data->timestamp = jiffies; |
| 3233 | data->read_done_cb = nfs4_read_done_cb; | 3317 | data->read_done_cb = nfs4_read_done_cb; |
| 3234 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; | 3318 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; |
| 3319 | nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); | ||
| 3320 | } | ||
| 3321 | |||
| 3322 | static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) | ||
| 3323 | { | ||
| 3324 | if (nfs4_setup_sequence(NFS_SERVER(data->inode), | ||
| 3325 | &data->args.seq_args, | ||
| 3326 | &data->res.seq_res, | ||
| 3327 | task)) | ||
| 3328 | return; | ||
| 3329 | rpc_call_start(task); | ||
| 3235 | } | 3330 | } |
| 3236 | 3331 | ||
| 3237 | /* Reset the the nfs_read_data to send the read to the MDS. */ | 3332 | /* Reset the the nfs_read_data to send the read to the MDS. */ |
| @@ -3305,6 +3400,17 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag | |||
| 3305 | data->timestamp = jiffies; | 3400 | data->timestamp = jiffies; |
| 3306 | 3401 | ||
| 3307 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; | 3402 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; |
| 3403 | nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); | ||
| 3404 | } | ||
| 3405 | |||
| 3406 | static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data) | ||
| 3407 | { | ||
| 3408 | if (nfs4_setup_sequence(NFS_SERVER(data->inode), | ||
| 3409 | &data->args.seq_args, | ||
| 3410 | &data->res.seq_res, | ||
| 3411 | task)) | ||
| 3412 | return; | ||
| 3413 | rpc_call_start(task); | ||
| 3308 | } | 3414 | } |
| 3309 | 3415 | ||
| 3310 | static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data) | 3416 | static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data) |
| @@ -3339,6 +3445,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa | |||
| 3339 | data->write_done_cb = nfs4_commit_done_cb; | 3445 | data->write_done_cb = nfs4_commit_done_cb; |
| 3340 | data->res.server = server; | 3446 | data->res.server = server; |
| 3341 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; | 3447 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; |
| 3448 | nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); | ||
| 3342 | } | 3449 | } |
| 3343 | 3450 | ||
| 3344 | struct nfs4_renewdata { | 3451 | struct nfs4_renewdata { |
| @@ -3714,8 +3821,11 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
| 3714 | if (task->tk_status >= 0) | 3821 | if (task->tk_status >= 0) |
| 3715 | return 0; | 3822 | return 0; |
| 3716 | switch(task->tk_status) { | 3823 | switch(task->tk_status) { |
| 3824 | case -NFS4ERR_DELEG_REVOKED: | ||
| 3717 | case -NFS4ERR_ADMIN_REVOKED: | 3825 | case -NFS4ERR_ADMIN_REVOKED: |
| 3718 | case -NFS4ERR_BAD_STATEID: | 3826 | case -NFS4ERR_BAD_STATEID: |
| 3827 | if (state != NULL) | ||
| 3828 | nfs_remove_bad_delegation(state->inode); | ||
| 3719 | case -NFS4ERR_OPENMODE: | 3829 | case -NFS4ERR_OPENMODE: |
| 3720 | if (state == NULL) | 3830 | if (state == NULL) |
| 3721 | break; | 3831 | break; |
| @@ -3764,6 +3874,16 @@ wait_on_recovery: | |||
| 3764 | return -EAGAIN; | 3874 | return -EAGAIN; |
| 3765 | } | 3875 | } |
| 3766 | 3876 | ||
| 3877 | static void nfs4_construct_boot_verifier(struct nfs_client *clp, | ||
| 3878 | nfs4_verifier *bootverf) | ||
| 3879 | { | ||
| 3880 | __be32 verf[2]; | ||
| 3881 | |||
| 3882 | verf[0] = htonl((u32)clp->cl_boot_time.tv_sec); | ||
| 3883 | verf[1] = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
| 3884 | memcpy(bootverf->data, verf, sizeof(bootverf->data)); | ||
| 3885 | } | ||
| 3886 | |||
| 3767 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | 3887 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, |
| 3768 | unsigned short port, struct rpc_cred *cred, | 3888 | unsigned short port, struct rpc_cred *cred, |
| 3769 | struct nfs4_setclientid_res *res) | 3889 | struct nfs4_setclientid_res *res) |
| @@ -3780,15 +3900,13 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
| 3780 | .rpc_resp = res, | 3900 | .rpc_resp = res, |
| 3781 | .rpc_cred = cred, | 3901 | .rpc_cred = cred, |
| 3782 | }; | 3902 | }; |
| 3783 | __be32 *p; | ||
| 3784 | int loop = 0; | 3903 | int loop = 0; |
| 3785 | int status; | 3904 | int status; |
| 3786 | 3905 | ||
| 3787 | p = (__be32*)sc_verifier.data; | 3906 | nfs4_construct_boot_verifier(clp, &sc_verifier); |
| 3788 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
| 3789 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
| 3790 | 3907 | ||
| 3791 | for(;;) { | 3908 | for(;;) { |
| 3909 | rcu_read_lock(); | ||
| 3792 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 3910 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
| 3793 | sizeof(setclientid.sc_name), "%s/%s %s %s %u", | 3911 | sizeof(setclientid.sc_name), "%s/%s %s %s %u", |
| 3794 | clp->cl_ipaddr, | 3912 | clp->cl_ipaddr, |
| @@ -3805,6 +3923,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
| 3805 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, | 3923 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, |
| 3806 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", | 3924 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", |
| 3807 | clp->cl_ipaddr, port >> 8, port & 255); | 3925 | clp->cl_ipaddr, port >> 8, port & 255); |
| 3926 | rcu_read_unlock(); | ||
| 3808 | 3927 | ||
| 3809 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 3928 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
| 3810 | if (status != -NFS4ERR_CLID_INUSE) | 3929 | if (status != -NFS4ERR_CLID_INUSE) |
| @@ -3891,7 +4010,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | |||
| 3891 | 4010 | ||
| 3892 | if (nfs4_setup_sequence(d_data->res.server, | 4011 | if (nfs4_setup_sequence(d_data->res.server, |
| 3893 | &d_data->args.seq_args, | 4012 | &d_data->args.seq_args, |
| 3894 | &d_data->res.seq_res, 1, task)) | 4013 | &d_data->res.seq_res, task)) |
| 3895 | return; | 4014 | return; |
| 3896 | rpc_call_start(task); | 4015 | rpc_call_start(task); |
| 3897 | } | 4016 | } |
| @@ -3925,11 +4044,12 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
| 3925 | data = kzalloc(sizeof(*data), GFP_NOFS); | 4044 | data = kzalloc(sizeof(*data), GFP_NOFS); |
| 3926 | if (data == NULL) | 4045 | if (data == NULL) |
| 3927 | return -ENOMEM; | 4046 | return -ENOMEM; |
| 4047 | nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); | ||
| 3928 | data->args.fhandle = &data->fh; | 4048 | data->args.fhandle = &data->fh; |
| 3929 | data->args.stateid = &data->stateid; | 4049 | data->args.stateid = &data->stateid; |
| 3930 | data->args.bitmask = server->attr_bitmask; | 4050 | data->args.bitmask = server->attr_bitmask; |
| 3931 | nfs_copy_fh(&data->fh, NFS_FH(inode)); | 4051 | nfs_copy_fh(&data->fh, NFS_FH(inode)); |
| 3932 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 4052 | nfs4_stateid_copy(&data->stateid, stateid); |
| 3933 | data->res.fattr = &data->fattr; | 4053 | data->res.fattr = &data->fattr; |
| 3934 | data->res.server = server; | 4054 | data->res.server = server; |
| 3935 | nfs_fattr_init(data->res.fattr); | 4055 | nfs_fattr_init(data->res.fattr); |
| @@ -4016,7 +4136,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
| 4016 | if (status != 0) | 4136 | if (status != 0) |
| 4017 | goto out; | 4137 | goto out; |
| 4018 | lsp = request->fl_u.nfs4_fl.owner; | 4138 | lsp = request->fl_u.nfs4_fl.owner; |
| 4019 | arg.lock_owner.id = lsp->ls_id.id; | 4139 | arg.lock_owner.id = lsp->ls_seqid.owner_id; |
| 4020 | arg.lock_owner.s_dev = server->s_dev; | 4140 | arg.lock_owner.s_dev = server->s_dev; |
| 4021 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); | 4141 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
| 4022 | switch (status) { | 4142 | switch (status) { |
| @@ -4112,9 +4232,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
| 4112 | return; | 4232 | return; |
| 4113 | switch (task->tk_status) { | 4233 | switch (task->tk_status) { |
| 4114 | case 0: | 4234 | case 0: |
| 4115 | memcpy(calldata->lsp->ls_stateid.data, | 4235 | nfs4_stateid_copy(&calldata->lsp->ls_stateid, |
| 4116 | calldata->res.stateid.data, | 4236 | &calldata->res.stateid); |
| 4117 | sizeof(calldata->lsp->ls_stateid.data)); | ||
| 4118 | renew_lease(calldata->server, calldata->timestamp); | 4237 | renew_lease(calldata->server, calldata->timestamp); |
| 4119 | break; | 4238 | break; |
| 4120 | case -NFS4ERR_BAD_STATEID: | 4239 | case -NFS4ERR_BAD_STATEID: |
| @@ -4142,7 +4261,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
| 4142 | calldata->timestamp = jiffies; | 4261 | calldata->timestamp = jiffies; |
| 4143 | if (nfs4_setup_sequence(calldata->server, | 4262 | if (nfs4_setup_sequence(calldata->server, |
| 4144 | &calldata->arg.seq_args, | 4263 | &calldata->arg.seq_args, |
| 4145 | &calldata->res.seq_res, 1, task)) | 4264 | &calldata->res.seq_res, task)) |
| 4146 | return; | 4265 | return; |
| 4147 | rpc_call_start(task); | 4266 | rpc_call_start(task); |
| 4148 | } | 4267 | } |
| @@ -4182,6 +4301,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
| 4182 | return ERR_PTR(-ENOMEM); | 4301 | return ERR_PTR(-ENOMEM); |
| 4183 | } | 4302 | } |
| 4184 | 4303 | ||
| 4304 | nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1); | ||
| 4185 | msg.rpc_argp = &data->arg; | 4305 | msg.rpc_argp = &data->arg; |
| 4186 | msg.rpc_resp = &data->res; | 4306 | msg.rpc_resp = &data->res; |
| 4187 | task_setup_data.callback_data = data; | 4307 | task_setup_data.callback_data = data; |
| @@ -4261,7 +4381,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
| 4261 | goto out_free_seqid; | 4381 | goto out_free_seqid; |
| 4262 | p->arg.lock_stateid = &lsp->ls_stateid; | 4382 | p->arg.lock_stateid = &lsp->ls_stateid; |
| 4263 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 4383 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
| 4264 | p->arg.lock_owner.id = lsp->ls_id.id; | 4384 | p->arg.lock_owner.id = lsp->ls_seqid.owner_id; |
| 4265 | p->arg.lock_owner.s_dev = server->s_dev; | 4385 | p->arg.lock_owner.s_dev = server->s_dev; |
| 4266 | p->res.lock_seqid = p->arg.lock_seqid; | 4386 | p->res.lock_seqid = p->arg.lock_seqid; |
| 4267 | p->lsp = lsp; | 4387 | p->lsp = lsp; |
| @@ -4297,7 +4417,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
| 4297 | data->timestamp = jiffies; | 4417 | data->timestamp = jiffies; |
| 4298 | if (nfs4_setup_sequence(data->server, | 4418 | if (nfs4_setup_sequence(data->server, |
| 4299 | &data->arg.seq_args, | 4419 | &data->arg.seq_args, |
| 4300 | &data->res.seq_res, 1, task)) | 4420 | &data->res.seq_res, task)) |
| 4301 | return; | 4421 | return; |
| 4302 | rpc_call_start(task); | 4422 | rpc_call_start(task); |
| 4303 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 4423 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
| @@ -4326,8 +4446,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
| 4326 | goto out; | 4446 | goto out; |
| 4327 | } | 4447 | } |
| 4328 | if (data->rpc_status == 0) { | 4448 | if (data->rpc_status == 0) { |
| 4329 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, | 4449 | nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid); |
| 4330 | sizeof(data->lsp->ls_stateid.data)); | ||
| 4331 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 4450 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; |
| 4332 | renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); | 4451 | renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); |
| 4333 | } | 4452 | } |
| @@ -4415,6 +4534,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
| 4415 | data->arg.reclaim = NFS_LOCK_RECLAIM; | 4534 | data->arg.reclaim = NFS_LOCK_RECLAIM; |
| 4416 | task_setup_data.callback_ops = &nfs4_recover_lock_ops; | 4535 | task_setup_data.callback_ops = &nfs4_recover_lock_ops; |
| 4417 | } | 4536 | } |
| 4537 | nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1); | ||
| 4418 | msg.rpc_argp = &data->arg; | 4538 | msg.rpc_argp = &data->arg; |
| 4419 | msg.rpc_resp = &data->res; | 4539 | msg.rpc_resp = &data->res; |
| 4420 | task_setup_data.callback_data = data; | 4540 | task_setup_data.callback_data = data; |
| @@ -4479,15 +4599,34 @@ out: | |||
| 4479 | } | 4599 | } |
| 4480 | 4600 | ||
| 4481 | #if defined(CONFIG_NFS_V4_1) | 4601 | #if defined(CONFIG_NFS_V4_1) |
| 4482 | static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request) | 4602 | static int nfs41_check_expired_locks(struct nfs4_state *state) |
| 4483 | { | 4603 | { |
| 4484 | int status; | 4604 | int status, ret = NFS_OK; |
| 4605 | struct nfs4_lock_state *lsp; | ||
| 4485 | struct nfs_server *server = NFS_SERVER(state->inode); | 4606 | struct nfs_server *server = NFS_SERVER(state->inode); |
| 4486 | 4607 | ||
| 4487 | status = nfs41_test_stateid(server, state); | 4608 | list_for_each_entry(lsp, &state->lock_states, ls_locks) { |
| 4609 | if (lsp->ls_flags & NFS_LOCK_INITIALIZED) { | ||
| 4610 | status = nfs41_test_stateid(server, &lsp->ls_stateid); | ||
| 4611 | if (status != NFS_OK) { | ||
| 4612 | nfs41_free_stateid(server, &lsp->ls_stateid); | ||
| 4613 | lsp->ls_flags &= ~NFS_LOCK_INITIALIZED; | ||
| 4614 | ret = status; | ||
| 4615 | } | ||
| 4616 | } | ||
| 4617 | }; | ||
| 4618 | |||
| 4619 | return ret; | ||
| 4620 | } | ||
| 4621 | |||
| 4622 | static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request) | ||
| 4623 | { | ||
| 4624 | int status = NFS_OK; | ||
| 4625 | |||
| 4626 | if (test_bit(LK_STATE_IN_USE, &state->flags)) | ||
| 4627 | status = nfs41_check_expired_locks(state); | ||
| 4488 | if (status == NFS_OK) | 4628 | if (status == NFS_OK) |
| 4489 | return 0; | 4629 | return status; |
| 4490 | nfs41_free_stateid(server, state); | ||
| 4491 | return nfs4_lock_expired(state, request); | 4630 | return nfs4_lock_expired(state, request); |
| 4492 | } | 4631 | } |
| 4493 | #endif | 4632 | #endif |
| @@ -4523,7 +4662,8 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
| 4523 | /* Note: we always want to sleep here! */ | 4662 | /* Note: we always want to sleep here! */ |
| 4524 | request->fl_flags = fl_flags | FL_SLEEP; | 4663 | request->fl_flags = fl_flags | FL_SLEEP; |
| 4525 | if (do_vfs_lock(request->fl_file, request) < 0) | 4664 | if (do_vfs_lock(request->fl_file, request) < 0) |
| 4526 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__); | 4665 | printk(KERN_WARNING "NFS: %s: VFS is out of sync with lock " |
| 4666 | "manager!\n", __func__); | ||
| 4527 | out_unlock: | 4667 | out_unlock: |
| 4528 | up_read(&nfsi->rwsem); | 4668 | up_read(&nfsi->rwsem); |
| 4529 | out: | 4669 | out: |
| @@ -4533,7 +4673,9 @@ out: | |||
| 4533 | 4673 | ||
| 4534 | static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 4674 | static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
| 4535 | { | 4675 | { |
| 4536 | struct nfs4_exception exception = { }; | 4676 | struct nfs4_exception exception = { |
| 4677 | .state = state, | ||
| 4678 | }; | ||
| 4537 | int err; | 4679 | int err; |
| 4538 | 4680 | ||
| 4539 | do { | 4681 | do { |
| @@ -4603,8 +4745,8 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
| 4603 | err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); | 4745 | err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); |
| 4604 | switch (err) { | 4746 | switch (err) { |
| 4605 | default: | 4747 | default: |
| 4606 | printk(KERN_ERR "%s: unhandled error %d.\n", | 4748 | printk(KERN_ERR "NFS: %s: unhandled error " |
| 4607 | __func__, err); | 4749 | "%d.\n", __func__, err); |
| 4608 | case 0: | 4750 | case 0: |
| 4609 | case -ESTALE: | 4751 | case -ESTALE: |
| 4610 | goto out; | 4752 | goto out; |
| @@ -4626,6 +4768,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
| 4626 | * The show must go on: exit, but mark the | 4768 | * The show must go on: exit, but mark the |
| 4627 | * stateid as needing recovery. | 4769 | * stateid as needing recovery. |
| 4628 | */ | 4770 | */ |
| 4771 | case -NFS4ERR_DELEG_REVOKED: | ||
| 4629 | case -NFS4ERR_ADMIN_REVOKED: | 4772 | case -NFS4ERR_ADMIN_REVOKED: |
| 4630 | case -NFS4ERR_BAD_STATEID: | 4773 | case -NFS4ERR_BAD_STATEID: |
| 4631 | case -NFS4ERR_OPENMODE: | 4774 | case -NFS4ERR_OPENMODE: |
| @@ -4655,33 +4798,44 @@ out: | |||
| 4655 | return err; | 4798 | return err; |
| 4656 | } | 4799 | } |
| 4657 | 4800 | ||
| 4801 | struct nfs_release_lockowner_data { | ||
| 4802 | struct nfs4_lock_state *lsp; | ||
| 4803 | struct nfs_server *server; | ||
| 4804 | struct nfs_release_lockowner_args args; | ||
| 4805 | }; | ||
| 4806 | |||
| 4658 | static void nfs4_release_lockowner_release(void *calldata) | 4807 | static void nfs4_release_lockowner_release(void *calldata) |
| 4659 | { | 4808 | { |
| 4809 | struct nfs_release_lockowner_data *data = calldata; | ||
| 4810 | nfs4_free_lock_state(data->server, data->lsp); | ||
| 4660 | kfree(calldata); | 4811 | kfree(calldata); |
| 4661 | } | 4812 | } |
| 4662 | 4813 | ||
| 4663 | const struct rpc_call_ops nfs4_release_lockowner_ops = { | 4814 | static const struct rpc_call_ops nfs4_release_lockowner_ops = { |
| 4664 | .rpc_release = nfs4_release_lockowner_release, | 4815 | .rpc_release = nfs4_release_lockowner_release, |
| 4665 | }; | 4816 | }; |
| 4666 | 4817 | ||
| 4667 | void nfs4_release_lockowner(const struct nfs4_lock_state *lsp) | 4818 | int nfs4_release_lockowner(struct nfs4_lock_state *lsp) |
| 4668 | { | 4819 | { |
| 4669 | struct nfs_server *server = lsp->ls_state->owner->so_server; | 4820 | struct nfs_server *server = lsp->ls_state->owner->so_server; |
| 4670 | struct nfs_release_lockowner_args *args; | 4821 | struct nfs_release_lockowner_data *data; |
| 4671 | struct rpc_message msg = { | 4822 | struct rpc_message msg = { |
| 4672 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER], | 4823 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER], |
| 4673 | }; | 4824 | }; |
| 4674 | 4825 | ||
| 4675 | if (server->nfs_client->cl_mvops->minor_version != 0) | 4826 | if (server->nfs_client->cl_mvops->minor_version != 0) |
| 4676 | return; | 4827 | return -EINVAL; |
| 4677 | args = kmalloc(sizeof(*args), GFP_NOFS); | 4828 | data = kmalloc(sizeof(*data), GFP_NOFS); |
| 4678 | if (!args) | 4829 | if (!data) |
| 4679 | return; | 4830 | return -ENOMEM; |
| 4680 | args->lock_owner.clientid = server->nfs_client->cl_clientid; | 4831 | data->lsp = lsp; |
| 4681 | args->lock_owner.id = lsp->ls_id.id; | 4832 | data->server = server; |
| 4682 | args->lock_owner.s_dev = server->s_dev; | 4833 | data->args.lock_owner.clientid = server->nfs_client->cl_clientid; |
| 4683 | msg.rpc_argp = args; | 4834 | data->args.lock_owner.id = lsp->ls_seqid.owner_id; |
| 4684 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args); | 4835 | data->args.lock_owner.s_dev = server->s_dev; |
| 4836 | msg.rpc_argp = &data->args; | ||
| 4837 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data); | ||
| 4838 | return 0; | ||
| 4685 | } | 4839 | } |
| 4686 | 4840 | ||
| 4687 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | 4841 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" |
| @@ -4727,11 +4881,11 @@ static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr) | |||
| 4727 | if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) || | 4881 | if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) || |
| 4728 | (fattr->valid & NFS_ATTR_FATTR_FILEID)) && | 4882 | (fattr->valid & NFS_ATTR_FATTR_FILEID)) && |
| 4729 | (fattr->valid & NFS_ATTR_FATTR_FSID) && | 4883 | (fattr->valid & NFS_ATTR_FATTR_FSID) && |
| 4730 | (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL))) | 4884 | (fattr->valid & NFS_ATTR_FATTR_V4_LOCATIONS))) |
| 4731 | return; | 4885 | return; |
| 4732 | 4886 | ||
| 4733 | fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | | 4887 | fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | |
| 4734 | NFS_ATTR_FATTR_NLINK; | 4888 | NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_V4_REFERRAL; |
| 4735 | fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 4889 | fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO; |
| 4736 | fattr->nlink = 2; | 4890 | fattr->nlink = 2; |
| 4737 | } | 4891 | } |
| @@ -4798,7 +4952,8 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct | |||
| 4798 | return status; | 4952 | return status; |
| 4799 | } | 4953 | } |
| 4800 | 4954 | ||
| 4801 | int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) | 4955 | static int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, |
| 4956 | struct nfs4_secinfo_flavors *flavors) | ||
| 4802 | { | 4957 | { |
| 4803 | struct nfs4_exception exception = { }; | 4958 | struct nfs4_exception exception = { }; |
| 4804 | int err; | 4959 | int err; |
| @@ -4852,6 +5007,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 4852 | { | 5007 | { |
| 4853 | nfs4_verifier verifier; | 5008 | nfs4_verifier verifier; |
| 4854 | struct nfs41_exchange_id_args args = { | 5009 | struct nfs41_exchange_id_args args = { |
| 5010 | .verifier = &verifier, | ||
| 4855 | .client = clp, | 5011 | .client = clp, |
| 4856 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER, | 5012 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER, |
| 4857 | }; | 5013 | }; |
| @@ -4865,15 +5021,11 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 4865 | .rpc_resp = &res, | 5021 | .rpc_resp = &res, |
| 4866 | .rpc_cred = cred, | 5022 | .rpc_cred = cred, |
| 4867 | }; | 5023 | }; |
| 4868 | __be32 *p; | ||
| 4869 | 5024 | ||
| 4870 | dprintk("--> %s\n", __func__); | 5025 | dprintk("--> %s\n", __func__); |
| 4871 | BUG_ON(clp == NULL); | 5026 | BUG_ON(clp == NULL); |
| 4872 | 5027 | ||
| 4873 | p = (u32 *)verifier.data; | 5028 | nfs4_construct_boot_verifier(clp, &verifier); |
| 4874 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
| 4875 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
| 4876 | args.verifier = &verifier; | ||
| 4877 | 5029 | ||
| 4878 | args.id_len = scnprintf(args.id, sizeof(args.id), | 5030 | args.id_len = scnprintf(args.id, sizeof(args.id), |
| 4879 | "%s/%s.%s/%u", | 5031 | "%s/%s.%s/%u", |
| @@ -4888,11 +5040,24 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 4888 | goto out; | 5040 | goto out; |
| 4889 | } | 5041 | } |
| 4890 | 5042 | ||
| 5043 | res.impl_id = kzalloc(sizeof(struct nfs41_impl_id), GFP_KERNEL); | ||
| 5044 | if (unlikely(!res.impl_id)) { | ||
| 5045 | status = -ENOMEM; | ||
| 5046 | goto out_server_scope; | ||
| 5047 | } | ||
| 5048 | |||
| 4891 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 5049 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
| 4892 | if (!status) | 5050 | if (!status) |
| 4893 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); | 5051 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); |
| 4894 | 5052 | ||
| 4895 | if (!status) { | 5053 | if (!status) { |
| 5054 | /* use the most recent implementation id */ | ||
| 5055 | kfree(clp->impl_id); | ||
| 5056 | clp->impl_id = res.impl_id; | ||
| 5057 | } else | ||
| 5058 | kfree(res.impl_id); | ||
| 5059 | |||
| 5060 | if (!status) { | ||
| 4896 | if (clp->server_scope && | 5061 | if (clp->server_scope && |
| 4897 | !nfs41_same_server_scope(clp->server_scope, | 5062 | !nfs41_same_server_scope(clp->server_scope, |
| 4898 | res.server_scope)) { | 5063 | res.server_scope)) { |
| @@ -4908,8 +5073,16 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 4908 | goto out; | 5073 | goto out; |
| 4909 | } | 5074 | } |
| 4910 | } | 5075 | } |
| 5076 | |||
| 5077 | out_server_scope: | ||
| 4911 | kfree(res.server_scope); | 5078 | kfree(res.server_scope); |
| 4912 | out: | 5079 | out: |
| 5080 | if (clp->impl_id) | ||
| 5081 | dprintk("%s: Server Implementation ID: " | ||
| 5082 | "domain: %s, name: %s, date: %llu,%u\n", | ||
| 5083 | __func__, clp->impl_id->domain, clp->impl_id->name, | ||
| 5084 | clp->impl_id->date.seconds, | ||
| 5085 | clp->impl_id->date.nseconds); | ||
| 4913 | dprintk("<-- %s status= %d\n", __func__, status); | 5086 | dprintk("<-- %s status= %d\n", __func__, status); |
| 4914 | return status; | 5087 | return status; |
| 4915 | } | 5088 | } |
| @@ -4933,7 +5106,7 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task, | |||
| 4933 | since we're invoked within one */ | 5106 | since we're invoked within one */ |
| 4934 | ret = nfs41_setup_sequence(data->clp->cl_session, | 5107 | ret = nfs41_setup_sequence(data->clp->cl_session, |
| 4935 | &data->args->la_seq_args, | 5108 | &data->args->la_seq_args, |
| 4936 | &data->res->lr_seq_res, 0, task); | 5109 | &data->res->lr_seq_res, task); |
| 4937 | 5110 | ||
| 4938 | BUG_ON(ret == -EAGAIN); | 5111 | BUG_ON(ret == -EAGAIN); |
| 4939 | rpc_call_start(task); | 5112 | rpc_call_start(task); |
| @@ -4966,7 +5139,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
| 4966 | dprintk("<-- %s\n", __func__); | 5139 | dprintk("<-- %s\n", __func__); |
| 4967 | } | 5140 | } |
| 4968 | 5141 | ||
| 4969 | struct rpc_call_ops nfs4_get_lease_time_ops = { | 5142 | static const struct rpc_call_ops nfs4_get_lease_time_ops = { |
| 4970 | .rpc_call_prepare = nfs4_get_lease_time_prepare, | 5143 | .rpc_call_prepare = nfs4_get_lease_time_prepare, |
| 4971 | .rpc_call_done = nfs4_get_lease_time_done, | 5144 | .rpc_call_done = nfs4_get_lease_time_done, |
| 4972 | }; | 5145 | }; |
| @@ -4997,6 +5170,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
| 4997 | }; | 5170 | }; |
| 4998 | int status; | 5171 | int status; |
| 4999 | 5172 | ||
| 5173 | nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0); | ||
| 5000 | dprintk("--> %s\n", __func__); | 5174 | dprintk("--> %s\n", __func__); |
| 5001 | task = rpc_run_task(&task_setup); | 5175 | task = rpc_run_task(&task_setup); |
| 5002 | 5176 | ||
| @@ -5113,13 +5287,13 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
| 5113 | return NULL; | 5287 | return NULL; |
| 5114 | 5288 | ||
| 5115 | tbl = &session->fc_slot_table; | 5289 | tbl = &session->fc_slot_table; |
| 5116 | tbl->highest_used_slotid = -1; | 5290 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
| 5117 | spin_lock_init(&tbl->slot_tbl_lock); | 5291 | spin_lock_init(&tbl->slot_tbl_lock); |
| 5118 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | 5292 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); |
| 5119 | init_completion(&tbl->complete); | 5293 | init_completion(&tbl->complete); |
| 5120 | 5294 | ||
| 5121 | tbl = &session->bc_slot_table; | 5295 | tbl = &session->bc_slot_table; |
| 5122 | tbl->highest_used_slotid = -1; | 5296 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
| 5123 | spin_lock_init(&tbl->slot_tbl_lock); | 5297 | spin_lock_init(&tbl->slot_tbl_lock); |
| 5124 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | 5298 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); |
| 5125 | init_completion(&tbl->complete); | 5299 | init_completion(&tbl->complete); |
| @@ -5132,11 +5306,16 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
| 5132 | 5306 | ||
| 5133 | void nfs4_destroy_session(struct nfs4_session *session) | 5307 | void nfs4_destroy_session(struct nfs4_session *session) |
| 5134 | { | 5308 | { |
| 5309 | struct rpc_xprt *xprt; | ||
| 5310 | |||
| 5135 | nfs4_proc_destroy_session(session); | 5311 | nfs4_proc_destroy_session(session); |
| 5312 | |||
| 5313 | rcu_read_lock(); | ||
| 5314 | xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt); | ||
| 5315 | rcu_read_unlock(); | ||
| 5136 | dprintk("%s Destroy backchannel for xprt %p\n", | 5316 | dprintk("%s Destroy backchannel for xprt %p\n", |
| 5137 | __func__, session->clp->cl_rpcclient->cl_xprt); | 5317 | __func__, xprt); |
| 5138 | xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, | 5318 | xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS); |
| 5139 | NFS41_BC_MIN_CALLBACKS); | ||
| 5140 | nfs4_destroy_slot_tables(session); | 5319 | nfs4_destroy_slot_tables(session); |
| 5141 | kfree(session); | 5320 | kfree(session); |
| 5142 | } | 5321 | } |
| @@ -5164,7 +5343,7 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
| 5164 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | 5343 | args->fc_attrs.max_rqst_sz = mxrqst_sz; |
| 5165 | args->fc_attrs.max_resp_sz = mxresp_sz; | 5344 | args->fc_attrs.max_resp_sz = mxresp_sz; |
| 5166 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | 5345 | args->fc_attrs.max_ops = NFS4_MAX_OPS; |
| 5167 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | 5346 | args->fc_attrs.max_reqs = max_session_slots; |
| 5168 | 5347 | ||
| 5169 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | 5348 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " |
| 5170 | "max_ops=%u max_reqs=%u\n", | 5349 | "max_ops=%u max_reqs=%u\n", |
| @@ -5204,6 +5383,8 @@ static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args | |||
| 5204 | return -EINVAL; | 5383 | return -EINVAL; |
| 5205 | if (rcvd->max_reqs == 0) | 5384 | if (rcvd->max_reqs == 0) |
| 5206 | return -EINVAL; | 5385 | return -EINVAL; |
| 5386 | if (rcvd->max_reqs > NFS4_MAX_SLOT_TABLE) | ||
| 5387 | rcvd->max_reqs = NFS4_MAX_SLOT_TABLE; | ||
| 5207 | return 0; | 5388 | return 0; |
| 5208 | } | 5389 | } |
| 5209 | 5390 | ||
| @@ -5219,9 +5400,9 @@ static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args | |||
| 5219 | if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached) | 5400 | if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached) |
| 5220 | return -EINVAL; | 5401 | return -EINVAL; |
| 5221 | /* These would render the backchannel useless: */ | 5402 | /* These would render the backchannel useless: */ |
| 5222 | if (rcvd->max_ops == 0) | 5403 | if (rcvd->max_ops != sent->max_ops) |
| 5223 | return -EINVAL; | 5404 | return -EINVAL; |
| 5224 | if (rcvd->max_reqs == 0) | 5405 | if (rcvd->max_reqs != sent->max_reqs) |
| 5225 | return -EINVAL; | 5406 | return -EINVAL; |
| 5226 | return 0; | 5407 | return 0; |
| 5227 | } | 5408 | } |
| @@ -5324,7 +5505,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session) | |||
| 5324 | 5505 | ||
| 5325 | if (status) | 5506 | if (status) |
| 5326 | printk(KERN_WARNING | 5507 | printk(KERN_WARNING |
| 5327 | "Got error %d from the server on DESTROY_SESSION. " | 5508 | "NFS: Got error %d from the server on DESTROY_SESSION. " |
| 5328 | "Session has been destroyed regardless...\n", status); | 5509 | "Session has been destroyed regardless...\n", status); |
| 5329 | 5510 | ||
| 5330 | dprintk("<-- nfs4_proc_destroy_session\n"); | 5511 | dprintk("<-- nfs4_proc_destroy_session\n"); |
| @@ -5447,7 +5628,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | |||
| 5447 | args = task->tk_msg.rpc_argp; | 5628 | args = task->tk_msg.rpc_argp; |
| 5448 | res = task->tk_msg.rpc_resp; | 5629 | res = task->tk_msg.rpc_resp; |
| 5449 | 5630 | ||
| 5450 | if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task)) | 5631 | if (nfs41_setup_sequence(clp->cl_session, args, res, task)) |
| 5451 | return; | 5632 | return; |
| 5452 | rpc_call_start(task); | 5633 | rpc_call_start(task); |
| 5453 | } | 5634 | } |
| @@ -5479,6 +5660,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_ | |||
| 5479 | nfs_put_client(clp); | 5660 | nfs_put_client(clp); |
| 5480 | return ERR_PTR(-ENOMEM); | 5661 | return ERR_PTR(-ENOMEM); |
| 5481 | } | 5662 | } |
| 5663 | nfs41_init_sequence(&calldata->args, &calldata->res, 0); | ||
| 5482 | msg.rpc_argp = &calldata->args; | 5664 | msg.rpc_argp = &calldata->args; |
| 5483 | msg.rpc_resp = &calldata->res; | 5665 | msg.rpc_resp = &calldata->res; |
| 5484 | calldata->clp = clp; | 5666 | calldata->clp = clp; |
| @@ -5540,7 +5722,7 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) | |||
| 5540 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | 5722 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); |
| 5541 | if (nfs41_setup_sequence(calldata->clp->cl_session, | 5723 | if (nfs41_setup_sequence(calldata->clp->cl_session, |
| 5542 | &calldata->arg.seq_args, | 5724 | &calldata->arg.seq_args, |
| 5543 | &calldata->res.seq_res, 0, task)) | 5725 | &calldata->res.seq_res, task)) |
| 5544 | return; | 5726 | return; |
| 5545 | 5727 | ||
| 5546 | rpc_call_start(task); | 5728 | rpc_call_start(task); |
| @@ -5619,6 +5801,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | |||
| 5619 | calldata->clp = clp; | 5801 | calldata->clp = clp; |
| 5620 | calldata->arg.one_fs = 0; | 5802 | calldata->arg.one_fs = 0; |
| 5621 | 5803 | ||
| 5804 | nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0); | ||
| 5622 | msg.rpc_argp = &calldata->arg; | 5805 | msg.rpc_argp = &calldata->arg; |
| 5623 | msg.rpc_resp = &calldata->res; | 5806 | msg.rpc_resp = &calldata->res; |
| 5624 | task_setup_data.callback_data = calldata; | 5807 | task_setup_data.callback_data = calldata; |
| @@ -5650,7 +5833,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata) | |||
| 5650 | * to be no way to prevent it completely. | 5833 | * to be no way to prevent it completely. |
| 5651 | */ | 5834 | */ |
| 5652 | if (nfs4_setup_sequence(server, &lgp->args.seq_args, | 5835 | if (nfs4_setup_sequence(server, &lgp->args.seq_args, |
| 5653 | &lgp->res.seq_res, 0, task)) | 5836 | &lgp->res.seq_res, task)) |
| 5654 | return; | 5837 | return; |
| 5655 | if (pnfs_choose_layoutget_stateid(&lgp->args.stateid, | 5838 | if (pnfs_choose_layoutget_stateid(&lgp->args.stateid, |
| 5656 | NFS_I(lgp->args.inode)->layout, | 5839 | NFS_I(lgp->args.inode)->layout, |
| @@ -5725,6 +5908,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | |||
| 5725 | 5908 | ||
| 5726 | lgp->res.layoutp = &lgp->args.layout; | 5909 | lgp->res.layoutp = &lgp->args.layout; |
| 5727 | lgp->res.seq_res.sr_slot = NULL; | 5910 | lgp->res.seq_res.sr_slot = NULL; |
| 5911 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); | ||
| 5728 | task = rpc_run_task(&task_setup_data); | 5912 | task = rpc_run_task(&task_setup_data); |
| 5729 | if (IS_ERR(task)) | 5913 | if (IS_ERR(task)) |
| 5730 | return PTR_ERR(task); | 5914 | return PTR_ERR(task); |
| @@ -5745,7 +5929,7 @@ nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata) | |||
| 5745 | 5929 | ||
| 5746 | dprintk("--> %s\n", __func__); | 5930 | dprintk("--> %s\n", __func__); |
| 5747 | if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args, | 5931 | if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args, |
| 5748 | &lrp->res.seq_res, 0, task)) | 5932 | &lrp->res.seq_res, task)) |
| 5749 | return; | 5933 | return; |
| 5750 | rpc_call_start(task); | 5934 | rpc_call_start(task); |
| 5751 | } | 5935 | } |
| @@ -5811,6 +5995,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp) | |||
| 5811 | int status; | 5995 | int status; |
| 5812 | 5996 | ||
| 5813 | dprintk("--> %s\n", __func__); | 5997 | dprintk("--> %s\n", __func__); |
| 5998 | nfs41_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1); | ||
| 5814 | task = rpc_run_task(&task_setup_data); | 5999 | task = rpc_run_task(&task_setup_data); |
| 5815 | if (IS_ERR(task)) | 6000 | if (IS_ERR(task)) |
| 5816 | return PTR_ERR(task); | 6001 | return PTR_ERR(task); |
| @@ -5911,7 +6096,7 @@ static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata) | |||
| 5911 | struct nfs_server *server = NFS_SERVER(data->args.inode); | 6096 | struct nfs_server *server = NFS_SERVER(data->args.inode); |
| 5912 | 6097 | ||
| 5913 | if (nfs4_setup_sequence(server, &data->args.seq_args, | 6098 | if (nfs4_setup_sequence(server, &data->args.seq_args, |
| 5914 | &data->res.seq_res, 1, task)) | 6099 | &data->res.seq_res, task)) |
| 5915 | return; | 6100 | return; |
| 5916 | rpc_call_start(task); | 6101 | rpc_call_start(task); |
| 5917 | } | 6102 | } |
| @@ -5998,6 +6183,7 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync) | |||
| 5998 | data->args.lastbytewritten, | 6183 | data->args.lastbytewritten, |
| 5999 | data->args.inode->i_ino); | 6184 | data->args.inode->i_ino); |
| 6000 | 6185 | ||
| 6186 | nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); | ||
| 6001 | task = rpc_run_task(&task_setup_data); | 6187 | task = rpc_run_task(&task_setup_data); |
| 6002 | if (IS_ERR(task)) | 6188 | if (IS_ERR(task)) |
| 6003 | return PTR_ERR(task); | 6189 | return PTR_ERR(task); |
| @@ -6091,11 +6277,12 @@ out_freepage: | |||
| 6091 | out: | 6277 | out: |
| 6092 | return err; | 6278 | return err; |
| 6093 | } | 6279 | } |
| 6094 | static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state) | 6280 | |
| 6281 | static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) | ||
| 6095 | { | 6282 | { |
| 6096 | int status; | 6283 | int status; |
| 6097 | struct nfs41_test_stateid_args args = { | 6284 | struct nfs41_test_stateid_args args = { |
| 6098 | .stateid = &state->stateid, | 6285 | .stateid = stateid, |
| 6099 | }; | 6286 | }; |
| 6100 | struct nfs41_test_stateid_res res; | 6287 | struct nfs41_test_stateid_res res; |
| 6101 | struct rpc_message msg = { | 6288 | struct rpc_message msg = { |
| @@ -6103,28 +6290,31 @@ static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *sta | |||
| 6103 | .rpc_argp = &args, | 6290 | .rpc_argp = &args, |
| 6104 | .rpc_resp = &res, | 6291 | .rpc_resp = &res, |
| 6105 | }; | 6292 | }; |
| 6106 | args.seq_args.sa_session = res.seq_res.sr_session = NULL; | 6293 | |
| 6107 | status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1); | 6294 | nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); |
| 6295 | status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); | ||
| 6296 | |||
| 6297 | if (status == NFS_OK) | ||
| 6298 | return res.status; | ||
| 6108 | return status; | 6299 | return status; |
| 6109 | } | 6300 | } |
| 6110 | 6301 | ||
| 6111 | static int nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state) | 6302 | static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) |
| 6112 | { | 6303 | { |
| 6113 | struct nfs4_exception exception = { }; | 6304 | struct nfs4_exception exception = { }; |
| 6114 | int err; | 6305 | int err; |
| 6115 | do { | 6306 | do { |
| 6116 | err = nfs4_handle_exception(server, | 6307 | err = nfs4_handle_exception(server, |
| 6117 | _nfs41_test_stateid(server, state), | 6308 | _nfs41_test_stateid(server, stateid), |
| 6118 | &exception); | 6309 | &exception); |
| 6119 | } while (exception.retry); | 6310 | } while (exception.retry); |
| 6120 | return err; | 6311 | return err; |
| 6121 | } | 6312 | } |
| 6122 | 6313 | ||
| 6123 | static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *state) | 6314 | static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) |
| 6124 | { | 6315 | { |
| 6125 | int status; | ||
| 6126 | struct nfs41_free_stateid_args args = { | 6316 | struct nfs41_free_stateid_args args = { |
| 6127 | .stateid = &state->stateid, | 6317 | .stateid = stateid, |
| 6128 | }; | 6318 | }; |
| 6129 | struct nfs41_free_stateid_res res; | 6319 | struct nfs41_free_stateid_res res; |
| 6130 | struct rpc_message msg = { | 6320 | struct rpc_message msg = { |
| @@ -6133,25 +6323,46 @@ static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *stat | |||
| 6133 | .rpc_resp = &res, | 6323 | .rpc_resp = &res, |
| 6134 | }; | 6324 | }; |
| 6135 | 6325 | ||
| 6136 | args.seq_args.sa_session = res.seq_res.sr_session = NULL; | 6326 | nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); |
| 6137 | status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1); | 6327 | return nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); |
| 6138 | return status; | ||
| 6139 | } | 6328 | } |
| 6140 | 6329 | ||
| 6141 | static int nfs41_free_stateid(struct nfs_server *server, struct nfs4_state *state) | 6330 | static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) |
| 6142 | { | 6331 | { |
| 6143 | struct nfs4_exception exception = { }; | 6332 | struct nfs4_exception exception = { }; |
| 6144 | int err; | 6333 | int err; |
| 6145 | do { | 6334 | do { |
| 6146 | err = nfs4_handle_exception(server, | 6335 | err = nfs4_handle_exception(server, |
| 6147 | _nfs4_free_stateid(server, state), | 6336 | _nfs4_free_stateid(server, stateid), |
| 6148 | &exception); | 6337 | &exception); |
| 6149 | } while (exception.retry); | 6338 | } while (exception.retry); |
| 6150 | return err; | 6339 | return err; |
| 6151 | } | 6340 | } |
| 6341 | |||
| 6342 | static bool nfs41_match_stateid(const nfs4_stateid *s1, | ||
| 6343 | const nfs4_stateid *s2) | ||
| 6344 | { | ||
| 6345 | if (memcmp(s1->other, s2->other, sizeof(s1->other)) != 0) | ||
| 6346 | return false; | ||
| 6347 | |||
| 6348 | if (s1->seqid == s2->seqid) | ||
| 6349 | return true; | ||
| 6350 | if (s1->seqid == 0 || s2->seqid == 0) | ||
| 6351 | return true; | ||
| 6352 | |||
| 6353 | return false; | ||
| 6354 | } | ||
| 6355 | |||
| 6152 | #endif /* CONFIG_NFS_V4_1 */ | 6356 | #endif /* CONFIG_NFS_V4_1 */ |
| 6153 | 6357 | ||
| 6154 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 6358 | static bool nfs4_match_stateid(const nfs4_stateid *s1, |
| 6359 | const nfs4_stateid *s2) | ||
| 6360 | { | ||
| 6361 | return nfs4_stateid_match(s1, s2); | ||
| 6362 | } | ||
| 6363 | |||
| 6364 | |||
| 6365 | static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | ||
| 6155 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | 6366 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, |
| 6156 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 6367 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
| 6157 | .recover_open = nfs4_open_reclaim, | 6368 | .recover_open = nfs4_open_reclaim, |
| @@ -6161,7 +6372,7 @@ struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | |||
| 6161 | }; | 6372 | }; |
| 6162 | 6373 | ||
| 6163 | #if defined(CONFIG_NFS_V4_1) | 6374 | #if defined(CONFIG_NFS_V4_1) |
| 6164 | struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | 6375 | static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { |
| 6165 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | 6376 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, |
| 6166 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 6377 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
| 6167 | .recover_open = nfs4_open_reclaim, | 6378 | .recover_open = nfs4_open_reclaim, |
| @@ -6172,7 +6383,7 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | |||
| 6172 | }; | 6383 | }; |
| 6173 | #endif /* CONFIG_NFS_V4_1 */ | 6384 | #endif /* CONFIG_NFS_V4_1 */ |
| 6174 | 6385 | ||
| 6175 | struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | 6386 | static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { |
| 6176 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 6387 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
| 6177 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 6388 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
| 6178 | .recover_open = nfs4_open_expired, | 6389 | .recover_open = nfs4_open_expired, |
| @@ -6182,7 +6393,7 @@ struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | |||
| 6182 | }; | 6393 | }; |
| 6183 | 6394 | ||
| 6184 | #if defined(CONFIG_NFS_V4_1) | 6395 | #if defined(CONFIG_NFS_V4_1) |
| 6185 | struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | 6396 | static const struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { |
| 6186 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 6397 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
| 6187 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 6398 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
| 6188 | .recover_open = nfs41_open_expired, | 6399 | .recover_open = nfs41_open_expired, |
| @@ -6192,14 +6403,14 @@ struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | |||
| 6192 | }; | 6403 | }; |
| 6193 | #endif /* CONFIG_NFS_V4_1 */ | 6404 | #endif /* CONFIG_NFS_V4_1 */ |
| 6194 | 6405 | ||
| 6195 | struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = { | 6406 | static const struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = { |
| 6196 | .sched_state_renewal = nfs4_proc_async_renew, | 6407 | .sched_state_renewal = nfs4_proc_async_renew, |
| 6197 | .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked, | 6408 | .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked, |
| 6198 | .renew_lease = nfs4_proc_renew, | 6409 | .renew_lease = nfs4_proc_renew, |
| 6199 | }; | 6410 | }; |
| 6200 | 6411 | ||
| 6201 | #if defined(CONFIG_NFS_V4_1) | 6412 | #if defined(CONFIG_NFS_V4_1) |
| 6202 | struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | 6413 | static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { |
| 6203 | .sched_state_renewal = nfs41_proc_async_sequence, | 6414 | .sched_state_renewal = nfs41_proc_async_sequence, |
| 6204 | .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked, | 6415 | .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked, |
| 6205 | .renew_lease = nfs4_proc_sequence, | 6416 | .renew_lease = nfs4_proc_sequence, |
| @@ -6209,7 +6420,7 @@ struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | |||
| 6209 | static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { | 6420 | static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { |
| 6210 | .minor_version = 0, | 6421 | .minor_version = 0, |
| 6211 | .call_sync = _nfs4_call_sync, | 6422 | .call_sync = _nfs4_call_sync, |
| 6212 | .validate_stateid = nfs4_validate_delegation_stateid, | 6423 | .match_stateid = nfs4_match_stateid, |
| 6213 | .find_root_sec = nfs4_find_root_sec, | 6424 | .find_root_sec = nfs4_find_root_sec, |
| 6214 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, | 6425 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, |
| 6215 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, | 6426 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, |
| @@ -6220,7 +6431,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { | |||
| 6220 | static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | 6431 | static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { |
| 6221 | .minor_version = 1, | 6432 | .minor_version = 1, |
| 6222 | .call_sync = _nfs4_call_sync_session, | 6433 | .call_sync = _nfs4_call_sync_session, |
| 6223 | .validate_stateid = nfs41_validate_delegation_stateid, | 6434 | .match_stateid = nfs41_match_stateid, |
| 6224 | .find_root_sec = nfs41_find_root_sec, | 6435 | .find_root_sec = nfs41_find_root_sec, |
| 6225 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, | 6436 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, |
| 6226 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, | 6437 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, |
| @@ -6260,9 +6471,11 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
| 6260 | .create = nfs4_proc_create, | 6471 | .create = nfs4_proc_create, |
| 6261 | .remove = nfs4_proc_remove, | 6472 | .remove = nfs4_proc_remove, |
| 6262 | .unlink_setup = nfs4_proc_unlink_setup, | 6473 | .unlink_setup = nfs4_proc_unlink_setup, |
| 6474 | .unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare, | ||
| 6263 | .unlink_done = nfs4_proc_unlink_done, | 6475 | .unlink_done = nfs4_proc_unlink_done, |
| 6264 | .rename = nfs4_proc_rename, | 6476 | .rename = nfs4_proc_rename, |
| 6265 | .rename_setup = nfs4_proc_rename_setup, | 6477 | .rename_setup = nfs4_proc_rename_setup, |
| 6478 | .rename_rpc_prepare = nfs4_proc_rename_rpc_prepare, | ||
| 6266 | .rename_done = nfs4_proc_rename_done, | 6479 | .rename_done = nfs4_proc_rename_done, |
| 6267 | .link = nfs4_proc_link, | 6480 | .link = nfs4_proc_link, |
| 6268 | .symlink = nfs4_proc_symlink, | 6481 | .symlink = nfs4_proc_symlink, |
| @@ -6276,8 +6489,10 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
| 6276 | .set_capabilities = nfs4_server_capabilities, | 6489 | .set_capabilities = nfs4_server_capabilities, |
| 6277 | .decode_dirent = nfs4_decode_dirent, | 6490 | .decode_dirent = nfs4_decode_dirent, |
| 6278 | .read_setup = nfs4_proc_read_setup, | 6491 | .read_setup = nfs4_proc_read_setup, |
| 6492 | .read_rpc_prepare = nfs4_proc_read_rpc_prepare, | ||
| 6279 | .read_done = nfs4_read_done, | 6493 | .read_done = nfs4_read_done, |
| 6280 | .write_setup = nfs4_proc_write_setup, | 6494 | .write_setup = nfs4_proc_write_setup, |
| 6495 | .write_rpc_prepare = nfs4_proc_write_rpc_prepare, | ||
| 6281 | .write_done = nfs4_write_done, | 6496 | .write_done = nfs4_write_done, |
| 6282 | .commit_setup = nfs4_proc_commit_setup, | 6497 | .commit_setup = nfs4_proc_commit_setup, |
| 6283 | .commit_done = nfs4_commit_done, | 6498 | .commit_done = nfs4_commit_done, |
| @@ -6301,6 +6516,10 @@ const struct xattr_handler *nfs4_xattr_handlers[] = { | |||
| 6301 | NULL | 6516 | NULL |
| 6302 | }; | 6517 | }; |
| 6303 | 6518 | ||
| 6519 | module_param(max_session_slots, ushort, 0644); | ||
| 6520 | MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 " | ||
| 6521 | "requests the client will negotiate"); | ||
| 6522 | |||
| 6304 | /* | 6523 | /* |
| 6305 | * Local variables: | 6524 | * Local variables: |
| 6306 | * c-basic-offset: 8 | 6525 | * c-basic-offset: 8 |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 45392032e7bd..0f43414eb25a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -146,6 +146,11 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | |||
| 146 | struct rpc_cred *cred = NULL; | 146 | struct rpc_cred *cred = NULL; |
| 147 | struct nfs_server *server; | 147 | struct nfs_server *server; |
| 148 | 148 | ||
| 149 | /* Use machine credentials if available */ | ||
| 150 | cred = nfs4_get_machine_cred_locked(clp); | ||
| 151 | if (cred != NULL) | ||
| 152 | goto out; | ||
| 153 | |||
| 149 | rcu_read_lock(); | 154 | rcu_read_lock(); |
| 150 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | 155 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
| 151 | cred = nfs4_get_renew_cred_server_locked(server); | 156 | cred = nfs4_get_renew_cred_server_locked(server); |
| @@ -153,6 +158,8 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | |||
| 153 | break; | 158 | break; |
| 154 | } | 159 | } |
| 155 | rcu_read_unlock(); | 160 | rcu_read_unlock(); |
| 161 | |||
| 162 | out: | ||
| 156 | return cred; | 163 | return cred; |
| 157 | } | 164 | } |
| 158 | 165 | ||
| @@ -190,30 +197,29 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp) | |||
| 190 | static void nfs4_end_drain_session(struct nfs_client *clp) | 197 | static void nfs4_end_drain_session(struct nfs_client *clp) |
| 191 | { | 198 | { |
| 192 | struct nfs4_session *ses = clp->cl_session; | 199 | struct nfs4_session *ses = clp->cl_session; |
| 200 | struct nfs4_slot_table *tbl; | ||
| 193 | int max_slots; | 201 | int max_slots; |
| 194 | 202 | ||
| 195 | if (ses == NULL) | 203 | if (ses == NULL) |
| 196 | return; | 204 | return; |
| 205 | tbl = &ses->fc_slot_table; | ||
| 197 | if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { | 206 | if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { |
| 198 | spin_lock(&ses->fc_slot_table.slot_tbl_lock); | 207 | spin_lock(&tbl->slot_tbl_lock); |
| 199 | max_slots = ses->fc_slot_table.max_slots; | 208 | max_slots = tbl->max_slots; |
| 200 | while (max_slots--) { | 209 | while (max_slots--) { |
| 201 | struct rpc_task *task; | 210 | if (rpc_wake_up_first(&tbl->slot_tbl_waitq, |
| 202 | 211 | nfs4_set_task_privileged, | |
| 203 | task = rpc_wake_up_next(&ses->fc_slot_table. | 212 | NULL) == NULL) |
| 204 | slot_tbl_waitq); | ||
| 205 | if (!task) | ||
| 206 | break; | 213 | break; |
| 207 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
| 208 | } | 214 | } |
| 209 | spin_unlock(&ses->fc_slot_table.slot_tbl_lock); | 215 | spin_unlock(&tbl->slot_tbl_lock); |
| 210 | } | 216 | } |
| 211 | } | 217 | } |
| 212 | 218 | ||
| 213 | static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl) | 219 | static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl) |
| 214 | { | 220 | { |
| 215 | spin_lock(&tbl->slot_tbl_lock); | 221 | spin_lock(&tbl->slot_tbl_lock); |
| 216 | if (tbl->highest_used_slotid != -1) { | 222 | if (tbl->highest_used_slotid != NFS4_NO_SLOT) { |
| 217 | INIT_COMPLETION(tbl->complete); | 223 | INIT_COMPLETION(tbl->complete); |
| 218 | spin_unlock(&tbl->slot_tbl_lock); | 224 | spin_unlock(&tbl->slot_tbl_lock); |
| 219 | return wait_for_completion_interruptible(&tbl->complete); | 225 | return wait_for_completion_interruptible(&tbl->complete); |
| @@ -317,62 +323,6 @@ out: | |||
| 317 | return cred; | 323 | return cred; |
| 318 | } | 324 | } |
| 319 | 325 | ||
| 320 | static void nfs_alloc_unique_id_locked(struct rb_root *root, | ||
| 321 | struct nfs_unique_id *new, | ||
| 322 | __u64 minval, int maxbits) | ||
| 323 | { | ||
| 324 | struct rb_node **p, *parent; | ||
| 325 | struct nfs_unique_id *pos; | ||
| 326 | __u64 mask = ~0ULL; | ||
| 327 | |||
| 328 | if (maxbits < 64) | ||
| 329 | mask = (1ULL << maxbits) - 1ULL; | ||
| 330 | |||
| 331 | /* Ensure distribution is more or less flat */ | ||
| 332 | get_random_bytes(&new->id, sizeof(new->id)); | ||
| 333 | new->id &= mask; | ||
| 334 | if (new->id < minval) | ||
| 335 | new->id += minval; | ||
| 336 | retry: | ||
| 337 | p = &root->rb_node; | ||
| 338 | parent = NULL; | ||
| 339 | |||
| 340 | while (*p != NULL) { | ||
| 341 | parent = *p; | ||
| 342 | pos = rb_entry(parent, struct nfs_unique_id, rb_node); | ||
| 343 | |||
| 344 | if (new->id < pos->id) | ||
| 345 | p = &(*p)->rb_left; | ||
| 346 | else if (new->id > pos->id) | ||
| 347 | p = &(*p)->rb_right; | ||
| 348 | else | ||
| 349 | goto id_exists; | ||
| 350 | } | ||
| 351 | rb_link_node(&new->rb_node, parent, p); | ||
| 352 | rb_insert_color(&new->rb_node, root); | ||
| 353 | return; | ||
| 354 | id_exists: | ||
| 355 | for (;;) { | ||
| 356 | new->id++; | ||
| 357 | if (new->id < minval || (new->id & mask) != new->id) { | ||
| 358 | new->id = minval; | ||
| 359 | break; | ||
| 360 | } | ||
| 361 | parent = rb_next(parent); | ||
| 362 | if (parent == NULL) | ||
| 363 | break; | ||
| 364 | pos = rb_entry(parent, struct nfs_unique_id, rb_node); | ||
| 365 | if (new->id < pos->id) | ||
| 366 | break; | ||
| 367 | } | ||
| 368 | goto retry; | ||
| 369 | } | ||
| 370 | |||
| 371 | static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id) | ||
| 372 | { | ||
| 373 | rb_erase(&id->rb_node, root); | ||
| 374 | } | ||
| 375 | |||
| 376 | static struct nfs4_state_owner * | 326 | static struct nfs4_state_owner * |
| 377 | nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred) | 327 | nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred) |
| 378 | { | 328 | { |
| @@ -405,6 +355,7 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new) | |||
| 405 | struct rb_node **p = &server->state_owners.rb_node, | 355 | struct rb_node **p = &server->state_owners.rb_node, |
| 406 | *parent = NULL; | 356 | *parent = NULL; |
| 407 | struct nfs4_state_owner *sp; | 357 | struct nfs4_state_owner *sp; |
| 358 | int err; | ||
| 408 | 359 | ||
| 409 | while (*p != NULL) { | 360 | while (*p != NULL) { |
| 410 | parent = *p; | 361 | parent = *p; |
| @@ -421,8 +372,9 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new) | |||
| 421 | return sp; | 372 | return sp; |
| 422 | } | 373 | } |
| 423 | } | 374 | } |
| 424 | nfs_alloc_unique_id_locked(&server->openowner_id, | 375 | err = ida_get_new(&server->openowner_id, &new->so_seqid.owner_id); |
| 425 | &new->so_owner_id, 1, 64); | 376 | if (err) |
| 377 | return ERR_PTR(err); | ||
| 426 | rb_link_node(&new->so_server_node, parent, p); | 378 | rb_link_node(&new->so_server_node, parent, p); |
| 427 | rb_insert_color(&new->so_server_node, &server->state_owners); | 379 | rb_insert_color(&new->so_server_node, &server->state_owners); |
| 428 | return new; | 380 | return new; |
| @@ -435,7 +387,23 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp) | |||
| 435 | 387 | ||
| 436 | if (!RB_EMPTY_NODE(&sp->so_server_node)) | 388 | if (!RB_EMPTY_NODE(&sp->so_server_node)) |
| 437 | rb_erase(&sp->so_server_node, &server->state_owners); | 389 | rb_erase(&sp->so_server_node, &server->state_owners); |
| 438 | nfs_free_unique_id(&server->openowner_id, &sp->so_owner_id); | 390 | ida_remove(&server->openowner_id, sp->so_seqid.owner_id); |
| 391 | } | ||
| 392 | |||
| 393 | static void | ||
| 394 | nfs4_init_seqid_counter(struct nfs_seqid_counter *sc) | ||
| 395 | { | ||
| 396 | sc->flags = 0; | ||
| 397 | sc->counter = 0; | ||
| 398 | spin_lock_init(&sc->lock); | ||
| 399 | INIT_LIST_HEAD(&sc->list); | ||
| 400 | rpc_init_wait_queue(&sc->wait, "Seqid_waitqueue"); | ||
| 401 | } | ||
| 402 | |||
| 403 | static void | ||
| 404 | nfs4_destroy_seqid_counter(struct nfs_seqid_counter *sc) | ||
| 405 | { | ||
| 406 | rpc_destroy_wait_queue(&sc->wait); | ||
| 439 | } | 407 | } |
| 440 | 408 | ||
| 441 | /* | 409 | /* |
| @@ -444,19 +412,20 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp) | |||
| 444 | * | 412 | * |
| 445 | */ | 413 | */ |
| 446 | static struct nfs4_state_owner * | 414 | static struct nfs4_state_owner * |
| 447 | nfs4_alloc_state_owner(void) | 415 | nfs4_alloc_state_owner(struct nfs_server *server, |
| 416 | struct rpc_cred *cred, | ||
| 417 | gfp_t gfp_flags) | ||
| 448 | { | 418 | { |
| 449 | struct nfs4_state_owner *sp; | 419 | struct nfs4_state_owner *sp; |
| 450 | 420 | ||
| 451 | sp = kzalloc(sizeof(*sp),GFP_NOFS); | 421 | sp = kzalloc(sizeof(*sp), gfp_flags); |
| 452 | if (!sp) | 422 | if (!sp) |
| 453 | return NULL; | 423 | return NULL; |
| 424 | sp->so_server = server; | ||
| 425 | sp->so_cred = get_rpccred(cred); | ||
| 454 | spin_lock_init(&sp->so_lock); | 426 | spin_lock_init(&sp->so_lock); |
| 455 | INIT_LIST_HEAD(&sp->so_states); | 427 | INIT_LIST_HEAD(&sp->so_states); |
| 456 | rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue"); | 428 | nfs4_init_seqid_counter(&sp->so_seqid); |
| 457 | sp->so_seqid.sequence = &sp->so_sequence; | ||
| 458 | spin_lock_init(&sp->so_sequence.lock); | ||
| 459 | INIT_LIST_HEAD(&sp->so_sequence.list); | ||
| 460 | atomic_set(&sp->so_count, 1); | 429 | atomic_set(&sp->so_count, 1); |
| 461 | INIT_LIST_HEAD(&sp->so_lru); | 430 | INIT_LIST_HEAD(&sp->so_lru); |
| 462 | return sp; | 431 | return sp; |
| @@ -478,7 +447,7 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp) | |||
| 478 | 447 | ||
| 479 | static void nfs4_free_state_owner(struct nfs4_state_owner *sp) | 448 | static void nfs4_free_state_owner(struct nfs4_state_owner *sp) |
| 480 | { | 449 | { |
| 481 | rpc_destroy_wait_queue(&sp->so_sequence.wait); | 450 | nfs4_destroy_seqid_counter(&sp->so_seqid); |
| 482 | put_rpccred(sp->so_cred); | 451 | put_rpccred(sp->so_cred); |
| 483 | kfree(sp); | 452 | kfree(sp); |
| 484 | } | 453 | } |
| @@ -516,7 +485,8 @@ static void nfs4_gc_state_owners(struct nfs_server *server) | |||
| 516 | * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL. | 485 | * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL. |
| 517 | */ | 486 | */ |
| 518 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, | 487 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, |
| 519 | struct rpc_cred *cred) | 488 | struct rpc_cred *cred, |
| 489 | gfp_t gfp_flags) | ||
| 520 | { | 490 | { |
| 521 | struct nfs_client *clp = server->nfs_client; | 491 | struct nfs_client *clp = server->nfs_client; |
| 522 | struct nfs4_state_owner *sp, *new; | 492 | struct nfs4_state_owner *sp, *new; |
| @@ -526,20 +496,18 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, | |||
| 526 | spin_unlock(&clp->cl_lock); | 496 | spin_unlock(&clp->cl_lock); |
| 527 | if (sp != NULL) | 497 | if (sp != NULL) |
| 528 | goto out; | 498 | goto out; |
| 529 | new = nfs4_alloc_state_owner(); | 499 | new = nfs4_alloc_state_owner(server, cred, gfp_flags); |
| 530 | if (new == NULL) | 500 | if (new == NULL) |
| 531 | goto out; | 501 | goto out; |
| 532 | new->so_server = server; | 502 | do { |
| 533 | new->so_cred = cred; | 503 | if (ida_pre_get(&server->openowner_id, gfp_flags) == 0) |
| 534 | spin_lock(&clp->cl_lock); | 504 | break; |
| 535 | sp = nfs4_insert_state_owner_locked(new); | 505 | spin_lock(&clp->cl_lock); |
| 536 | spin_unlock(&clp->cl_lock); | 506 | sp = nfs4_insert_state_owner_locked(new); |
| 537 | if (sp == new) | 507 | spin_unlock(&clp->cl_lock); |
| 538 | get_rpccred(cred); | 508 | } while (sp == ERR_PTR(-EAGAIN)); |
| 539 | else { | 509 | if (sp != new) |
| 540 | rpc_destroy_wait_queue(&new->so_sequence.wait); | 510 | nfs4_free_state_owner(new); |
| 541 | kfree(new); | ||
| 542 | } | ||
| 543 | out: | 511 | out: |
| 544 | nfs4_gc_state_owners(server); | 512 | nfs4_gc_state_owners(server); |
| 545 | return sp; | 513 | return sp; |
| @@ -795,15 +763,11 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
| 795 | { | 763 | { |
| 796 | struct nfs4_lock_state *lsp; | 764 | struct nfs4_lock_state *lsp; |
| 797 | struct nfs_server *server = state->owner->so_server; | 765 | struct nfs_server *server = state->owner->so_server; |
| 798 | struct nfs_client *clp = server->nfs_client; | ||
| 799 | 766 | ||
| 800 | lsp = kzalloc(sizeof(*lsp), GFP_NOFS); | 767 | lsp = kzalloc(sizeof(*lsp), GFP_NOFS); |
| 801 | if (lsp == NULL) | 768 | if (lsp == NULL) |
| 802 | return NULL; | 769 | return NULL; |
| 803 | rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue"); | 770 | nfs4_init_seqid_counter(&lsp->ls_seqid); |
| 804 | spin_lock_init(&lsp->ls_sequence.lock); | ||
| 805 | INIT_LIST_HEAD(&lsp->ls_sequence.list); | ||
| 806 | lsp->ls_seqid.sequence = &lsp->ls_sequence; | ||
| 807 | atomic_set(&lsp->ls_count, 1); | 771 | atomic_set(&lsp->ls_count, 1); |
| 808 | lsp->ls_state = state; | 772 | lsp->ls_state = state; |
| 809 | lsp->ls_owner.lo_type = type; | 773 | lsp->ls_owner.lo_type = type; |
| @@ -815,25 +779,22 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
| 815 | lsp->ls_owner.lo_u.posix_owner = fl_owner; | 779 | lsp->ls_owner.lo_u.posix_owner = fl_owner; |
| 816 | break; | 780 | break; |
| 817 | default: | 781 | default: |
| 818 | kfree(lsp); | 782 | goto out_free; |
| 819 | return NULL; | ||
| 820 | } | 783 | } |
| 821 | spin_lock(&clp->cl_lock); | 784 | lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS); |
| 822 | nfs_alloc_unique_id_locked(&server->lockowner_id, &lsp->ls_id, 1, 64); | 785 | if (lsp->ls_seqid.owner_id < 0) |
| 823 | spin_unlock(&clp->cl_lock); | 786 | goto out_free; |
| 824 | INIT_LIST_HEAD(&lsp->ls_locks); | 787 | INIT_LIST_HEAD(&lsp->ls_locks); |
| 825 | return lsp; | 788 | return lsp; |
| 789 | out_free: | ||
| 790 | kfree(lsp); | ||
| 791 | return NULL; | ||
| 826 | } | 792 | } |
| 827 | 793 | ||
| 828 | static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | 794 | void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) |
| 829 | { | 795 | { |
| 830 | struct nfs_server *server = lsp->ls_state->owner->so_server; | 796 | ida_simple_remove(&server->lockowner_id, lsp->ls_seqid.owner_id); |
| 831 | struct nfs_client *clp = server->nfs_client; | 797 | nfs4_destroy_seqid_counter(&lsp->ls_seqid); |
| 832 | |||
| 833 | spin_lock(&clp->cl_lock); | ||
| 834 | nfs_free_unique_id(&server->lockowner_id, &lsp->ls_id); | ||
| 835 | spin_unlock(&clp->cl_lock); | ||
| 836 | rpc_destroy_wait_queue(&lsp->ls_sequence.wait); | ||
| 837 | kfree(lsp); | 798 | kfree(lsp); |
| 838 | } | 799 | } |
| 839 | 800 | ||
| @@ -865,7 +826,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ | |||
| 865 | } | 826 | } |
| 866 | spin_unlock(&state->state_lock); | 827 | spin_unlock(&state->state_lock); |
| 867 | if (new != NULL) | 828 | if (new != NULL) |
| 868 | nfs4_free_lock_state(new); | 829 | nfs4_free_lock_state(state->owner->so_server, new); |
| 869 | return lsp; | 830 | return lsp; |
| 870 | } | 831 | } |
| 871 | 832 | ||
| @@ -886,9 +847,11 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | |||
| 886 | if (list_empty(&state->lock_states)) | 847 | if (list_empty(&state->lock_states)) |
| 887 | clear_bit(LK_STATE_IN_USE, &state->flags); | 848 | clear_bit(LK_STATE_IN_USE, &state->flags); |
| 888 | spin_unlock(&state->state_lock); | 849 | spin_unlock(&state->state_lock); |
| 889 | if (lsp->ls_flags & NFS_LOCK_INITIALIZED) | 850 | if (lsp->ls_flags & NFS_LOCK_INITIALIZED) { |
| 890 | nfs4_release_lockowner(lsp); | 851 | if (nfs4_release_lockowner(lsp) == 0) |
| 891 | nfs4_free_lock_state(lsp); | 852 | return; |
| 853 | } | ||
| 854 | nfs4_free_lock_state(lsp->ls_state->owner->so_server, lsp); | ||
| 892 | } | 855 | } |
| 893 | 856 | ||
| 894 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) | 857 | 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) | |||
| 918 | if (fl->fl_flags & FL_POSIX) | 881 | if (fl->fl_flags & FL_POSIX) |
| 919 | lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE); | 882 | lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE); |
| 920 | else if (fl->fl_flags & FL_FLOCK) | 883 | else if (fl->fl_flags & FL_FLOCK) |
| 921 | lsp = nfs4_get_lock_state(state, 0, fl->fl_pid, NFS4_FLOCK_LOCK_TYPE); | 884 | lsp = nfs4_get_lock_state(state, NULL, fl->fl_pid, |
| 885 | NFS4_FLOCK_LOCK_TYPE); | ||
| 922 | else | 886 | else |
| 923 | return -EINVAL; | 887 | return -EINVAL; |
| 924 | if (lsp == NULL) | 888 | if (lsp == NULL) |
| @@ -928,28 +892,49 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |||
| 928 | return 0; | 892 | return 0; |
| 929 | } | 893 | } |
| 930 | 894 | ||
| 931 | /* | 895 | static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state, |
| 932 | * Byte-range lock aware utility to initialize the stateid of read/write | 896 | fl_owner_t fl_owner, pid_t fl_pid) |
| 933 | * requests. | ||
| 934 | */ | ||
| 935 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid) | ||
| 936 | { | 897 | { |
| 937 | struct nfs4_lock_state *lsp; | 898 | struct nfs4_lock_state *lsp; |
| 938 | int seq; | 899 | bool ret = false; |
| 939 | 900 | ||
| 940 | do { | ||
| 941 | seq = read_seqbegin(&state->seqlock); | ||
| 942 | memcpy(dst, &state->stateid, sizeof(*dst)); | ||
| 943 | } while (read_seqretry(&state->seqlock, seq)); | ||
| 944 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) | 901 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) |
| 945 | return; | 902 | goto out; |
| 946 | 903 | ||
| 947 | spin_lock(&state->state_lock); | 904 | spin_lock(&state->state_lock); |
| 948 | lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); | 905 | lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); |
| 949 | if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | 906 | if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) { |
| 950 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); | 907 | nfs4_stateid_copy(dst, &lsp->ls_stateid); |
| 908 | ret = true; | ||
| 909 | } | ||
| 951 | spin_unlock(&state->state_lock); | 910 | spin_unlock(&state->state_lock); |
| 952 | nfs4_put_lock_state(lsp); | 911 | nfs4_put_lock_state(lsp); |
| 912 | out: | ||
| 913 | return ret; | ||
| 914 | } | ||
| 915 | |||
| 916 | static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) | ||
| 917 | { | ||
| 918 | int seq; | ||
| 919 | |||
| 920 | do { | ||
| 921 | seq = read_seqbegin(&state->seqlock); | ||
| 922 | nfs4_stateid_copy(dst, &state->stateid); | ||
| 923 | } while (read_seqretry(&state->seqlock, seq)); | ||
| 924 | } | ||
| 925 | |||
| 926 | /* | ||
| 927 | * Byte-range lock aware utility to initialize the stateid of read/write | ||
| 928 | * requests. | ||
| 929 | */ | ||
| 930 | void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, | ||
| 931 | fmode_t fmode, fl_owner_t fl_owner, pid_t fl_pid) | ||
| 932 | { | ||
| 933 | if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) | ||
| 934 | return; | ||
| 935 | if (nfs4_copy_lock_stateid(dst, state, fl_owner, fl_pid)) | ||
| 936 | return; | ||
| 937 | nfs4_copy_open_stateid(dst, state); | ||
| 953 | } | 938 | } |
| 954 | 939 | ||
| 955 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) | 940 | 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 | |||
| 960 | if (new != NULL) { | 945 | if (new != NULL) { |
| 961 | new->sequence = counter; | 946 | new->sequence = counter; |
| 962 | INIT_LIST_HEAD(&new->list); | 947 | INIT_LIST_HEAD(&new->list); |
| 948 | new->task = NULL; | ||
| 963 | } | 949 | } |
| 964 | return new; | 950 | return new; |
| 965 | } | 951 | } |
| 966 | 952 | ||
| 967 | void nfs_release_seqid(struct nfs_seqid *seqid) | 953 | void nfs_release_seqid(struct nfs_seqid *seqid) |
| 968 | { | 954 | { |
| 969 | if (!list_empty(&seqid->list)) { | 955 | struct nfs_seqid_counter *sequence; |
| 970 | struct rpc_sequence *sequence = seqid->sequence->sequence; | ||
| 971 | 956 | ||
| 972 | spin_lock(&sequence->lock); | 957 | if (list_empty(&seqid->list)) |
| 973 | list_del_init(&seqid->list); | 958 | return; |
| 974 | spin_unlock(&sequence->lock); | 959 | sequence = seqid->sequence; |
| 975 | rpc_wake_up(&sequence->wait); | 960 | spin_lock(&sequence->lock); |
| 961 | list_del_init(&seqid->list); | ||
| 962 | if (!list_empty(&sequence->list)) { | ||
| 963 | struct nfs_seqid *next; | ||
| 964 | |||
| 965 | next = list_first_entry(&sequence->list, | ||
| 966 | struct nfs_seqid, list); | ||
| 967 | rpc_wake_up_queued_task(&sequence->wait, next->task); | ||
| 976 | } | 968 | } |
| 969 | spin_unlock(&sequence->lock); | ||
| 977 | } | 970 | } |
| 978 | 971 | ||
| 979 | void nfs_free_seqid(struct nfs_seqid *seqid) | 972 | void nfs_free_seqid(struct nfs_seqid *seqid) |
| @@ -989,14 +982,14 @@ void nfs_free_seqid(struct nfs_seqid *seqid) | |||
| 989 | */ | 982 | */ |
| 990 | static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | 983 | static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) |
| 991 | { | 984 | { |
| 992 | BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid); | 985 | BUG_ON(list_first_entry(&seqid->sequence->list, struct nfs_seqid, list) != seqid); |
| 993 | switch (status) { | 986 | switch (status) { |
| 994 | case 0: | 987 | case 0: |
| 995 | break; | 988 | break; |
| 996 | case -NFS4ERR_BAD_SEQID: | 989 | case -NFS4ERR_BAD_SEQID: |
| 997 | if (seqid->sequence->flags & NFS_SEQID_CONFIRMED) | 990 | if (seqid->sequence->flags & NFS_SEQID_CONFIRMED) |
| 998 | return; | 991 | return; |
| 999 | printk(KERN_WARNING "NFS: v4 server returned a bad" | 992 | pr_warn_ratelimited("NFS: v4 server returned a bad" |
| 1000 | " sequence-id error on an" | 993 | " sequence-id error on an" |
| 1001 | " unconfirmed sequence %p!\n", | 994 | " unconfirmed sequence %p!\n", |
| 1002 | seqid->sequence); | 995 | seqid->sequence); |
| @@ -1040,10 +1033,11 @@ void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid) | |||
| 1040 | 1033 | ||
| 1041 | int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) | 1034 | int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) |
| 1042 | { | 1035 | { |
| 1043 | struct rpc_sequence *sequence = seqid->sequence->sequence; | 1036 | struct nfs_seqid_counter *sequence = seqid->sequence; |
| 1044 | int status = 0; | 1037 | int status = 0; |
| 1045 | 1038 | ||
| 1046 | spin_lock(&sequence->lock); | 1039 | spin_lock(&sequence->lock); |
| 1040 | seqid->task = task; | ||
| 1047 | if (list_empty(&seqid->list)) | 1041 | if (list_empty(&seqid->list)) |
| 1048 | list_add_tail(&seqid->list, &sequence->list); | 1042 | list_add_tail(&seqid->list, &sequence->list); |
| 1049 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) | 1043 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) |
| @@ -1072,19 +1066,28 @@ static void nfs4_clear_state_manager_bit(struct nfs_client *clp) | |||
| 1072 | void nfs4_schedule_state_manager(struct nfs_client *clp) | 1066 | void nfs4_schedule_state_manager(struct nfs_client *clp) |
| 1073 | { | 1067 | { |
| 1074 | struct task_struct *task; | 1068 | struct task_struct *task; |
| 1069 | char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1]; | ||
| 1075 | 1070 | ||
| 1076 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) | 1071 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) |
| 1077 | return; | 1072 | return; |
| 1078 | __module_get(THIS_MODULE); | 1073 | __module_get(THIS_MODULE); |
| 1079 | atomic_inc(&clp->cl_count); | 1074 | atomic_inc(&clp->cl_count); |
| 1080 | task = kthread_run(nfs4_run_state_manager, clp, "%s-manager", | 1075 | |
| 1081 | rpc_peeraddr2str(clp->cl_rpcclient, | 1076 | /* The rcu_read_lock() is not strictly necessary, as the state |
| 1082 | RPC_DISPLAY_ADDR)); | 1077 | * manager is the only thread that ever changes the rpc_xprt |
| 1083 | if (!IS_ERR(task)) | 1078 | * after it's initialized. At this point, we're single threaded. */ |
| 1084 | return; | 1079 | rcu_read_lock(); |
| 1085 | nfs4_clear_state_manager_bit(clp); | 1080 | snprintf(buf, sizeof(buf), "%s-manager", |
| 1086 | nfs_put_client(clp); | 1081 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
| 1087 | module_put(THIS_MODULE); | 1082 | rcu_read_unlock(); |
| 1083 | task = kthread_run(nfs4_run_state_manager, clp, buf); | ||
| 1084 | if (IS_ERR(task)) { | ||
| 1085 | printk(KERN_ERR "%s: kthread_run: %ld\n", | ||
| 1086 | __func__, PTR_ERR(task)); | ||
| 1087 | nfs4_clear_state_manager_bit(clp); | ||
| 1088 | nfs_put_client(clp); | ||
| 1089 | module_put(THIS_MODULE); | ||
| 1090 | } | ||
| 1088 | } | 1091 | } |
| 1089 | 1092 | ||
| 1090 | /* | 1093 | /* |
| @@ -1098,10 +1101,25 @@ void nfs4_schedule_lease_recovery(struct nfs_client *clp) | |||
| 1098 | set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1101 | set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
| 1099 | nfs4_schedule_state_manager(clp); | 1102 | nfs4_schedule_state_manager(clp); |
| 1100 | } | 1103 | } |
| 1104 | EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery); | ||
| 1105 | |||
| 1106 | /* | ||
| 1107 | * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN | ||
| 1108 | * @clp: client to process | ||
| 1109 | * | ||
| 1110 | * Set the NFS4CLNT_LEASE_EXPIRED state in order to force a | ||
| 1111 | * resend of the SETCLIENTID and hence re-establish the | ||
| 1112 | * callback channel. Then return all existing delegations. | ||
| 1113 | */ | ||
| 1114 | static void nfs40_handle_cb_pathdown(struct nfs_client *clp) | ||
| 1115 | { | ||
| 1116 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 1117 | nfs_expire_all_delegations(clp); | ||
| 1118 | } | ||
| 1101 | 1119 | ||
| 1102 | void nfs4_schedule_path_down_recovery(struct nfs_client *clp) | 1120 | void nfs4_schedule_path_down_recovery(struct nfs_client *clp) |
| 1103 | { | 1121 | { |
| 1104 | nfs_handle_cb_pathdown(clp); | 1122 | nfs40_handle_cb_pathdown(clp); |
| 1105 | nfs4_schedule_state_manager(clp); | 1123 | nfs4_schedule_state_manager(clp); |
| 1106 | } | 1124 | } |
| 1107 | 1125 | ||
| @@ -1132,11 +1150,37 @@ void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4 | |||
| 1132 | { | 1150 | { |
| 1133 | struct nfs_client *clp = server->nfs_client; | 1151 | struct nfs_client *clp = server->nfs_client; |
| 1134 | 1152 | ||
| 1135 | if (test_and_clear_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
| 1136 | nfs_async_inode_return_delegation(state->inode, &state->stateid); | ||
| 1137 | nfs4_state_mark_reclaim_nograce(clp, state); | 1153 | nfs4_state_mark_reclaim_nograce(clp, state); |
| 1138 | nfs4_schedule_state_manager(clp); | 1154 | nfs4_schedule_state_manager(clp); |
| 1139 | } | 1155 | } |
| 1156 | EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery); | ||
| 1157 | |||
| 1158 | void nfs_inode_find_state_and_recover(struct inode *inode, | ||
| 1159 | const nfs4_stateid *stateid) | ||
| 1160 | { | ||
| 1161 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | ||
| 1162 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 1163 | struct nfs_open_context *ctx; | ||
| 1164 | struct nfs4_state *state; | ||
| 1165 | bool found = false; | ||
| 1166 | |||
| 1167 | spin_lock(&inode->i_lock); | ||
| 1168 | list_for_each_entry(ctx, &nfsi->open_files, list) { | ||
| 1169 | state = ctx->state; | ||
| 1170 | if (state == NULL) | ||
| 1171 | continue; | ||
| 1172 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
| 1173 | continue; | ||
| 1174 | if (!nfs4_stateid_match(&state->stateid, stateid)) | ||
| 1175 | continue; | ||
| 1176 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
| 1177 | found = true; | ||
| 1178 | } | ||
| 1179 | spin_unlock(&inode->i_lock); | ||
| 1180 | if (found) | ||
| 1181 | nfs4_schedule_state_manager(clp); | ||
| 1182 | } | ||
| 1183 | |||
| 1140 | 1184 | ||
| 1141 | static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) | 1185 | static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) |
| 1142 | { | 1186 | { |
| @@ -1175,8 +1219,8 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
| 1175 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | 1219 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: |
| 1176 | goto out; | 1220 | goto out; |
| 1177 | default: | 1221 | default: |
| 1178 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 1222 | printk(KERN_ERR "NFS: %s: unhandled error %d. " |
| 1179 | __func__, status); | 1223 | "Zeroing state\n", __func__, status); |
| 1180 | case -ENOMEM: | 1224 | case -ENOMEM: |
| 1181 | case -NFS4ERR_DENIED: | 1225 | case -NFS4ERR_DENIED: |
| 1182 | case -NFS4ERR_RECLAIM_BAD: | 1226 | case -NFS4ERR_RECLAIM_BAD: |
| @@ -1222,8 +1266,9 @@ restart: | |||
| 1222 | spin_lock(&state->state_lock); | 1266 | spin_lock(&state->state_lock); |
| 1223 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | 1267 | list_for_each_entry(lock, &state->lock_states, ls_locks) { |
| 1224 | if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) | 1268 | if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) |
| 1225 | printk("%s: Lock reclaim failed!\n", | 1269 | pr_warn_ratelimited("NFS: " |
| 1226 | __func__); | 1270 | "%s: Lock reclaim " |
| 1271 | "failed!\n", __func__); | ||
| 1227 | } | 1272 | } |
| 1228 | spin_unlock(&state->state_lock); | 1273 | spin_unlock(&state->state_lock); |
| 1229 | nfs4_put_open_state(state); | 1274 | nfs4_put_open_state(state); |
| @@ -1232,8 +1277,8 @@ restart: | |||
| 1232 | } | 1277 | } |
| 1233 | switch (status) { | 1278 | switch (status) { |
| 1234 | default: | 1279 | default: |
| 1235 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 1280 | printk(KERN_ERR "NFS: %s: unhandled error %d. " |
| 1236 | __func__, status); | 1281 | "Zeroing state\n", __func__, status); |
| 1237 | case -ENOENT: | 1282 | case -ENOENT: |
| 1238 | case -ENOMEM: | 1283 | case -ENOMEM: |
| 1239 | case -ESTALE: | 1284 | case -ESTALE: |
| @@ -1241,8 +1286,8 @@ restart: | |||
| 1241 | * Open state on this file cannot be recovered | 1286 | * Open state on this file cannot be recovered |
| 1242 | * All we can do is revert to using the zero stateid. | 1287 | * All we can do is revert to using the zero stateid. |
| 1243 | */ | 1288 | */ |
| 1244 | memset(state->stateid.data, 0, | 1289 | memset(&state->stateid, 0, |
| 1245 | sizeof(state->stateid.data)); | 1290 | sizeof(state->stateid)); |
| 1246 | /* Mark the file as being 'closed' */ | 1291 | /* Mark the file as being 'closed' */ |
| 1247 | state->state = 0; | 1292 | state->state = 0; |
| 1248 | break; | 1293 | break; |
| @@ -1420,7 +1465,7 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
| 1420 | case 0: | 1465 | case 0: |
| 1421 | break; | 1466 | break; |
| 1422 | case -NFS4ERR_CB_PATH_DOWN: | 1467 | case -NFS4ERR_CB_PATH_DOWN: |
| 1423 | nfs_handle_cb_pathdown(clp); | 1468 | nfs40_handle_cb_pathdown(clp); |
| 1424 | break; | 1469 | break; |
| 1425 | case -NFS4ERR_NO_GRACE: | 1470 | case -NFS4ERR_NO_GRACE: |
| 1426 | nfs4_state_end_reclaim_reboot(clp); | 1471 | nfs4_state_end_reclaim_reboot(clp); |
| @@ -1801,7 +1846,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
| 1801 | } while (atomic_read(&clp->cl_count) > 1); | 1846 | } while (atomic_read(&clp->cl_count) > 1); |
| 1802 | return; | 1847 | return; |
| 1803 | out_error: | 1848 | out_error: |
| 1804 | printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" | 1849 | pr_warn_ratelimited("NFS: state manager failed on NFSv4 server %s" |
| 1805 | " with error %d\n", clp->cl_hostname, -status); | 1850 | " with error %d\n", clp->cl_hostname, -status); |
| 1806 | nfs4_end_drain_session(clp); | 1851 | nfs4_end_drain_session(clp); |
| 1807 | nfs4_clear_state_manager_bit(clp); | 1852 | nfs4_clear_state_manager_bit(clp); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 33bd8d0f745d..c74fdb114b48 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -44,6 +44,8 @@ | |||
| 44 | #include <linux/pagemap.h> | 44 | #include <linux/pagemap.h> |
| 45 | #include <linux/proc_fs.h> | 45 | #include <linux/proc_fs.h> |
| 46 | #include <linux/kdev_t.h> | 46 | #include <linux/kdev_t.h> |
| 47 | #include <linux/module.h> | ||
| 48 | #include <linux/utsname.h> | ||
| 47 | #include <linux/sunrpc/clnt.h> | 49 | #include <linux/sunrpc/clnt.h> |
| 48 | #include <linux/sunrpc/msg_prot.h> | 50 | #include <linux/sunrpc/msg_prot.h> |
| 49 | #include <linux/sunrpc/gss_api.h> | 51 | #include <linux/sunrpc/gss_api.h> |
| @@ -271,7 +273,12 @@ static int nfs4_stat_to_errno(int); | |||
| 271 | 1 /* flags */ + \ | 273 | 1 /* flags */ + \ |
| 272 | 1 /* spa_how */ + \ | 274 | 1 /* spa_how */ + \ |
| 273 | 0 /* SP4_NONE (for now) */ + \ | 275 | 0 /* SP4_NONE (for now) */ + \ |
| 274 | 1 /* zero implemetation id array */) | 276 | 1 /* implementation id array of size 1 */ + \ |
| 277 | 1 /* nii_domain */ + \ | ||
| 278 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \ | ||
| 279 | 1 /* nii_name */ + \ | ||
| 280 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \ | ||
| 281 | 3 /* nii_date */) | ||
| 275 | #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \ | 282 | #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \ |
| 276 | 2 /* eir_clientid */ + \ | 283 | 2 /* eir_clientid */ + \ |
| 277 | 1 /* eir_sequenceid */ + \ | 284 | 1 /* eir_sequenceid */ + \ |
| @@ -284,7 +291,11 @@ static int nfs4_stat_to_errno(int); | |||
| 284 | /* eir_server_scope<> */ \ | 291 | /* eir_server_scope<> */ \ |
| 285 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | 292 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ |
| 286 | 1 /* eir_server_impl_id array length */ + \ | 293 | 1 /* eir_server_impl_id array length */ + \ |
| 287 | 0 /* ignored eir_server_impl_id contents */) | 294 | 1 /* nii_domain */ + \ |
| 295 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \ | ||
| 296 | 1 /* nii_name */ + \ | ||
| 297 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \ | ||
| 298 | 3 /* nii_date */) | ||
| 288 | #define encode_channel_attrs_maxsz (6 + 1 /* ca_rdma_ird.len (0) */) | 299 | #define encode_channel_attrs_maxsz (6 + 1 /* ca_rdma_ird.len (0) */) |
| 289 | #define decode_channel_attrs_maxsz (6 + \ | 300 | #define decode_channel_attrs_maxsz (6 + \ |
| 290 | 1 /* ca_rdma_ird.len */ + \ | 301 | 1 /* ca_rdma_ird.len */ + \ |
| @@ -838,6 +849,12 @@ const u32 nfs41_maxread_overhead = ((RPC_MAX_HEADER_WITH_AUTH + | |||
| 838 | XDR_UNIT); | 849 | XDR_UNIT); |
| 839 | #endif /* CONFIG_NFS_V4_1 */ | 850 | #endif /* CONFIG_NFS_V4_1 */ |
| 840 | 851 | ||
| 852 | static unsigned short send_implementation_id = 1; | ||
| 853 | |||
| 854 | module_param(send_implementation_id, ushort, 0644); | ||
| 855 | MODULE_PARM_DESC(send_implementation_id, | ||
| 856 | "Send implementation ID with NFSv4.1 exchange_id"); | ||
| 857 | |||
| 841 | static const umode_t nfs_type2fmt[] = { | 858 | static const umode_t nfs_type2fmt[] = { |
| 842 | [NF4BAD] = 0, | 859 | [NF4BAD] = 0, |
| 843 | [NF4REG] = S_IFREG, | 860 | [NF4REG] = S_IFREG, |
| @@ -868,15 +885,44 @@ static __be32 *reserve_space(struct xdr_stream *xdr, size_t nbytes) | |||
| 868 | return p; | 885 | return p; |
| 869 | } | 886 | } |
| 870 | 887 | ||
| 888 | static void encode_opaque_fixed(struct xdr_stream *xdr, const void *buf, size_t len) | ||
| 889 | { | ||
| 890 | __be32 *p; | ||
| 891 | |||
| 892 | p = xdr_reserve_space(xdr, len); | ||
| 893 | xdr_encode_opaque_fixed(p, buf, len); | ||
| 894 | } | ||
| 895 | |||
| 871 | static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 896 | static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
| 872 | { | 897 | { |
| 873 | __be32 *p; | 898 | __be32 *p; |
| 874 | 899 | ||
| 875 | p = xdr_reserve_space(xdr, 4 + len); | 900 | p = reserve_space(xdr, 4 + len); |
| 876 | BUG_ON(p == NULL); | ||
| 877 | xdr_encode_opaque(p, str, len); | 901 | xdr_encode_opaque(p, str, len); |
| 878 | } | 902 | } |
| 879 | 903 | ||
| 904 | static void encode_uint32(struct xdr_stream *xdr, u32 n) | ||
| 905 | { | ||
| 906 | __be32 *p; | ||
| 907 | |||
| 908 | p = reserve_space(xdr, 4); | ||
| 909 | *p = cpu_to_be32(n); | ||
| 910 | } | ||
| 911 | |||
| 912 | static void encode_uint64(struct xdr_stream *xdr, u64 n) | ||
| 913 | { | ||
| 914 | __be32 *p; | ||
| 915 | |||
| 916 | p = reserve_space(xdr, 8); | ||
| 917 | xdr_encode_hyper(p, n); | ||
| 918 | } | ||
| 919 | |||
| 920 | static void encode_nfs4_seqid(struct xdr_stream *xdr, | ||
| 921 | const struct nfs_seqid *seqid) | ||
| 922 | { | ||
| 923 | encode_uint32(xdr, seqid->sequence->counter); | ||
| 924 | } | ||
| 925 | |||
| 880 | static void encode_compound_hdr(struct xdr_stream *xdr, | 926 | static void encode_compound_hdr(struct xdr_stream *xdr, |
| 881 | struct rpc_rqst *req, | 927 | struct rpc_rqst *req, |
| 882 | struct compound_hdr *hdr) | 928 | struct compound_hdr *hdr) |
| @@ -889,28 +935,37 @@ static void encode_compound_hdr(struct xdr_stream *xdr, | |||
| 889 | * but this is not required as a MUST for the server to do so. */ | 935 | * but this is not required as a MUST for the server to do so. */ |
| 890 | hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen; | 936 | hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen; |
| 891 | 937 | ||
| 892 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); | ||
| 893 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); | 938 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); |
| 894 | p = reserve_space(xdr, 4 + hdr->taglen + 8); | 939 | encode_string(xdr, hdr->taglen, hdr->tag); |
| 895 | p = xdr_encode_opaque(p, hdr->tag, hdr->taglen); | 940 | p = reserve_space(xdr, 8); |
| 896 | *p++ = cpu_to_be32(hdr->minorversion); | 941 | *p++ = cpu_to_be32(hdr->minorversion); |
| 897 | hdr->nops_p = p; | 942 | hdr->nops_p = p; |
| 898 | *p = cpu_to_be32(hdr->nops); | 943 | *p = cpu_to_be32(hdr->nops); |
| 899 | } | 944 | } |
| 900 | 945 | ||
| 946 | static void encode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 op, | ||
| 947 | uint32_t replen, | ||
| 948 | struct compound_hdr *hdr) | ||
| 949 | { | ||
| 950 | encode_uint32(xdr, op); | ||
| 951 | hdr->nops++; | ||
| 952 | hdr->replen += replen; | ||
| 953 | } | ||
| 954 | |||
| 901 | static void encode_nops(struct compound_hdr *hdr) | 955 | static void encode_nops(struct compound_hdr *hdr) |
| 902 | { | 956 | { |
| 903 | BUG_ON(hdr->nops > NFS4_MAX_OPS); | 957 | BUG_ON(hdr->nops > NFS4_MAX_OPS); |
| 904 | *hdr->nops_p = htonl(hdr->nops); | 958 | *hdr->nops_p = htonl(hdr->nops); |
| 905 | } | 959 | } |
| 906 | 960 | ||
| 907 | static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf) | 961 | static void encode_nfs4_stateid(struct xdr_stream *xdr, const nfs4_stateid *stateid) |
| 908 | { | 962 | { |
| 909 | __be32 *p; | 963 | encode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE); |
| 964 | } | ||
| 910 | 965 | ||
| 911 | p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE); | 966 | static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf) |
| 912 | BUG_ON(p == NULL); | 967 | { |
| 913 | xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE); | 968 | encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE); |
| 914 | } | 969 | } |
| 915 | 970 | ||
| 916 | static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server) | 971 | static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server) |
| @@ -1023,7 +1078,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
| 1023 | * Now we backfill the bitmap and the attribute buffer length. | 1078 | * Now we backfill the bitmap and the attribute buffer length. |
| 1024 | */ | 1079 | */ |
| 1025 | if (len != ((char *)p - (char *)q) + 4) { | 1080 | if (len != ((char *)p - (char *)q) + 4) { |
| 1026 | printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n", | 1081 | printk(KERN_ERR "NFS: Attr length error, %u != %Zu\n", |
| 1027 | len, ((char *)p - (char *)q) + 4); | 1082 | len, ((char *)p - (char *)q) + 4); |
| 1028 | BUG(); | 1083 | BUG(); |
| 1029 | } | 1084 | } |
| @@ -1037,46 +1092,33 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
| 1037 | 1092 | ||
| 1038 | static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr) | 1093 | static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr) |
| 1039 | { | 1094 | { |
| 1040 | __be32 *p; | 1095 | encode_op_hdr(xdr, OP_ACCESS, decode_access_maxsz, hdr); |
| 1041 | 1096 | encode_uint32(xdr, access); | |
| 1042 | p = reserve_space(xdr, 8); | ||
| 1043 | *p++ = cpu_to_be32(OP_ACCESS); | ||
| 1044 | *p = cpu_to_be32(access); | ||
| 1045 | hdr->nops++; | ||
| 1046 | hdr->replen += decode_access_maxsz; | ||
| 1047 | } | 1097 | } |
| 1048 | 1098 | ||
| 1049 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 1099 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
| 1050 | { | 1100 | { |
| 1051 | __be32 *p; | 1101 | encode_op_hdr(xdr, OP_CLOSE, decode_close_maxsz, hdr); |
| 1052 | 1102 | encode_nfs4_seqid(xdr, arg->seqid); | |
| 1053 | p = reserve_space(xdr, 8+NFS4_STATEID_SIZE); | 1103 | encode_nfs4_stateid(xdr, arg->stateid); |
| 1054 | *p++ = cpu_to_be32(OP_CLOSE); | ||
| 1055 | *p++ = cpu_to_be32(arg->seqid->sequence->counter); | ||
| 1056 | xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); | ||
| 1057 | hdr->nops++; | ||
| 1058 | hdr->replen += decode_close_maxsz; | ||
| 1059 | } | 1104 | } |
| 1060 | 1105 | ||
| 1061 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 1106 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
| 1062 | { | 1107 | { |
| 1063 | __be32 *p; | 1108 | __be32 *p; |
| 1064 | 1109 | ||
| 1065 | p = reserve_space(xdr, 16); | 1110 | encode_op_hdr(xdr, OP_COMMIT, decode_commit_maxsz, hdr); |
| 1066 | *p++ = cpu_to_be32(OP_COMMIT); | 1111 | p = reserve_space(xdr, 12); |
| 1067 | p = xdr_encode_hyper(p, args->offset); | 1112 | p = xdr_encode_hyper(p, args->offset); |
| 1068 | *p = cpu_to_be32(args->count); | 1113 | *p = cpu_to_be32(args->count); |
| 1069 | hdr->nops++; | ||
| 1070 | hdr->replen += decode_commit_maxsz; | ||
| 1071 | } | 1114 | } |
| 1072 | 1115 | ||
| 1073 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) | 1116 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) |
| 1074 | { | 1117 | { |
| 1075 | __be32 *p; | 1118 | __be32 *p; |
| 1076 | 1119 | ||
| 1077 | p = reserve_space(xdr, 8); | 1120 | encode_op_hdr(xdr, OP_CREATE, decode_create_maxsz, hdr); |
| 1078 | *p++ = cpu_to_be32(OP_CREATE); | 1121 | encode_uint32(xdr, create->ftype); |
| 1079 | *p = cpu_to_be32(create->ftype); | ||
| 1080 | 1122 | ||
| 1081 | switch (create->ftype) { | 1123 | switch (create->ftype) { |
| 1082 | case NF4LNK: | 1124 | case NF4LNK: |
| @@ -1096,9 +1138,6 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * | |||
| 1096 | } | 1138 | } |
| 1097 | 1139 | ||
| 1098 | encode_string(xdr, create->name->len, create->name->name); | 1140 | encode_string(xdr, create->name->len, create->name->name); |
| 1099 | hdr->nops++; | ||
| 1100 | hdr->replen += decode_create_maxsz; | ||
| 1101 | |||
| 1102 | encode_attrs(xdr, create->attrs, create->server); | 1141 | encode_attrs(xdr, create->attrs, create->server); |
| 1103 | } | 1142 | } |
| 1104 | 1143 | ||
| @@ -1106,25 +1145,21 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c | |||
| 1106 | { | 1145 | { |
| 1107 | __be32 *p; | 1146 | __be32 *p; |
| 1108 | 1147 | ||
| 1109 | p = reserve_space(xdr, 12); | 1148 | encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr); |
| 1110 | *p++ = cpu_to_be32(OP_GETATTR); | 1149 | p = reserve_space(xdr, 8); |
| 1111 | *p++ = cpu_to_be32(1); | 1150 | *p++ = cpu_to_be32(1); |
| 1112 | *p = cpu_to_be32(bitmap); | 1151 | *p = cpu_to_be32(bitmap); |
| 1113 | hdr->nops++; | ||
| 1114 | hdr->replen += decode_getattr_maxsz; | ||
| 1115 | } | 1152 | } |
| 1116 | 1153 | ||
| 1117 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) | 1154 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) |
| 1118 | { | 1155 | { |
| 1119 | __be32 *p; | 1156 | __be32 *p; |
| 1120 | 1157 | ||
| 1121 | p = reserve_space(xdr, 16); | 1158 | encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr); |
| 1122 | *p++ = cpu_to_be32(OP_GETATTR); | 1159 | p = reserve_space(xdr, 12); |
| 1123 | *p++ = cpu_to_be32(2); | 1160 | *p++ = cpu_to_be32(2); |
| 1124 | *p++ = cpu_to_be32(bm0); | 1161 | *p++ = cpu_to_be32(bm0); |
| 1125 | *p = cpu_to_be32(bm1); | 1162 | *p = cpu_to_be32(bm1); |
| 1126 | hdr->nops++; | ||
| 1127 | hdr->replen += decode_getattr_maxsz; | ||
| 1128 | } | 1163 | } |
| 1129 | 1164 | ||
| 1130 | static void | 1165 | static void |
| @@ -1134,8 +1169,7 @@ encode_getattr_three(struct xdr_stream *xdr, | |||
| 1134 | { | 1169 | { |
| 1135 | __be32 *p; | 1170 | __be32 *p; |
| 1136 | 1171 | ||
| 1137 | p = reserve_space(xdr, 4); | 1172 | encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr); |
| 1138 | *p = cpu_to_be32(OP_GETATTR); | ||
| 1139 | if (bm2) { | 1173 | if (bm2) { |
| 1140 | p = reserve_space(xdr, 16); | 1174 | p = reserve_space(xdr, 16); |
| 1141 | *p++ = cpu_to_be32(3); | 1175 | *p++ = cpu_to_be32(3); |
| @@ -1152,8 +1186,6 @@ encode_getattr_three(struct xdr_stream *xdr, | |||
| 1152 | *p++ = cpu_to_be32(1); | 1186 | *p++ = cpu_to_be32(1); |
| 1153 | *p = cpu_to_be32(bm0); | 1187 | *p = cpu_to_be32(bm0); |
| 1154 | } | 1188 | } |
| 1155 | hdr->nops++; | ||
| 1156 | hdr->replen += decode_getattr_maxsz; | ||
| 1157 | } | 1189 | } |
| 1158 | 1190 | ||
| 1159 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 1191 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
| @@ -1179,23 +1211,13 @@ static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, stru | |||
| 1179 | 1211 | ||
| 1180 | static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1212 | static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 1181 | { | 1213 | { |
| 1182 | __be32 *p; | 1214 | encode_op_hdr(xdr, OP_GETFH, decode_getfh_maxsz, hdr); |
| 1183 | |||
| 1184 | p = reserve_space(xdr, 4); | ||
| 1185 | *p = cpu_to_be32(OP_GETFH); | ||
| 1186 | hdr->nops++; | ||
| 1187 | hdr->replen += decode_getfh_maxsz; | ||
| 1188 | } | 1215 | } |
| 1189 | 1216 | ||
| 1190 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1217 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| 1191 | { | 1218 | { |
| 1192 | __be32 *p; | 1219 | encode_op_hdr(xdr, OP_LINK, decode_link_maxsz, hdr); |
| 1193 | 1220 | encode_string(xdr, name->len, name->name); | |
| 1194 | p = reserve_space(xdr, 8 + name->len); | ||
| 1195 | *p++ = cpu_to_be32(OP_LINK); | ||
| 1196 | xdr_encode_opaque(p, name->name, name->len); | ||
| 1197 | hdr->nops++; | ||
| 1198 | hdr->replen += decode_link_maxsz; | ||
| 1199 | } | 1221 | } |
| 1200 | 1222 | ||
| 1201 | static inline int nfs4_lock_type(struct file_lock *fl, int block) | 1223 | static inline int nfs4_lock_type(struct file_lock *fl, int block) |
| @@ -1232,79 +1254,60 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args | |||
| 1232 | { | 1254 | { |
| 1233 | __be32 *p; | 1255 | __be32 *p; |
| 1234 | 1256 | ||
| 1235 | p = reserve_space(xdr, 32); | 1257 | encode_op_hdr(xdr, OP_LOCK, decode_lock_maxsz, hdr); |
| 1236 | *p++ = cpu_to_be32(OP_LOCK); | 1258 | p = reserve_space(xdr, 28); |
| 1237 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block)); | 1259 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block)); |
| 1238 | *p++ = cpu_to_be32(args->reclaim); | 1260 | *p++ = cpu_to_be32(args->reclaim); |
| 1239 | p = xdr_encode_hyper(p, args->fl->fl_start); | 1261 | p = xdr_encode_hyper(p, args->fl->fl_start); |
| 1240 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); | 1262 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
| 1241 | *p = cpu_to_be32(args->new_lock_owner); | 1263 | *p = cpu_to_be32(args->new_lock_owner); |
| 1242 | if (args->new_lock_owner){ | 1264 | if (args->new_lock_owner){ |
| 1243 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); | 1265 | encode_nfs4_seqid(xdr, args->open_seqid); |
| 1244 | *p++ = cpu_to_be32(args->open_seqid->sequence->counter); | 1266 | encode_nfs4_stateid(xdr, args->open_stateid); |
| 1245 | p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE); | 1267 | encode_nfs4_seqid(xdr, args->lock_seqid); |
| 1246 | *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); | ||
| 1247 | encode_lockowner(xdr, &args->lock_owner); | 1268 | encode_lockowner(xdr, &args->lock_owner); |
| 1248 | } | 1269 | } |
| 1249 | else { | 1270 | else { |
| 1250 | p = reserve_space(xdr, NFS4_STATEID_SIZE+4); | 1271 | encode_nfs4_stateid(xdr, args->lock_stateid); |
| 1251 | p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE); | 1272 | encode_nfs4_seqid(xdr, args->lock_seqid); |
| 1252 | *p = cpu_to_be32(args->lock_seqid->sequence->counter); | ||
| 1253 | } | 1273 | } |
| 1254 | hdr->nops++; | ||
| 1255 | hdr->replen += decode_lock_maxsz; | ||
| 1256 | } | 1274 | } |
| 1257 | 1275 | ||
| 1258 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) | 1276 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) |
| 1259 | { | 1277 | { |
| 1260 | __be32 *p; | 1278 | __be32 *p; |
| 1261 | 1279 | ||
| 1262 | p = reserve_space(xdr, 24); | 1280 | encode_op_hdr(xdr, OP_LOCKT, decode_lockt_maxsz, hdr); |
| 1263 | *p++ = cpu_to_be32(OP_LOCKT); | 1281 | p = reserve_space(xdr, 20); |
| 1264 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); | 1282 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); |
| 1265 | p = xdr_encode_hyper(p, args->fl->fl_start); | 1283 | p = xdr_encode_hyper(p, args->fl->fl_start); |
| 1266 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); | 1284 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
| 1267 | encode_lockowner(xdr, &args->lock_owner); | 1285 | encode_lockowner(xdr, &args->lock_owner); |
| 1268 | hdr->nops++; | ||
| 1269 | hdr->replen += decode_lockt_maxsz; | ||
| 1270 | } | 1286 | } |
| 1271 | 1287 | ||
| 1272 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) | 1288 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) |
| 1273 | { | 1289 | { |
| 1274 | __be32 *p; | 1290 | __be32 *p; |
| 1275 | 1291 | ||
| 1276 | p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16); | 1292 | encode_op_hdr(xdr, OP_LOCKU, decode_locku_maxsz, hdr); |
| 1277 | *p++ = cpu_to_be32(OP_LOCKU); | 1293 | encode_uint32(xdr, nfs4_lock_type(args->fl, 0)); |
| 1278 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); | 1294 | encode_nfs4_seqid(xdr, args->seqid); |
| 1279 | *p++ = cpu_to_be32(args->seqid->sequence->counter); | 1295 | encode_nfs4_stateid(xdr, args->stateid); |
| 1280 | p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE); | 1296 | p = reserve_space(xdr, 16); |
| 1281 | p = xdr_encode_hyper(p, args->fl->fl_start); | 1297 | p = xdr_encode_hyper(p, args->fl->fl_start); |
| 1282 | xdr_encode_hyper(p, nfs4_lock_length(args->fl)); | 1298 | xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
| 1283 | hdr->nops++; | ||
| 1284 | hdr->replen += decode_locku_maxsz; | ||
| 1285 | } | 1299 | } |
| 1286 | 1300 | ||
| 1287 | static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr) | 1301 | static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr) |
| 1288 | { | 1302 | { |
| 1289 | __be32 *p; | 1303 | encode_op_hdr(xdr, OP_RELEASE_LOCKOWNER, decode_release_lockowner_maxsz, hdr); |
| 1290 | |||
| 1291 | p = reserve_space(xdr, 4); | ||
| 1292 | *p = cpu_to_be32(OP_RELEASE_LOCKOWNER); | ||
| 1293 | encode_lockowner(xdr, lowner); | 1304 | encode_lockowner(xdr, lowner); |
| 1294 | hdr->nops++; | ||
| 1295 | hdr->replen += decode_release_lockowner_maxsz; | ||
| 1296 | } | 1305 | } |
| 1297 | 1306 | ||
| 1298 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1307 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| 1299 | { | 1308 | { |
| 1300 | int len = name->len; | 1309 | encode_op_hdr(xdr, OP_LOOKUP, decode_lookup_maxsz, hdr); |
| 1301 | __be32 *p; | 1310 | encode_string(xdr, name->len, name->name); |
| 1302 | |||
| 1303 | p = reserve_space(xdr, 8 + len); | ||
| 1304 | *p++ = cpu_to_be32(OP_LOOKUP); | ||
| 1305 | xdr_encode_opaque(p, name->name, len); | ||
| 1306 | hdr->nops++; | ||
| 1307 | hdr->replen += decode_lookup_maxsz; | ||
| 1308 | } | 1311 | } |
| 1309 | 1312 | ||
| 1310 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) | 1313 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) |
| @@ -1335,9 +1338,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena | |||
| 1335 | * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4, | 1338 | * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4, |
| 1336 | * owner 4 = 32 | 1339 | * owner 4 = 32 |
| 1337 | */ | 1340 | */ |
| 1338 | p = reserve_space(xdr, 8); | 1341 | encode_nfs4_seqid(xdr, arg->seqid); |
| 1339 | *p++ = cpu_to_be32(OP_OPEN); | ||
| 1340 | *p = cpu_to_be32(arg->seqid->sequence->counter); | ||
| 1341 | encode_share_access(xdr, arg->fmode); | 1342 | encode_share_access(xdr, arg->fmode); |
| 1342 | p = reserve_space(xdr, 32); | 1343 | p = reserve_space(xdr, 32); |
| 1343 | p = xdr_encode_hyper(p, arg->clientid); | 1344 | p = xdr_encode_hyper(p, arg->clientid); |
| @@ -1437,14 +1438,15 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc | |||
| 1437 | { | 1438 | { |
| 1438 | __be32 *p; | 1439 | __be32 *p; |
| 1439 | 1440 | ||
| 1440 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); | 1441 | p = reserve_space(xdr, 4); |
| 1441 | *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR); | 1442 | *p = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR); |
| 1442 | xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); | 1443 | encode_nfs4_stateid(xdr, stateid); |
| 1443 | encode_string(xdr, name->len, name->name); | 1444 | encode_string(xdr, name->len, name->name); |
| 1444 | } | 1445 | } |
| 1445 | 1446 | ||
| 1446 | static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr) | 1447 | static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr) |
| 1447 | { | 1448 | { |
| 1449 | encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr); | ||
| 1448 | encode_openhdr(xdr, arg); | 1450 | encode_openhdr(xdr, arg); |
| 1449 | encode_opentype(xdr, arg); | 1451 | encode_opentype(xdr, arg); |
| 1450 | switch (arg->claim) { | 1452 | switch (arg->claim) { |
| @@ -1460,88 +1462,64 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, | |||
| 1460 | default: | 1462 | default: |
| 1461 | BUG(); | 1463 | BUG(); |
| 1462 | } | 1464 | } |
| 1463 | hdr->nops++; | ||
| 1464 | hdr->replen += decode_open_maxsz; | ||
| 1465 | } | 1465 | } |
| 1466 | 1466 | ||
| 1467 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) | 1467 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) |
| 1468 | { | 1468 | { |
| 1469 | __be32 *p; | 1469 | encode_op_hdr(xdr, OP_OPEN_CONFIRM, decode_open_confirm_maxsz, hdr); |
| 1470 | 1470 | encode_nfs4_stateid(xdr, arg->stateid); | |
| 1471 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); | 1471 | encode_nfs4_seqid(xdr, arg->seqid); |
| 1472 | *p++ = cpu_to_be32(OP_OPEN_CONFIRM); | ||
| 1473 | p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); | ||
| 1474 | *p = cpu_to_be32(arg->seqid->sequence->counter); | ||
| 1475 | hdr->nops++; | ||
| 1476 | hdr->replen += decode_open_confirm_maxsz; | ||
| 1477 | } | 1472 | } |
| 1478 | 1473 | ||
| 1479 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 1474 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
| 1480 | { | 1475 | { |
| 1481 | __be32 *p; | 1476 | encode_op_hdr(xdr, OP_OPEN_DOWNGRADE, decode_open_downgrade_maxsz, hdr); |
| 1482 | 1477 | encode_nfs4_stateid(xdr, arg->stateid); | |
| 1483 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); | 1478 | encode_nfs4_seqid(xdr, arg->seqid); |
| 1484 | *p++ = cpu_to_be32(OP_OPEN_DOWNGRADE); | ||
| 1485 | p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE); | ||
| 1486 | *p = cpu_to_be32(arg->seqid->sequence->counter); | ||
| 1487 | encode_share_access(xdr, arg->fmode); | 1479 | encode_share_access(xdr, arg->fmode); |
| 1488 | hdr->nops++; | ||
| 1489 | hdr->replen += decode_open_downgrade_maxsz; | ||
| 1490 | } | 1480 | } |
| 1491 | 1481 | ||
| 1492 | static void | 1482 | static void |
| 1493 | encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr) | 1483 | encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr) |
| 1494 | { | 1484 | { |
| 1495 | int len = fh->size; | 1485 | encode_op_hdr(xdr, OP_PUTFH, decode_putfh_maxsz, hdr); |
| 1496 | __be32 *p; | 1486 | encode_string(xdr, fh->size, fh->data); |
| 1497 | |||
| 1498 | p = reserve_space(xdr, 8 + len); | ||
| 1499 | *p++ = cpu_to_be32(OP_PUTFH); | ||
| 1500 | xdr_encode_opaque(p, fh->data, len); | ||
| 1501 | hdr->nops++; | ||
| 1502 | hdr->replen += decode_putfh_maxsz; | ||
| 1503 | } | 1487 | } |
| 1504 | 1488 | ||
| 1505 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1489 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 1506 | { | 1490 | { |
| 1507 | __be32 *p; | 1491 | encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr); |
| 1508 | |||
| 1509 | p = reserve_space(xdr, 4); | ||
| 1510 | *p = cpu_to_be32(OP_PUTROOTFH); | ||
| 1511 | hdr->nops++; | ||
| 1512 | hdr->replen += decode_putrootfh_maxsz; | ||
| 1513 | } | 1492 | } |
| 1514 | 1493 | ||
| 1515 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx, int zero_seqid) | 1494 | static void encode_open_stateid(struct xdr_stream *xdr, |
| 1495 | const struct nfs_open_context *ctx, | ||
| 1496 | const struct nfs_lock_context *l_ctx, | ||
| 1497 | fmode_t fmode, | ||
| 1498 | int zero_seqid) | ||
| 1516 | { | 1499 | { |
| 1517 | nfs4_stateid stateid; | 1500 | nfs4_stateid stateid; |
| 1518 | __be32 *p; | ||
| 1519 | 1501 | ||
| 1520 | p = reserve_space(xdr, NFS4_STATEID_SIZE); | ||
| 1521 | if (ctx->state != NULL) { | 1502 | if (ctx->state != NULL) { |
| 1522 | nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid); | 1503 | nfs4_select_rw_stateid(&stateid, ctx->state, |
| 1504 | fmode, l_ctx->lockowner, l_ctx->pid); | ||
| 1523 | if (zero_seqid) | 1505 | if (zero_seqid) |
| 1524 | stateid.stateid.seqid = 0; | 1506 | stateid.seqid = 0; |
| 1525 | xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); | 1507 | encode_nfs4_stateid(xdr, &stateid); |
| 1526 | } else | 1508 | } else |
| 1527 | xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); | 1509 | encode_nfs4_stateid(xdr, &zero_stateid); |
| 1528 | } | 1510 | } |
| 1529 | 1511 | ||
| 1530 | static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) | 1512 | static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) |
| 1531 | { | 1513 | { |
| 1532 | __be32 *p; | 1514 | __be32 *p; |
| 1533 | 1515 | ||
| 1534 | p = reserve_space(xdr, 4); | 1516 | encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr); |
| 1535 | *p = cpu_to_be32(OP_READ); | 1517 | encode_open_stateid(xdr, args->context, args->lock_context, |
| 1536 | 1518 | FMODE_READ, hdr->minorversion); | |
| 1537 | encode_stateid(xdr, args->context, args->lock_context, | ||
| 1538 | hdr->minorversion); | ||
| 1539 | 1519 | ||
| 1540 | p = reserve_space(xdr, 12); | 1520 | p = reserve_space(xdr, 12); |
| 1541 | p = xdr_encode_hyper(p, args->offset); | 1521 | p = xdr_encode_hyper(p, args->offset); |
| 1542 | *p = cpu_to_be32(args->count); | 1522 | *p = cpu_to_be32(args->count); |
| 1543 | hdr->nops++; | ||
| 1544 | hdr->replen += decode_read_maxsz; | ||
| 1545 | } | 1523 | } |
| 1546 | 1524 | ||
| 1547 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1525 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
| @@ -1551,7 +1529,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
| 1551 | FATTR4_WORD1_MOUNTED_ON_FILEID, | 1529 | FATTR4_WORD1_MOUNTED_ON_FILEID, |
| 1552 | }; | 1530 | }; |
| 1553 | uint32_t dircount = readdir->count >> 1; | 1531 | uint32_t dircount = readdir->count >> 1; |
| 1554 | __be32 *p; | 1532 | __be32 *p, verf[2]; |
| 1555 | 1533 | ||
| 1556 | if (readdir->plus) { | 1534 | if (readdir->plus) { |
| 1557 | attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| | 1535 | attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| |
| @@ -1566,80 +1544,54 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
| 1566 | if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) | 1544 | if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) |
| 1567 | attrs[0] |= FATTR4_WORD0_FILEID; | 1545 | attrs[0] |= FATTR4_WORD0_FILEID; |
| 1568 | 1546 | ||
| 1569 | p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); | 1547 | encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr); |
| 1570 | *p++ = cpu_to_be32(OP_READDIR); | 1548 | encode_uint64(xdr, readdir->cookie); |
| 1571 | p = xdr_encode_hyper(p, readdir->cookie); | 1549 | encode_nfs4_verifier(xdr, &readdir->verifier); |
| 1572 | p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE); | 1550 | p = reserve_space(xdr, 20); |
| 1573 | *p++ = cpu_to_be32(dircount); | 1551 | *p++ = cpu_to_be32(dircount); |
| 1574 | *p++ = cpu_to_be32(readdir->count); | 1552 | *p++ = cpu_to_be32(readdir->count); |
| 1575 | *p++ = cpu_to_be32(2); | 1553 | *p++ = cpu_to_be32(2); |
| 1576 | 1554 | ||
| 1577 | *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); | 1555 | *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); |
| 1578 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); | 1556 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); |
| 1579 | hdr->nops++; | 1557 | memcpy(verf, readdir->verifier.data, sizeof(verf)); |
| 1580 | hdr->replen += decode_readdir_maxsz; | ||
| 1581 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1558 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
| 1582 | __func__, | 1559 | __func__, |
| 1583 | (unsigned long long)readdir->cookie, | 1560 | (unsigned long long)readdir->cookie, |
| 1584 | ((u32 *)readdir->verifier.data)[0], | 1561 | verf[0], verf[1], |
| 1585 | ((u32 *)readdir->verifier.data)[1], | ||
| 1586 | attrs[0] & readdir->bitmask[0], | 1562 | attrs[0] & readdir->bitmask[0], |
| 1587 | attrs[1] & readdir->bitmask[1]); | 1563 | attrs[1] & readdir->bitmask[1]); |
| 1588 | } | 1564 | } |
| 1589 | 1565 | ||
| 1590 | static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr) | 1566 | static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr) |
| 1591 | { | 1567 | { |
| 1592 | __be32 *p; | 1568 | encode_op_hdr(xdr, OP_READLINK, decode_readlink_maxsz, hdr); |
| 1593 | |||
| 1594 | p = reserve_space(xdr, 4); | ||
| 1595 | *p = cpu_to_be32(OP_READLINK); | ||
| 1596 | hdr->nops++; | ||
| 1597 | hdr->replen += decode_readlink_maxsz; | ||
| 1598 | } | 1569 | } |
| 1599 | 1570 | ||
| 1600 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1571 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| 1601 | { | 1572 | { |
| 1602 | __be32 *p; | 1573 | encode_op_hdr(xdr, OP_REMOVE, decode_remove_maxsz, hdr); |
| 1603 | 1574 | encode_string(xdr, name->len, name->name); | |
| 1604 | p = reserve_space(xdr, 8 + name->len); | ||
| 1605 | *p++ = cpu_to_be32(OP_REMOVE); | ||
| 1606 | xdr_encode_opaque(p, name->name, name->len); | ||
| 1607 | hdr->nops++; | ||
| 1608 | hdr->replen += decode_remove_maxsz; | ||
| 1609 | } | 1575 | } |
| 1610 | 1576 | ||
| 1611 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) | 1577 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) |
| 1612 | { | 1578 | { |
| 1613 | __be32 *p; | 1579 | encode_op_hdr(xdr, OP_RENAME, decode_rename_maxsz, hdr); |
| 1614 | |||
| 1615 | p = reserve_space(xdr, 4); | ||
| 1616 | *p = cpu_to_be32(OP_RENAME); | ||
| 1617 | encode_string(xdr, oldname->len, oldname->name); | 1580 | encode_string(xdr, oldname->len, oldname->name); |
| 1618 | encode_string(xdr, newname->len, newname->name); | 1581 | encode_string(xdr, newname->len, newname->name); |
| 1619 | hdr->nops++; | ||
| 1620 | hdr->replen += decode_rename_maxsz; | ||
| 1621 | } | 1582 | } |
| 1622 | 1583 | ||
| 1623 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) | 1584 | static void encode_renew(struct xdr_stream *xdr, clientid4 clid, |
| 1585 | struct compound_hdr *hdr) | ||
| 1624 | { | 1586 | { |
| 1625 | __be32 *p; | 1587 | encode_op_hdr(xdr, OP_RENEW, decode_renew_maxsz, hdr); |
| 1626 | 1588 | encode_uint64(xdr, clid); | |
| 1627 | p = reserve_space(xdr, 12); | ||
| 1628 | *p++ = cpu_to_be32(OP_RENEW); | ||
| 1629 | xdr_encode_hyper(p, client_stateid->cl_clientid); | ||
| 1630 | hdr->nops++; | ||
| 1631 | hdr->replen += decode_renew_maxsz; | ||
| 1632 | } | 1589 | } |
| 1633 | 1590 | ||
| 1634 | static void | 1591 | static void |
| 1635 | encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1592 | encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 1636 | { | 1593 | { |
| 1637 | __be32 *p; | 1594 | encode_op_hdr(xdr, OP_RESTOREFH, decode_restorefh_maxsz, hdr); |
| 1638 | |||
| 1639 | p = reserve_space(xdr, 4); | ||
| 1640 | *p = cpu_to_be32(OP_RESTOREFH); | ||
| 1641 | hdr->nops++; | ||
| 1642 | hdr->replen += decode_restorefh_maxsz; | ||
| 1643 | } | 1595 | } |
| 1644 | 1596 | ||
| 1645 | static void | 1597 | static void |
| @@ -1647,9 +1599,8 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun | |||
| 1647 | { | 1599 | { |
| 1648 | __be32 *p; | 1600 | __be32 *p; |
| 1649 | 1601 | ||
| 1650 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); | 1602 | encode_op_hdr(xdr, OP_SETATTR, decode_setacl_maxsz, hdr); |
| 1651 | *p++ = cpu_to_be32(OP_SETATTR); | 1603 | encode_nfs4_stateid(xdr, &zero_stateid); |
| 1652 | xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); | ||
| 1653 | p = reserve_space(xdr, 2*4); | 1604 | p = reserve_space(xdr, 2*4); |
| 1654 | *p++ = cpu_to_be32(1); | 1605 | *p++ = cpu_to_be32(1); |
| 1655 | *p = cpu_to_be32(FATTR4_WORD0_ACL); | 1606 | *p = cpu_to_be32(FATTR4_WORD0_ACL); |
| @@ -1657,30 +1608,18 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun | |||
| 1657 | p = reserve_space(xdr, 4); | 1608 | p = reserve_space(xdr, 4); |
| 1658 | *p = cpu_to_be32(arg->acl_len); | 1609 | *p = cpu_to_be32(arg->acl_len); |
| 1659 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | 1610 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); |
| 1660 | hdr->nops++; | ||
| 1661 | hdr->replen += decode_setacl_maxsz; | ||
| 1662 | } | 1611 | } |
| 1663 | 1612 | ||
| 1664 | static void | 1613 | static void |
| 1665 | encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1614 | encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| 1666 | { | 1615 | { |
| 1667 | __be32 *p; | 1616 | encode_op_hdr(xdr, OP_SAVEFH, decode_savefh_maxsz, hdr); |
| 1668 | |||
| 1669 | p = reserve_space(xdr, 4); | ||
| 1670 | *p = cpu_to_be32(OP_SAVEFH); | ||
| 1671 | hdr->nops++; | ||
| 1672 | hdr->replen += decode_savefh_maxsz; | ||
| 1673 | } | 1617 | } |
| 1674 | 1618 | ||
| 1675 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) | 1619 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) |
| 1676 | { | 1620 | { |
| 1677 | __be32 *p; | 1621 | encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr); |
| 1678 | 1622 | encode_nfs4_stateid(xdr, &arg->stateid); | |
| 1679 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); | ||
| 1680 | *p++ = cpu_to_be32(OP_SETATTR); | ||
| 1681 | xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE); | ||
| 1682 | hdr->nops++; | ||
| 1683 | hdr->replen += decode_setattr_maxsz; | ||
| 1684 | encode_attrs(xdr, arg->iap, server); | 1623 | encode_attrs(xdr, arg->iap, server); |
| 1685 | } | 1624 | } |
| 1686 | 1625 | ||
| @@ -1688,9 +1627,8 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
| 1688 | { | 1627 | { |
| 1689 | __be32 *p; | 1628 | __be32 *p; |
| 1690 | 1629 | ||
| 1691 | p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE); | 1630 | encode_op_hdr(xdr, OP_SETCLIENTID, decode_setclientid_maxsz, hdr); |
| 1692 | *p++ = cpu_to_be32(OP_SETCLIENTID); | 1631 | encode_nfs4_verifier(xdr, setclientid->sc_verifier); |
| 1693 | xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE); | ||
| 1694 | 1632 | ||
| 1695 | encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); | 1633 | encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); |
| 1696 | p = reserve_space(xdr, 4); | 1634 | p = reserve_space(xdr, 4); |
| @@ -1699,31 +1637,23 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
| 1699 | encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); | 1637 | encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); |
| 1700 | p = reserve_space(xdr, 4); | 1638 | p = reserve_space(xdr, 4); |
| 1701 | *p = cpu_to_be32(setclientid->sc_cb_ident); | 1639 | *p = cpu_to_be32(setclientid->sc_cb_ident); |
| 1702 | hdr->nops++; | ||
| 1703 | hdr->replen += decode_setclientid_maxsz; | ||
| 1704 | } | 1640 | } |
| 1705 | 1641 | ||
| 1706 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr) | 1642 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr) |
| 1707 | { | 1643 | { |
| 1708 | __be32 *p; | 1644 | encode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM, |
| 1709 | 1645 | decode_setclientid_confirm_maxsz, hdr); | |
| 1710 | p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); | 1646 | encode_uint64(xdr, arg->clientid); |
| 1711 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); | 1647 | encode_nfs4_verifier(xdr, &arg->confirm); |
| 1712 | p = xdr_encode_hyper(p, arg->clientid); | ||
| 1713 | xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE); | ||
| 1714 | hdr->nops++; | ||
| 1715 | hdr->replen += decode_setclientid_confirm_maxsz; | ||
| 1716 | } | 1648 | } |
| 1717 | 1649 | ||
| 1718 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 1650 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
| 1719 | { | 1651 | { |
| 1720 | __be32 *p; | 1652 | __be32 *p; |
| 1721 | 1653 | ||
| 1722 | p = reserve_space(xdr, 4); | 1654 | encode_op_hdr(xdr, OP_WRITE, decode_write_maxsz, hdr); |
| 1723 | *p = cpu_to_be32(OP_WRITE); | 1655 | encode_open_stateid(xdr, args->context, args->lock_context, |
| 1724 | 1656 | FMODE_WRITE, hdr->minorversion); | |
| 1725 | encode_stateid(xdr, args->context, args->lock_context, | ||
| 1726 | hdr->minorversion); | ||
| 1727 | 1657 | ||
| 1728 | p = reserve_space(xdr, 16); | 1658 | p = reserve_space(xdr, 16); |
| 1729 | p = xdr_encode_hyper(p, args->offset); | 1659 | p = xdr_encode_hyper(p, args->offset); |
| @@ -1731,32 +1661,18 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
| 1731 | *p = cpu_to_be32(args->count); | 1661 | *p = cpu_to_be32(args->count); |
| 1732 | 1662 | ||
| 1733 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); | 1663 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); |
| 1734 | hdr->nops++; | ||
| 1735 | hdr->replen += decode_write_maxsz; | ||
| 1736 | } | 1664 | } |
| 1737 | 1665 | ||
| 1738 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) | 1666 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) |
| 1739 | { | 1667 | { |
| 1740 | __be32 *p; | 1668 | encode_op_hdr(xdr, OP_DELEGRETURN, decode_delegreturn_maxsz, hdr); |
| 1741 | 1669 | encode_nfs4_stateid(xdr, stateid); | |
| 1742 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE); | ||
| 1743 | |||
| 1744 | *p++ = cpu_to_be32(OP_DELEGRETURN); | ||
| 1745 | xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE); | ||
| 1746 | hdr->nops++; | ||
| 1747 | hdr->replen += decode_delegreturn_maxsz; | ||
| 1748 | } | 1670 | } |
| 1749 | 1671 | ||
| 1750 | static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1672 | static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| 1751 | { | 1673 | { |
| 1752 | int len = name->len; | 1674 | encode_op_hdr(xdr, OP_SECINFO, decode_secinfo_maxsz, hdr); |
| 1753 | __be32 *p; | 1675 | encode_string(xdr, name->len, name->name); |
| 1754 | |||
| 1755 | p = reserve_space(xdr, 8 + len); | ||
| 1756 | *p++ = cpu_to_be32(OP_SECINFO); | ||
| 1757 | xdr_encode_opaque(p, name->name, len); | ||
| 1758 | hdr->nops++; | ||
| 1759 | hdr->replen += decode_secinfo_maxsz; | ||
| 1760 | } | 1676 | } |
| 1761 | 1677 | ||
| 1762 | #if defined(CONFIG_NFS_V4_1) | 1678 | #if defined(CONFIG_NFS_V4_1) |
| @@ -1766,19 +1682,39 @@ static void encode_exchange_id(struct xdr_stream *xdr, | |||
| 1766 | struct compound_hdr *hdr) | 1682 | struct compound_hdr *hdr) |
| 1767 | { | 1683 | { |
| 1768 | __be32 *p; | 1684 | __be32 *p; |
| 1685 | char impl_name[NFS4_OPAQUE_LIMIT]; | ||
| 1686 | int len = 0; | ||
| 1769 | 1687 | ||
| 1770 | p = reserve_space(xdr, 4 + sizeof(args->verifier->data)); | 1688 | encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr); |
| 1771 | *p++ = cpu_to_be32(OP_EXCHANGE_ID); | 1689 | encode_nfs4_verifier(xdr, args->verifier); |
| 1772 | xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data)); | ||
| 1773 | 1690 | ||
| 1774 | encode_string(xdr, args->id_len, args->id); | 1691 | encode_string(xdr, args->id_len, args->id); |
| 1775 | 1692 | ||
| 1776 | p = reserve_space(xdr, 12); | 1693 | p = reserve_space(xdr, 12); |
| 1777 | *p++ = cpu_to_be32(args->flags); | 1694 | *p++ = cpu_to_be32(args->flags); |
| 1778 | *p++ = cpu_to_be32(0); /* zero length state_protect4_a */ | 1695 | *p++ = cpu_to_be32(0); /* zero length state_protect4_a */ |
| 1779 | *p = cpu_to_be32(0); /* zero length implementation id array */ | 1696 | |
| 1780 | hdr->nops++; | 1697 | if (send_implementation_id && |
| 1781 | hdr->replen += decode_exchange_id_maxsz; | 1698 | sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 && |
| 1699 | sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) | ||
| 1700 | <= NFS4_OPAQUE_LIMIT + 1) | ||
| 1701 | len = snprintf(impl_name, sizeof(impl_name), "%s %s %s %s", | ||
| 1702 | utsname()->sysname, utsname()->release, | ||
| 1703 | utsname()->version, utsname()->machine); | ||
| 1704 | |||
| 1705 | if (len > 0) { | ||
| 1706 | *p = cpu_to_be32(1); /* implementation id array length=1 */ | ||
| 1707 | |||
| 1708 | encode_string(xdr, | ||
| 1709 | sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) - 1, | ||
| 1710 | CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN); | ||
| 1711 | encode_string(xdr, len, impl_name); | ||
| 1712 | /* just send zeros for nii_date - the date is in nii_name */ | ||
| 1713 | p = reserve_space(xdr, 12); | ||
| 1714 | p = xdr_encode_hyper(p, 0); | ||
| 1715 | *p = cpu_to_be32(0); | ||
| 1716 | } else | ||
| 1717 | *p = cpu_to_be32(0); /* implementation id array length=0 */ | ||
| 1782 | } | 1718 | } |
| 1783 | 1719 | ||
| 1784 | static void encode_create_session(struct xdr_stream *xdr, | 1720 | static void encode_create_session(struct xdr_stream *xdr, |
| @@ -1801,8 +1737,8 @@ static void encode_create_session(struct xdr_stream *xdr, | |||
| 1801 | len = scnprintf(machine_name, sizeof(machine_name), "%s", | 1737 | len = scnprintf(machine_name, sizeof(machine_name), "%s", |
| 1802 | clp->cl_ipaddr); | 1738 | clp->cl_ipaddr); |
| 1803 | 1739 | ||
| 1804 | p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12); | 1740 | encode_op_hdr(xdr, OP_CREATE_SESSION, decode_create_session_maxsz, hdr); |
| 1805 | *p++ = cpu_to_be32(OP_CREATE_SESSION); | 1741 | p = reserve_space(xdr, 16 + 2*28 + 20 + len + 12); |
| 1806 | p = xdr_encode_hyper(p, clp->cl_clientid); | 1742 | p = xdr_encode_hyper(p, clp->cl_clientid); |
| 1807 | *p++ = cpu_to_be32(clp->cl_seqid); /*Sequence id */ | 1743 | *p++ = cpu_to_be32(clp->cl_seqid); /*Sequence id */ |
| 1808 | *p++ = cpu_to_be32(args->flags); /*flags */ | 1744 | *p++ = cpu_to_be32(args->flags); /*flags */ |
| @@ -1835,33 +1771,22 @@ static void encode_create_session(struct xdr_stream *xdr, | |||
| 1835 | *p++ = cpu_to_be32(0); /* UID */ | 1771 | *p++ = cpu_to_be32(0); /* UID */ |
| 1836 | *p++ = cpu_to_be32(0); /* GID */ | 1772 | *p++ = cpu_to_be32(0); /* GID */ |
| 1837 | *p = cpu_to_be32(0); /* No more gids */ | 1773 | *p = cpu_to_be32(0); /* No more gids */ |
| 1838 | hdr->nops++; | ||
| 1839 | hdr->replen += decode_create_session_maxsz; | ||
| 1840 | } | 1774 | } |
| 1841 | 1775 | ||
| 1842 | static void encode_destroy_session(struct xdr_stream *xdr, | 1776 | static void encode_destroy_session(struct xdr_stream *xdr, |
| 1843 | struct nfs4_session *session, | 1777 | struct nfs4_session *session, |
| 1844 | struct compound_hdr *hdr) | 1778 | struct compound_hdr *hdr) |
| 1845 | { | 1779 | { |
| 1846 | __be32 *p; | 1780 | encode_op_hdr(xdr, OP_DESTROY_SESSION, decode_destroy_session_maxsz, hdr); |
| 1847 | p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN); | 1781 | encode_opaque_fixed(xdr, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); |
| 1848 | *p++ = cpu_to_be32(OP_DESTROY_SESSION); | ||
| 1849 | xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
| 1850 | hdr->nops++; | ||
| 1851 | hdr->replen += decode_destroy_session_maxsz; | ||
| 1852 | } | 1782 | } |
| 1853 | 1783 | ||
| 1854 | static void encode_reclaim_complete(struct xdr_stream *xdr, | 1784 | static void encode_reclaim_complete(struct xdr_stream *xdr, |
| 1855 | struct nfs41_reclaim_complete_args *args, | 1785 | struct nfs41_reclaim_complete_args *args, |
| 1856 | struct compound_hdr *hdr) | 1786 | struct compound_hdr *hdr) |
| 1857 | { | 1787 | { |
| 1858 | __be32 *p; | 1788 | encode_op_hdr(xdr, OP_RECLAIM_COMPLETE, decode_reclaim_complete_maxsz, hdr); |
| 1859 | 1789 | encode_uint32(xdr, args->one_fs); | |
| 1860 | p = reserve_space(xdr, 8); | ||
| 1861 | *p++ = cpu_to_be32(OP_RECLAIM_COMPLETE); | ||
| 1862 | *p++ = cpu_to_be32(args->one_fs); | ||
| 1863 | hdr->nops++; | ||
| 1864 | hdr->replen += decode_reclaim_complete_maxsz; | ||
| 1865 | } | 1790 | } |
| 1866 | #endif /* CONFIG_NFS_V4_1 */ | 1791 | #endif /* CONFIG_NFS_V4_1 */ |
| 1867 | 1792 | ||
| @@ -1883,8 +1808,7 @@ static void encode_sequence(struct xdr_stream *xdr, | |||
| 1883 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); | 1808 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); |
| 1884 | slot = tp->slots + args->sa_slotid; | 1809 | slot = tp->slots + args->sa_slotid; |
| 1885 | 1810 | ||
| 1886 | p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16); | 1811 | encode_op_hdr(xdr, OP_SEQUENCE, decode_sequence_maxsz, hdr); |
| 1887 | *p++ = cpu_to_be32(OP_SEQUENCE); | ||
| 1888 | 1812 | ||
| 1889 | /* | 1813 | /* |
| 1890 | * Sessionid + seqid + slotid + max slotid + cache_this | 1814 | * Sessionid + seqid + slotid + max slotid + cache_this |
| @@ -1898,13 +1822,12 @@ static void encode_sequence(struct xdr_stream *xdr, | |||
| 1898 | ((u32 *)session->sess_id.data)[3], | 1822 | ((u32 *)session->sess_id.data)[3], |
| 1899 | slot->seq_nr, args->sa_slotid, | 1823 | slot->seq_nr, args->sa_slotid, |
| 1900 | tp->highest_used_slotid, args->sa_cache_this); | 1824 | tp->highest_used_slotid, args->sa_cache_this); |
| 1825 | p = reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 16); | ||
| 1901 | p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | 1826 | p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); |
| 1902 | *p++ = cpu_to_be32(slot->seq_nr); | 1827 | *p++ = cpu_to_be32(slot->seq_nr); |
| 1903 | *p++ = cpu_to_be32(args->sa_slotid); | 1828 | *p++ = cpu_to_be32(args->sa_slotid); |
| 1904 | *p++ = cpu_to_be32(tp->highest_used_slotid); | 1829 | *p++ = cpu_to_be32(tp->highest_used_slotid); |
| 1905 | *p = cpu_to_be32(args->sa_cache_this); | 1830 | *p = cpu_to_be32(args->sa_cache_this); |
| 1906 | hdr->nops++; | ||
| 1907 | hdr->replen += decode_sequence_maxsz; | ||
| 1908 | #endif /* CONFIG_NFS_V4_1 */ | 1831 | #endif /* CONFIG_NFS_V4_1 */ |
| 1909 | } | 1832 | } |
| 1910 | 1833 | ||
| @@ -1919,14 +1842,12 @@ encode_getdevicelist(struct xdr_stream *xdr, | |||
| 1919 | .data = "dummmmmy", | 1842 | .data = "dummmmmy", |
| 1920 | }; | 1843 | }; |
| 1921 | 1844 | ||
| 1922 | p = reserve_space(xdr, 20); | 1845 | encode_op_hdr(xdr, OP_GETDEVICELIST, decode_getdevicelist_maxsz, hdr); |
| 1923 | *p++ = cpu_to_be32(OP_GETDEVICELIST); | 1846 | p = reserve_space(xdr, 16); |
| 1924 | *p++ = cpu_to_be32(args->layoutclass); | 1847 | *p++ = cpu_to_be32(args->layoutclass); |
| 1925 | *p++ = cpu_to_be32(NFS4_PNFS_GETDEVLIST_MAXNUM); | 1848 | *p++ = cpu_to_be32(NFS4_PNFS_GETDEVLIST_MAXNUM); |
| 1926 | xdr_encode_hyper(p, 0ULL); /* cookie */ | 1849 | xdr_encode_hyper(p, 0ULL); /* cookie */ |
| 1927 | encode_nfs4_verifier(xdr, &dummy); | 1850 | encode_nfs4_verifier(xdr, &dummy); |
| 1928 | hdr->nops++; | ||
| 1929 | hdr->replen += decode_getdevicelist_maxsz; | ||
| 1930 | } | 1851 | } |
| 1931 | 1852 | ||
| 1932 | static void | 1853 | static void |
| @@ -1936,15 +1857,13 @@ encode_getdeviceinfo(struct xdr_stream *xdr, | |||
| 1936 | { | 1857 | { |
| 1937 | __be32 *p; | 1858 | __be32 *p; |
| 1938 | 1859 | ||
| 1939 | p = reserve_space(xdr, 16 + NFS4_DEVICEID4_SIZE); | 1860 | encode_op_hdr(xdr, OP_GETDEVICEINFO, decode_getdeviceinfo_maxsz, hdr); |
| 1940 | *p++ = cpu_to_be32(OP_GETDEVICEINFO); | 1861 | p = reserve_space(xdr, 12 + NFS4_DEVICEID4_SIZE); |
| 1941 | p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data, | 1862 | p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data, |
| 1942 | NFS4_DEVICEID4_SIZE); | 1863 | NFS4_DEVICEID4_SIZE); |
| 1943 | *p++ = cpu_to_be32(args->pdev->layout_type); | 1864 | *p++ = cpu_to_be32(args->pdev->layout_type); |
| 1944 | *p++ = cpu_to_be32(args->pdev->pglen); /* gdia_maxcount */ | 1865 | *p++ = cpu_to_be32(args->pdev->pglen); /* gdia_maxcount */ |
| 1945 | *p++ = cpu_to_be32(0); /* bitmap length 0 */ | 1866 | *p++ = cpu_to_be32(0); /* bitmap length 0 */ |
| 1946 | hdr->nops++; | ||
| 1947 | hdr->replen += decode_getdeviceinfo_maxsz; | ||
| 1948 | } | 1867 | } |
| 1949 | 1868 | ||
| 1950 | static void | 1869 | static void |
| @@ -1954,16 +1873,16 @@ encode_layoutget(struct xdr_stream *xdr, | |||
| 1954 | { | 1873 | { |
| 1955 | __be32 *p; | 1874 | __be32 *p; |
| 1956 | 1875 | ||
| 1957 | p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE); | 1876 | encode_op_hdr(xdr, OP_LAYOUTGET, decode_layoutget_maxsz, hdr); |
| 1958 | *p++ = cpu_to_be32(OP_LAYOUTGET); | 1877 | p = reserve_space(xdr, 36); |
| 1959 | *p++ = cpu_to_be32(0); /* Signal layout available */ | 1878 | *p++ = cpu_to_be32(0); /* Signal layout available */ |
| 1960 | *p++ = cpu_to_be32(args->type); | 1879 | *p++ = cpu_to_be32(args->type); |
| 1961 | *p++ = cpu_to_be32(args->range.iomode); | 1880 | *p++ = cpu_to_be32(args->range.iomode); |
| 1962 | p = xdr_encode_hyper(p, args->range.offset); | 1881 | p = xdr_encode_hyper(p, args->range.offset); |
| 1963 | p = xdr_encode_hyper(p, args->range.length); | 1882 | p = xdr_encode_hyper(p, args->range.length); |
| 1964 | p = xdr_encode_hyper(p, args->minlength); | 1883 | p = xdr_encode_hyper(p, args->minlength); |
| 1965 | p = xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE); | 1884 | encode_nfs4_stateid(xdr, &args->stateid); |
| 1966 | *p = cpu_to_be32(args->maxcount); | 1885 | encode_uint32(xdr, args->maxcount); |
| 1967 | 1886 | ||
| 1968 | dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n", | 1887 | dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n", |
| 1969 | __func__, | 1888 | __func__, |
| @@ -1972,8 +1891,6 @@ encode_layoutget(struct xdr_stream *xdr, | |||
| 1972 | (unsigned long)args->range.offset, | 1891 | (unsigned long)args->range.offset, |
| 1973 | (unsigned long)args->range.length, | 1892 | (unsigned long)args->range.length, |
| 1974 | args->maxcount); | 1893 | args->maxcount); |
| 1975 | hdr->nops++; | ||
| 1976 | hdr->replen += decode_layoutget_maxsz; | ||
| 1977 | } | 1894 | } |
| 1978 | 1895 | ||
| 1979 | static int | 1896 | static int |
| @@ -1987,13 +1904,14 @@ encode_layoutcommit(struct xdr_stream *xdr, | |||
| 1987 | dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten, | 1904 | dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten, |
| 1988 | NFS_SERVER(args->inode)->pnfs_curr_ld->id); | 1905 | NFS_SERVER(args->inode)->pnfs_curr_ld->id); |
| 1989 | 1906 | ||
| 1990 | p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE); | 1907 | encode_op_hdr(xdr, OP_LAYOUTCOMMIT, decode_layoutcommit_maxsz, hdr); |
| 1991 | *p++ = cpu_to_be32(OP_LAYOUTCOMMIT); | 1908 | p = reserve_space(xdr, 20); |
| 1992 | /* Only whole file layouts */ | 1909 | /* Only whole file layouts */ |
| 1993 | p = xdr_encode_hyper(p, 0); /* offset */ | 1910 | p = xdr_encode_hyper(p, 0); /* offset */ |
| 1994 | p = xdr_encode_hyper(p, args->lastbytewritten + 1); /* length */ | 1911 | p = xdr_encode_hyper(p, args->lastbytewritten + 1); /* length */ |
| 1995 | *p++ = cpu_to_be32(0); /* reclaim */ | 1912 | *p = cpu_to_be32(0); /* reclaim */ |
| 1996 | p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE); | 1913 | encode_nfs4_stateid(xdr, &args->stateid); |
| 1914 | p = reserve_space(xdr, 20); | ||
| 1997 | *p++ = cpu_to_be32(1); /* newoffset = TRUE */ | 1915 | *p++ = cpu_to_be32(1); /* newoffset = TRUE */ |
| 1998 | p = xdr_encode_hyper(p, args->lastbytewritten); | 1916 | p = xdr_encode_hyper(p, args->lastbytewritten); |
| 1999 | *p++ = cpu_to_be32(0); /* Never send time_modify_changed */ | 1917 | *p++ = cpu_to_be32(0); /* Never send time_modify_changed */ |
| @@ -2002,13 +1920,9 @@ encode_layoutcommit(struct xdr_stream *xdr, | |||
| 2002 | if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit) | 1920 | if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit) |
| 2003 | NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit( | 1921 | NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit( |
| 2004 | NFS_I(inode)->layout, xdr, args); | 1922 | NFS_I(inode)->layout, xdr, args); |
| 2005 | else { | 1923 | else |
| 2006 | p = reserve_space(xdr, 4); | 1924 | encode_uint32(xdr, 0); /* no layout-type payload */ |
| 2007 | *p = cpu_to_be32(0); /* no layout-type payload */ | ||
| 2008 | } | ||
| 2009 | 1925 | ||
| 2010 | hdr->nops++; | ||
| 2011 | hdr->replen += decode_layoutcommit_maxsz; | ||
| 2012 | return 0; | 1926 | return 0; |
| 2013 | } | 1927 | } |
| 2014 | 1928 | ||
| @@ -2019,27 +1933,23 @@ encode_layoutreturn(struct xdr_stream *xdr, | |||
| 2019 | { | 1933 | { |
| 2020 | __be32 *p; | 1934 | __be32 *p; |
| 2021 | 1935 | ||
| 2022 | p = reserve_space(xdr, 20); | 1936 | encode_op_hdr(xdr, OP_LAYOUTRETURN, decode_layoutreturn_maxsz, hdr); |
| 2023 | *p++ = cpu_to_be32(OP_LAYOUTRETURN); | 1937 | p = reserve_space(xdr, 16); |
| 2024 | *p++ = cpu_to_be32(0); /* reclaim. always 0 for now */ | 1938 | *p++ = cpu_to_be32(0); /* reclaim. always 0 for now */ |
| 2025 | *p++ = cpu_to_be32(args->layout_type); | 1939 | *p++ = cpu_to_be32(args->layout_type); |
| 2026 | *p++ = cpu_to_be32(IOMODE_ANY); | 1940 | *p++ = cpu_to_be32(IOMODE_ANY); |
| 2027 | *p = cpu_to_be32(RETURN_FILE); | 1941 | *p = cpu_to_be32(RETURN_FILE); |
| 2028 | p = reserve_space(xdr, 16 + NFS4_STATEID_SIZE); | 1942 | p = reserve_space(xdr, 16); |
| 2029 | p = xdr_encode_hyper(p, 0); | 1943 | p = xdr_encode_hyper(p, 0); |
| 2030 | p = xdr_encode_hyper(p, NFS4_MAX_UINT64); | 1944 | p = xdr_encode_hyper(p, NFS4_MAX_UINT64); |
| 2031 | spin_lock(&args->inode->i_lock); | 1945 | spin_lock(&args->inode->i_lock); |
| 2032 | xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE); | 1946 | encode_nfs4_stateid(xdr, &args->stateid); |
| 2033 | spin_unlock(&args->inode->i_lock); | 1947 | spin_unlock(&args->inode->i_lock); |
| 2034 | if (NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn) { | 1948 | if (NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn) { |
| 2035 | NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn( | 1949 | NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn( |
| 2036 | NFS_I(args->inode)->layout, xdr, args); | 1950 | NFS_I(args->inode)->layout, xdr, args); |
| 2037 | } else { | 1951 | } else |
| 2038 | p = reserve_space(xdr, 4); | 1952 | encode_uint32(xdr, 0); |
| 2039 | *p = cpu_to_be32(0); | ||
| 2040 | } | ||
| 2041 | hdr->nops++; | ||
| 2042 | hdr->replen += decode_layoutreturn_maxsz; | ||
| 2043 | } | 1953 | } |
| 2044 | 1954 | ||
| 2045 | static int | 1955 | static int |
| @@ -2047,12 +1957,8 @@ encode_secinfo_no_name(struct xdr_stream *xdr, | |||
| 2047 | const struct nfs41_secinfo_no_name_args *args, | 1957 | const struct nfs41_secinfo_no_name_args *args, |
| 2048 | struct compound_hdr *hdr) | 1958 | struct compound_hdr *hdr) |
| 2049 | { | 1959 | { |
| 2050 | __be32 *p; | 1960 | encode_op_hdr(xdr, OP_SECINFO_NO_NAME, decode_secinfo_no_name_maxsz, hdr); |
| 2051 | p = reserve_space(xdr, 8); | 1961 | encode_uint32(xdr, args->style); |
| 2052 | *p++ = cpu_to_be32(OP_SECINFO_NO_NAME); | ||
| 2053 | *p++ = cpu_to_be32(args->style); | ||
| 2054 | hdr->nops++; | ||
| 2055 | hdr->replen += decode_secinfo_no_name_maxsz; | ||
| 2056 | return 0; | 1962 | return 0; |
| 2057 | } | 1963 | } |
| 2058 | 1964 | ||
| @@ -2060,26 +1966,17 @@ static void encode_test_stateid(struct xdr_stream *xdr, | |||
| 2060 | struct nfs41_test_stateid_args *args, | 1966 | struct nfs41_test_stateid_args *args, |
| 2061 | struct compound_hdr *hdr) | 1967 | struct compound_hdr *hdr) |
| 2062 | { | 1968 | { |
| 2063 | __be32 *p; | 1969 | encode_op_hdr(xdr, OP_TEST_STATEID, decode_test_stateid_maxsz, hdr); |
| 2064 | 1970 | encode_uint32(xdr, 1); | |
| 2065 | p = reserve_space(xdr, 8 + NFS4_STATEID_SIZE); | 1971 | encode_nfs4_stateid(xdr, args->stateid); |
| 2066 | *p++ = cpu_to_be32(OP_TEST_STATEID); | ||
| 2067 | *p++ = cpu_to_be32(1); | ||
| 2068 | xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE); | ||
| 2069 | hdr->nops++; | ||
| 2070 | hdr->replen += decode_test_stateid_maxsz; | ||
| 2071 | } | 1972 | } |
| 2072 | 1973 | ||
| 2073 | static void encode_free_stateid(struct xdr_stream *xdr, | 1974 | static void encode_free_stateid(struct xdr_stream *xdr, |
| 2074 | struct nfs41_free_stateid_args *args, | 1975 | struct nfs41_free_stateid_args *args, |
| 2075 | struct compound_hdr *hdr) | 1976 | struct compound_hdr *hdr) |
| 2076 | { | 1977 | { |
| 2077 | __be32 *p; | 1978 | encode_op_hdr(xdr, OP_FREE_STATEID, decode_free_stateid_maxsz, hdr); |
| 2078 | p = reserve_space(xdr, 4 + NFS4_STATEID_SIZE); | 1979 | encode_nfs4_stateid(xdr, args->stateid); |
| 2079 | *p++ = cpu_to_be32(OP_FREE_STATEID); | ||
| 2080 | xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE); | ||
| 2081 | hdr->nops++; | ||
| 2082 | hdr->replen += decode_free_stateid_maxsz; | ||
| 2083 | } | 1980 | } |
| 2084 | #endif /* CONFIG_NFS_V4_1 */ | 1981 | #endif /* CONFIG_NFS_V4_1 */ |
| 2085 | 1982 | ||
| @@ -2633,6 +2530,7 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req, | |||
| 2633 | encode_sequence(xdr, &args->seq_args, &hdr); | 2530 | encode_sequence(xdr, &args->seq_args, &hdr); |
| 2634 | encode_putfh(xdr, args->fhandle, &hdr); | 2531 | encode_putfh(xdr, args->fhandle, &hdr); |
| 2635 | encode_getattr_one(xdr, FATTR4_WORD0_SUPPORTED_ATTRS| | 2532 | encode_getattr_one(xdr, FATTR4_WORD0_SUPPORTED_ATTRS| |
| 2533 | FATTR4_WORD0_FH_EXPIRE_TYPE| | ||
| 2636 | FATTR4_WORD0_LINK_SUPPORT| | 2534 | FATTR4_WORD0_LINK_SUPPORT| |
| 2637 | FATTR4_WORD0_SYMLINK_SUPPORT| | 2535 | FATTR4_WORD0_SYMLINK_SUPPORT| |
| 2638 | FATTR4_WORD0_ACLSUPPORT, &hdr); | 2536 | FATTR4_WORD0_ACLSUPPORT, &hdr); |
| @@ -2650,7 +2548,7 @@ static void nfs4_xdr_enc_renew(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
| 2650 | }; | 2548 | }; |
| 2651 | 2549 | ||
| 2652 | encode_compound_hdr(xdr, req, &hdr); | 2550 | encode_compound_hdr(xdr, req, &hdr); |
| 2653 | encode_renew(xdr, clp, &hdr); | 2551 | encode_renew(xdr, clp->cl_clientid, &hdr); |
| 2654 | encode_nops(&hdr); | 2552 | encode_nops(&hdr); |
| 2655 | } | 2553 | } |
| 2656 | 2554 | ||
| @@ -3180,6 +3078,28 @@ out_overflow: | |||
| 3180 | return -EIO; | 3078 | return -EIO; |
| 3181 | } | 3079 | } |
| 3182 | 3080 | ||
| 3081 | static int decode_attr_fh_expire_type(struct xdr_stream *xdr, | ||
| 3082 | uint32_t *bitmap, uint32_t *type) | ||
| 3083 | { | ||
| 3084 | __be32 *p; | ||
| 3085 | |||
| 3086 | *type = 0; | ||
| 3087 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FH_EXPIRE_TYPE - 1U))) | ||
| 3088 | return -EIO; | ||
| 3089 | if (likely(bitmap[0] & FATTR4_WORD0_FH_EXPIRE_TYPE)) { | ||
| 3090 | p = xdr_inline_decode(xdr, 4); | ||
| 3091 | if (unlikely(!p)) | ||
| 3092 | goto out_overflow; | ||
| 3093 | *type = be32_to_cpup(p); | ||
| 3094 | bitmap[0] &= ~FATTR4_WORD0_FH_EXPIRE_TYPE; | ||
| 3095 | } | ||
| 3096 | dprintk("%s: expire type=0x%x\n", __func__, *type); | ||
| 3097 | return 0; | ||
| 3098 | out_overflow: | ||
| 3099 | print_overflow_msg(__func__, xdr); | ||
| 3100 | return -EIO; | ||
| 3101 | } | ||
| 3102 | |||
| 3183 | static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change) | 3103 | static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change) |
| 3184 | { | 3104 | { |
| 3185 | __be32 *p; | 3105 | __be32 *p; |
| @@ -3513,16 +3433,17 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) | |||
| 3513 | n = be32_to_cpup(p); | 3433 | n = be32_to_cpup(p); |
| 3514 | if (n == 0) | 3434 | if (n == 0) |
| 3515 | goto root_path; | 3435 | goto root_path; |
| 3516 | dprintk("path "); | 3436 | dprintk("pathname4: "); |
| 3517 | path->ncomponents = 0; | 3437 | path->ncomponents = 0; |
| 3518 | while (path->ncomponents < n) { | 3438 | while (path->ncomponents < n) { |
| 3519 | struct nfs4_string *component = &path->components[path->ncomponents]; | 3439 | struct nfs4_string *component = &path->components[path->ncomponents]; |
| 3520 | status = decode_opaque_inline(xdr, &component->len, &component->data); | 3440 | status = decode_opaque_inline(xdr, &component->len, &component->data); |
| 3521 | if (unlikely(status != 0)) | 3441 | if (unlikely(status != 0)) |
| 3522 | goto out_eio; | 3442 | goto out_eio; |
| 3523 | if (path->ncomponents != n) | 3443 | ifdebug (XDR) |
| 3524 | dprintk("/"); | 3444 | pr_cont("%s%.*s ", |
| 3525 | dprintk("%s", component->data); | 3445 | (path->ncomponents != n ? "/ " : ""), |
| 3446 | component->len, component->data); | ||
| 3526 | if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS) | 3447 | if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS) |
| 3527 | path->ncomponents++; | 3448 | path->ncomponents++; |
| 3528 | else { | 3449 | else { |
| @@ -3531,14 +3452,13 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) | |||
| 3531 | } | 3452 | } |
| 3532 | } | 3453 | } |
| 3533 | out: | 3454 | out: |
| 3534 | dprintk("\n"); | ||
| 3535 | return status; | 3455 | return status; |
| 3536 | root_path: | 3456 | root_path: |
| 3537 | /* a root pathname is sent as a zero component4 */ | 3457 | /* a root pathname is sent as a zero component4 */ |
| 3538 | path->ncomponents = 1; | 3458 | path->ncomponents = 1; |
| 3539 | path->components[0].len=0; | 3459 | path->components[0].len=0; |
| 3540 | path->components[0].data=NULL; | 3460 | path->components[0].data=NULL; |
| 3541 | dprintk("path /\n"); | 3461 | dprintk("pathname4: /\n"); |
| 3542 | goto out; | 3462 | goto out; |
| 3543 | out_eio: | 3463 | out_eio: |
| 3544 | dprintk(" status %d", status); | 3464 | dprintk(" status %d", status); |
| @@ -3560,7 +3480,11 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
| 3560 | status = 0; | 3480 | status = 0; |
| 3561 | if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS))) | 3481 | if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS))) |
| 3562 | goto out; | 3482 | goto out; |
| 3563 | dprintk("%s: fsroot ", __func__); | 3483 | status = -EIO; |
| 3484 | /* Ignore borken servers that return unrequested attrs */ | ||
| 3485 | if (unlikely(res == NULL)) | ||
| 3486 | goto out; | ||
| 3487 | dprintk("%s: fsroot:\n", __func__); | ||
| 3564 | status = decode_pathname(xdr, &res->fs_path); | 3488 | status = decode_pathname(xdr, &res->fs_path); |
| 3565 | if (unlikely(status != 0)) | 3489 | if (unlikely(status != 0)) |
| 3566 | goto out; | 3490 | goto out; |
| @@ -3581,7 +3505,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
| 3581 | m = be32_to_cpup(p); | 3505 | m = be32_to_cpup(p); |
| 3582 | 3506 | ||
| 3583 | loc->nservers = 0; | 3507 | loc->nservers = 0; |
| 3584 | dprintk("%s: servers ", __func__); | 3508 | dprintk("%s: servers:\n", __func__); |
| 3585 | while (loc->nservers < m) { | 3509 | while (loc->nservers < m) { |
| 3586 | struct nfs4_string *server = &loc->servers[loc->nservers]; | 3510 | struct nfs4_string *server = &loc->servers[loc->nservers]; |
| 3587 | status = decode_opaque_inline(xdr, &server->len, &server->data); | 3511 | status = decode_opaque_inline(xdr, &server->len, &server->data); |
| @@ -3613,7 +3537,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
| 3613 | res->nlocations++; | 3537 | res->nlocations++; |
| 3614 | } | 3538 | } |
| 3615 | if (res->nlocations != 0) | 3539 | if (res->nlocations != 0) |
| 3616 | status = NFS_ATTR_FATTR_V4_REFERRAL; | 3540 | status = NFS_ATTR_FATTR_V4_LOCATIONS; |
| 3617 | out: | 3541 | out: |
| 3618 | dprintk("%s: fs_locations done, error = %d\n", __func__, status); | 3542 | dprintk("%s: fs_locations done, error = %d\n", __func__, status); |
| 3619 | return status; | 3543 | return status; |
| @@ -4157,7 +4081,7 @@ static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len) | |||
| 4157 | 4081 | ||
| 4158 | static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) | 4082 | static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) |
| 4159 | { | 4083 | { |
| 4160 | return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE); | 4084 | return decode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE); |
| 4161 | } | 4085 | } |
| 4162 | 4086 | ||
| 4163 | static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) | 4087 | static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) |
| @@ -4174,7 +4098,7 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) | |||
| 4174 | 4098 | ||
| 4175 | static int decode_verifier(struct xdr_stream *xdr, void *verifier) | 4099 | static int decode_verifier(struct xdr_stream *xdr, void *verifier) |
| 4176 | { | 4100 | { |
| 4177 | return decode_opaque_fixed(xdr, verifier, 8); | 4101 | return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE); |
| 4178 | } | 4102 | } |
| 4179 | 4103 | ||
| 4180 | static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) | 4104 | static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res) |
| @@ -4224,6 +4148,9 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re | |||
| 4224 | goto xdr_error; | 4148 | goto xdr_error; |
| 4225 | if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0) | 4149 | if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0) |
| 4226 | goto xdr_error; | 4150 | goto xdr_error; |
| 4151 | if ((status = decode_attr_fh_expire_type(xdr, bitmap, | ||
| 4152 | &res->fh_expire_type)) != 0) | ||
| 4153 | goto xdr_error; | ||
| 4227 | if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0) | 4154 | if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0) |
| 4228 | goto xdr_error; | 4155 | goto xdr_error; |
| 4229 | if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0) | 4156 | if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0) |
| @@ -4294,6 +4221,7 @@ xdr_error: | |||
| 4294 | 4221 | ||
| 4295 | static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | 4222 | static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, |
| 4296 | struct nfs_fattr *fattr, struct nfs_fh *fh, | 4223 | struct nfs_fattr *fattr, struct nfs_fh *fh, |
| 4224 | struct nfs4_fs_locations *fs_loc, | ||
| 4297 | const struct nfs_server *server) | 4225 | const struct nfs_server *server) |
| 4298 | { | 4226 | { |
| 4299 | int status; | 4227 | int status; |
| @@ -4341,9 +4269,7 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
| 4341 | goto xdr_error; | 4269 | goto xdr_error; |
| 4342 | fattr->valid |= status; | 4270 | fattr->valid |= status; |
| 4343 | 4271 | ||
| 4344 | status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr, | 4272 | status = decode_attr_fs_locations(xdr, bitmap, fs_loc); |
| 4345 | struct nfs4_fs_locations, | ||
| 4346 | fattr)); | ||
| 4347 | if (status < 0) | 4273 | if (status < 0) |
| 4348 | goto xdr_error; | 4274 | goto xdr_error; |
| 4349 | fattr->valid |= status; | 4275 | fattr->valid |= status; |
| @@ -4407,7 +4333,8 @@ xdr_error: | |||
| 4407 | } | 4333 | } |
| 4408 | 4334 | ||
| 4409 | static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, | 4335 | static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, |
| 4410 | struct nfs_fh *fh, const struct nfs_server *server) | 4336 | struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc, |
| 4337 | const struct nfs_server *server) | ||
| 4411 | { | 4338 | { |
| 4412 | __be32 *savep; | 4339 | __be32 *savep; |
| 4413 | uint32_t attrlen, | 4340 | uint32_t attrlen, |
| @@ -4426,7 +4353,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat | |||
| 4426 | if (status < 0) | 4353 | if (status < 0) |
| 4427 | goto xdr_error; | 4354 | goto xdr_error; |
| 4428 | 4355 | ||
| 4429 | status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server); | 4356 | status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server); |
| 4430 | if (status < 0) | 4357 | if (status < 0) |
| 4431 | goto xdr_error; | 4358 | goto xdr_error; |
| 4432 | 4359 | ||
| @@ -4439,7 +4366,7 @@ xdr_error: | |||
| 4439 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | 4366 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, |
| 4440 | const struct nfs_server *server) | 4367 | const struct nfs_server *server) |
| 4441 | { | 4368 | { |
| 4442 | return decode_getfattr_generic(xdr, fattr, NULL, server); | 4369 | return decode_getfattr_generic(xdr, fattr, NULL, NULL, server); |
| 4443 | } | 4370 | } |
| 4444 | 4371 | ||
| 4445 | /* | 4372 | /* |
| @@ -4463,8 +4390,8 @@ static int decode_first_pnfs_layout_type(struct xdr_stream *xdr, | |||
| 4463 | return 0; | 4390 | return 0; |
| 4464 | } | 4391 | } |
| 4465 | if (num > 1) | 4392 | if (num > 1) |
| 4466 | printk(KERN_INFO "%s: Warning: Multiple pNFS layout drivers " | 4393 | printk(KERN_INFO "NFS: %s: Warning: Multiple pNFS layout " |
| 4467 | "per filesystem not supported\n", __func__); | 4394 | "drivers per filesystem not supported\n", __func__); |
| 4468 | 4395 | ||
| 4469 | /* Decode and set first layout type, move xdr->p past unused types */ | 4396 | /* Decode and set first layout type, move xdr->p past unused types */ |
| 4470 | p = xdr_inline_decode(xdr, num * 4); | 4397 | p = xdr_inline_decode(xdr, num * 4); |
| @@ -4863,17 +4790,16 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
| 4863 | size_t hdrlen; | 4790 | size_t hdrlen; |
| 4864 | u32 recvd, pglen = rcvbuf->page_len; | 4791 | u32 recvd, pglen = rcvbuf->page_len; |
| 4865 | int status; | 4792 | int status; |
| 4793 | __be32 verf[2]; | ||
| 4866 | 4794 | ||
| 4867 | status = decode_op_hdr(xdr, OP_READDIR); | 4795 | status = decode_op_hdr(xdr, OP_READDIR); |
| 4868 | if (!status) | 4796 | if (!status) |
| 4869 | status = decode_verifier(xdr, readdir->verifier.data); | 4797 | status = decode_verifier(xdr, readdir->verifier.data); |
| 4870 | if (unlikely(status)) | 4798 | if (unlikely(status)) |
| 4871 | return status; | 4799 | return status; |
| 4800 | memcpy(verf, readdir->verifier.data, sizeof(verf)); | ||
| 4872 | dprintk("%s: verifier = %08x:%08x\n", | 4801 | dprintk("%s: verifier = %08x:%08x\n", |
| 4873 | __func__, | 4802 | __func__, verf[0], verf[1]); |
| 4874 | ((u32 *)readdir->verifier.data)[0], | ||
| 4875 | ((u32 *)readdir->verifier.data)[1]); | ||
| 4876 | |||
| 4877 | 4803 | ||
| 4878 | hdrlen = (char *) xdr->p - (char *) iov->iov_base; | 4804 | hdrlen = (char *) xdr->p - (char *) iov->iov_base; |
| 4879 | recvd = rcvbuf->len - hdrlen; | 4805 | recvd = rcvbuf->len - hdrlen; |
| @@ -5120,7 +5046,7 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) | |||
| 5120 | goto out_overflow; | 5046 | goto out_overflow; |
| 5121 | res->count = be32_to_cpup(p++); | 5047 | res->count = be32_to_cpup(p++); |
| 5122 | res->verf->committed = be32_to_cpup(p++); | 5048 | res->verf->committed = be32_to_cpup(p++); |
| 5123 | memcpy(res->verf->verifier, p, 8); | 5049 | memcpy(res->verf->verifier, p, NFS4_VERIFIER_SIZE); |
| 5124 | return 0; | 5050 | return 0; |
| 5125 | out_overflow: | 5051 | out_overflow: |
| 5126 | print_overflow_msg(__func__, xdr); | 5052 | print_overflow_msg(__func__, xdr); |
| @@ -5214,6 +5140,7 @@ static int decode_exchange_id(struct xdr_stream *xdr, | |||
| 5214 | char *dummy_str; | 5140 | char *dummy_str; |
| 5215 | int status; | 5141 | int status; |
| 5216 | struct nfs_client *clp = res->client; | 5142 | struct nfs_client *clp = res->client; |
| 5143 | uint32_t impl_id_count; | ||
| 5217 | 5144 | ||
| 5218 | status = decode_op_hdr(xdr, OP_EXCHANGE_ID); | 5145 | status = decode_op_hdr(xdr, OP_EXCHANGE_ID); |
| 5219 | if (status) | 5146 | if (status) |
| @@ -5255,11 +5182,38 @@ static int decode_exchange_id(struct xdr_stream *xdr, | |||
| 5255 | memcpy(res->server_scope->server_scope, dummy_str, dummy); | 5182 | memcpy(res->server_scope->server_scope, dummy_str, dummy); |
| 5256 | res->server_scope->server_scope_sz = dummy; | 5183 | res->server_scope->server_scope_sz = dummy; |
| 5257 | 5184 | ||
| 5258 | /* Throw away Implementation id array */ | 5185 | /* Implementation Id */ |
| 5259 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); | 5186 | p = xdr_inline_decode(xdr, 4); |
| 5260 | if (unlikely(status)) | 5187 | if (unlikely(!p)) |
| 5261 | return status; | 5188 | goto out_overflow; |
| 5189 | impl_id_count = be32_to_cpup(p++); | ||
| 5190 | |||
| 5191 | if (impl_id_count) { | ||
| 5192 | /* nii_domain */ | ||
| 5193 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); | ||
| 5194 | if (unlikely(status)) | ||
| 5195 | return status; | ||
| 5196 | if (unlikely(dummy > NFS4_OPAQUE_LIMIT)) | ||
| 5197 | return -EIO; | ||
| 5198 | memcpy(res->impl_id->domain, dummy_str, dummy); | ||
| 5262 | 5199 | ||
| 5200 | /* nii_name */ | ||
| 5201 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); | ||
| 5202 | if (unlikely(status)) | ||
| 5203 | return status; | ||
| 5204 | if (unlikely(dummy > NFS4_OPAQUE_LIMIT)) | ||
| 5205 | return -EIO; | ||
| 5206 | memcpy(res->impl_id->name, dummy_str, dummy); | ||
| 5207 | |||
| 5208 | /* nii_date */ | ||
| 5209 | p = xdr_inline_decode(xdr, 12); | ||
| 5210 | if (unlikely(!p)) | ||
| 5211 | goto out_overflow; | ||
| 5212 | p = xdr_decode_hyper(p, &res->impl_id->date.seconds); | ||
| 5213 | res->impl_id->date.nseconds = be32_to_cpup(p); | ||
| 5214 | |||
| 5215 | /* if there's more than one entry, ignore the rest */ | ||
| 5216 | } | ||
| 5263 | return 0; | 5217 | return 0; |
| 5264 | out_overflow: | 5218 | out_overflow: |
| 5265 | print_overflow_msg(__func__, xdr); | 5219 | print_overflow_msg(__func__, xdr); |
| @@ -5285,8 +5239,8 @@ static int decode_chan_attrs(struct xdr_stream *xdr, | |||
| 5285 | attrs->max_reqs = be32_to_cpup(p++); | 5239 | attrs->max_reqs = be32_to_cpup(p++); |
| 5286 | nr_attrs = be32_to_cpup(p); | 5240 | nr_attrs = be32_to_cpup(p); |
| 5287 | if (unlikely(nr_attrs > 1)) { | 5241 | if (unlikely(nr_attrs > 1)) { |
| 5288 | printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", | 5242 | printk(KERN_WARNING "NFS: %s: Invalid rdma channel attrs " |
| 5289 | __func__, nr_attrs); | 5243 | "count %u\n", __func__, nr_attrs); |
| 5290 | return -EINVAL; | 5244 | return -EINVAL; |
| 5291 | } | 5245 | } |
| 5292 | if (nr_attrs == 1) { | 5246 | if (nr_attrs == 1) { |
| @@ -5436,14 +5390,14 @@ static int decode_getdevicelist(struct xdr_stream *xdr, | |||
| 5436 | p += 2; | 5390 | p += 2; |
| 5437 | 5391 | ||
| 5438 | /* Read verifier */ | 5392 | /* Read verifier */ |
| 5439 | p = xdr_decode_opaque_fixed(p, verftemp.verifier, 8); | 5393 | p = xdr_decode_opaque_fixed(p, verftemp.verifier, NFS4_VERIFIER_SIZE); |
| 5440 | 5394 | ||
| 5441 | res->num_devs = be32_to_cpup(p); | 5395 | res->num_devs = be32_to_cpup(p); |
| 5442 | 5396 | ||
| 5443 | dprintk("%s: num_dev %d\n", __func__, res->num_devs); | 5397 | dprintk("%s: num_dev %d\n", __func__, res->num_devs); |
| 5444 | 5398 | ||
| 5445 | if (res->num_devs > NFS4_PNFS_GETDEVLIST_MAXNUM) { | 5399 | if (res->num_devs > NFS4_PNFS_GETDEVLIST_MAXNUM) { |
| 5446 | printk(KERN_ERR "%s too many result dev_num %u\n", | 5400 | printk(KERN_ERR "NFS: %s too many result dev_num %u\n", |
| 5447 | __func__, res->num_devs); | 5401 | __func__, res->num_devs); |
| 5448 | return -EIO; | 5402 | return -EIO; |
| 5449 | } | 5403 | } |
| @@ -5537,11 +5491,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
| 5537 | status = decode_op_hdr(xdr, OP_LAYOUTGET); | 5491 | status = decode_op_hdr(xdr, OP_LAYOUTGET); |
| 5538 | if (status) | 5492 | if (status) |
| 5539 | return status; | 5493 | return status; |
| 5540 | p = xdr_inline_decode(xdr, 8 + NFS4_STATEID_SIZE); | 5494 | p = xdr_inline_decode(xdr, 4); |
| 5495 | if (unlikely(!p)) | ||
| 5496 | goto out_overflow; | ||
| 5497 | res->return_on_close = be32_to_cpup(p); | ||
| 5498 | decode_stateid(xdr, &res->stateid); | ||
| 5499 | p = xdr_inline_decode(xdr, 4); | ||
| 5541 | if (unlikely(!p)) | 5500 | if (unlikely(!p)) |
| 5542 | goto out_overflow; | 5501 | goto out_overflow; |
| 5543 | res->return_on_close = be32_to_cpup(p++); | ||
| 5544 | p = xdr_decode_opaque_fixed(p, res->stateid.data, NFS4_STATEID_SIZE); | ||
| 5545 | layout_count = be32_to_cpup(p); | 5502 | layout_count = be32_to_cpup(p); |
| 5546 | if (!layout_count) { | 5503 | if (!layout_count) { |
| 5547 | dprintk("%s: server responded with empty layout array\n", | 5504 | dprintk("%s: server responded with empty layout array\n", |
| @@ -5666,7 +5623,8 @@ static int decode_test_stateid(struct xdr_stream *xdr, | |||
| 5666 | if (unlikely(!p)) | 5623 | if (unlikely(!p)) |
| 5667 | goto out_overflow; | 5624 | goto out_overflow; |
| 5668 | res->status = be32_to_cpup(p++); | 5625 | res->status = be32_to_cpup(p++); |
| 5669 | return res->status; | 5626 | |
| 5627 | return status; | ||
| 5670 | out_overflow: | 5628 | out_overflow: |
| 5671 | print_overflow_msg(__func__, xdr); | 5629 | print_overflow_msg(__func__, xdr); |
| 5672 | out: | 5630 | out: |
| @@ -6583,8 +6541,9 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, | |||
| 6583 | if (status) | 6541 | if (status) |
| 6584 | goto out; | 6542 | goto out; |
| 6585 | xdr_enter_page(xdr, PAGE_SIZE); | 6543 | xdr_enter_page(xdr, PAGE_SIZE); |
| 6586 | status = decode_getfattr(xdr, &res->fs_locations->fattr, | 6544 | status = decode_getfattr_generic(xdr, &res->fs_locations->fattr, |
| 6587 | res->fs_locations->server); | 6545 | NULL, res->fs_locations, |
| 6546 | res->fs_locations->server); | ||
| 6588 | out: | 6547 | out: |
| 6589 | return status; | 6548 | return status; |
| 6590 | } | 6549 | } |
| @@ -6964,7 +6923,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
| 6964 | goto out_overflow; | 6923 | goto out_overflow; |
| 6965 | 6924 | ||
| 6966 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, | 6925 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, |
| 6967 | entry->server) < 0) | 6926 | NULL, entry->server) < 0) |
| 6968 | goto out_overflow; | 6927 | goto out_overflow; |
| 6969 | if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) | 6928 | if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) |
| 6970 | entry->ino = entry->fattr->mounted_on_fileid; | 6929 | entry->ino = entry->fattr->mounted_on_fileid; |
| @@ -7112,7 +7071,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
| 7112 | #endif /* CONFIG_NFS_V4_1 */ | 7071 | #endif /* CONFIG_NFS_V4_1 */ |
| 7113 | }; | 7072 | }; |
| 7114 | 7073 | ||
| 7115 | struct rpc_version nfs_version4 = { | 7074 | const struct rpc_version nfs_version4 = { |
| 7116 | .number = 4, | 7075 | .number = 4, |
| 7117 | .nrprocs = ARRAY_SIZE(nfs4_procedures), | 7076 | .nrprocs = ARRAY_SIZE(nfs4_procedures), |
| 7118 | .procs = nfs4_procedures | 7077 | .procs = nfs4_procedures |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index c4744e1d513c..cd3c910d2d12 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
| @@ -104,7 +104,7 @@ static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = ""; | |||
| 104 | /* server:export path string passed to super.c */ | 104 | /* server:export path string passed to super.c */ |
| 105 | static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = ""; | 105 | static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = ""; |
| 106 | 106 | ||
| 107 | #ifdef RPC_DEBUG | 107 | #ifdef NFS_DEBUG |
| 108 | /* | 108 | /* |
| 109 | * When the "nfsrootdebug" kernel command line option is specified, | 109 | * When the "nfsrootdebug" kernel command line option is specified, |
| 110 | * enable debugging messages for NFSROOT. | 110 | * enable debugging messages for NFSROOT. |
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index 55d01280a609..4bff4a3dab46 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c | |||
| @@ -137,6 +137,7 @@ static int objio_devices_lookup(struct pnfs_layout_hdr *pnfslay, | |||
| 137 | struct objio_dev_ent *ode; | 137 | struct objio_dev_ent *ode; |
| 138 | struct osd_dev *od; | 138 | struct osd_dev *od; |
| 139 | struct osd_dev_info odi; | 139 | struct osd_dev_info odi; |
| 140 | bool retry_flag = true; | ||
| 140 | int err; | 141 | int err; |
| 141 | 142 | ||
| 142 | ode = _dev_list_find(NFS_SERVER(pnfslay->plh_inode), d_id); | 143 | 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, | |||
| 171 | goto out; | 172 | goto out; |
| 172 | } | 173 | } |
| 173 | 174 | ||
| 175 | retry_lookup: | ||
| 174 | od = osduld_info_lookup(&odi); | 176 | od = osduld_info_lookup(&odi); |
| 175 | if (unlikely(IS_ERR(od))) { | 177 | if (unlikely(IS_ERR(od))) { |
| 176 | err = PTR_ERR(od); | 178 | err = PTR_ERR(od); |
| 177 | dprintk("%s: osduld_info_lookup => %d\n", __func__, err); | 179 | dprintk("%s: osduld_info_lookup => %d\n", __func__, err); |
| 180 | if (err == -ENODEV && retry_flag) { | ||
| 181 | err = objlayout_autologin(deviceaddr); | ||
| 182 | if (likely(!err)) { | ||
| 183 | retry_flag = false; | ||
| 184 | goto retry_lookup; | ||
| 185 | } | ||
| 186 | } | ||
| 178 | goto out; | 187 | goto out; |
| 179 | } | 188 | } |
| 180 | 189 | ||
| @@ -205,25 +214,36 @@ static void copy_single_comp(struct ore_components *oc, unsigned c, | |||
| 205 | int __alloc_objio_seg(unsigned numdevs, gfp_t gfp_flags, | 214 | int __alloc_objio_seg(unsigned numdevs, gfp_t gfp_flags, |
| 206 | struct objio_segment **pseg) | 215 | struct objio_segment **pseg) |
| 207 | { | 216 | { |
| 208 | struct __alloc_objio_segment { | 217 | /* This is the in memory structure of the objio_segment |
| 209 | struct objio_segment olseg; | 218 | * |
| 210 | struct ore_dev *ods[numdevs]; | 219 | * struct __alloc_objio_segment { |
| 211 | struct ore_comp comps[numdevs]; | 220 | * struct objio_segment olseg; |
| 212 | } *aolseg; | 221 | * struct ore_dev *ods[numdevs]; |
| 213 | 222 | * struct ore_comp comps[numdevs]; | |
| 214 | aolseg = kzalloc(sizeof(*aolseg), gfp_flags); | 223 | * } *aolseg; |
| 215 | if (unlikely(!aolseg)) { | 224 | * NOTE: The code as above compiles and runs perfectly. It is elegant, |
| 225 | * type safe and compact. At some Past time Linus has decided he does not | ||
| 226 | * like variable length arrays, For the sake of this principal we uglify | ||
| 227 | * the code as below. | ||
| 228 | */ | ||
| 229 | struct objio_segment *lseg; | ||
| 230 | size_t lseg_size = sizeof(*lseg) + | ||
| 231 | numdevs * sizeof(lseg->oc.ods[0]) + | ||
| 232 | numdevs * sizeof(*lseg->oc.comps); | ||
| 233 | |||
| 234 | lseg = kzalloc(lseg_size, gfp_flags); | ||
| 235 | if (unlikely(!lseg)) { | ||
| 216 | dprintk("%s: Faild allocation numdevs=%d size=%zd\n", __func__, | 236 | dprintk("%s: Faild allocation numdevs=%d size=%zd\n", __func__, |
| 217 | numdevs, sizeof(*aolseg)); | 237 | numdevs, lseg_size); |
| 218 | return -ENOMEM; | 238 | return -ENOMEM; |
| 219 | } | 239 | } |
| 220 | 240 | ||
| 221 | aolseg->olseg.oc.numdevs = numdevs; | 241 | lseg->oc.numdevs = numdevs; |
| 222 | aolseg->olseg.oc.single_comp = EC_MULTPLE_COMPS; | 242 | lseg->oc.single_comp = EC_MULTPLE_COMPS; |
| 223 | aolseg->olseg.oc.comps = aolseg->comps; | 243 | lseg->oc.ods = (void *)(lseg + 1); |
| 224 | aolseg->olseg.oc.ods = aolseg->ods; | 244 | lseg->oc.comps = (void *)(lseg->oc.ods + numdevs); |
| 225 | 245 | ||
| 226 | *pseg = &aolseg->olseg; | 246 | *pseg = lseg; |
| 227 | return 0; | 247 | return 0; |
| 228 | } | 248 | } |
| 229 | 249 | ||
| @@ -582,10 +602,10 @@ objlayout_init(void) | |||
| 582 | 602 | ||
| 583 | if (ret) | 603 | if (ret) |
| 584 | printk(KERN_INFO | 604 | printk(KERN_INFO |
| 585 | "%s: Registering OSD pNFS Layout Driver failed: error=%d\n", | 605 | "NFS: %s: Registering OSD pNFS Layout Driver failed: error=%d\n", |
| 586 | __func__, ret); | 606 | __func__, ret); |
| 587 | else | 607 | else |
| 588 | printk(KERN_INFO "%s: Registered OSD pNFS Layout Driver\n", | 608 | printk(KERN_INFO "NFS: %s: Registered OSD pNFS Layout Driver\n", |
| 589 | __func__); | 609 | __func__); |
| 590 | return ret; | 610 | return ret; |
| 591 | } | 611 | } |
| @@ -594,7 +614,7 @@ static void __exit | |||
| 594 | objlayout_exit(void) | 614 | objlayout_exit(void) |
| 595 | { | 615 | { |
| 596 | pnfs_unregister_layoutdriver(&objlayout_type); | 616 | pnfs_unregister_layoutdriver(&objlayout_type); |
| 597 | printk(KERN_INFO "%s: Unregistered OSD pNFS Layout Driver\n", | 617 | printk(KERN_INFO "NFS: %s: Unregistered OSD pNFS Layout Driver\n", |
| 598 | __func__); | 618 | __func__); |
| 599 | } | 619 | } |
| 600 | 620 | ||
diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c index b3c29039f5b8..8d45f1c318ce 100644 --- a/fs/nfs/objlayout/objlayout.c +++ b/fs/nfs/objlayout/objlayout.c | |||
| @@ -37,6 +37,9 @@ | |||
| 37 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 37 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 38 | */ | 38 | */ |
| 39 | 39 | ||
| 40 | #include <linux/kmod.h> | ||
| 41 | #include <linux/moduleparam.h> | ||
| 42 | #include <linux/ratelimit.h> | ||
| 40 | #include <scsi/osd_initiator.h> | 43 | #include <scsi/osd_initiator.h> |
| 41 | #include "objlayout.h" | 44 | #include "objlayout.h" |
| 42 | 45 | ||
| @@ -156,7 +159,7 @@ last_byte_offset(u64 start, u64 len) | |||
| 156 | return end > start ? end - 1 : NFS4_MAX_UINT64; | 159 | return end > start ? end - 1 : NFS4_MAX_UINT64; |
| 157 | } | 160 | } |
| 158 | 161 | ||
| 159 | void _fix_verify_io_params(struct pnfs_layout_segment *lseg, | 162 | static void _fix_verify_io_params(struct pnfs_layout_segment *lseg, |
| 160 | struct page ***p_pages, unsigned *p_pgbase, | 163 | struct page ***p_pages, unsigned *p_pgbase, |
| 161 | u64 offset, unsigned long count) | 164 | u64 offset, unsigned long count) |
| 162 | { | 165 | { |
| @@ -490,9 +493,9 @@ encode_accumulated_error(struct objlayout *objlay, __be32 *p) | |||
| 490 | if (!ioerr->oer_errno) | 493 | if (!ioerr->oer_errno) |
| 491 | continue; | 494 | continue; |
| 492 | 495 | ||
| 493 | printk(KERN_ERR "%s: err[%d]: errno=%d is_write=%d " | 496 | printk(KERN_ERR "NFS: %s: err[%d]: errno=%d " |
| 494 | "dev(%llx:%llx) par=0x%llx obj=0x%llx " | 497 | "is_write=%d dev(%llx:%llx) par=0x%llx " |
| 495 | "offset=0x%llx length=0x%llx\n", | 498 | "obj=0x%llx offset=0x%llx length=0x%llx\n", |
| 496 | __func__, i, ioerr->oer_errno, | 499 | __func__, i, ioerr->oer_errno, |
| 497 | ioerr->oer_iswrite, | 500 | ioerr->oer_iswrite, |
| 498 | _DEVID_LO(&ioerr->oer_component.oid_device_id), | 501 | _DEVID_LO(&ioerr->oer_component.oid_device_id), |
| @@ -651,3 +654,134 @@ void objlayout_put_deviceinfo(struct pnfs_osd_deviceaddr *deviceaddr) | |||
| 651 | __free_page(odi->page); | 654 | __free_page(odi->page); |
| 652 | kfree(odi); | 655 | kfree(odi); |
| 653 | } | 656 | } |
| 657 | |||
| 658 | enum { | ||
| 659 | OBJLAYOUT_MAX_URI_LEN = 256, OBJLAYOUT_MAX_OSDNAME_LEN = 64, | ||
| 660 | OBJLAYOUT_MAX_SYSID_HEX_LEN = OSD_SYSTEMID_LEN * 2 + 1, | ||
| 661 | OSD_LOGIN_UPCALL_PATHLEN = 256 | ||
| 662 | }; | ||
| 663 | |||
| 664 | static char osd_login_prog[OSD_LOGIN_UPCALL_PATHLEN] = "/sbin/osd_login"; | ||
| 665 | |||
| 666 | module_param_string(osd_login_prog, osd_login_prog, sizeof(osd_login_prog), | ||
| 667 | 0600); | ||
| 668 | MODULE_PARM_DESC(osd_login_prog, "Path to the osd_login upcall program"); | ||
| 669 | |||
| 670 | struct __auto_login { | ||
| 671 | char uri[OBJLAYOUT_MAX_URI_LEN]; | ||
| 672 | char osdname[OBJLAYOUT_MAX_OSDNAME_LEN]; | ||
| 673 | char systemid_hex[OBJLAYOUT_MAX_SYSID_HEX_LEN]; | ||
| 674 | }; | ||
| 675 | |||
| 676 | static int __objlayout_upcall(struct __auto_login *login) | ||
| 677 | { | ||
| 678 | static char *envp[] = { "HOME=/", | ||
| 679 | "TERM=linux", | ||
| 680 | "PATH=/sbin:/usr/sbin:/bin:/usr/bin", | ||
| 681 | NULL | ||
| 682 | }; | ||
| 683 | char *argv[8]; | ||
| 684 | int ret; | ||
| 685 | |||
| 686 | if (unlikely(!osd_login_prog[0])) { | ||
| 687 | dprintk("%s: osd_login_prog is disabled\n", __func__); | ||
| 688 | return -EACCES; | ||
| 689 | } | ||
| 690 | |||
| 691 | dprintk("%s uri: %s\n", __func__, login->uri); | ||
| 692 | dprintk("%s osdname %s\n", __func__, login->osdname); | ||
| 693 | dprintk("%s systemid_hex %s\n", __func__, login->systemid_hex); | ||
| 694 | |||
| 695 | argv[0] = (char *)osd_login_prog; | ||
| 696 | argv[1] = "-u"; | ||
| 697 | argv[2] = login->uri; | ||
| 698 | argv[3] = "-o"; | ||
| 699 | argv[4] = login->osdname; | ||
| 700 | argv[5] = "-s"; | ||
| 701 | argv[6] = login->systemid_hex; | ||
| 702 | argv[7] = NULL; | ||
| 703 | |||
| 704 | ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); | ||
| 705 | /* | ||
| 706 | * Disable the upcall mechanism if we're getting an ENOENT or | ||
| 707 | * EACCES error. The admin can re-enable it on the fly by using | ||
| 708 | * sysfs to set the objlayoutdriver.osd_login_prog module parameter once | ||
| 709 | * the problem has been fixed. | ||
| 710 | */ | ||
| 711 | if (ret == -ENOENT || ret == -EACCES) { | ||
| 712 | printk(KERN_ERR "PNFS-OBJ: %s was not found please set " | ||
| 713 | "objlayoutdriver.osd_login_prog kernel parameter!\n", | ||
| 714 | osd_login_prog); | ||
| 715 | osd_login_prog[0] = '\0'; | ||
| 716 | } | ||
| 717 | dprintk("%s %s return value: %d\n", __func__, osd_login_prog, ret); | ||
| 718 | |||
| 719 | return ret; | ||
| 720 | } | ||
| 721 | |||
| 722 | /* Assume dest is all zeros */ | ||
| 723 | static void __copy_nfsS_and_zero_terminate(struct nfs4_string s, | ||
| 724 | char *dest, int max_len, | ||
| 725 | const char *var_name) | ||
| 726 | { | ||
| 727 | if (!s.len) | ||
| 728 | return; | ||
| 729 | |||
| 730 | if (s.len >= max_len) { | ||
| 731 | pr_warn_ratelimited( | ||
| 732 | "objlayout_autologin: %s: s.len(%d) >= max_len(%d)", | ||
| 733 | var_name, s.len, max_len); | ||
| 734 | s.len = max_len - 1; /* space for null terminator */ | ||
| 735 | } | ||
| 736 | |||
| 737 | memcpy(dest, s.data, s.len); | ||
| 738 | } | ||
| 739 | |||
| 740 | /* Assume sysid is all zeros */ | ||
| 741 | static void _sysid_2_hex(struct nfs4_string s, | ||
| 742 | char sysid[OBJLAYOUT_MAX_SYSID_HEX_LEN]) | ||
| 743 | { | ||
| 744 | int i; | ||
| 745 | char *cur; | ||
| 746 | |||
| 747 | if (!s.len) | ||
| 748 | return; | ||
| 749 | |||
| 750 | if (s.len != OSD_SYSTEMID_LEN) { | ||
| 751 | pr_warn_ratelimited( | ||
| 752 | "objlayout_autologin: systemid_len(%d) != OSD_SYSTEMID_LEN", | ||
| 753 | s.len); | ||
| 754 | if (s.len > OSD_SYSTEMID_LEN) | ||
| 755 | s.len = OSD_SYSTEMID_LEN; | ||
| 756 | } | ||
| 757 | |||
| 758 | cur = sysid; | ||
| 759 | for (i = 0; i < s.len; i++) | ||
| 760 | cur = hex_byte_pack(cur, s.data[i]); | ||
| 761 | } | ||
| 762 | |||
| 763 | int objlayout_autologin(struct pnfs_osd_deviceaddr *deviceaddr) | ||
| 764 | { | ||
| 765 | int rc; | ||
| 766 | struct __auto_login login; | ||
| 767 | |||
| 768 | if (!deviceaddr->oda_targetaddr.ota_netaddr.r_addr.len) | ||
| 769 | return -ENODEV; | ||
| 770 | |||
| 771 | memset(&login, 0, sizeof(login)); | ||
| 772 | __copy_nfsS_and_zero_terminate( | ||
| 773 | deviceaddr->oda_targetaddr.ota_netaddr.r_addr, | ||
| 774 | login.uri, sizeof(login.uri), "URI"); | ||
| 775 | |||
| 776 | __copy_nfsS_and_zero_terminate( | ||
| 777 | deviceaddr->oda_osdname, | ||
| 778 | login.osdname, sizeof(login.osdname), "OSDNAME"); | ||
| 779 | |||
| 780 | _sysid_2_hex(deviceaddr->oda_systemid, login.systemid_hex); | ||
| 781 | |||
| 782 | rc = __objlayout_upcall(&login); | ||
| 783 | if (rc > 0) /* script returns positive values */ | ||
| 784 | rc = -ENODEV; | ||
| 785 | |||
| 786 | return rc; | ||
| 787 | } | ||
diff --git a/fs/nfs/objlayout/objlayout.h b/fs/nfs/objlayout/objlayout.h index 8ec34727ed21..880ba086be94 100644 --- a/fs/nfs/objlayout/objlayout.h +++ b/fs/nfs/objlayout/objlayout.h | |||
| @@ -184,4 +184,6 @@ extern void objlayout_encode_layoutreturn( | |||
| 184 | struct xdr_stream *, | 184 | struct xdr_stream *, |
| 185 | const struct nfs4_layoutreturn_args *); | 185 | const struct nfs4_layoutreturn_args *); |
| 186 | 186 | ||
| 187 | extern int objlayout_autologin(struct pnfs_osd_deviceaddr *deviceaddr); | ||
| 188 | |||
| 187 | #endif /* _OBJLAYOUT_H */ | 189 | #endif /* _OBJLAYOUT_H */ |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 5668f7c54c41..d21fceaa9f62 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/file.h> | 13 | #include <linux/file.h> |
| 14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
| 15 | #include <linux/sunrpc/clnt.h> | 15 | #include <linux/sunrpc/clnt.h> |
| 16 | #include <linux/nfs.h> | ||
| 16 | #include <linux/nfs3.h> | 17 | #include <linux/nfs3.h> |
| 17 | #include <linux/nfs4.h> | 18 | #include <linux/nfs4.h> |
| 18 | #include <linux/nfs_page.h> | 19 | #include <linux/nfs_page.h> |
| @@ -106,36 +107,6 @@ void nfs_unlock_request(struct nfs_page *req) | |||
| 106 | nfs_release_request(req); | 107 | nfs_release_request(req); |
| 107 | } | 108 | } |
| 108 | 109 | ||
| 109 | /** | ||
| 110 | * nfs_set_page_tag_locked - Tag a request as locked | ||
| 111 | * @req: | ||
| 112 | */ | ||
| 113 | int nfs_set_page_tag_locked(struct nfs_page *req) | ||
| 114 | { | ||
| 115 | if (!nfs_lock_request_dontget(req)) | ||
| 116 | return 0; | ||
| 117 | if (test_bit(PG_MAPPED, &req->wb_flags)) | ||
| 118 | radix_tree_tag_set(&NFS_I(req->wb_context->dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | ||
| 119 | return 1; | ||
| 120 | } | ||
| 121 | |||
| 122 | /** | ||
| 123 | * nfs_clear_page_tag_locked - Clear request tag and wake up sleepers | ||
| 124 | */ | ||
| 125 | void nfs_clear_page_tag_locked(struct nfs_page *req) | ||
| 126 | { | ||
| 127 | if (test_bit(PG_MAPPED, &req->wb_flags)) { | ||
| 128 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
| 129 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 130 | |||
| 131 | spin_lock(&inode->i_lock); | ||
| 132 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | ||
| 133 | nfs_unlock_request(req); | ||
| 134 | spin_unlock(&inode->i_lock); | ||
| 135 | } else | ||
| 136 | nfs_unlock_request(req); | ||
| 137 | } | ||
| 138 | |||
| 139 | /* | 110 | /* |
| 140 | * nfs_clear_request - Free up all resources allocated to the request | 111 | * nfs_clear_request - Free up all resources allocated to the request |
| 141 | * @req: | 112 | * @req: |
| @@ -425,67 +396,6 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) | |||
| 425 | } | 396 | } |
| 426 | } | 397 | } |
| 427 | 398 | ||
| 428 | #define NFS_SCAN_MAXENTRIES 16 | ||
| 429 | /** | ||
| 430 | * nfs_scan_list - Scan a list for matching requests | ||
| 431 | * @nfsi: NFS inode | ||
| 432 | * @dst: Destination list | ||
| 433 | * @idx_start: lower bound of page->index to scan | ||
| 434 | * @npages: idx_start + npages sets the upper bound to scan. | ||
| 435 | * @tag: tag to scan for | ||
| 436 | * | ||
| 437 | * Moves elements from one of the inode request lists. | ||
| 438 | * If the number of requests is set to 0, the entire address_space | ||
| 439 | * starting at index idx_start, is scanned. | ||
| 440 | * The requests are *not* checked to ensure that they form a contiguous set. | ||
| 441 | * You must be holding the inode's i_lock when calling this function | ||
| 442 | */ | ||
| 443 | int nfs_scan_list(struct nfs_inode *nfsi, | ||
| 444 | struct list_head *dst, pgoff_t idx_start, | ||
| 445 | unsigned int npages, int tag) | ||
| 446 | { | ||
| 447 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; | ||
| 448 | struct nfs_page *req; | ||
| 449 | pgoff_t idx_end; | ||
| 450 | int found, i; | ||
| 451 | int res; | ||
| 452 | struct list_head *list; | ||
| 453 | |||
| 454 | res = 0; | ||
| 455 | if (npages == 0) | ||
| 456 | idx_end = ~0; | ||
| 457 | else | ||
| 458 | idx_end = idx_start + npages - 1; | ||
| 459 | |||
| 460 | for (;;) { | ||
| 461 | found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, | ||
| 462 | (void **)&pgvec[0], idx_start, | ||
| 463 | NFS_SCAN_MAXENTRIES, tag); | ||
| 464 | if (found <= 0) | ||
| 465 | break; | ||
| 466 | for (i = 0; i < found; i++) { | ||
| 467 | req = pgvec[i]; | ||
| 468 | if (req->wb_index > idx_end) | ||
| 469 | goto out; | ||
| 470 | idx_start = req->wb_index + 1; | ||
| 471 | if (nfs_set_page_tag_locked(req)) { | ||
| 472 | kref_get(&req->wb_kref); | ||
| 473 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | ||
| 474 | req->wb_index, tag); | ||
| 475 | list = pnfs_choose_commit_list(req, dst); | ||
| 476 | nfs_list_add_request(req, list); | ||
| 477 | res++; | ||
| 478 | if (res == INT_MAX) | ||
| 479 | goto out; | ||
| 480 | } | ||
| 481 | } | ||
| 482 | /* for latency reduction */ | ||
| 483 | cond_resched_lock(&nfsi->vfs_inode.i_lock); | ||
| 484 | } | ||
| 485 | out: | ||
| 486 | return res; | ||
| 487 | } | ||
| 488 | |||
| 489 | int __init nfs_init_nfspagecache(void) | 399 | int __init nfs_init_nfspagecache(void) |
| 490 | { | 400 | { |
| 491 | nfs_page_cachep = kmem_cache_create("nfs_page", | 401 | nfs_page_cachep = kmem_cache_create("nfs_page", |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 17149a490065..b5d451586943 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
| @@ -101,8 +101,8 @@ set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh, | |||
| 101 | goto out_no_driver; | 101 | goto out_no_driver; |
| 102 | if (!(server->nfs_client->cl_exchange_flags & | 102 | if (!(server->nfs_client->cl_exchange_flags & |
| 103 | (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) { | 103 | (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) { |
| 104 | printk(KERN_ERR "%s: id %u cl_exchange_flags 0x%x\n", __func__, | 104 | printk(KERN_ERR "NFS: %s: id %u cl_exchange_flags 0x%x\n", |
| 105 | id, server->nfs_client->cl_exchange_flags); | 105 | __func__, id, server->nfs_client->cl_exchange_flags); |
| 106 | goto out_no_driver; | 106 | goto out_no_driver; |
| 107 | } | 107 | } |
| 108 | ld_type = find_pnfs_driver(id); | 108 | ld_type = find_pnfs_driver(id); |
| @@ -122,8 +122,8 @@ set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh, | |||
| 122 | server->pnfs_curr_ld = ld_type; | 122 | server->pnfs_curr_ld = ld_type; |
| 123 | if (ld_type->set_layoutdriver | 123 | if (ld_type->set_layoutdriver |
| 124 | && ld_type->set_layoutdriver(server, mntfh)) { | 124 | && ld_type->set_layoutdriver(server, mntfh)) { |
| 125 | printk(KERN_ERR "%s: Error initializing pNFS layout driver %u.\n", | 125 | printk(KERN_ERR "NFS: %s: Error initializing pNFS layout " |
| 126 | __func__, id); | 126 | "driver %u.\n", __func__, id); |
| 127 | module_put(ld_type->owner); | 127 | module_put(ld_type->owner); |
| 128 | goto out_no_driver; | 128 | goto out_no_driver; |
| 129 | } | 129 | } |
| @@ -143,11 +143,11 @@ pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type) | |||
| 143 | struct pnfs_layoutdriver_type *tmp; | 143 | struct pnfs_layoutdriver_type *tmp; |
| 144 | 144 | ||
| 145 | if (ld_type->id == 0) { | 145 | if (ld_type->id == 0) { |
| 146 | printk(KERN_ERR "%s id 0 is reserved\n", __func__); | 146 | printk(KERN_ERR "NFS: %s id 0 is reserved\n", __func__); |
| 147 | return status; | 147 | return status; |
| 148 | } | 148 | } |
| 149 | if (!ld_type->alloc_lseg || !ld_type->free_lseg) { | 149 | if (!ld_type->alloc_lseg || !ld_type->free_lseg) { |
| 150 | printk(KERN_ERR "%s Layout driver must provide " | 150 | printk(KERN_ERR "NFS: %s Layout driver must provide " |
| 151 | "alloc_lseg and free_lseg.\n", __func__); | 151 | "alloc_lseg and free_lseg.\n", __func__); |
| 152 | return status; | 152 | return status; |
| 153 | } | 153 | } |
| @@ -160,7 +160,7 @@ pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type) | |||
| 160 | dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id, | 160 | dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id, |
| 161 | ld_type->name); | 161 | ld_type->name); |
| 162 | } else { | 162 | } else { |
| 163 | printk(KERN_ERR "%s Module with id %d already loaded!\n", | 163 | printk(KERN_ERR "NFS: %s Module with id %d already loaded!\n", |
| 164 | __func__, ld_type->id); | 164 | __func__, ld_type->id); |
| 165 | } | 165 | } |
| 166 | spin_unlock(&pnfs_spinlock); | 166 | spin_unlock(&pnfs_spinlock); |
| @@ -496,12 +496,12 @@ pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, | |||
| 496 | { | 496 | { |
| 497 | u32 oldseq, newseq; | 497 | u32 oldseq, newseq; |
| 498 | 498 | ||
| 499 | oldseq = be32_to_cpu(lo->plh_stateid.stateid.seqid); | 499 | oldseq = be32_to_cpu(lo->plh_stateid.seqid); |
| 500 | newseq = be32_to_cpu(new->stateid.seqid); | 500 | newseq = be32_to_cpu(new->seqid); |
| 501 | if ((int)(newseq - oldseq) > 0) { | 501 | if ((int)(newseq - oldseq) > 0) { |
| 502 | memcpy(&lo->plh_stateid, &new->stateid, sizeof(new->stateid)); | 502 | nfs4_stateid_copy(&lo->plh_stateid, new); |
| 503 | if (update_barrier) { | 503 | if (update_barrier) { |
| 504 | u32 new_barrier = be32_to_cpu(new->stateid.seqid); | 504 | u32 new_barrier = be32_to_cpu(new->seqid); |
| 505 | 505 | ||
| 506 | if ((int)(new_barrier - lo->plh_barrier)) | 506 | if ((int)(new_barrier - lo->plh_barrier)) |
| 507 | lo->plh_barrier = new_barrier; | 507 | lo->plh_barrier = new_barrier; |
| @@ -525,7 +525,7 @@ pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid, | |||
| 525 | int lget) | 525 | int lget) |
| 526 | { | 526 | { |
| 527 | if ((stateid) && | 527 | if ((stateid) && |
| 528 | (int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0) | 528 | (int)(lo->plh_barrier - be32_to_cpu(stateid->seqid)) >= 0) |
| 529 | return true; | 529 | return true; |
| 530 | return lo->plh_block_lgets || | 530 | return lo->plh_block_lgets || |
| 531 | test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) || | 531 | test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) || |
| @@ -549,11 +549,10 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, | |||
| 549 | 549 | ||
| 550 | do { | 550 | do { |
| 551 | seq = read_seqbegin(&open_state->seqlock); | 551 | seq = read_seqbegin(&open_state->seqlock); |
| 552 | memcpy(dst->data, open_state->stateid.data, | 552 | nfs4_stateid_copy(dst, &open_state->stateid); |
| 553 | sizeof(open_state->stateid.data)); | ||
| 554 | } while (read_seqretry(&open_state->seqlock, seq)); | 553 | } while (read_seqretry(&open_state->seqlock, seq)); |
| 555 | } else | 554 | } else |
| 556 | memcpy(dst->data, lo->plh_stateid.data, sizeof(lo->plh_stateid.data)); | 555 | nfs4_stateid_copy(dst, &lo->plh_stateid); |
| 557 | spin_unlock(&lo->plh_inode->i_lock); | 556 | spin_unlock(&lo->plh_inode->i_lock); |
| 558 | dprintk("<-- %s\n", __func__); | 557 | dprintk("<-- %s\n", __func__); |
| 559 | return status; | 558 | return status; |
| @@ -590,7 +589,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 590 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | 589 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; |
| 591 | max_pages = max_resp_sz >> PAGE_SHIFT; | 590 | max_pages = max_resp_sz >> PAGE_SHIFT; |
| 592 | 591 | ||
| 593 | pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags); | 592 | pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); |
| 594 | if (!pages) | 593 | if (!pages) |
| 595 | goto out_err_free; | 594 | goto out_err_free; |
| 596 | 595 | ||
| @@ -760,7 +759,7 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier) | |||
| 760 | } | 759 | } |
| 761 | if (!found) { | 760 | if (!found) { |
| 762 | struct pnfs_layout_hdr *lo = nfsi->layout; | 761 | struct pnfs_layout_hdr *lo = nfsi->layout; |
| 763 | u32 current_seqid = be32_to_cpu(lo->plh_stateid.stateid.seqid); | 762 | u32 current_seqid = be32_to_cpu(lo->plh_stateid.seqid); |
| 764 | 763 | ||
| 765 | /* Since close does not return a layout stateid for use as | 764 | /* Since close does not return a layout stateid for use as |
| 766 | * a barrier, we choose the worst-case barrier. | 765 | * a barrier, we choose the worst-case barrier. |
| @@ -966,8 +965,7 @@ pnfs_update_layout(struct inode *ino, | |||
| 966 | } | 965 | } |
| 967 | 966 | ||
| 968 | /* Do we even need to bother with this? */ | 967 | /* Do we even need to bother with this? */ |
| 969 | if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) || | 968 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { |
| 970 | test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { | ||
| 971 | dprintk("%s matches recall, use MDS\n", __func__); | 969 | dprintk("%s matches recall, use MDS\n", __func__); |
| 972 | goto out_unlock; | 970 | goto out_unlock; |
| 973 | } | 971 | } |
| @@ -1032,7 +1030,6 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
| 1032 | struct nfs4_layoutget_res *res = &lgp->res; | 1030 | struct nfs4_layoutget_res *res = &lgp->res; |
| 1033 | struct pnfs_layout_segment *lseg; | 1031 | struct pnfs_layout_segment *lseg; |
| 1034 | struct inode *ino = lo->plh_inode; | 1032 | struct inode *ino = lo->plh_inode; |
| 1035 | struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; | ||
| 1036 | int status = 0; | 1033 | int status = 0; |
| 1037 | 1034 | ||
| 1038 | /* Inject layout blob into I/O device driver */ | 1035 | /* Inject layout blob into I/O device driver */ |
| @@ -1048,8 +1045,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
| 1048 | } | 1045 | } |
| 1049 | 1046 | ||
| 1050 | spin_lock(&ino->i_lock); | 1047 | spin_lock(&ino->i_lock); |
| 1051 | if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) || | 1048 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { |
| 1052 | test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { | ||
| 1053 | dprintk("%s forget reply due to recall\n", __func__); | 1049 | dprintk("%s forget reply due to recall\n", __func__); |
| 1054 | goto out_forget_reply; | 1050 | goto out_forget_reply; |
| 1055 | } | 1051 | } |
| @@ -1214,6 +1210,7 @@ void pnfs_ld_write_done(struct nfs_write_data *data) | |||
| 1214 | } | 1210 | } |
| 1215 | data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages); | 1211 | data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages); |
| 1216 | } | 1212 | } |
| 1213 | put_lseg(data->lseg); | ||
| 1217 | data->mds_ops->rpc_release(data); | 1214 | data->mds_ops->rpc_release(data); |
| 1218 | } | 1215 | } |
| 1219 | EXPORT_SYMBOL_GPL(pnfs_ld_write_done); | 1216 | EXPORT_SYMBOL_GPL(pnfs_ld_write_done); |
| @@ -1227,6 +1224,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, | |||
| 1227 | nfs_list_add_request(data->req, &desc->pg_list); | 1224 | nfs_list_add_request(data->req, &desc->pg_list); |
| 1228 | nfs_pageio_reset_write_mds(desc); | 1225 | nfs_pageio_reset_write_mds(desc); |
| 1229 | desc->pg_recoalesce = 1; | 1226 | desc->pg_recoalesce = 1; |
| 1227 | put_lseg(data->lseg); | ||
| 1230 | nfs_writedata_release(data); | 1228 | nfs_writedata_release(data); |
| 1231 | } | 1229 | } |
| 1232 | 1230 | ||
| @@ -1327,6 +1325,7 @@ void pnfs_ld_read_done(struct nfs_read_data *data) | |||
| 1327 | data->mds_ops->rpc_call_done(&data->task, data); | 1325 | data->mds_ops->rpc_call_done(&data->task, data); |
| 1328 | } else | 1326 | } else |
| 1329 | pnfs_ld_handle_read_error(data); | 1327 | pnfs_ld_handle_read_error(data); |
| 1328 | put_lseg(data->lseg); | ||
| 1330 | data->mds_ops->rpc_release(data); | 1329 | data->mds_ops->rpc_release(data); |
| 1331 | } | 1330 | } |
| 1332 | EXPORT_SYMBOL_GPL(pnfs_ld_read_done); | 1331 | EXPORT_SYMBOL_GPL(pnfs_ld_read_done); |
| @@ -1530,8 +1529,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) | |||
| 1530 | end_pos = nfsi->layout->plh_lwb; | 1529 | end_pos = nfsi->layout->plh_lwb; |
| 1531 | nfsi->layout->plh_lwb = 0; | 1530 | nfsi->layout->plh_lwb = 0; |
| 1532 | 1531 | ||
| 1533 | memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data, | 1532 | nfs4_stateid_copy(&data->args.stateid, &nfsi->layout->plh_stateid); |
| 1534 | sizeof(nfsi->layout->plh_stateid.data)); | ||
| 1535 | spin_unlock(&inode->i_lock); | 1533 | spin_unlock(&inode->i_lock); |
| 1536 | 1534 | ||
| 1537 | data->args.inode = inode; | 1535 | data->args.inode = inode; |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 53d593a0a4f2..442ebf68eeec 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
| @@ -94,11 +94,10 @@ struct pnfs_layoutdriver_type { | |||
| 94 | const struct nfs_pageio_ops *pg_read_ops; | 94 | const struct nfs_pageio_ops *pg_read_ops; |
| 95 | const struct nfs_pageio_ops *pg_write_ops; | 95 | const struct nfs_pageio_ops *pg_write_ops; |
| 96 | 96 | ||
| 97 | /* Returns true if layoutdriver wants to divert this request to | 97 | void (*mark_request_commit) (struct nfs_page *req, |
| 98 | * driver's commit routine. | 98 | struct pnfs_layout_segment *lseg); |
| 99 | */ | 99 | void (*clear_request_commit) (struct nfs_page *req); |
| 100 | bool (*mark_pnfs_commit)(struct pnfs_layout_segment *lseg); | 100 | int (*scan_commit_lists) (struct inode *inode, int max, spinlock_t *lock); |
| 101 | struct list_head * (*choose_commit_list) (struct nfs_page *req); | ||
| 102 | int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how); | 101 | int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how); |
| 103 | 102 | ||
| 104 | /* | 103 | /* |
| @@ -229,7 +228,6 @@ struct nfs4_deviceid_node { | |||
| 229 | atomic_t ref; | 228 | atomic_t ref; |
| 230 | }; | 229 | }; |
| 231 | 230 | ||
| 232 | void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id); | ||
| 233 | struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *); | 231 | struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *); |
| 234 | void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *); | 232 | void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *); |
| 235 | void nfs4_init_deviceid_node(struct nfs4_deviceid_node *, | 233 | void nfs4_init_deviceid_node(struct nfs4_deviceid_node *, |
| @@ -262,20 +260,6 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss) | |||
| 262 | return nfss->pnfs_curr_ld != NULL; | 260 | return nfss->pnfs_curr_ld != NULL; |
| 263 | } | 261 | } |
| 264 | 262 | ||
| 265 | static inline void | ||
| 266 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | ||
| 267 | { | ||
| 268 | if (lseg) { | ||
| 269 | struct pnfs_layoutdriver_type *ld; | ||
| 270 | |||
| 271 | ld = NFS_SERVER(req->wb_page->mapping->host)->pnfs_curr_ld; | ||
| 272 | if (ld->mark_pnfs_commit && ld->mark_pnfs_commit(lseg)) { | ||
| 273 | set_bit(PG_PNFS_COMMIT, &req->wb_flags); | ||
| 274 | req->wb_commit_lseg = get_lseg(lseg); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | static inline int | 263 | static inline int |
| 280 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) | 264 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) |
| 281 | { | 265 | { |
| @@ -284,27 +268,42 @@ pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) | |||
| 284 | return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how); | 268 | return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how); |
| 285 | } | 269 | } |
| 286 | 270 | ||
| 287 | static inline struct list_head * | 271 | static inline bool |
| 288 | pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds) | 272 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) |
| 289 | { | 273 | { |
| 290 | struct list_head *rv; | 274 | struct inode *inode = req->wb_context->dentry->d_inode; |
| 275 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; | ||
| 291 | 276 | ||
| 292 | if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) { | 277 | if (lseg == NULL || ld->mark_request_commit == NULL) |
| 293 | struct inode *inode = req->wb_commit_lseg->pls_layout->plh_inode; | 278 | return false; |
| 279 | ld->mark_request_commit(req, lseg); | ||
| 280 | return true; | ||
| 281 | } | ||
| 294 | 282 | ||
| 295 | set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags); | 283 | static inline bool |
| 296 | rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req); | 284 | pnfs_clear_request_commit(struct nfs_page *req) |
| 297 | /* matched by ref taken when PG_PNFS_COMMIT is set */ | 285 | { |
| 298 | put_lseg(req->wb_commit_lseg); | 286 | struct inode *inode = req->wb_context->dentry->d_inode; |
| 299 | } else | 287 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; |
| 300 | rv = mds; | 288 | |
| 301 | return rv; | 289 | if (ld == NULL || ld->clear_request_commit == NULL) |
| 290 | return false; | ||
| 291 | ld->clear_request_commit(req); | ||
| 292 | return true; | ||
| 302 | } | 293 | } |
| 303 | 294 | ||
| 304 | static inline void pnfs_clear_request_commit(struct nfs_page *req) | 295 | static inline int |
| 296 | pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock) | ||
| 305 | { | 297 | { |
| 306 | if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) | 298 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; |
| 307 | put_lseg(req->wb_commit_lseg); | 299 | int ret; |
| 300 | |||
| 301 | if (ld == NULL || ld->scan_commit_lists == NULL) | ||
| 302 | return 0; | ||
| 303 | ret = ld->scan_commit_lists(inode, max, lock); | ||
| 304 | if (ret != 0) | ||
| 305 | set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags); | ||
| 306 | return ret; | ||
| 308 | } | 307 | } |
| 309 | 308 | ||
| 310 | /* Should the pNFS client commit and return the layout upon a setattr */ | 309 | /* 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) | |||
| 328 | return 0; | 327 | return 0; |
| 329 | } | 328 | } |
| 330 | 329 | ||
| 330 | #ifdef NFS_DEBUG | ||
| 331 | void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id); | ||
| 332 | #else | ||
| 333 | static inline void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id) | ||
| 334 | { | ||
| 335 | } | ||
| 336 | #endif /* NFS_DEBUG */ | ||
| 331 | #else /* CONFIG_NFS_V4_1 */ | 337 | #else /* CONFIG_NFS_V4_1 */ |
| 332 | 338 | ||
| 333 | static inline void pnfs_destroy_all_layouts(struct nfs_client *clp) | 339 | static inline void pnfs_destroy_all_layouts(struct nfs_client *clp) |
| @@ -400,35 +406,35 @@ static inline bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, st | |||
| 400 | return false; | 406 | return false; |
| 401 | } | 407 | } |
| 402 | 408 | ||
| 403 | static inline void | ||
| 404 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | ||
| 405 | { | ||
| 406 | } | ||
| 407 | |||
| 408 | static inline int | 409 | static inline int |
| 409 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) | 410 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) |
| 410 | { | 411 | { |
| 411 | return PNFS_NOT_ATTEMPTED; | 412 | return PNFS_NOT_ATTEMPTED; |
| 412 | } | 413 | } |
| 413 | 414 | ||
| 414 | static inline struct list_head * | 415 | static inline bool |
| 415 | pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds) | 416 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) |
| 416 | { | 417 | { |
| 417 | return mds; | 418 | return false; |
| 418 | } | 419 | } |
| 419 | 420 | ||
| 420 | static inline void pnfs_clear_request_commit(struct nfs_page *req) | 421 | static inline bool |
| 422 | pnfs_clear_request_commit(struct nfs_page *req) | ||
| 421 | { | 423 | { |
| 424 | return false; | ||
| 422 | } | 425 | } |
| 423 | 426 | ||
| 424 | static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync) | 427 | static inline int |
| 428 | pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock) | ||
| 425 | { | 429 | { |
| 426 | return 0; | 430 | return 0; |
| 427 | } | 431 | } |
| 428 | 432 | ||
| 429 | static inline void nfs4_deviceid_purge_client(struct nfs_client *ncl) | 433 | static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync) |
| 430 | { | 434 | { |
| 435 | return 0; | ||
| 431 | } | 436 | } |
| 437 | |||
| 432 | #endif /* CONFIG_NFS_V4_1 */ | 438 | #endif /* CONFIG_NFS_V4_1 */ |
| 433 | 439 | ||
| 434 | #endif /* FS_NFS_PNFS_H */ | 440 | #endif /* FS_NFS_PNFS_H */ |
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c index 4f359d2a26eb..73f701f1f4d3 100644 --- a/fs/nfs/pnfs_dev.c +++ b/fs/nfs/pnfs_dev.c | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE]; | 43 | static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE]; |
| 44 | static DEFINE_SPINLOCK(nfs4_deviceid_lock); | 44 | static DEFINE_SPINLOCK(nfs4_deviceid_lock); |
| 45 | 45 | ||
| 46 | #ifdef NFS_DEBUG | ||
| 46 | void | 47 | void |
| 47 | nfs4_print_deviceid(const struct nfs4_deviceid *id) | 48 | nfs4_print_deviceid(const struct nfs4_deviceid *id) |
| 48 | { | 49 | { |
| @@ -52,6 +53,7 @@ nfs4_print_deviceid(const struct nfs4_deviceid *id) | |||
| 52 | p[0], p[1], p[2], p[3]); | 53 | p[0], p[1], p[2], p[3]); |
| 53 | } | 54 | } |
| 54 | EXPORT_SYMBOL_GPL(nfs4_print_deviceid); | 55 | EXPORT_SYMBOL_GPL(nfs4_print_deviceid); |
| 56 | #endif | ||
| 55 | 57 | ||
| 56 | static inline u32 | 58 | static inline u32 |
| 57 | nfs4_deviceid_hash(const struct nfs4_deviceid *id) | 59 | nfs4_deviceid_hash(const struct nfs4_deviceid *id) |
| @@ -92,7 +94,7 @@ _lookup_deviceid(const struct pnfs_layoutdriver_type *ld, | |||
| 92 | * @clp nfs_client associated with deviceid | 94 | * @clp nfs_client associated with deviceid |
| 93 | * @id deviceid to look up | 95 | * @id deviceid to look up |
| 94 | */ | 96 | */ |
| 95 | struct nfs4_deviceid_node * | 97 | static struct nfs4_deviceid_node * |
| 96 | _find_get_deviceid(const struct pnfs_layoutdriver_type *ld, | 98 | _find_get_deviceid(const struct pnfs_layoutdriver_type *ld, |
| 97 | const struct nfs_client *clp, const struct nfs4_deviceid *id, | 99 | const struct nfs_client *clp, const struct nfs4_deviceid *id, |
| 98 | long hash) | 100 | long hash) |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 0c672588fe5a..b63b6f4d14fb 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
| @@ -358,6 +358,11 @@ nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) | |||
| 358 | msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE]; | 358 | msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE]; |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | static void nfs_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) | ||
| 362 | { | ||
| 363 | rpc_call_start(task); | ||
| 364 | } | ||
| 365 | |||
| 361 | static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) | 366 | static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) |
| 362 | { | 367 | { |
| 363 | if (nfs_async_handle_expired_key(task)) | 368 | if (nfs_async_handle_expired_key(task)) |
| @@ -372,6 +377,11 @@ nfs_proc_rename_setup(struct rpc_message *msg, struct inode *dir) | |||
| 372 | msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME]; | 377 | msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME]; |
| 373 | } | 378 | } |
| 374 | 379 | ||
| 380 | static void nfs_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data) | ||
| 381 | { | ||
| 382 | rpc_call_start(task); | ||
| 383 | } | ||
| 384 | |||
| 375 | static int | 385 | static int |
| 376 | nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir, | 386 | nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir, |
| 377 | struct inode *new_dir) | 387 | struct inode *new_dir) |
| @@ -651,6 +661,11 @@ static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message * | |||
| 651 | msg->rpc_proc = &nfs_procedures[NFSPROC_READ]; | 661 | msg->rpc_proc = &nfs_procedures[NFSPROC_READ]; |
| 652 | } | 662 | } |
| 653 | 663 | ||
| 664 | static void nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) | ||
| 665 | { | ||
| 666 | rpc_call_start(task); | ||
| 667 | } | ||
| 668 | |||
| 654 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) | 669 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) |
| 655 | { | 670 | { |
| 656 | if (nfs_async_handle_expired_key(task)) | 671 | 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 | |||
| 668 | msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE]; | 683 | msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE]; |
| 669 | } | 684 | } |
| 670 | 685 | ||
| 686 | static void nfs_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data) | ||
| 687 | { | ||
| 688 | rpc_call_start(task); | ||
| 689 | } | ||
| 690 | |||
| 671 | static void | 691 | static void |
| 672 | nfs_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) | 692 | nfs_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) |
| 673 | { | 693 | { |
| @@ -721,9 +741,11 @@ const struct nfs_rpc_ops nfs_v2_clientops = { | |||
| 721 | .create = nfs_proc_create, | 741 | .create = nfs_proc_create, |
| 722 | .remove = nfs_proc_remove, | 742 | .remove = nfs_proc_remove, |
| 723 | .unlink_setup = nfs_proc_unlink_setup, | 743 | .unlink_setup = nfs_proc_unlink_setup, |
| 744 | .unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare, | ||
| 724 | .unlink_done = nfs_proc_unlink_done, | 745 | .unlink_done = nfs_proc_unlink_done, |
| 725 | .rename = nfs_proc_rename, | 746 | .rename = nfs_proc_rename, |
| 726 | .rename_setup = nfs_proc_rename_setup, | 747 | .rename_setup = nfs_proc_rename_setup, |
| 748 | .rename_rpc_prepare = nfs_proc_rename_rpc_prepare, | ||
| 727 | .rename_done = nfs_proc_rename_done, | 749 | .rename_done = nfs_proc_rename_done, |
| 728 | .link = nfs_proc_link, | 750 | .link = nfs_proc_link, |
| 729 | .symlink = nfs_proc_symlink, | 751 | .symlink = nfs_proc_symlink, |
| @@ -736,8 +758,10 @@ const struct nfs_rpc_ops nfs_v2_clientops = { | |||
| 736 | .pathconf = nfs_proc_pathconf, | 758 | .pathconf = nfs_proc_pathconf, |
| 737 | .decode_dirent = nfs2_decode_dirent, | 759 | .decode_dirent = nfs2_decode_dirent, |
| 738 | .read_setup = nfs_proc_read_setup, | 760 | .read_setup = nfs_proc_read_setup, |
| 761 | .read_rpc_prepare = nfs_proc_read_rpc_prepare, | ||
| 739 | .read_done = nfs_read_done, | 762 | .read_done = nfs_read_done, |
| 740 | .write_setup = nfs_proc_write_setup, | 763 | .write_setup = nfs_proc_write_setup, |
| 764 | .write_rpc_prepare = nfs_proc_write_rpc_prepare, | ||
| 741 | .write_done = nfs_write_done, | 765 | .write_done = nfs_write_done, |
| 742 | .commit_setup = nfs_proc_commit_setup, | 766 | .commit_setup = nfs_proc_commit_setup, |
| 743 | .lock = nfs_proc_lock, | 767 | .lock = nfs_proc_lock, |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index cfa175c223dc..cc1f758a7ee1 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -66,7 +66,6 @@ void nfs_readdata_free(struct nfs_read_data *p) | |||
| 66 | 66 | ||
| 67 | void nfs_readdata_release(struct nfs_read_data *rdata) | 67 | void nfs_readdata_release(struct nfs_read_data *rdata) |
| 68 | { | 68 | { |
| 69 | put_lseg(rdata->lseg); | ||
| 70 | put_nfs_open_context(rdata->args.context); | 69 | put_nfs_open_context(rdata->args.context); |
| 71 | nfs_readdata_free(rdata); | 70 | nfs_readdata_free(rdata); |
| 72 | } | 71 | } |
| @@ -465,23 +464,14 @@ static void nfs_readpage_release_partial(void *calldata) | |||
| 465 | nfs_readdata_release(calldata); | 464 | nfs_readdata_release(calldata); |
| 466 | } | 465 | } |
| 467 | 466 | ||
| 468 | #if defined(CONFIG_NFS_V4_1) | ||
| 469 | void nfs_read_prepare(struct rpc_task *task, void *calldata) | 467 | void nfs_read_prepare(struct rpc_task *task, void *calldata) |
| 470 | { | 468 | { |
| 471 | struct nfs_read_data *data = calldata; | 469 | struct nfs_read_data *data = calldata; |
| 472 | 470 | NFS_PROTO(data->inode)->read_rpc_prepare(task, data); | |
| 473 | if (nfs4_setup_sequence(NFS_SERVER(data->inode), | ||
| 474 | &data->args.seq_args, &data->res.seq_res, | ||
| 475 | 0, task)) | ||
| 476 | return; | ||
| 477 | rpc_call_start(task); | ||
| 478 | } | 471 | } |
| 479 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 480 | 472 | ||
| 481 | static const struct rpc_call_ops nfs_read_partial_ops = { | 473 | static const struct rpc_call_ops nfs_read_partial_ops = { |
| 482 | #if defined(CONFIG_NFS_V4_1) | ||
| 483 | .rpc_call_prepare = nfs_read_prepare, | 474 | .rpc_call_prepare = nfs_read_prepare, |
| 484 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 485 | .rpc_call_done = nfs_readpage_result_partial, | 475 | .rpc_call_done = nfs_readpage_result_partial, |
| 486 | .rpc_release = nfs_readpage_release_partial, | 476 | .rpc_release = nfs_readpage_release_partial, |
| 487 | }; | 477 | }; |
| @@ -545,9 +535,7 @@ static void nfs_readpage_release_full(void *calldata) | |||
| 545 | } | 535 | } |
| 546 | 536 | ||
| 547 | static const struct rpc_call_ops nfs_read_full_ops = { | 537 | static const struct rpc_call_ops nfs_read_full_ops = { |
| 548 | #if defined(CONFIG_NFS_V4_1) | ||
| 549 | .rpc_call_prepare = nfs_read_prepare, | 538 | .rpc_call_prepare = nfs_read_prepare, |
| 550 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 551 | .rpc_call_done = nfs_readpage_result_full, | 539 | .rpc_call_done = nfs_readpage_result_full, |
| 552 | .rpc_release = nfs_readpage_release_full, | 540 | .rpc_release = nfs_readpage_release_full, |
| 553 | }; | 541 | }; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 3dfa4f112c0a..ccc4cdb1efe9 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -52,6 +52,8 @@ | |||
| 52 | #include <linux/nfs_xdr.h> | 52 | #include <linux/nfs_xdr.h> |
| 53 | #include <linux/magic.h> | 53 | #include <linux/magic.h> |
| 54 | #include <linux/parser.h> | 54 | #include <linux/parser.h> |
| 55 | #include <linux/nsproxy.h> | ||
| 56 | #include <linux/rcupdate.h> | ||
| 55 | 57 | ||
| 56 | #include <asm/system.h> | 58 | #include <asm/system.h> |
| 57 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
| @@ -79,7 +81,6 @@ enum { | |||
| 79 | Opt_cto, Opt_nocto, | 81 | Opt_cto, Opt_nocto, |
| 80 | Opt_ac, Opt_noac, | 82 | Opt_ac, Opt_noac, |
| 81 | Opt_lock, Opt_nolock, | 83 | Opt_lock, Opt_nolock, |
| 82 | Opt_v2, Opt_v3, Opt_v4, | ||
| 83 | Opt_udp, Opt_tcp, Opt_rdma, | 84 | Opt_udp, Opt_tcp, Opt_rdma, |
| 84 | Opt_acl, Opt_noacl, | 85 | Opt_acl, Opt_noacl, |
| 85 | Opt_rdirplus, Opt_nordirplus, | 86 | Opt_rdirplus, Opt_nordirplus, |
| @@ -97,10 +98,10 @@ enum { | |||
| 97 | Opt_namelen, | 98 | Opt_namelen, |
| 98 | Opt_mountport, | 99 | Opt_mountport, |
| 99 | Opt_mountvers, | 100 | Opt_mountvers, |
| 100 | Opt_nfsvers, | ||
| 101 | Opt_minorversion, | 101 | Opt_minorversion, |
| 102 | 102 | ||
| 103 | /* Mount options that take string arguments */ | 103 | /* Mount options that take string arguments */ |
| 104 | Opt_nfsvers, | ||
| 104 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 105 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
| 105 | Opt_addr, Opt_mountaddr, Opt_clientaddr, | 106 | Opt_addr, Opt_mountaddr, Opt_clientaddr, |
| 106 | Opt_lookupcache, | 107 | Opt_lookupcache, |
| @@ -132,9 +133,6 @@ static const match_table_t nfs_mount_option_tokens = { | |||
| 132 | { Opt_noac, "noac" }, | 133 | { Opt_noac, "noac" }, |
| 133 | { Opt_lock, "lock" }, | 134 | { Opt_lock, "lock" }, |
| 134 | { Opt_nolock, "nolock" }, | 135 | { Opt_nolock, "nolock" }, |
| 135 | { Opt_v2, "v2" }, | ||
| 136 | { Opt_v3, "v3" }, | ||
| 137 | { Opt_v4, "v4" }, | ||
| 138 | { Opt_udp, "udp" }, | 136 | { Opt_udp, "udp" }, |
| 139 | { Opt_tcp, "tcp" }, | 137 | { Opt_tcp, "tcp" }, |
| 140 | { Opt_rdma, "rdma" }, | 138 | { Opt_rdma, "rdma" }, |
| @@ -163,9 +161,10 @@ static const match_table_t nfs_mount_option_tokens = { | |||
| 163 | { Opt_namelen, "namlen=%s" }, | 161 | { Opt_namelen, "namlen=%s" }, |
| 164 | { Opt_mountport, "mountport=%s" }, | 162 | { Opt_mountport, "mountport=%s" }, |
| 165 | { Opt_mountvers, "mountvers=%s" }, | 163 | { Opt_mountvers, "mountvers=%s" }, |
| 164 | { Opt_minorversion, "minorversion=%s" }, | ||
| 165 | |||
| 166 | { Opt_nfsvers, "nfsvers=%s" }, | 166 | { Opt_nfsvers, "nfsvers=%s" }, |
| 167 | { Opt_nfsvers, "vers=%s" }, | 167 | { Opt_nfsvers, "vers=%s" }, |
| 168 | { Opt_minorversion, "minorversion=%s" }, | ||
| 169 | 168 | ||
| 170 | { Opt_sec, "sec=%s" }, | 169 | { Opt_sec, "sec=%s" }, |
| 171 | { Opt_proto, "proto=%s" }, | 170 | { Opt_proto, "proto=%s" }, |
| @@ -179,6 +178,9 @@ static const match_table_t nfs_mount_option_tokens = { | |||
| 179 | { Opt_fscache_uniq, "fsc=%s" }, | 178 | { Opt_fscache_uniq, "fsc=%s" }, |
| 180 | { Opt_local_lock, "local_lock=%s" }, | 179 | { Opt_local_lock, "local_lock=%s" }, |
| 181 | 180 | ||
| 181 | /* The following needs to be listed after all other options */ | ||
| 182 | { Opt_nfsvers, "v%s" }, | ||
| 183 | |||
| 182 | { Opt_err, NULL } | 184 | { Opt_err, NULL } |
| 183 | }; | 185 | }; |
| 184 | 186 | ||
| @@ -259,6 +261,22 @@ static match_table_t nfs_local_lock_tokens = { | |||
| 259 | { Opt_local_lock_err, NULL } | 261 | { Opt_local_lock_err, NULL } |
| 260 | }; | 262 | }; |
| 261 | 263 | ||
| 264 | enum { | ||
| 265 | Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0, | ||
| 266 | Opt_vers_4_1, | ||
| 267 | |||
| 268 | Opt_vers_err | ||
| 269 | }; | ||
| 270 | |||
| 271 | static match_table_t nfs_vers_tokens = { | ||
| 272 | { Opt_vers_2, "2" }, | ||
| 273 | { Opt_vers_3, "3" }, | ||
| 274 | { Opt_vers_4, "4" }, | ||
| 275 | { Opt_vers_4_0, "4.0" }, | ||
| 276 | { Opt_vers_4_1, "4.1" }, | ||
| 277 | |||
| 278 | { Opt_vers_err, NULL } | ||
| 279 | }; | ||
| 262 | 280 | ||
| 263 | static void nfs_umount_begin(struct super_block *); | 281 | static void nfs_umount_begin(struct super_block *); |
| 264 | static int nfs_statfs(struct dentry *, struct kstatfs *); | 282 | 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, | |||
| 620 | struct nfs_client *clp = nfss->nfs_client; | 638 | struct nfs_client *clp = nfss->nfs_client; |
| 621 | 639 | ||
| 622 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | 640 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); |
| 623 | seq_printf(m, ",minorversion=%u", clp->cl_minorversion); | ||
| 624 | } | 641 | } |
| 625 | #else | 642 | #else |
| 626 | static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, | 643 | 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, | |||
| 629 | } | 646 | } |
| 630 | #endif | 647 | #endif |
| 631 | 648 | ||
| 649 | static void nfs_show_nfs_version(struct seq_file *m, | ||
| 650 | unsigned int version, | ||
| 651 | unsigned int minorversion) | ||
| 652 | { | ||
| 653 | seq_printf(m, ",vers=%u", version); | ||
| 654 | if (version == 4) | ||
| 655 | seq_printf(m, ".%u", minorversion); | ||
| 656 | } | ||
| 657 | |||
| 632 | /* | 658 | /* |
| 633 | * Describe the mount options in force on this server representation | 659 | * Describe the mount options in force on this server representation |
| 634 | */ | 660 | */ |
| @@ -656,7 +682,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
| 656 | u32 version = clp->rpc_ops->version; | 682 | u32 version = clp->rpc_ops->version; |
| 657 | int local_flock, local_fcntl; | 683 | int local_flock, local_fcntl; |
| 658 | 684 | ||
| 659 | seq_printf(m, ",vers=%u", version); | 685 | nfs_show_nfs_version(m, version, clp->cl_minorversion); |
| 660 | seq_printf(m, ",rsize=%u", nfss->rsize); | 686 | seq_printf(m, ",rsize=%u", nfss->rsize); |
| 661 | seq_printf(m, ",wsize=%u", nfss->wsize); | 687 | seq_printf(m, ",wsize=%u", nfss->wsize); |
| 662 | if (nfss->bsize != 0) | 688 | if (nfss->bsize != 0) |
| @@ -676,8 +702,10 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
| 676 | else | 702 | else |
| 677 | seq_puts(m, nfs_infop->nostr); | 703 | seq_puts(m, nfs_infop->nostr); |
| 678 | } | 704 | } |
| 705 | rcu_read_lock(); | ||
| 679 | seq_printf(m, ",proto=%s", | 706 | seq_printf(m, ",proto=%s", |
| 680 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); | 707 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); |
| 708 | rcu_read_unlock(); | ||
| 681 | if (version == 4) { | 709 | if (version == 4) { |
| 682 | if (nfss->port != NFS_PORT) | 710 | if (nfss->port != NFS_PORT) |
| 683 | seq_printf(m, ",port=%u", nfss->port); | 711 | seq_printf(m, ",port=%u", nfss->port); |
| @@ -726,9 +754,11 @@ static int nfs_show_options(struct seq_file *m, struct dentry *root) | |||
| 726 | 754 | ||
| 727 | nfs_show_mount_options(m, nfss, 0); | 755 | nfs_show_mount_options(m, nfss, 0); |
| 728 | 756 | ||
| 757 | rcu_read_lock(); | ||
| 729 | seq_printf(m, ",addr=%s", | 758 | seq_printf(m, ",addr=%s", |
| 730 | rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, | 759 | rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, |
| 731 | RPC_DISPLAY_ADDR)); | 760 | RPC_DISPLAY_ADDR)); |
| 761 | rcu_read_unlock(); | ||
| 732 | 762 | ||
| 733 | return 0; | 763 | return 0; |
| 734 | } | 764 | } |
| @@ -745,7 +775,6 @@ static void show_sessions(struct seq_file *m, struct nfs_server *server) {} | |||
| 745 | #endif | 775 | #endif |
| 746 | #endif | 776 | #endif |
| 747 | 777 | ||
| 748 | #ifdef CONFIG_NFS_V4 | ||
| 749 | #ifdef CONFIG_NFS_V4_1 | 778 | #ifdef CONFIG_NFS_V4_1 |
| 750 | static void show_pnfs(struct seq_file *m, struct nfs_server *server) | 779 | static void show_pnfs(struct seq_file *m, struct nfs_server *server) |
| 751 | { | 780 | { |
| @@ -755,9 +784,26 @@ static void show_pnfs(struct seq_file *m, struct nfs_server *server) | |||
| 755 | else | 784 | else |
| 756 | seq_printf(m, "not configured"); | 785 | seq_printf(m, "not configured"); |
| 757 | } | 786 | } |
| 787 | |||
| 788 | static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss) | ||
| 789 | { | ||
| 790 | if (nfss->nfs_client && nfss->nfs_client->impl_id) { | ||
| 791 | struct nfs41_impl_id *impl_id = nfss->nfs_client->impl_id; | ||
| 792 | seq_printf(m, "\n\timpl_id:\tname='%s',domain='%s'," | ||
| 793 | "date='%llu,%u'", | ||
| 794 | impl_id->name, impl_id->domain, | ||
| 795 | impl_id->date.seconds, impl_id->date.nseconds); | ||
| 796 | } | ||
| 797 | } | ||
| 758 | #else | 798 | #else |
| 759 | static void show_pnfs(struct seq_file *m, struct nfs_server *server) {} | 799 | #ifdef CONFIG_NFS_V4 |
| 800 | static void show_pnfs(struct seq_file *m, struct nfs_server *server) | ||
| 801 | { | ||
| 802 | } | ||
| 760 | #endif | 803 | #endif |
| 804 | static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss) | ||
| 805 | { | ||
| 806 | } | ||
| 761 | #endif | 807 | #endif |
| 762 | 808 | ||
| 763 | static int nfs_show_devname(struct seq_file *m, struct dentry *root) | 809 | 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) | |||
| 806 | 852 | ||
| 807 | seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ); | 853 | seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ); |
| 808 | 854 | ||
| 855 | show_implementation_id(m, nfss); | ||
| 856 | |||
| 809 | seq_printf(m, "\n\tcaps:\t"); | 857 | seq_printf(m, "\n\tcaps:\t"); |
| 810 | seq_printf(m, "caps=0x%x", nfss->caps); | 858 | seq_printf(m, "caps=0x%x", nfss->caps); |
| 811 | seq_printf(m, ",wtmult=%u", nfss->wtmult); | 859 | 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 | |||
| 908 | data->auth_flavor_len = 1; | 956 | data->auth_flavor_len = 1; |
| 909 | data->version = version; | 957 | data->version = version; |
| 910 | data->minorversion = 0; | 958 | data->minorversion = 0; |
| 959 | data->net = current->nsproxy->net_ns; | ||
| 911 | security_init_mnt_opts(&data->lsm_opts); | 960 | security_init_mnt_opts(&data->lsm_opts); |
| 912 | } | 961 | } |
| 913 | return data; | 962 | return data; |
| @@ -1052,6 +1101,40 @@ static int nfs_parse_security_flavors(char *value, | |||
| 1052 | return 1; | 1101 | return 1; |
| 1053 | } | 1102 | } |
| 1054 | 1103 | ||
| 1104 | static int nfs_parse_version_string(char *string, | ||
| 1105 | struct nfs_parsed_mount_data *mnt, | ||
| 1106 | substring_t *args) | ||
| 1107 | { | ||
| 1108 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
| 1109 | switch (match_token(string, nfs_vers_tokens, args)) { | ||
| 1110 | case Opt_vers_2: | ||
| 1111 | mnt->version = 2; | ||
| 1112 | break; | ||
| 1113 | case Opt_vers_3: | ||
| 1114 | mnt->flags |= NFS_MOUNT_VER3; | ||
| 1115 | mnt->version = 3; | ||
| 1116 | break; | ||
| 1117 | case Opt_vers_4: | ||
| 1118 | /* Backward compatibility option. In future, | ||
| 1119 | * the mount program should always supply | ||
| 1120 | * a NFSv4 minor version number. | ||
| 1121 | */ | ||
| 1122 | mnt->version = 4; | ||
| 1123 | break; | ||
| 1124 | case Opt_vers_4_0: | ||
| 1125 | mnt->version = 4; | ||
| 1126 | mnt->minorversion = 0; | ||
| 1127 | break; | ||
| 1128 | case Opt_vers_4_1: | ||
| 1129 | mnt->version = 4; | ||
| 1130 | mnt->minorversion = 1; | ||
| 1131 | break; | ||
| 1132 | default: | ||
| 1133 | return 0; | ||
| 1134 | } | ||
| 1135 | return 1; | ||
| 1136 | } | ||
| 1137 | |||
| 1055 | static int nfs_get_option_str(substring_t args[], char **option) | 1138 | static int nfs_get_option_str(substring_t args[], char **option) |
| 1056 | { | 1139 | { |
| 1057 | kfree(*option); | 1140 | kfree(*option); |
| @@ -1157,18 +1240,6 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1157 | mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK | | 1240 | mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK | |
| 1158 | NFS_MOUNT_LOCAL_FCNTL); | 1241 | NFS_MOUNT_LOCAL_FCNTL); |
| 1159 | break; | 1242 | break; |
| 1160 | case Opt_v2: | ||
| 1161 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
| 1162 | mnt->version = 2; | ||
| 1163 | break; | ||
| 1164 | case Opt_v3: | ||
| 1165 | mnt->flags |= NFS_MOUNT_VER3; | ||
| 1166 | mnt->version = 3; | ||
| 1167 | break; | ||
| 1168 | case Opt_v4: | ||
| 1169 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
| 1170 | mnt->version = 4; | ||
| 1171 | break; | ||
| 1172 | case Opt_udp: | 1243 | case Opt_udp: |
| 1173 | mnt->flags &= ~NFS_MOUNT_TCP; | 1244 | mnt->flags &= ~NFS_MOUNT_TCP; |
| 1174 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1245 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
| @@ -1295,26 +1366,6 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1295 | goto out_invalid_value; | 1366 | goto out_invalid_value; |
| 1296 | mnt->mount_server.version = option; | 1367 | mnt->mount_server.version = option; |
| 1297 | break; | 1368 | break; |
| 1298 | case Opt_nfsvers: | ||
| 1299 | if (nfs_get_option_ul(args, &option)) | ||
| 1300 | goto out_invalid_value; | ||
| 1301 | switch (option) { | ||
| 1302 | case NFS2_VERSION: | ||
| 1303 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
| 1304 | mnt->version = 2; | ||
| 1305 | break; | ||
| 1306 | case NFS3_VERSION: | ||
| 1307 | mnt->flags |= NFS_MOUNT_VER3; | ||
| 1308 | mnt->version = 3; | ||
| 1309 | break; | ||
| 1310 | case NFS4_VERSION: | ||
| 1311 | mnt->flags &= ~NFS_MOUNT_VER3; | ||
| 1312 | mnt->version = 4; | ||
| 1313 | break; | ||
| 1314 | default: | ||
| 1315 | goto out_invalid_value; | ||
| 1316 | } | ||
| 1317 | break; | ||
| 1318 | case Opt_minorversion: | 1369 | case Opt_minorversion: |
| 1319 | if (nfs_get_option_ul(args, &option)) | 1370 | if (nfs_get_option_ul(args, &option)) |
| 1320 | goto out_invalid_value; | 1371 | goto out_invalid_value; |
| @@ -1326,6 +1377,15 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1326 | /* | 1377 | /* |
| 1327 | * options that take text values | 1378 | * options that take text values |
| 1328 | */ | 1379 | */ |
| 1380 | case Opt_nfsvers: | ||
| 1381 | string = match_strdup(args); | ||
| 1382 | if (string == NULL) | ||
| 1383 | goto out_nomem; | ||
| 1384 | rc = nfs_parse_version_string(string, mnt, args); | ||
| 1385 | kfree(string); | ||
| 1386 | if (!rc) | ||
| 1387 | goto out_invalid_value; | ||
| 1388 | break; | ||
| 1329 | case Opt_sec: | 1389 | case Opt_sec: |
| 1330 | string = match_strdup(args); | 1390 | string = match_strdup(args); |
| 1331 | if (string == NULL) | 1391 | if (string == NULL) |
| @@ -1405,7 +1465,7 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1405 | if (string == NULL) | 1465 | if (string == NULL) |
| 1406 | goto out_nomem; | 1466 | goto out_nomem; |
| 1407 | mnt->nfs_server.addrlen = | 1467 | mnt->nfs_server.addrlen = |
| 1408 | rpc_pton(string, strlen(string), | 1468 | rpc_pton(mnt->net, string, strlen(string), |
| 1409 | (struct sockaddr *) | 1469 | (struct sockaddr *) |
| 1410 | &mnt->nfs_server.address, | 1470 | &mnt->nfs_server.address, |
| 1411 | sizeof(mnt->nfs_server.address)); | 1471 | sizeof(mnt->nfs_server.address)); |
| @@ -1427,7 +1487,7 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1427 | if (string == NULL) | 1487 | if (string == NULL) |
| 1428 | goto out_nomem; | 1488 | goto out_nomem; |
| 1429 | mnt->mount_server.addrlen = | 1489 | mnt->mount_server.addrlen = |
| 1430 | rpc_pton(string, strlen(string), | 1490 | rpc_pton(mnt->net, string, strlen(string), |
| 1431 | (struct sockaddr *) | 1491 | (struct sockaddr *) |
| 1432 | &mnt->mount_server.address, | 1492 | &mnt->mount_server.address, |
| 1433 | sizeof(mnt->mount_server.address)); | 1493 | sizeof(mnt->mount_server.address)); |
| @@ -1516,6 +1576,9 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1516 | if (!sloppy && invalid_option) | 1576 | if (!sloppy && invalid_option) |
| 1517 | return 0; | 1577 | return 0; |
| 1518 | 1578 | ||
| 1579 | if (mnt->minorversion && mnt->version != 4) | ||
| 1580 | goto out_minorversion_mismatch; | ||
| 1581 | |||
| 1519 | /* | 1582 | /* |
| 1520 | * verify that any proto=/mountproto= options match the address | 1583 | * verify that any proto=/mountproto= options match the address |
| 1521 | * familiies in the addr=/mountaddr= options. | 1584 | * familiies in the addr=/mountaddr= options. |
| @@ -1549,6 +1612,10 @@ out_invalid_address: | |||
| 1549 | out_invalid_value: | 1612 | out_invalid_value: |
| 1550 | printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); | 1613 | printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p); |
| 1551 | return 0; | 1614 | return 0; |
| 1615 | out_minorversion_mismatch: | ||
| 1616 | printk(KERN_INFO "NFS: mount option vers=%u does not support " | ||
| 1617 | "minorversion=%u\n", mnt->version, mnt->minorversion); | ||
| 1618 | return 0; | ||
| 1552 | out_nomem: | 1619 | out_nomem: |
| 1553 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1620 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
| 1554 | return 0; | 1621 | return 0; |
| @@ -1622,6 +1689,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
| 1622 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1689 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
| 1623 | .auth_flav_len = &server_authlist_len, | 1690 | .auth_flav_len = &server_authlist_len, |
| 1624 | .auth_flavs = server_authlist, | 1691 | .auth_flavs = server_authlist, |
| 1692 | .net = args->net, | ||
| 1625 | }; | 1693 | }; |
| 1626 | int status; | 1694 | int status; |
| 1627 | 1695 | ||
| @@ -2047,7 +2115,7 @@ static inline void nfs_initialise_sb(struct super_block *sb) | |||
| 2047 | 2115 | ||
| 2048 | /* We probably want something more informative here */ | 2116 | /* We probably want something more informative here */ |
| 2049 | snprintf(sb->s_id, sizeof(sb->s_id), | 2117 | snprintf(sb->s_id, sizeof(sb->s_id), |
| 2050 | "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); | 2118 | "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev)); |
| 2051 | 2119 | ||
| 2052 | if (sb->s_blocksize == 0) | 2120 | if (sb->s_blocksize == 0) |
| 2053 | sb->s_blocksize = nfs_block_bits(server->wsize, | 2121 | sb->s_blocksize = nfs_block_bits(server->wsize, |
| @@ -2499,12 +2567,6 @@ static int nfs4_validate_text_mount_data(void *options, | |||
| 2499 | return -EINVAL; | 2567 | return -EINVAL; |
| 2500 | } | 2568 | } |
| 2501 | 2569 | ||
| 2502 | if (args->client_address == NULL) { | ||
| 2503 | dfprintk(MOUNT, | ||
| 2504 | "NFS4: mount program didn't pass callback address\n"); | ||
| 2505 | return -EINVAL; | ||
| 2506 | } | ||
| 2507 | |||
| 2508 | return nfs_parse_devname(dev_name, | 2570 | return nfs_parse_devname(dev_name, |
| 2509 | &args->nfs_server.hostname, | 2571 | &args->nfs_server.hostname, |
| 2510 | NFS4_MAXNAMLEN, | 2572 | NFS4_MAXNAMLEN, |
| @@ -2663,8 +2725,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags, | |||
| 2663 | if (!s->s_root) { | 2725 | if (!s->s_root) { |
| 2664 | /* initial superblock/root creation */ | 2726 | /* initial superblock/root creation */ |
| 2665 | nfs4_fill_super(s); | 2727 | nfs4_fill_super(s); |
| 2666 | nfs_fscache_get_super_cookie( | 2728 | nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL); |
| 2667 | s, data ? data->fscache_uniq : NULL, NULL); | ||
| 2668 | } | 2729 | } |
| 2669 | 2730 | ||
| 2670 | mntroot = nfs4_get_root(s, mntfh, dev_name); | 2731 | mntroot = nfs4_get_root(s, mntfh, dev_name); |
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index 978aaeb8a093..ad4d2e787b20 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c | |||
| @@ -32,7 +32,6 @@ static ctl_table nfs_cb_sysctls[] = { | |||
| 32 | .extra1 = (int *)&nfs_set_port_min, | 32 | .extra1 = (int *)&nfs_set_port_min, |
| 33 | .extra2 = (int *)&nfs_set_port_max, | 33 | .extra2 = (int *)&nfs_set_port_max, |
| 34 | }, | 34 | }, |
| 35 | #ifndef CONFIG_NFS_USE_NEW_IDMAPPER | ||
| 36 | { | 35 | { |
| 37 | .procname = "idmap_cache_timeout", | 36 | .procname = "idmap_cache_timeout", |
| 38 | .data = &nfs_idmap_cache_timeout, | 37 | .data = &nfs_idmap_cache_timeout, |
| @@ -40,7 +39,6 @@ static ctl_table nfs_cb_sysctls[] = { | |||
| 40 | .mode = 0644, | 39 | .mode = 0644, |
| 41 | .proc_handler = proc_dointvec_jiffies, | 40 | .proc_handler = proc_dointvec_jiffies, |
| 42 | }, | 41 | }, |
| 43 | #endif /* CONFIG_NFS_USE_NEW_IDMAPPER */ | ||
| 44 | #endif | 42 | #endif |
| 45 | { | 43 | { |
| 46 | .procname = "nfs_mountpoint_timeout", | 44 | .procname = "nfs_mountpoint_timeout", |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 4f9319a2e567..3210a03342f9 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
| @@ -20,15 +20,6 @@ | |||
| 20 | #include "iostat.h" | 20 | #include "iostat.h" |
| 21 | #include "delegation.h" | 21 | #include "delegation.h" |
| 22 | 22 | ||
| 23 | struct nfs_unlinkdata { | ||
| 24 | struct hlist_node list; | ||
| 25 | struct nfs_removeargs args; | ||
| 26 | struct nfs_removeres res; | ||
| 27 | struct inode *dir; | ||
| 28 | struct rpc_cred *cred; | ||
| 29 | struct nfs_fattr dir_attr; | ||
| 30 | }; | ||
| 31 | |||
| 32 | /** | 23 | /** |
| 33 | * nfs_free_unlinkdata - release data from a sillydelete operation. | 24 | * nfs_free_unlinkdata - release data from a sillydelete operation. |
| 34 | * @data: pointer to unlink structure. | 25 | * @data: pointer to unlink structure. |
| @@ -107,25 +98,16 @@ static void nfs_async_unlink_release(void *calldata) | |||
| 107 | nfs_sb_deactive(sb); | 98 | nfs_sb_deactive(sb); |
| 108 | } | 99 | } |
| 109 | 100 | ||
| 110 | #if defined(CONFIG_NFS_V4_1) | 101 | static void nfs_unlink_prepare(struct rpc_task *task, void *calldata) |
| 111 | void nfs_unlink_prepare(struct rpc_task *task, void *calldata) | ||
| 112 | { | 102 | { |
| 113 | struct nfs_unlinkdata *data = calldata; | 103 | struct nfs_unlinkdata *data = calldata; |
| 114 | struct nfs_server *server = NFS_SERVER(data->dir); | 104 | NFS_PROTO(data->dir)->unlink_rpc_prepare(task, data); |
| 115 | |||
| 116 | if (nfs4_setup_sequence(server, &data->args.seq_args, | ||
| 117 | &data->res.seq_res, 1, task)) | ||
| 118 | return; | ||
| 119 | rpc_call_start(task); | ||
| 120 | } | 105 | } |
| 121 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 122 | 106 | ||
| 123 | static const struct rpc_call_ops nfs_unlink_ops = { | 107 | static const struct rpc_call_ops nfs_unlink_ops = { |
| 124 | .rpc_call_done = nfs_async_unlink_done, | 108 | .rpc_call_done = nfs_async_unlink_done, |
| 125 | .rpc_release = nfs_async_unlink_release, | 109 | .rpc_release = nfs_async_unlink_release, |
| 126 | #if defined(CONFIG_NFS_V4_1) | ||
| 127 | .rpc_call_prepare = nfs_unlink_prepare, | 110 | .rpc_call_prepare = nfs_unlink_prepare, |
| 128 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 129 | }; | 111 | }; |
| 130 | 112 | ||
| 131 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) | 113 | 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) | |||
| 341 | spin_unlock(&dentry->d_lock); | 323 | spin_unlock(&dentry->d_lock); |
| 342 | } | 324 | } |
| 343 | 325 | ||
| 344 | struct nfs_renamedata { | ||
| 345 | struct nfs_renameargs args; | ||
| 346 | struct nfs_renameres res; | ||
| 347 | struct rpc_cred *cred; | ||
| 348 | struct inode *old_dir; | ||
| 349 | struct dentry *old_dentry; | ||
| 350 | struct nfs_fattr old_fattr; | ||
| 351 | struct inode *new_dir; | ||
| 352 | struct dentry *new_dentry; | ||
| 353 | struct nfs_fattr new_fattr; | ||
| 354 | }; | ||
| 355 | |||
| 356 | /** | 326 | /** |
| 357 | * nfs_async_rename_done - Sillyrename post-processing | 327 | * nfs_async_rename_done - Sillyrename post-processing |
| 358 | * @task: rpc_task of the sillyrename | 328 | * @task: rpc_task of the sillyrename |
| @@ -403,25 +373,16 @@ static void nfs_async_rename_release(void *calldata) | |||
| 403 | kfree(data); | 373 | kfree(data); |
| 404 | } | 374 | } |
| 405 | 375 | ||
| 406 | #if defined(CONFIG_NFS_V4_1) | ||
| 407 | static void nfs_rename_prepare(struct rpc_task *task, void *calldata) | 376 | static void nfs_rename_prepare(struct rpc_task *task, void *calldata) |
| 408 | { | 377 | { |
| 409 | struct nfs_renamedata *data = calldata; | 378 | struct nfs_renamedata *data = calldata; |
| 410 | struct nfs_server *server = NFS_SERVER(data->old_dir); | 379 | NFS_PROTO(data->old_dir)->rename_rpc_prepare(task, data); |
| 411 | |||
| 412 | if (nfs4_setup_sequence(server, &data->args.seq_args, | ||
| 413 | &data->res.seq_res, 1, task)) | ||
| 414 | return; | ||
| 415 | rpc_call_start(task); | ||
| 416 | } | 380 | } |
| 417 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 418 | 381 | ||
| 419 | static const struct rpc_call_ops nfs_rename_ops = { | 382 | static const struct rpc_call_ops nfs_rename_ops = { |
| 420 | .rpc_call_done = nfs_async_rename_done, | 383 | .rpc_call_done = nfs_async_rename_done, |
| 421 | .rpc_release = nfs_async_rename_release, | 384 | .rpc_release = nfs_async_rename_release, |
| 422 | #if defined(CONFIG_NFS_V4_1) | ||
| 423 | .rpc_call_prepare = nfs_rename_prepare, | 385 | .rpc_call_prepare = nfs_rename_prepare, |
| 424 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 425 | }; | 386 | }; |
| 426 | 387 | ||
| 427 | /** | 388 | /** |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 834f0fe96f89..2c68818f68ac 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -100,7 +100,6 @@ void nfs_writedata_free(struct nfs_write_data *p) | |||
| 100 | 100 | ||
| 101 | void nfs_writedata_release(struct nfs_write_data *wdata) | 101 | void nfs_writedata_release(struct nfs_write_data *wdata) |
| 102 | { | 102 | { |
| 103 | put_lseg(wdata->lseg); | ||
| 104 | put_nfs_open_context(wdata->args.context); | 103 | put_nfs_open_context(wdata->args.context); |
| 105 | nfs_writedata_free(wdata); | 104 | nfs_writedata_free(wdata); |
| 106 | } | 105 | } |
| @@ -236,10 +235,10 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblo | |||
| 236 | req = nfs_page_find_request_locked(page); | 235 | req = nfs_page_find_request_locked(page); |
| 237 | if (req == NULL) | 236 | if (req == NULL) |
| 238 | break; | 237 | break; |
| 239 | if (nfs_set_page_tag_locked(req)) | 238 | if (nfs_lock_request_dontget(req)) |
| 240 | break; | 239 | break; |
| 241 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | 240 | /* Note: If we hold the page lock, as is the case in nfs_writepage, |
| 242 | * then the call to nfs_set_page_tag_locked() will always | 241 | * then the call to nfs_lock_request_dontget() will always |
| 243 | * succeed provided that someone hasn't already marked the | 242 | * succeed provided that someone hasn't already marked the |
| 244 | * request as dirty (in which case we don't care). | 243 | * request as dirty (in which case we don't care). |
| 245 | */ | 244 | */ |
| @@ -375,21 +374,14 @@ out_err: | |||
| 375 | /* | 374 | /* |
| 376 | * Insert a write request into an inode | 375 | * Insert a write request into an inode |
| 377 | */ | 376 | */ |
| 378 | static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | 377 | static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) |
| 379 | { | 378 | { |
| 380 | struct nfs_inode *nfsi = NFS_I(inode); | 379 | struct nfs_inode *nfsi = NFS_I(inode); |
| 381 | int error; | ||
| 382 | |||
| 383 | error = radix_tree_preload(GFP_NOFS); | ||
| 384 | if (error != 0) | ||
| 385 | goto out; | ||
| 386 | 380 | ||
| 387 | /* Lock the request! */ | 381 | /* Lock the request! */ |
| 388 | nfs_lock_request_dontget(req); | 382 | nfs_lock_request_dontget(req); |
| 389 | 383 | ||
| 390 | spin_lock(&inode->i_lock); | 384 | spin_lock(&inode->i_lock); |
| 391 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); | ||
| 392 | BUG_ON(error); | ||
| 393 | if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE)) | 385 | if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE)) |
| 394 | inode->i_version++; | 386 | inode->i_version++; |
| 395 | set_bit(PG_MAPPED, &req->wb_flags); | 387 | set_bit(PG_MAPPED, &req->wb_flags); |
| @@ -397,12 +389,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
| 397 | set_page_private(req->wb_page, (unsigned long)req); | 389 | set_page_private(req->wb_page, (unsigned long)req); |
| 398 | nfsi->npages++; | 390 | nfsi->npages++; |
| 399 | kref_get(&req->wb_kref); | 391 | kref_get(&req->wb_kref); |
| 400 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, | ||
| 401 | NFS_PAGE_TAG_LOCKED); | ||
| 402 | spin_unlock(&inode->i_lock); | 392 | spin_unlock(&inode->i_lock); |
| 403 | radix_tree_preload_end(); | ||
| 404 | out: | ||
| 405 | return error; | ||
| 406 | } | 393 | } |
| 407 | 394 | ||
| 408 | /* | 395 | /* |
| @@ -419,7 +406,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
| 419 | set_page_private(req->wb_page, 0); | 406 | set_page_private(req->wb_page, 0); |
| 420 | ClearPagePrivate(req->wb_page); | 407 | ClearPagePrivate(req->wb_page); |
| 421 | clear_bit(PG_MAPPED, &req->wb_flags); | 408 | clear_bit(PG_MAPPED, &req->wb_flags); |
| 422 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | ||
| 423 | nfsi->npages--; | 409 | nfsi->npages--; |
| 424 | spin_unlock(&inode->i_lock); | 410 | spin_unlock(&inode->i_lock); |
| 425 | nfs_release_request(req); | 411 | nfs_release_request(req); |
| @@ -432,39 +418,90 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
| 432 | } | 418 | } |
| 433 | 419 | ||
| 434 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 420 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
| 435 | /* | 421 | /** |
| 436 | * Add a request to the inode's commit list. | 422 | * nfs_request_add_commit_list - add request to a commit list |
| 423 | * @req: pointer to a struct nfs_page | ||
| 424 | * @head: commit list head | ||
| 425 | * | ||
| 426 | * This sets the PG_CLEAN bit, updates the inode global count of | ||
| 427 | * number of outstanding requests requiring a commit as well as | ||
| 428 | * the MM page stats. | ||
| 429 | * | ||
| 430 | * The caller must _not_ hold the inode->i_lock, but must be | ||
| 431 | * holding the nfs_page lock. | ||
| 437 | */ | 432 | */ |
| 438 | static void | 433 | void |
| 439 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 434 | nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head) |
| 440 | { | 435 | { |
| 441 | struct inode *inode = req->wb_context->dentry->d_inode; | 436 | struct inode *inode = req->wb_context->dentry->d_inode; |
| 442 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 443 | 437 | ||
| 444 | spin_lock(&inode->i_lock); | ||
| 445 | set_bit(PG_CLEAN, &(req)->wb_flags); | 438 | set_bit(PG_CLEAN, &(req)->wb_flags); |
| 446 | radix_tree_tag_set(&nfsi->nfs_page_tree, | 439 | spin_lock(&inode->i_lock); |
| 447 | req->wb_index, | 440 | nfs_list_add_request(req, head); |
| 448 | NFS_PAGE_TAG_COMMIT); | 441 | NFS_I(inode)->ncommit++; |
| 449 | nfsi->ncommit++; | ||
| 450 | spin_unlock(&inode->i_lock); | 442 | spin_unlock(&inode->i_lock); |
| 451 | pnfs_mark_request_commit(req, lseg); | ||
| 452 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 443 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
| 453 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); | 444 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); |
| 454 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 445 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
| 455 | } | 446 | } |
| 447 | EXPORT_SYMBOL_GPL(nfs_request_add_commit_list); | ||
| 456 | 448 | ||
| 457 | static int | 449 | /** |
| 450 | * nfs_request_remove_commit_list - Remove request from a commit list | ||
| 451 | * @req: pointer to a nfs_page | ||
| 452 | * | ||
| 453 | * This clears the PG_CLEAN bit, and updates the inode global count of | ||
| 454 | * number of outstanding requests requiring a commit | ||
| 455 | * It does not update the MM page stats. | ||
| 456 | * | ||
| 457 | * The caller _must_ hold the inode->i_lock and the nfs_page lock. | ||
| 458 | */ | ||
| 459 | void | ||
| 460 | nfs_request_remove_commit_list(struct nfs_page *req) | ||
| 461 | { | ||
| 462 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
| 463 | |||
| 464 | if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) | ||
| 465 | return; | ||
| 466 | nfs_list_remove_request(req); | ||
| 467 | NFS_I(inode)->ncommit--; | ||
| 468 | } | ||
| 469 | EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list); | ||
| 470 | |||
| 471 | |||
| 472 | /* | ||
| 473 | * Add a request to the inode's commit list. | ||
| 474 | */ | ||
| 475 | static void | ||
| 476 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | ||
| 477 | { | ||
| 478 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
| 479 | |||
| 480 | if (pnfs_mark_request_commit(req, lseg)) | ||
| 481 | return; | ||
| 482 | nfs_request_add_commit_list(req, &NFS_I(inode)->commit_list); | ||
| 483 | } | ||
| 484 | |||
| 485 | static void | ||
| 486 | nfs_clear_page_commit(struct page *page) | ||
| 487 | { | ||
| 488 | dec_zone_page_state(page, NR_UNSTABLE_NFS); | ||
| 489 | dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE); | ||
| 490 | } | ||
| 491 | |||
| 492 | static void | ||
| 458 | nfs_clear_request_commit(struct nfs_page *req) | 493 | nfs_clear_request_commit(struct nfs_page *req) |
| 459 | { | 494 | { |
| 460 | struct page *page = req->wb_page; | 495 | if (test_bit(PG_CLEAN, &req->wb_flags)) { |
| 496 | struct inode *inode = req->wb_context->dentry->d_inode; | ||
| 461 | 497 | ||
| 462 | if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) { | 498 | if (!pnfs_clear_request_commit(req)) { |
| 463 | dec_zone_page_state(page, NR_UNSTABLE_NFS); | 499 | spin_lock(&inode->i_lock); |
| 464 | dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE); | 500 | nfs_request_remove_commit_list(req); |
| 465 | return 1; | 501 | spin_unlock(&inode->i_lock); |
| 502 | } | ||
| 503 | nfs_clear_page_commit(req->wb_page); | ||
| 466 | } | 504 | } |
| 467 | return 0; | ||
| 468 | } | 505 | } |
| 469 | 506 | ||
| 470 | static inline | 507 | static inline |
| @@ -491,15 +528,14 @@ int nfs_reschedule_unstable_write(struct nfs_page *req, | |||
| 491 | return 0; | 528 | return 0; |
| 492 | } | 529 | } |
| 493 | #else | 530 | #else |
| 494 | static inline void | 531 | static void |
| 495 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 532 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) |
| 496 | { | 533 | { |
| 497 | } | 534 | } |
| 498 | 535 | ||
| 499 | static inline int | 536 | static void |
| 500 | nfs_clear_request_commit(struct nfs_page *req) | 537 | nfs_clear_request_commit(struct nfs_page *req) |
| 501 | { | 538 | { |
| 502 | return 0; | ||
| 503 | } | 539 | } |
| 504 | 540 | ||
| 505 | static inline | 541 | static inline |
| @@ -520,46 +556,65 @@ int nfs_reschedule_unstable_write(struct nfs_page *req, | |||
| 520 | static int | 556 | static int |
| 521 | nfs_need_commit(struct nfs_inode *nfsi) | 557 | nfs_need_commit(struct nfs_inode *nfsi) |
| 522 | { | 558 | { |
| 523 | return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT); | 559 | return nfsi->ncommit > 0; |
| 560 | } | ||
| 561 | |||
| 562 | /* i_lock held by caller */ | ||
| 563 | static int | ||
| 564 | nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max, | ||
| 565 | spinlock_t *lock) | ||
| 566 | { | ||
| 567 | struct nfs_page *req, *tmp; | ||
| 568 | int ret = 0; | ||
| 569 | |||
| 570 | list_for_each_entry_safe(req, tmp, src, wb_list) { | ||
| 571 | if (!nfs_lock_request(req)) | ||
| 572 | continue; | ||
| 573 | if (cond_resched_lock(lock)) | ||
| 574 | list_safe_reset_next(req, tmp, wb_list); | ||
| 575 | nfs_request_remove_commit_list(req); | ||
| 576 | nfs_list_add_request(req, dst); | ||
| 577 | ret++; | ||
| 578 | if (ret == max) | ||
| 579 | break; | ||
| 580 | } | ||
| 581 | return ret; | ||
| 524 | } | 582 | } |
| 525 | 583 | ||
| 526 | /* | 584 | /* |
| 527 | * nfs_scan_commit - Scan an inode for commit requests | 585 | * nfs_scan_commit - Scan an inode for commit requests |
| 528 | * @inode: NFS inode to scan | 586 | * @inode: NFS inode to scan |
| 529 | * @dst: destination list | 587 | * @dst: destination list |
| 530 | * @idx_start: lower bound of page->index to scan. | ||
| 531 | * @npages: idx_start + npages sets the upper bound to scan. | ||
| 532 | * | 588 | * |
| 533 | * Moves requests from the inode's 'commit' request list. | 589 | * Moves requests from the inode's 'commit' request list. |
| 534 | * The requests are *not* checked to ensure that they form a contiguous set. | 590 | * The requests are *not* checked to ensure that they form a contiguous set. |
| 535 | */ | 591 | */ |
| 536 | static int | 592 | static int |
| 537 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) | 593 | nfs_scan_commit(struct inode *inode, struct list_head *dst) |
| 538 | { | 594 | { |
| 539 | struct nfs_inode *nfsi = NFS_I(inode); | 595 | struct nfs_inode *nfsi = NFS_I(inode); |
| 540 | int ret; | 596 | int ret = 0; |
| 541 | |||
| 542 | if (!nfs_need_commit(nfsi)) | ||
| 543 | return 0; | ||
| 544 | 597 | ||
| 545 | spin_lock(&inode->i_lock); | 598 | spin_lock(&inode->i_lock); |
| 546 | ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); | 599 | if (nfsi->ncommit > 0) { |
| 547 | if (ret > 0) | 600 | const int max = INT_MAX; |
| 548 | nfsi->ncommit -= ret; | ||
| 549 | spin_unlock(&inode->i_lock); | ||
| 550 | |||
| 551 | if (nfs_need_commit(NFS_I(inode))) | ||
| 552 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | ||
| 553 | 601 | ||
| 602 | ret = nfs_scan_commit_list(&nfsi->commit_list, dst, max, | ||
| 603 | &inode->i_lock); | ||
| 604 | ret += pnfs_scan_commit_lists(inode, max - ret, | ||
| 605 | &inode->i_lock); | ||
| 606 | } | ||
| 607 | spin_unlock(&inode->i_lock); | ||
| 554 | return ret; | 608 | return ret; |
| 555 | } | 609 | } |
| 610 | |||
| 556 | #else | 611 | #else |
| 557 | static inline int nfs_need_commit(struct nfs_inode *nfsi) | 612 | static inline int nfs_need_commit(struct nfs_inode *nfsi) |
| 558 | { | 613 | { |
| 559 | return 0; | 614 | return 0; |
| 560 | } | 615 | } |
| 561 | 616 | ||
| 562 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) | 617 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst) |
| 563 | { | 618 | { |
| 564 | return 0; | 619 | return 0; |
| 565 | } | 620 | } |
| @@ -604,7 +659,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, | |||
| 604 | || end < req->wb_offset) | 659 | || end < req->wb_offset) |
| 605 | goto out_flushme; | 660 | goto out_flushme; |
| 606 | 661 | ||
| 607 | if (nfs_set_page_tag_locked(req)) | 662 | if (nfs_lock_request_dontget(req)) |
| 608 | break; | 663 | break; |
| 609 | 664 | ||
| 610 | /* The request is locked, so wait and then retry */ | 665 | /* 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, | |||
| 616 | spin_lock(&inode->i_lock); | 671 | spin_lock(&inode->i_lock); |
| 617 | } | 672 | } |
| 618 | 673 | ||
| 619 | if (nfs_clear_request_commit(req) && | ||
| 620 | radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, | ||
| 621 | req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) { | ||
| 622 | NFS_I(inode)->ncommit--; | ||
| 623 | pnfs_clear_request_commit(req); | ||
| 624 | } | ||
| 625 | |||
| 626 | /* Okay, the request matches. Update the region */ | 674 | /* Okay, the request matches. Update the region */ |
| 627 | if (offset < req->wb_offset) { | 675 | if (offset < req->wb_offset) { |
| 628 | req->wb_offset = offset; | 676 | req->wb_offset = offset; |
| @@ -634,6 +682,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, | |||
| 634 | req->wb_bytes = rqend - req->wb_offset; | 682 | req->wb_bytes = rqend - req->wb_offset; |
| 635 | out_unlock: | 683 | out_unlock: |
| 636 | spin_unlock(&inode->i_lock); | 684 | spin_unlock(&inode->i_lock); |
| 685 | nfs_clear_request_commit(req); | ||
| 637 | return req; | 686 | return req; |
| 638 | out_flushme: | 687 | out_flushme: |
| 639 | spin_unlock(&inode->i_lock); | 688 | spin_unlock(&inode->i_lock); |
| @@ -655,7 +704,6 @@ static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx, | |||
| 655 | { | 704 | { |
| 656 | struct inode *inode = page->mapping->host; | 705 | struct inode *inode = page->mapping->host; |
| 657 | struct nfs_page *req; | 706 | struct nfs_page *req; |
| 658 | int error; | ||
| 659 | 707 | ||
| 660 | req = nfs_try_to_update_request(inode, page, offset, bytes); | 708 | req = nfs_try_to_update_request(inode, page, offset, bytes); |
| 661 | if (req != NULL) | 709 | if (req != NULL) |
| @@ -663,11 +711,7 @@ static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx, | |||
| 663 | req = nfs_create_request(ctx, inode, page, offset, bytes); | 711 | req = nfs_create_request(ctx, inode, page, offset, bytes); |
| 664 | if (IS_ERR(req)) | 712 | if (IS_ERR(req)) |
| 665 | goto out; | 713 | goto out; |
| 666 | error = nfs_inode_add_request(inode, req); | 714 | nfs_inode_add_request(inode, req); |
| 667 | if (error != 0) { | ||
| 668 | nfs_release_request(req); | ||
| 669 | req = ERR_PTR(error); | ||
| 670 | } | ||
| 671 | out: | 715 | out: |
| 672 | return req; | 716 | return req; |
| 673 | } | 717 | } |
| @@ -684,7 +728,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
| 684 | nfs_grow_file(page, offset, count); | 728 | nfs_grow_file(page, offset, count); |
| 685 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | 729 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); |
| 686 | nfs_mark_request_dirty(req); | 730 | nfs_mark_request_dirty(req); |
| 687 | nfs_clear_page_tag_locked(req); | 731 | nfs_unlock_request(req); |
| 688 | return 0; | 732 | return 0; |
| 689 | } | 733 | } |
| 690 | 734 | ||
| @@ -777,7 +821,7 @@ static void nfs_writepage_release(struct nfs_page *req, | |||
| 777 | 821 | ||
| 778 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data)) | 822 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data)) |
| 779 | nfs_inode_remove_request(req); | 823 | nfs_inode_remove_request(req); |
| 780 | nfs_clear_page_tag_locked(req); | 824 | nfs_unlock_request(req); |
| 781 | nfs_end_page_writeback(page); | 825 | nfs_end_page_writeback(page); |
| 782 | } | 826 | } |
| 783 | 827 | ||
| @@ -925,7 +969,7 @@ static void nfs_redirty_request(struct nfs_page *req) | |||
| 925 | struct page *page = req->wb_page; | 969 | struct page *page = req->wb_page; |
| 926 | 970 | ||
| 927 | nfs_mark_request_dirty(req); | 971 | nfs_mark_request_dirty(req); |
| 928 | nfs_clear_page_tag_locked(req); | 972 | nfs_unlock_request(req); |
| 929 | nfs_end_page_writeback(page); | 973 | nfs_end_page_writeback(page); |
| 930 | } | 974 | } |
| 931 | 975 | ||
| @@ -1128,23 +1172,14 @@ out: | |||
| 1128 | nfs_writedata_release(calldata); | 1172 | nfs_writedata_release(calldata); |
| 1129 | } | 1173 | } |
| 1130 | 1174 | ||
| 1131 | #if defined(CONFIG_NFS_V4_1) | ||
| 1132 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | 1175 | void nfs_write_prepare(struct rpc_task *task, void *calldata) |
| 1133 | { | 1176 | { |
| 1134 | struct nfs_write_data *data = calldata; | 1177 | struct nfs_write_data *data = calldata; |
| 1135 | 1178 | NFS_PROTO(data->inode)->write_rpc_prepare(task, data); | |
| 1136 | if (nfs4_setup_sequence(NFS_SERVER(data->inode), | ||
| 1137 | &data->args.seq_args, | ||
| 1138 | &data->res.seq_res, 1, task)) | ||
| 1139 | return; | ||
| 1140 | rpc_call_start(task); | ||
| 1141 | } | 1179 | } |
| 1142 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1143 | 1180 | ||
| 1144 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1181 | static const struct rpc_call_ops nfs_write_partial_ops = { |
| 1145 | #if defined(CONFIG_NFS_V4_1) | ||
| 1146 | .rpc_call_prepare = nfs_write_prepare, | 1182 | .rpc_call_prepare = nfs_write_prepare, |
| 1147 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1148 | .rpc_call_done = nfs_writeback_done_partial, | 1183 | .rpc_call_done = nfs_writeback_done_partial, |
| 1149 | .rpc_release = nfs_writeback_release_partial, | 1184 | .rpc_release = nfs_writeback_release_partial, |
| 1150 | }; | 1185 | }; |
| @@ -1199,16 +1234,14 @@ static void nfs_writeback_release_full(void *calldata) | |||
| 1199 | remove_request: | 1234 | remove_request: |
| 1200 | nfs_inode_remove_request(req); | 1235 | nfs_inode_remove_request(req); |
| 1201 | next: | 1236 | next: |
| 1202 | nfs_clear_page_tag_locked(req); | 1237 | nfs_unlock_request(req); |
| 1203 | nfs_end_page_writeback(page); | 1238 | nfs_end_page_writeback(page); |
| 1204 | } | 1239 | } |
| 1205 | nfs_writedata_release(calldata); | 1240 | nfs_writedata_release(calldata); |
| 1206 | } | 1241 | } |
| 1207 | 1242 | ||
| 1208 | static const struct rpc_call_ops nfs_write_full_ops = { | 1243 | static const struct rpc_call_ops nfs_write_full_ops = { |
| 1209 | #if defined(CONFIG_NFS_V4_1) | ||
| 1210 | .rpc_call_prepare = nfs_write_prepare, | 1244 | .rpc_call_prepare = nfs_write_prepare, |
| 1211 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1212 | .rpc_call_done = nfs_writeback_done_full, | 1245 | .rpc_call_done = nfs_writeback_done_full, |
| 1213 | .rpc_release = nfs_writeback_release_full, | 1246 | .rpc_release = nfs_writeback_release_full, |
| 1214 | }; | 1247 | }; |
| @@ -1325,7 +1358,6 @@ void nfs_commitdata_release(void *data) | |||
| 1325 | { | 1358 | { |
| 1326 | struct nfs_write_data *wdata = data; | 1359 | struct nfs_write_data *wdata = data; |
| 1327 | 1360 | ||
| 1328 | put_lseg(wdata->lseg); | ||
| 1329 | put_nfs_open_context(wdata->args.context); | 1361 | put_nfs_open_context(wdata->args.context); |
| 1330 | nfs_commit_free(wdata); | 1362 | nfs_commit_free(wdata); |
| 1331 | } | 1363 | } |
| @@ -1411,7 +1443,7 @@ void nfs_retry_commit(struct list_head *page_list, | |||
| 1411 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 1443 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
| 1412 | dec_bdi_stat(req->wb_page->mapping->backing_dev_info, | 1444 | dec_bdi_stat(req->wb_page->mapping->backing_dev_info, |
| 1413 | BDI_RECLAIMABLE); | 1445 | BDI_RECLAIMABLE); |
| 1414 | nfs_clear_page_tag_locked(req); | 1446 | nfs_unlock_request(req); |
| 1415 | } | 1447 | } |
| 1416 | } | 1448 | } |
| 1417 | EXPORT_SYMBOL_GPL(nfs_retry_commit); | 1449 | EXPORT_SYMBOL_GPL(nfs_retry_commit); |
| @@ -1460,7 +1492,7 @@ void nfs_commit_release_pages(struct nfs_write_data *data) | |||
| 1460 | while (!list_empty(&data->pages)) { | 1492 | while (!list_empty(&data->pages)) { |
| 1461 | req = nfs_list_entry(data->pages.next); | 1493 | req = nfs_list_entry(data->pages.next); |
| 1462 | nfs_list_remove_request(req); | 1494 | nfs_list_remove_request(req); |
| 1463 | nfs_clear_request_commit(req); | 1495 | nfs_clear_page_commit(req->wb_page); |
| 1464 | 1496 | ||
| 1465 | dprintk("NFS: commit (%s/%lld %d@%lld)", | 1497 | dprintk("NFS: commit (%s/%lld %d@%lld)", |
| 1466 | req->wb_context->dentry->d_sb->s_id, | 1498 | req->wb_context->dentry->d_sb->s_id, |
| @@ -1486,7 +1518,7 @@ void nfs_commit_release_pages(struct nfs_write_data *data) | |||
| 1486 | dprintk(" mismatch\n"); | 1518 | dprintk(" mismatch\n"); |
| 1487 | nfs_mark_request_dirty(req); | 1519 | nfs_mark_request_dirty(req); |
| 1488 | next: | 1520 | next: |
| 1489 | nfs_clear_page_tag_locked(req); | 1521 | nfs_unlock_request(req); |
| 1490 | } | 1522 | } |
| 1491 | } | 1523 | } |
| 1492 | EXPORT_SYMBOL_GPL(nfs_commit_release_pages); | 1524 | EXPORT_SYMBOL_GPL(nfs_commit_release_pages); |
| @@ -1501,9 +1533,7 @@ static void nfs_commit_release(void *calldata) | |||
| 1501 | } | 1533 | } |
| 1502 | 1534 | ||
| 1503 | static const struct rpc_call_ops nfs_commit_ops = { | 1535 | static const struct rpc_call_ops nfs_commit_ops = { |
| 1504 | #if defined(CONFIG_NFS_V4_1) | ||
| 1505 | .rpc_call_prepare = nfs_write_prepare, | 1536 | .rpc_call_prepare = nfs_write_prepare, |
| 1506 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1507 | .rpc_call_done = nfs_commit_done, | 1537 | .rpc_call_done = nfs_commit_done, |
| 1508 | .rpc_release = nfs_commit_release, | 1538 | .rpc_release = nfs_commit_release, |
| 1509 | }; | 1539 | }; |
| @@ -1517,7 +1547,7 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
| 1517 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); | 1547 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); |
| 1518 | if (res <= 0) | 1548 | if (res <= 0) |
| 1519 | goto out_mark_dirty; | 1549 | goto out_mark_dirty; |
| 1520 | res = nfs_scan_commit(inode, &head, 0, 0); | 1550 | res = nfs_scan_commit(inode, &head); |
| 1521 | if (res) { | 1551 | if (res) { |
| 1522 | int error; | 1552 | int error; |
| 1523 | 1553 | ||
| @@ -1635,6 +1665,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page) | |||
| 1635 | if (req == NULL) | 1665 | if (req == NULL) |
| 1636 | break; | 1666 | break; |
| 1637 | if (nfs_lock_request_dontget(req)) { | 1667 | if (nfs_lock_request_dontget(req)) { |
| 1668 | nfs_clear_request_commit(req); | ||
| 1638 | nfs_inode_remove_request(req); | 1669 | nfs_inode_remove_request(req); |
| 1639 | /* | 1670 | /* |
| 1640 | * In case nfs_inode_remove_request has marked the | 1671 | * In case nfs_inode_remove_request has marked the |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 6f3ebb48b12f..0e262f32ac41 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
| @@ -605,24 +605,24 @@ static struct rpc_version nfs_cb_version4 = { | |||
| 605 | .procs = nfs4_cb_procedures | 605 | .procs = nfs4_cb_procedures |
| 606 | }; | 606 | }; |
| 607 | 607 | ||
| 608 | static struct rpc_version *nfs_cb_version[] = { | 608 | static const struct rpc_version *nfs_cb_version[] = { |
| 609 | &nfs_cb_version4, | 609 | &nfs_cb_version4, |
| 610 | }; | 610 | }; |
| 611 | 611 | ||
| 612 | static struct rpc_program cb_program; | 612 | static const struct rpc_program cb_program; |
| 613 | 613 | ||
| 614 | static struct rpc_stat cb_stats = { | 614 | static struct rpc_stat cb_stats = { |
| 615 | .program = &cb_program | 615 | .program = &cb_program |
| 616 | }; | 616 | }; |
| 617 | 617 | ||
| 618 | #define NFS4_CALLBACK 0x40000000 | 618 | #define NFS4_CALLBACK 0x40000000 |
| 619 | static struct rpc_program cb_program = { | 619 | static const struct rpc_program cb_program = { |
| 620 | .name = "nfs4_cb", | 620 | .name = "nfs4_cb", |
| 621 | .number = NFS4_CALLBACK, | 621 | .number = NFS4_CALLBACK, |
| 622 | .nrvers = ARRAY_SIZE(nfs_cb_version), | 622 | .nrvers = ARRAY_SIZE(nfs_cb_version), |
| 623 | .version = nfs_cb_version, | 623 | .version = nfs_cb_version, |
| 624 | .stats = &cb_stats, | 624 | .stats = &cb_stats, |
| 625 | .pipe_dir_name = "/nfsd4_cb", | 625 | .pipe_dir_name = "nfsd4_cb", |
| 626 | }; | 626 | }; |
| 627 | 627 | ||
| 628 | static int max_cb_time(void) | 628 | static int max_cb_time(void) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e8c98f009670..c5cddd659429 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -1308,7 +1308,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r | |||
| 1308 | else | 1308 | else |
| 1309 | goto out_err; | 1309 | goto out_err; |
| 1310 | 1310 | ||
| 1311 | conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val, | 1311 | conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val, |
| 1312 | se->se_callback_addr_len, | 1312 | se->se_callback_addr_len, |
| 1313 | (struct sockaddr *)&conn->cb_addr, | 1313 | (struct sockaddr *)&conn->cb_addr, |
| 1314 | sizeof(conn->cb_addr)); | 1314 | sizeof(conn->cb_addr)); |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 748eda93ce59..64c24af8d7ea 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
| @@ -223,7 +223,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) | |||
| 223 | if (qword_get(&buf, fo_path, size) < 0) | 223 | if (qword_get(&buf, fo_path, size) < 0) |
| 224 | return -EINVAL; | 224 | return -EINVAL; |
| 225 | 225 | ||
| 226 | if (rpc_pton(fo_path, size, sap, salen) == 0) | 226 | if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0) |
| 227 | return -EINVAL; | 227 | return -EINVAL; |
| 228 | 228 | ||
| 229 | return nlmsvc_unlock_all_by_ip(sap); | 229 | return nlmsvc_unlock_all_by_ip(sap); |
| @@ -722,7 +722,7 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
| 722 | nfsd_serv->sv_nrthreads--; | 722 | nfsd_serv->sv_nrthreads--; |
| 723 | return 0; | 723 | return 0; |
| 724 | out_close: | 724 | out_close: |
| 725 | xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port); | 725 | xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port); |
| 726 | if (xprt != NULL) { | 726 | if (xprt != NULL) { |
| 727 | svc_close_xprt(xprt); | 727 | svc_close_xprt(xprt); |
| 728 | svc_xprt_put(xprt); | 728 | svc_xprt_put(xprt); |
| @@ -748,7 +748,7 @@ static ssize_t __write_ports_delxprt(char *buf) | |||
| 748 | if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL) | 748 | if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL) |
| 749 | return -EINVAL; | 749 | return -EINVAL; |
| 750 | 750 | ||
| 751 | xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port); | 751 | xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port); |
| 752 | if (xprt == NULL) | 752 | if (xprt == NULL) |
| 753 | return -ENOTCONN; | 753 | return -ENOTCONN; |
| 754 | 754 | ||
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index eda7d7e55e05..fce472f5f39e 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -251,13 +251,13 @@ static void nfsd_shutdown(void) | |||
| 251 | nfsd_up = false; | 251 | nfsd_up = false; |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | static void nfsd_last_thread(struct svc_serv *serv) | 254 | static void nfsd_last_thread(struct svc_serv *serv, struct net *net) |
| 255 | { | 255 | { |
| 256 | /* When last nfsd thread exits we need to do some clean-up */ | 256 | /* When last nfsd thread exits we need to do some clean-up */ |
| 257 | nfsd_serv = NULL; | 257 | nfsd_serv = NULL; |
| 258 | nfsd_shutdown(); | 258 | nfsd_shutdown(); |
| 259 | 259 | ||
| 260 | svc_rpcb_cleanup(serv); | 260 | svc_rpcb_cleanup(serv, net); |
| 261 | 261 | ||
| 262 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " | 262 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " |
| 263 | "cache\n"); | 263 | "cache\n"); |
diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c index a2e2402b2afb..6d4521feb6e3 100644 --- a/fs/nfsd/stats.c +++ b/fs/nfsd/stats.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 26 | #include <linux/sunrpc/stats.h> | 26 | #include <linux/sunrpc/stats.h> |
| 27 | #include <linux/nfsd/stats.h> | 27 | #include <linux/nfsd/stats.h> |
| 28 | #include <net/net_namespace.h> | ||
| 28 | 29 | ||
| 29 | #include "nfsd.h" | 30 | #include "nfsd.h" |
| 30 | 31 | ||
| @@ -94,11 +95,11 @@ static const struct file_operations nfsd_proc_fops = { | |||
| 94 | void | 95 | void |
| 95 | nfsd_stat_init(void) | 96 | nfsd_stat_init(void) |
| 96 | { | 97 | { |
| 97 | svc_proc_register(&nfsd_svcstats, &nfsd_proc_fops); | 98 | svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops); |
| 98 | } | 99 | } |
| 99 | 100 | ||
| 100 | void | 101 | void |
| 101 | nfsd_stat_shutdown(void) | 102 | nfsd_stat_shutdown(void) |
| 102 | { | 103 | { |
| 103 | svc_proc_unregister("nfsd"); | 104 | svc_proc_unregister(&init_net, "nfsd"); |
| 104 | } | 105 | } |
diff --git a/include/linux/key.h b/include/linux/key.h index 1600ebf717a7..96933b1e5d24 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
| @@ -277,6 +277,8 @@ static inline key_serial_t key_serial(const struct key *key) | |||
| 277 | return key ? key->serial : 0; | 277 | return key ? key->serial : 0; |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | extern void key_set_timeout(struct key *, unsigned); | ||
| 281 | |||
| 280 | /** | 282 | /** |
| 281 | * key_is_instantiated - Determine if a key has been positively instantiated | 283 | * key_is_instantiated - Determine if a key has been positively instantiated |
| 282 | * @key: The key to check. | 284 | * @key: The key to check. |
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index fbc48f898521..11a966e5f829 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h | |||
| @@ -42,6 +42,7 @@ struct nlmclnt_initdata { | |||
| 42 | unsigned short protocol; | 42 | unsigned short protocol; |
| 43 | u32 nfs_version; | 43 | u32 nfs_version; |
| 44 | int noresvport; | 44 | int noresvport; |
| 45 | struct net *net; | ||
| 45 | }; | 46 | }; |
| 46 | 47 | ||
| 47 | /* | 48 | /* |
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 88a114fce477..f04ce6ac6d04 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
| @@ -67,6 +67,7 @@ struct nlm_host { | |||
| 67 | struct list_head h_reclaim; /* Locks in RECLAIM state */ | 67 | struct list_head h_reclaim; /* Locks in RECLAIM state */ |
| 68 | struct nsm_handle *h_nsmhandle; /* NSM status handle */ | 68 | struct nsm_handle *h_nsmhandle; /* NSM status handle */ |
| 69 | char *h_addrbuf; /* address eyecatcher */ | 69 | char *h_addrbuf; /* address eyecatcher */ |
| 70 | struct net *net; /* host net */ | ||
| 70 | }; | 71 | }; |
| 71 | 72 | ||
| 72 | /* | 73 | /* |
| @@ -188,7 +189,7 @@ struct nlm_block { | |||
| 188 | /* | 189 | /* |
| 189 | * Global variables | 190 | * Global variables |
| 190 | */ | 191 | */ |
| 191 | extern struct rpc_program nlm_program; | 192 | extern const struct rpc_program nlm_program; |
| 192 | extern struct svc_procedure nlmsvc_procedures[]; | 193 | extern struct svc_procedure nlmsvc_procedures[]; |
| 193 | #ifdef CONFIG_LOCKD_V4 | 194 | #ifdef CONFIG_LOCKD_V4 |
| 194 | extern struct svc_procedure nlmsvc_procedures4[]; | 195 | extern struct svc_procedure nlmsvc_procedures4[]; |
| @@ -222,7 +223,8 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
| 222 | const unsigned short protocol, | 223 | const unsigned short protocol, |
| 223 | const u32 version, | 224 | const u32 version, |
| 224 | const char *hostname, | 225 | const char *hostname, |
| 225 | int noresvport); | 226 | int noresvport, |
| 227 | struct net *net); | ||
| 226 | void nlmclnt_release_host(struct nlm_host *); | 228 | void nlmclnt_release_host(struct nlm_host *); |
| 227 | struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | 229 | struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, |
| 228 | const char *hostname, | 230 | const char *hostname, |
| @@ -232,6 +234,7 @@ struct rpc_clnt * nlm_bind_host(struct nlm_host *); | |||
| 232 | void nlm_rebind_host(struct nlm_host *); | 234 | void nlm_rebind_host(struct nlm_host *); |
| 233 | struct nlm_host * nlm_get_host(struct nlm_host *); | 235 | struct nlm_host * nlm_get_host(struct nlm_host *); |
| 234 | void nlm_shutdown_hosts(void); | 236 | void nlm_shutdown_hosts(void); |
| 237 | void nlm_shutdown_hosts_net(struct net *net); | ||
| 235 | void nlm_host_rebooted(const struct nlm_reboot *); | 238 | void nlm_host_rebooted(const struct nlm_reboot *); |
| 236 | 239 | ||
| 237 | /* | 240 | /* |
diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h index 7353821341ed..e58c88b52ce1 100644 --- a/include/linux/lockd/xdr4.h +++ b/include/linux/lockd/xdr4.h | |||
| @@ -42,6 +42,6 @@ int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); | |||
| 42 | int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); | 42 | int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); |
| 43 | int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); | 43 | int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); |
| 44 | */ | 44 | */ |
| 45 | extern struct rpc_version nlm_version4; | 45 | extern const struct rpc_version nlm_version4; |
| 46 | 46 | ||
| 47 | #endif /* LOCKD_XDR4_H */ | 47 | #endif /* LOCKD_XDR4_H */ |
diff --git a/include/linux/nfs.h b/include/linux/nfs.h index 8c6ee44914cb..6d1fb63f5922 100644 --- a/include/linux/nfs.h +++ b/include/linux/nfs.h | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | #define NFS_MNT_VERSION 1 | 29 | #define NFS_MNT_VERSION 1 |
| 30 | #define NFS_MNT3_VERSION 3 | 30 | #define NFS_MNT3_VERSION 3 |
| 31 | 31 | ||
| 32 | #define NFS_PIPE_DIRNAME "/nfs" | 32 | #define NFS_PIPE_DIRNAME "nfs" |
| 33 | 33 | ||
| 34 | /* | 34 | /* |
| 35 | * NFS stats. The good thing with these values is that NFSv3 errors are | 35 | * NFS stats. The good thing with these values is that NFSv3 errors are |
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 32345c2805c0..834df8bf08b6 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h | |||
| @@ -183,15 +183,12 @@ struct nfs4_acl { | |||
| 183 | 183 | ||
| 184 | typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier; | 184 | typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier; |
| 185 | 185 | ||
| 186 | struct nfs41_stateid { | 186 | struct nfs_stateid4 { |
| 187 | __be32 seqid; | 187 | __be32 seqid; |
| 188 | char other[NFS4_STATEID_OTHER_SIZE]; | 188 | char other[NFS4_STATEID_OTHER_SIZE]; |
| 189 | } __attribute__ ((packed)); | 189 | } __attribute__ ((packed)); |
| 190 | 190 | ||
| 191 | typedef union { | 191 | typedef struct nfs_stateid4 nfs4_stateid; |
| 192 | char data[NFS4_STATEID_SIZE]; | ||
| 193 | struct nfs41_stateid stateid; | ||
| 194 | } nfs4_stateid; | ||
| 195 | 192 | ||
| 196 | enum nfs_opnum4 { | 193 | enum nfs_opnum4 { |
| 197 | OP_ACCESS = 3, | 194 | OP_ACCESS = 3, |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 8c29950d2fa5..52a1bdb4ee2b 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
| @@ -38,6 +38,13 @@ | |||
| 38 | 38 | ||
| 39 | #ifdef __KERNEL__ | 39 | #ifdef __KERNEL__ |
| 40 | 40 | ||
| 41 | /* | ||
| 42 | * Enable dprintk() debugging support for nfs client. | ||
| 43 | */ | ||
| 44 | #ifdef CONFIG_NFS_DEBUG | ||
| 45 | # define NFS_DEBUG | ||
| 46 | #endif | ||
| 47 | |||
| 41 | #include <linux/in.h> | 48 | #include <linux/in.h> |
| 42 | #include <linux/mm.h> | 49 | #include <linux/mm.h> |
| 43 | #include <linux/pagemap.h> | 50 | #include <linux/pagemap.h> |
| @@ -171,13 +178,9 @@ struct nfs_inode { | |||
| 171 | */ | 178 | */ |
| 172 | __be32 cookieverf[2]; | 179 | __be32 cookieverf[2]; |
| 173 | 180 | ||
| 174 | /* | ||
| 175 | * This is the list of dirty unwritten pages. | ||
| 176 | */ | ||
| 177 | struct radix_tree_root nfs_page_tree; | ||
| 178 | |||
| 179 | unsigned long npages; | 181 | unsigned long npages; |
| 180 | unsigned long ncommit; | 182 | unsigned long ncommit; |
| 183 | struct list_head commit_list; | ||
| 181 | 184 | ||
| 182 | /* Open contexts for shared mmap writes */ | 185 | /* Open contexts for shared mmap writes */ |
| 183 | struct list_head open_files; | 186 | struct list_head open_files; |
| @@ -395,6 +398,29 @@ static inline void nfs_free_fhandle(const struct nfs_fh *fh) | |||
| 395 | kfree(fh); | 398 | kfree(fh); |
| 396 | } | 399 | } |
| 397 | 400 | ||
| 401 | #ifdef NFS_DEBUG | ||
| 402 | extern u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh); | ||
| 403 | static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh) | ||
| 404 | { | ||
| 405 | return _nfs_display_fhandle_hash(fh); | ||
| 406 | } | ||
| 407 | extern void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption); | ||
| 408 | #define nfs_display_fhandle(fh, caption) \ | ||
| 409 | do { \ | ||
| 410 | if (unlikely(nfs_debug & NFSDBG_FACILITY)) \ | ||
| 411 | _nfs_display_fhandle(fh, caption); \ | ||
| 412 | } while (0) | ||
| 413 | #else | ||
| 414 | static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh) | ||
| 415 | { | ||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | static inline void nfs_display_fhandle(const struct nfs_fh *fh, | ||
| 419 | const char *caption) | ||
| 420 | { | ||
| 421 | } | ||
| 422 | #endif | ||
| 423 | |||
| 398 | /* | 424 | /* |
| 399 | * linux/fs/nfs/nfsroot.c | 425 | * linux/fs/nfs/nfsroot.c |
| 400 | */ | 426 | */ |
| @@ -632,19 +658,13 @@ nfs_fileid_to_ino_t(u64 fileid) | |||
| 632 | 658 | ||
| 633 | #ifdef __KERNEL__ | 659 | #ifdef __KERNEL__ |
| 634 | 660 | ||
| 635 | /* | ||
| 636 | * Enable debugging support for nfs client. | ||
| 637 | * Requires RPC_DEBUG. | ||
| 638 | */ | ||
| 639 | #ifdef RPC_DEBUG | ||
| 640 | # define NFS_DEBUG | ||
| 641 | #endif | ||
| 642 | |||
| 643 | # undef ifdebug | 661 | # undef ifdebug |
| 644 | # ifdef NFS_DEBUG | 662 | # ifdef NFS_DEBUG |
| 645 | # define ifdebug(fac) if (unlikely(nfs_debug & NFSDBG_##fac)) | 663 | # define ifdebug(fac) if (unlikely(nfs_debug & NFSDBG_##fac)) |
| 664 | # define NFS_IFDEBUG(x) x | ||
| 646 | # else | 665 | # else |
| 647 | # define ifdebug(fac) if (0) | 666 | # define ifdebug(fac) if (0) |
| 667 | # define NFS_IFDEBUG(x) | ||
| 648 | # endif | 668 | # endif |
| 649 | #endif /* __KERNEL */ | 669 | #endif /* __KERNEL */ |
| 650 | 670 | ||
diff --git a/include/linux/nfs_fs_i.h b/include/linux/nfs_fs_i.h index 861730275ba0..a5c50d97341e 100644 --- a/include/linux/nfs_fs_i.h +++ b/include/linux/nfs_fs_i.h | |||
| @@ -1,10 +1,6 @@ | |||
| 1 | #ifndef _NFS_FS_I | 1 | #ifndef _NFS_FS_I |
| 2 | #define _NFS_FS_I | 2 | #define _NFS_FS_I |
| 3 | 3 | ||
| 4 | #include <asm/types.h> | ||
| 5 | #include <linux/list.h> | ||
| 6 | #include <linux/nfs.h> | ||
| 7 | |||
| 8 | struct nlm_lockowner; | 4 | struct nlm_lockowner; |
| 9 | 5 | ||
| 10 | /* | 6 | /* |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index ba4d7656ecfd..7073fc74481c 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
| 5 | #include <linux/backing-dev.h> | 5 | #include <linux/backing-dev.h> |
| 6 | #include <linux/idr.h> | ||
| 6 | #include <linux/wait.h> | 7 | #include <linux/wait.h> |
| 7 | #include <linux/nfs_xdr.h> | 8 | #include <linux/nfs_xdr.h> |
| 8 | #include <linux/sunrpc/xprt.h> | 9 | #include <linux/sunrpc/xprt.h> |
| @@ -17,6 +18,7 @@ struct nfs4_sequence_res; | |||
| 17 | struct nfs_server; | 18 | struct nfs_server; |
| 18 | struct nfs4_minor_version_ops; | 19 | struct nfs4_minor_version_ops; |
| 19 | struct server_scope; | 20 | struct server_scope; |
| 21 | struct nfs41_impl_id; | ||
| 20 | 22 | ||
| 21 | /* | 23 | /* |
| 22 | * The nfs_client identifies our client state to the server. | 24 | * The nfs_client identifies our client state to the server. |
| @@ -85,6 +87,8 @@ struct nfs_client { | |||
| 85 | #endif | 87 | #endif |
| 86 | 88 | ||
| 87 | struct server_scope *server_scope; /* from exchange_id */ | 89 | struct server_scope *server_scope; /* from exchange_id */ |
| 90 | struct nfs41_impl_id *impl_id; /* from exchange_id */ | ||
| 91 | struct net *net; | ||
| 88 | }; | 92 | }; |
| 89 | 93 | ||
| 90 | /* | 94 | /* |
| @@ -144,15 +148,18 @@ struct nfs_server { | |||
| 144 | u32 acl_bitmask; /* V4 bitmask representing the ACEs | 148 | u32 acl_bitmask; /* V4 bitmask representing the ACEs |
| 145 | that are supported on this | 149 | that are supported on this |
| 146 | filesystem */ | 150 | filesystem */ |
| 151 | u32 fh_expire_type; /* V4 bitmask representing file | ||
| 152 | handle volatility type for | ||
| 153 | this filesystem */ | ||
| 147 | struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */ | 154 | struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */ |
| 148 | struct rpc_wait_queue roc_rpcwaitq; | 155 | struct rpc_wait_queue roc_rpcwaitq; |
| 149 | void *pnfs_ld_data; /* per mount point data */ | 156 | void *pnfs_ld_data; /* per mount point data */ |
| 150 | 157 | ||
| 151 | /* the following fields are protected by nfs_client->cl_lock */ | 158 | /* the following fields are protected by nfs_client->cl_lock */ |
| 152 | struct rb_root state_owners; | 159 | struct rb_root state_owners; |
| 153 | struct rb_root openowner_id; | ||
| 154 | struct rb_root lockowner_id; | ||
| 155 | #endif | 160 | #endif |
| 161 | struct ida openowner_id; | ||
| 162 | struct ida lockowner_id; | ||
| 156 | struct list_head state_owners_lru; | 163 | struct list_head state_owners_lru; |
| 157 | struct list_head layouts; | 164 | struct list_head layouts; |
| 158 | struct list_head delegations; | 165 | struct list_head delegations; |
| @@ -188,21 +195,23 @@ struct nfs_server { | |||
| 188 | 195 | ||
| 189 | 196 | ||
| 190 | /* maximum number of slots to use */ | 197 | /* maximum number of slots to use */ |
| 191 | #define NFS4_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE | 198 | #define NFS4_DEF_SLOT_TABLE_SIZE (16U) |
| 199 | #define NFS4_MAX_SLOT_TABLE (256U) | ||
| 200 | #define NFS4_NO_SLOT ((u32)-1) | ||
| 192 | 201 | ||
| 193 | #if defined(CONFIG_NFS_V4) | 202 | #if defined(CONFIG_NFS_V4) |
| 194 | 203 | ||
| 195 | /* Sessions */ | 204 | /* Sessions */ |
| 196 | #define SLOT_TABLE_SZ (NFS4_MAX_SLOT_TABLE/(8*sizeof(long))) | 205 | #define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long)) |
| 197 | struct nfs4_slot_table { | 206 | struct nfs4_slot_table { |
| 198 | struct nfs4_slot *slots; /* seqid per slot */ | 207 | struct nfs4_slot *slots; /* seqid per slot */ |
| 199 | unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */ | 208 | unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */ |
| 200 | spinlock_t slot_tbl_lock; | 209 | spinlock_t slot_tbl_lock; |
| 201 | struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ | 210 | struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ |
| 202 | int max_slots; /* # slots in table */ | 211 | u32 max_slots; /* # slots in table */ |
| 203 | int highest_used_slotid; /* sent to server on each SEQ. | 212 | u32 highest_used_slotid; /* sent to server on each SEQ. |
| 204 | * op for dynamic resizing */ | 213 | * op for dynamic resizing */ |
| 205 | int target_max_slots; /* Set by CB_RECALL_SLOT as | 214 | u32 target_max_slots; /* Set by CB_RECALL_SLOT as |
| 206 | * the new max_slots */ | 215 | * the new max_slots */ |
| 207 | struct completion complete; | 216 | struct completion complete; |
| 208 | }; | 217 | }; |
diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h index 308c18877018..7eed2012d288 100644 --- a/include/linux/nfs_idmap.h +++ b/include/linux/nfs_idmap.h | |||
| @@ -69,36 +69,22 @@ struct nfs_server; | |||
| 69 | struct nfs_fattr; | 69 | struct nfs_fattr; |
| 70 | struct nfs4_string; | 70 | struct nfs4_string; |
| 71 | 71 | ||
| 72 | #ifdef CONFIG_NFS_USE_NEW_IDMAPPER | 72 | #ifdef CONFIG_NFS_V4 |
| 73 | |||
| 74 | int nfs_idmap_init(void); | 73 | int nfs_idmap_init(void); |
| 75 | void nfs_idmap_quit(void); | 74 | void nfs_idmap_quit(void); |
| 76 | 75 | #else | |
| 77 | static inline int nfs_idmap_new(struct nfs_client *clp) | ||
| 78 | { | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | static inline void nfs_idmap_delete(struct nfs_client *clp) | ||
| 83 | { | ||
| 84 | } | ||
| 85 | |||
| 86 | #else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */ | ||
| 87 | |||
| 88 | static inline int nfs_idmap_init(void) | 76 | static inline int nfs_idmap_init(void) |
| 89 | { | 77 | { |
| 90 | return 0; | 78 | return 0; |
| 91 | } | 79 | } |
| 92 | 80 | ||
| 93 | static inline void nfs_idmap_quit(void) | 81 | static inline void nfs_idmap_quit(void) |
| 94 | { | 82 | {} |
| 95 | } | 83 | #endif |
| 96 | 84 | ||
| 97 | int nfs_idmap_new(struct nfs_client *); | 85 | int nfs_idmap_new(struct nfs_client *); |
| 98 | void nfs_idmap_delete(struct nfs_client *); | 86 | void nfs_idmap_delete(struct nfs_client *); |
| 99 | 87 | ||
| 100 | #endif /* CONFIG_NFS_USE_NEW_IDMAPPER */ | ||
| 101 | |||
| 102 | void nfs_fattr_init_names(struct nfs_fattr *fattr, | 88 | void nfs_fattr_init_names(struct nfs_fattr *fattr, |
| 103 | struct nfs4_string *owner_name, | 89 | struct nfs4_string *owner_name, |
| 104 | struct nfs4_string *group_name); | 90 | struct nfs4_string *group_name); |
diff --git a/include/linux/nfs_iostat.h b/include/linux/nfs_iostat.h index 8866bb3502ee..9dcbbe9a51fb 100644 --- a/include/linux/nfs_iostat.h +++ b/include/linux/nfs_iostat.h | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | #ifndef _LINUX_NFS_IOSTAT | 21 | #ifndef _LINUX_NFS_IOSTAT |
| 22 | #define _LINUX_NFS_IOSTAT | 22 | #define _LINUX_NFS_IOSTAT |
| 23 | 23 | ||
| 24 | #define NFS_IOSTAT_VERS "1.0" | 24 | #define NFS_IOSTAT_VERS "1.1" |
| 25 | 25 | ||
| 26 | /* | 26 | /* |
| 27 | * NFS byte counters | 27 | * NFS byte counters |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index ab465fe8c3d6..eac30d6bec17 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
| @@ -19,12 +19,6 @@ | |||
| 19 | #include <linux/kref.h> | 19 | #include <linux/kref.h> |
| 20 | 20 | ||
| 21 | /* | 21 | /* |
| 22 | * Valid flags for the radix tree | ||
| 23 | */ | ||
| 24 | #define NFS_PAGE_TAG_LOCKED 0 | ||
| 25 | #define NFS_PAGE_TAG_COMMIT 1 | ||
| 26 | |||
| 27 | /* | ||
| 28 | * Valid flags for a dirty buffer | 22 | * Valid flags for a dirty buffer |
| 29 | */ | 23 | */ |
| 30 | enum { | 24 | enum { |
| @@ -33,16 +27,13 @@ enum { | |||
| 33 | PG_CLEAN, | 27 | PG_CLEAN, |
| 34 | PG_NEED_COMMIT, | 28 | PG_NEED_COMMIT, |
| 35 | PG_NEED_RESCHED, | 29 | PG_NEED_RESCHED, |
| 36 | PG_PNFS_COMMIT, | ||
| 37 | PG_PARTIAL_READ_FAILED, | 30 | PG_PARTIAL_READ_FAILED, |
| 31 | PG_COMMIT_TO_DS, | ||
| 38 | }; | 32 | }; |
| 39 | 33 | ||
| 40 | struct nfs_inode; | 34 | struct nfs_inode; |
| 41 | struct nfs_page { | 35 | struct nfs_page { |
| 42 | union { | 36 | struct list_head wb_list; /* Defines state of page: */ |
| 43 | struct list_head wb_list; /* Defines state of page: */ | ||
| 44 | struct pnfs_layout_segment *wb_commit_lseg; /* Used when PG_PNFS_COMMIT set */ | ||
| 45 | }; | ||
| 46 | struct page *wb_page; /* page to read in/write out */ | 37 | struct page *wb_page; /* page to read in/write out */ |
| 47 | struct nfs_open_context *wb_context; /* File state context info */ | 38 | struct nfs_open_context *wb_context; /* File state context info */ |
| 48 | struct nfs_lock_context *wb_lock_context; /* lock context info */ | 39 | 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, | |||
| 90 | extern void nfs_release_request(struct nfs_page *req); | 81 | extern void nfs_release_request(struct nfs_page *req); |
| 91 | 82 | ||
| 92 | 83 | ||
| 93 | extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst, | ||
| 94 | pgoff_t idx_start, unsigned int npages, int tag); | ||
| 95 | extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | 84 | extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc, |
| 96 | struct inode *inode, | 85 | struct inode *inode, |
| 97 | const struct nfs_pageio_ops *pg_ops, | 86 | const struct nfs_pageio_ops *pg_ops, |
| @@ -106,8 +95,6 @@ extern bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, | |||
| 106 | struct nfs_page *req); | 95 | struct nfs_page *req); |
| 107 | extern int nfs_wait_on_request(struct nfs_page *); | 96 | extern int nfs_wait_on_request(struct nfs_page *); |
| 108 | extern void nfs_unlock_request(struct nfs_page *req); | 97 | extern void nfs_unlock_request(struct nfs_page *req); |
| 109 | extern int nfs_set_page_tag_locked(struct nfs_page *req); | ||
| 110 | extern void nfs_clear_page_tag_locked(struct nfs_page *req); | ||
| 111 | 98 | ||
| 112 | /* | 99 | /* |
| 113 | * Lock the page of an asynchronous request without getting a new reference | 100 | * Lock the page of an asynchronous request without getting a new reference |
| @@ -118,6 +105,16 @@ nfs_lock_request_dontget(struct nfs_page *req) | |||
| 118 | return !test_and_set_bit(PG_BUSY, &req->wb_flags); | 105 | return !test_and_set_bit(PG_BUSY, &req->wb_flags); |
| 119 | } | 106 | } |
| 120 | 107 | ||
| 108 | static inline int | ||
| 109 | nfs_lock_request(struct nfs_page *req) | ||
| 110 | { | ||
| 111 | if (test_and_set_bit(PG_BUSY, &req->wb_flags)) | ||
| 112 | return 0; | ||
| 113 | kref_get(&req->wb_kref); | ||
| 114 | return 1; | ||
| 115 | } | ||
| 116 | |||
| 117 | |||
| 121 | /** | 118 | /** |
| 122 | * nfs_list_add_request - Insert a request into a list | 119 | * nfs_list_add_request - Insert a request into a list |
| 123 | * @req: request | 120 | * @req: request |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index d6ba9a12591e..bfd0d1bf6707 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | #define _LINUX_NFS_XDR_H | 2 | #define _LINUX_NFS_XDR_H |
| 3 | 3 | ||
| 4 | #include <linux/nfsacl.h> | 4 | #include <linux/nfsacl.h> |
| 5 | #include <linux/nfs3.h> | ||
| 6 | #include <linux/sunrpc/gss_api.h> | 5 | #include <linux/sunrpc/gss_api.h> |
| 7 | 6 | ||
| 8 | /* | 7 | /* |
| @@ -89,11 +88,12 @@ struct nfs_fattr { | |||
| 89 | #define NFS_ATTR_FATTR_PRECTIME (1U << 16) | 88 | #define NFS_ATTR_FATTR_PRECTIME (1U << 16) |
| 90 | #define NFS_ATTR_FATTR_CHANGE (1U << 17) | 89 | #define NFS_ATTR_FATTR_CHANGE (1U << 17) |
| 91 | #define NFS_ATTR_FATTR_PRECHANGE (1U << 18) | 90 | #define NFS_ATTR_FATTR_PRECHANGE (1U << 18) |
| 92 | #define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */ | 91 | #define NFS_ATTR_FATTR_V4_LOCATIONS (1U << 19) |
| 93 | #define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */ | 92 | #define NFS_ATTR_FATTR_V4_REFERRAL (1U << 20) |
| 94 | #define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 21) | 93 | #define NFS_ATTR_FATTR_MOUNTPOINT (1U << 21) |
| 95 | #define NFS_ATTR_FATTR_OWNER_NAME (1U << 22) | 94 | #define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22) |
| 96 | #define NFS_ATTR_FATTR_GROUP_NAME (1U << 23) | 95 | #define NFS_ATTR_FATTR_OWNER_NAME (1U << 23) |
| 96 | #define NFS_ATTR_FATTR_GROUP_NAME (1U << 24) | ||
| 97 | 97 | ||
| 98 | #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ | 98 | #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ |
| 99 | | NFS_ATTR_FATTR_MODE \ | 99 | | NFS_ATTR_FATTR_MODE \ |
| @@ -182,7 +182,7 @@ struct nfs4_slot { | |||
| 182 | 182 | ||
| 183 | struct nfs4_sequence_args { | 183 | struct nfs4_sequence_args { |
| 184 | struct nfs4_session *sa_session; | 184 | struct nfs4_session *sa_session; |
| 185 | u8 sa_slotid; | 185 | u32 sa_slotid; |
| 186 | u8 sa_cache_this; | 186 | u8 sa_cache_this; |
| 187 | }; | 187 | }; |
| 188 | 188 | ||
| @@ -977,6 +977,7 @@ struct nfs4_server_caps_res { | |||
| 977 | u32 acl_bitmask; | 977 | u32 acl_bitmask; |
| 978 | u32 has_links; | 978 | u32 has_links; |
| 979 | u32 has_symlinks; | 979 | u32 has_symlinks; |
| 980 | u32 fh_expire_type; | ||
| 980 | struct nfs4_sequence_res seq_res; | 981 | struct nfs4_sequence_res seq_res; |
| 981 | }; | 982 | }; |
| 982 | 983 | ||
| @@ -1055,14 +1056,6 @@ struct nfstime4 { | |||
| 1055 | }; | 1056 | }; |
| 1056 | 1057 | ||
| 1057 | #ifdef CONFIG_NFS_V4_1 | 1058 | #ifdef CONFIG_NFS_V4_1 |
| 1058 | struct nfs_impl_id4 { | ||
| 1059 | u32 domain_len; | ||
| 1060 | char *domain; | ||
| 1061 | u32 name_len; | ||
| 1062 | char *name; | ||
| 1063 | struct nfstime4 date; | ||
| 1064 | }; | ||
| 1065 | |||
| 1066 | #define NFS4_EXCHANGE_ID_LEN (48) | 1059 | #define NFS4_EXCHANGE_ID_LEN (48) |
| 1067 | struct nfs41_exchange_id_args { | 1060 | struct nfs41_exchange_id_args { |
| 1068 | struct nfs_client *client; | 1061 | struct nfs_client *client; |
| @@ -1083,10 +1076,17 @@ struct server_scope { | |||
| 1083 | char server_scope[NFS4_OPAQUE_LIMIT]; | 1076 | char server_scope[NFS4_OPAQUE_LIMIT]; |
| 1084 | }; | 1077 | }; |
| 1085 | 1078 | ||
| 1079 | struct nfs41_impl_id { | ||
| 1080 | char domain[NFS4_OPAQUE_LIMIT + 1]; | ||
| 1081 | char name[NFS4_OPAQUE_LIMIT + 1]; | ||
| 1082 | struct nfstime4 date; | ||
| 1083 | }; | ||
| 1084 | |||
| 1086 | struct nfs41_exchange_id_res { | 1085 | struct nfs41_exchange_id_res { |
| 1087 | struct nfs_client *client; | 1086 | struct nfs_client *client; |
| 1088 | u32 flags; | 1087 | u32 flags; |
| 1089 | struct server_scope *server_scope; | 1088 | struct server_scope *server_scope; |
| 1089 | struct nfs41_impl_id *impl_id; | ||
| 1090 | }; | 1090 | }; |
| 1091 | 1091 | ||
| 1092 | struct nfs41_create_session_args { | 1092 | struct nfs41_create_session_args { |
| @@ -1192,6 +1192,27 @@ struct nfs_write_data { | |||
| 1192 | struct page *page_array[NFS_PAGEVEC_SIZE]; | 1192 | struct page *page_array[NFS_PAGEVEC_SIZE]; |
| 1193 | }; | 1193 | }; |
| 1194 | 1194 | ||
| 1195 | struct nfs_unlinkdata { | ||
| 1196 | struct hlist_node list; | ||
| 1197 | struct nfs_removeargs args; | ||
| 1198 | struct nfs_removeres res; | ||
| 1199 | struct inode *dir; | ||
| 1200 | struct rpc_cred *cred; | ||
| 1201 | struct nfs_fattr dir_attr; | ||
| 1202 | }; | ||
| 1203 | |||
| 1204 | struct nfs_renamedata { | ||
| 1205 | struct nfs_renameargs args; | ||
| 1206 | struct nfs_renameres res; | ||
| 1207 | struct rpc_cred *cred; | ||
| 1208 | struct inode *old_dir; | ||
| 1209 | struct dentry *old_dentry; | ||
| 1210 | struct nfs_fattr old_fattr; | ||
| 1211 | struct inode *new_dir; | ||
| 1212 | struct dentry *new_dentry; | ||
| 1213 | struct nfs_fattr new_fattr; | ||
| 1214 | }; | ||
| 1215 | |||
| 1195 | struct nfs_access_entry; | 1216 | struct nfs_access_entry; |
| 1196 | struct nfs_client; | 1217 | struct nfs_client; |
| 1197 | struct rpc_timeout; | 1218 | struct rpc_timeout; |
| @@ -1221,10 +1242,12 @@ struct nfs_rpc_ops { | |||
| 1221 | struct iattr *, int, struct nfs_open_context *); | 1242 | struct iattr *, int, struct nfs_open_context *); |
| 1222 | int (*remove) (struct inode *, struct qstr *); | 1243 | int (*remove) (struct inode *, struct qstr *); |
| 1223 | void (*unlink_setup) (struct rpc_message *, struct inode *dir); | 1244 | void (*unlink_setup) (struct rpc_message *, struct inode *dir); |
| 1245 | void (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *); | ||
| 1224 | int (*unlink_done) (struct rpc_task *, struct inode *); | 1246 | int (*unlink_done) (struct rpc_task *, struct inode *); |
| 1225 | int (*rename) (struct inode *, struct qstr *, | 1247 | int (*rename) (struct inode *, struct qstr *, |
| 1226 | struct inode *, struct qstr *); | 1248 | struct inode *, struct qstr *); |
| 1227 | void (*rename_setup) (struct rpc_message *msg, struct inode *dir); | 1249 | void (*rename_setup) (struct rpc_message *msg, struct inode *dir); |
| 1250 | void (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *); | ||
| 1228 | int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir); | 1251 | int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir); |
| 1229 | int (*link) (struct inode *, struct inode *, struct qstr *); | 1252 | int (*link) (struct inode *, struct inode *, struct qstr *); |
| 1230 | int (*symlink) (struct inode *, struct dentry *, struct page *, | 1253 | int (*symlink) (struct inode *, struct dentry *, struct page *, |
| @@ -1244,8 +1267,10 @@ struct nfs_rpc_ops { | |||
| 1244 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); | 1267 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); |
| 1245 | int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); | 1268 | int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); |
| 1246 | void (*read_setup) (struct nfs_read_data *, struct rpc_message *); | 1269 | void (*read_setup) (struct nfs_read_data *, struct rpc_message *); |
| 1270 | void (*read_rpc_prepare)(struct rpc_task *, struct nfs_read_data *); | ||
| 1247 | int (*read_done) (struct rpc_task *, struct nfs_read_data *); | 1271 | int (*read_done) (struct rpc_task *, struct nfs_read_data *); |
| 1248 | void (*write_setup) (struct nfs_write_data *, struct rpc_message *); | 1272 | void (*write_setup) (struct nfs_write_data *, struct rpc_message *); |
| 1273 | void (*write_rpc_prepare)(struct rpc_task *, struct nfs_write_data *); | ||
| 1249 | int (*write_done) (struct rpc_task *, struct nfs_write_data *); | 1274 | int (*write_done) (struct rpc_task *, struct nfs_write_data *); |
| 1250 | void (*commit_setup) (struct nfs_write_data *, struct rpc_message *); | 1275 | void (*commit_setup) (struct nfs_write_data *, struct rpc_message *); |
| 1251 | int (*commit_done) (struct rpc_task *, struct nfs_write_data *); | 1276 | int (*commit_done) (struct rpc_task *, struct nfs_write_data *); |
| @@ -1275,11 +1300,11 @@ struct nfs_rpc_ops { | |||
| 1275 | extern const struct nfs_rpc_ops nfs_v2_clientops; | 1300 | extern const struct nfs_rpc_ops nfs_v2_clientops; |
| 1276 | extern const struct nfs_rpc_ops nfs_v3_clientops; | 1301 | extern const struct nfs_rpc_ops nfs_v3_clientops; |
| 1277 | extern const struct nfs_rpc_ops nfs_v4_clientops; | 1302 | extern const struct nfs_rpc_ops nfs_v4_clientops; |
| 1278 | extern struct rpc_version nfs_version2; | 1303 | extern const struct rpc_version nfs_version2; |
| 1279 | extern struct rpc_version nfs_version3; | 1304 | extern const struct rpc_version nfs_version3; |
| 1280 | extern struct rpc_version nfs_version4; | 1305 | extern const struct rpc_version nfs_version4; |
| 1281 | 1306 | ||
| 1282 | extern struct rpc_version nfsacl_version3; | 1307 | extern const struct rpc_version nfsacl_version3; |
| 1283 | extern struct rpc_program nfsacl_program; | 1308 | extern const struct rpc_program nfsacl_program; |
| 1284 | 1309 | ||
| 1285 | #endif | 1310 | #endif |
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 7874a8a56638..492a36d72829 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
| @@ -99,6 +99,8 @@ struct rpc_authops { | |||
| 99 | 99 | ||
| 100 | struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); | 100 | struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); |
| 101 | struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); | 101 | struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); |
| 102 | int (*pipes_create)(struct rpc_auth *); | ||
| 103 | void (*pipes_destroy)(struct rpc_auth *); | ||
| 102 | }; | 104 | }; |
| 103 | 105 | ||
| 104 | struct rpc_credops { | 106 | struct rpc_credops { |
diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h index f7f3ce340c08..969c0a671dbf 100644 --- a/include/linux/sunrpc/bc_xprt.h +++ b/include/linux/sunrpc/bc_xprt.h | |||
| @@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 35 | struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt); | 35 | struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt); |
| 36 | void xprt_free_bc_request(struct rpc_rqst *req); | 36 | void xprt_free_bc_request(struct rpc_rqst *req); |
| 37 | int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); | 37 | int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); |
| 38 | void xprt_destroy_backchannel(struct rpc_xprt *, int max_reqs); | 38 | void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs); |
| 39 | int bc_send(struct rpc_rqst *req); | 39 | int bc_send(struct rpc_rqst *req); |
| 40 | 40 | ||
| 41 | /* | 41 | /* |
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 57531f8e5956..f5fd6160dbca 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h | |||
| @@ -117,6 +117,7 @@ struct cache_detail { | |||
| 117 | struct cache_detail_procfs procfs; | 117 | struct cache_detail_procfs procfs; |
| 118 | struct cache_detail_pipefs pipefs; | 118 | struct cache_detail_pipefs pipefs; |
| 119 | } u; | 119 | } u; |
| 120 | struct net *net; | ||
| 120 | }; | 121 | }; |
| 121 | 122 | ||
| 122 | 123 | ||
| @@ -197,11 +198,14 @@ extern void cache_flush(void); | |||
| 197 | extern void cache_purge(struct cache_detail *detail); | 198 | extern void cache_purge(struct cache_detail *detail); |
| 198 | #define NEVER (0x7FFFFFFF) | 199 | #define NEVER (0x7FFFFFFF) |
| 199 | extern void __init cache_initialize(void); | 200 | extern void __init cache_initialize(void); |
| 200 | extern int cache_register(struct cache_detail *cd); | ||
| 201 | extern int cache_register_net(struct cache_detail *cd, struct net *net); | 201 | extern int cache_register_net(struct cache_detail *cd, struct net *net); |
| 202 | extern void cache_unregister(struct cache_detail *cd); | ||
| 203 | extern void cache_unregister_net(struct cache_detail *cd, struct net *net); | 202 | extern void cache_unregister_net(struct cache_detail *cd, struct net *net); |
| 204 | 203 | ||
| 204 | extern struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net); | ||
| 205 | extern void cache_destroy_net(struct cache_detail *cd, struct net *net); | ||
| 206 | |||
| 207 | extern void sunrpc_init_cache_detail(struct cache_detail *cd); | ||
| 208 | extern void sunrpc_destroy_cache_detail(struct cache_detail *cd); | ||
| 205 | extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *, | 209 | extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *, |
| 206 | umode_t, struct cache_detail *); | 210 | umode_t, struct cache_detail *); |
| 207 | extern void sunrpc_cache_unregister_pipefs(struct cache_detail *); | 211 | extern void sunrpc_cache_unregister_pipefs(struct cache_detail *); |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 2c5993a17c33..523547ecfee2 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
| @@ -35,14 +35,13 @@ struct rpc_clnt { | |||
| 35 | struct list_head cl_clients; /* Global list of clients */ | 35 | struct list_head cl_clients; /* Global list of clients */ |
| 36 | struct list_head cl_tasks; /* List of tasks */ | 36 | struct list_head cl_tasks; /* List of tasks */ |
| 37 | spinlock_t cl_lock; /* spinlock */ | 37 | spinlock_t cl_lock; /* spinlock */ |
| 38 | struct rpc_xprt * cl_xprt; /* transport */ | 38 | struct rpc_xprt __rcu * cl_xprt; /* transport */ |
| 39 | struct rpc_procinfo * cl_procinfo; /* procedure info */ | 39 | struct rpc_procinfo * cl_procinfo; /* procedure info */ |
| 40 | u32 cl_prog, /* RPC program number */ | 40 | u32 cl_prog, /* RPC program number */ |
| 41 | cl_vers, /* RPC version number */ | 41 | cl_vers, /* RPC version number */ |
| 42 | cl_maxproc; /* max procedure number */ | 42 | cl_maxproc; /* max procedure number */ |
| 43 | 43 | ||
| 44 | char * cl_server; /* server machine name */ | 44 | const char * cl_protname; /* protocol name */ |
| 45 | char * cl_protname; /* protocol name */ | ||
| 46 | struct rpc_auth * cl_auth; /* authenticator */ | 45 | struct rpc_auth * cl_auth; /* authenticator */ |
| 47 | struct rpc_stat * cl_stats; /* per-program statistics */ | 46 | struct rpc_stat * cl_stats; /* per-program statistics */ |
| 48 | struct rpc_iostats * cl_metrics; /* per-client statistics */ | 47 | struct rpc_iostats * cl_metrics; /* per-client statistics */ |
| @@ -57,12 +56,11 @@ struct rpc_clnt { | |||
| 57 | 56 | ||
| 58 | int cl_nodelen; /* nodename length */ | 57 | int cl_nodelen; /* nodename length */ |
| 59 | char cl_nodename[UNX_MAXNODENAME]; | 58 | char cl_nodename[UNX_MAXNODENAME]; |
| 60 | struct path cl_path; | 59 | struct dentry * cl_dentry; |
| 61 | struct rpc_clnt * cl_parent; /* Points to parent of clones */ | 60 | struct rpc_clnt * cl_parent; /* Points to parent of clones */ |
| 62 | struct rpc_rtt cl_rtt_default; | 61 | struct rpc_rtt cl_rtt_default; |
| 63 | struct rpc_timeout cl_timeout_default; | 62 | struct rpc_timeout cl_timeout_default; |
| 64 | struct rpc_program * cl_program; | 63 | const struct rpc_program *cl_program; |
| 65 | char cl_inline_name[32]; | ||
| 66 | char *cl_principal; /* target to authenticate to */ | 64 | char *cl_principal; /* target to authenticate to */ |
| 67 | }; | 65 | }; |
| 68 | 66 | ||
| @@ -71,12 +69,12 @@ struct rpc_clnt { | |||
| 71 | */ | 69 | */ |
| 72 | #define RPC_MAXVERSION 4 | 70 | #define RPC_MAXVERSION 4 |
| 73 | struct rpc_program { | 71 | struct rpc_program { |
| 74 | char * name; /* protocol name */ | 72 | const char * name; /* protocol name */ |
| 75 | u32 number; /* program number */ | 73 | u32 number; /* program number */ |
| 76 | unsigned int nrvers; /* number of versions */ | 74 | unsigned int nrvers; /* number of versions */ |
| 77 | struct rpc_version ** version; /* version array */ | 75 | const struct rpc_version ** version; /* version array */ |
| 78 | struct rpc_stat * stats; /* statistics */ | 76 | struct rpc_stat * stats; /* statistics */ |
| 79 | char * pipe_dir_name; /* path to rpc_pipefs dir */ | 77 | const char * pipe_dir_name; /* path to rpc_pipefs dir */ |
| 80 | }; | 78 | }; |
| 81 | 79 | ||
| 82 | struct rpc_version { | 80 | struct rpc_version { |
| @@ -97,7 +95,7 @@ struct rpc_procinfo { | |||
| 97 | unsigned int p_count; /* call count */ | 95 | unsigned int p_count; /* call count */ |
| 98 | unsigned int p_timer; /* Which RTT timer to use */ | 96 | unsigned int p_timer; /* Which RTT timer to use */ |
| 99 | u32 p_statidx; /* Which procedure to account */ | 97 | u32 p_statidx; /* Which procedure to account */ |
| 100 | char * p_name; /* name of procedure */ | 98 | const char * p_name; /* name of procedure */ |
| 101 | }; | 99 | }; |
| 102 | 100 | ||
| 103 | #ifdef __KERNEL__ | 101 | #ifdef __KERNEL__ |
| @@ -109,8 +107,8 @@ struct rpc_create_args { | |||
| 109 | size_t addrsize; | 107 | size_t addrsize; |
| 110 | struct sockaddr *saddress; | 108 | struct sockaddr *saddress; |
| 111 | const struct rpc_timeout *timeout; | 109 | const struct rpc_timeout *timeout; |
| 112 | char *servername; | 110 | const char *servername; |
| 113 | struct rpc_program *program; | 111 | const struct rpc_program *program; |
| 114 | u32 prognumber; /* overrides program->number */ | 112 | u32 prognumber; /* overrides program->number */ |
| 115 | u32 version; | 113 | u32 version; |
| 116 | rpc_authflavor_t authflavor; | 114 | rpc_authflavor_t authflavor; |
| @@ -129,17 +127,18 @@ struct rpc_create_args { | |||
| 129 | 127 | ||
| 130 | struct rpc_clnt *rpc_create(struct rpc_create_args *args); | 128 | struct rpc_clnt *rpc_create(struct rpc_create_args *args); |
| 131 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, | 129 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, |
| 132 | struct rpc_program *, u32); | 130 | const struct rpc_program *, u32); |
| 133 | void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt); | 131 | void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt); |
| 134 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); | 132 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); |
| 135 | void rpc_shutdown_client(struct rpc_clnt *); | 133 | void rpc_shutdown_client(struct rpc_clnt *); |
| 136 | void rpc_release_client(struct rpc_clnt *); | 134 | void rpc_release_client(struct rpc_clnt *); |
| 137 | void rpc_task_release_client(struct rpc_task *); | 135 | void rpc_task_release_client(struct rpc_task *); |
| 138 | 136 | ||
| 139 | int rpcb_create_local(void); | 137 | int rpcb_create_local(struct net *); |
| 140 | void rpcb_put_local(void); | 138 | void rpcb_put_local(struct net *); |
| 141 | int rpcb_register(u32, u32, int, unsigned short); | 139 | int rpcb_register(struct net *, u32, u32, int, unsigned short); |
| 142 | int rpcb_v4_register(const u32 program, const u32 version, | 140 | int rpcb_v4_register(struct net *net, const u32 program, |
| 141 | const u32 version, | ||
| 143 | const struct sockaddr *address, | 142 | const struct sockaddr *address, |
| 144 | const char *netid); | 143 | const char *netid); |
| 145 | void rpcb_getport_async(struct rpc_task *); | 144 | 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, | |||
| 156 | int rpc_restart_call_prepare(struct rpc_task *); | 155 | int rpc_restart_call_prepare(struct rpc_task *); |
| 157 | int rpc_restart_call(struct rpc_task *); | 156 | int rpc_restart_call(struct rpc_task *); |
| 158 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); | 157 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); |
| 158 | int rpc_protocol(struct rpc_clnt *); | ||
| 159 | struct net * rpc_net_ns(struct rpc_clnt *); | ||
| 159 | size_t rpc_max_payload(struct rpc_clnt *); | 160 | size_t rpc_max_payload(struct rpc_clnt *); |
| 160 | void rpc_force_rebind(struct rpc_clnt *); | 161 | void rpc_force_rebind(struct rpc_clnt *); |
| 161 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); | 162 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); |
| 162 | const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); | 163 | const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); |
| 164 | int rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t); | ||
| 163 | 165 | ||
| 164 | size_t rpc_ntop(const struct sockaddr *, char *, const size_t); | 166 | size_t rpc_ntop(const struct sockaddr *, char *, const size_t); |
| 165 | size_t rpc_pton(const char *, const size_t, | 167 | size_t rpc_pton(struct net *, const char *, const size_t, |
| 166 | struct sockaddr *, const size_t); | 168 | struct sockaddr *, const size_t); |
| 167 | char * rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t); | 169 | char * rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t); |
| 168 | size_t rpc_uaddr2sockaddr(const char *, const size_t, | 170 | size_t rpc_uaddr2sockaddr(struct net *, const char *, const size_t, |
| 169 | struct sockaddr *, const size_t); | 171 | struct sockaddr *, const size_t); |
| 170 | 172 | ||
| 171 | static inline unsigned short rpc_get_port(const struct sockaddr *sap) | 173 | static inline unsigned short rpc_get_port(const struct sockaddr *sap) |
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index c2786f20016f..a76cc20d98ce 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h | |||
| @@ -31,9 +31,12 @@ | |||
| 31 | /* | 31 | /* |
| 32 | * Enable RPC debugging/profiling. | 32 | * Enable RPC debugging/profiling. |
| 33 | */ | 33 | */ |
| 34 | #ifdef CONFIG_SYSCTL | 34 | #ifdef CONFIG_SUNRPC_DEBUG |
| 35 | #define RPC_DEBUG | 35 | #define RPC_DEBUG |
| 36 | #endif | 36 | #endif |
| 37 | #ifdef CONFIG_TRACEPOINTS | ||
| 38 | #define RPC_TRACEPOINTS | ||
| 39 | #endif | ||
| 37 | /* #define RPC_PROFILE */ | 40 | /* #define RPC_PROFILE */ |
| 38 | 41 | ||
| 39 | /* | 42 | /* |
| @@ -47,15 +50,32 @@ extern unsigned int nlm_debug; | |||
| 47 | #endif | 50 | #endif |
| 48 | 51 | ||
| 49 | #define dprintk(args...) dfprintk(FACILITY, ## args) | 52 | #define dprintk(args...) dfprintk(FACILITY, ## args) |
| 53 | #define dprintk_rcu(args...) dfprintk_rcu(FACILITY, ## args) | ||
| 50 | 54 | ||
| 51 | #undef ifdebug | 55 | #undef ifdebug |
| 52 | #ifdef RPC_DEBUG | 56 | #ifdef RPC_DEBUG |
| 53 | # define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac)) | 57 | # define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac)) |
| 54 | # define dfprintk(fac, args...) do { ifdebug(fac) printk(args); } while(0) | 58 | |
| 59 | # define dfprintk(fac, args...) \ | ||
| 60 | do { \ | ||
| 61 | ifdebug(fac) \ | ||
| 62 | printk(KERN_DEFAULT args); \ | ||
| 63 | } while (0) | ||
| 64 | |||
| 65 | # define dfprintk_rcu(fac, args...) \ | ||
| 66 | do { \ | ||
| 67 | ifdebug(fac) { \ | ||
| 68 | rcu_read_lock(); \ | ||
| 69 | printk(KERN_DEFAULT args); \ | ||
| 70 | rcu_read_unlock(); \ | ||
| 71 | } \ | ||
| 72 | } while (0) | ||
| 73 | |||
| 55 | # define RPC_IFDEBUG(x) x | 74 | # define RPC_IFDEBUG(x) x |
| 56 | #else | 75 | #else |
| 57 | # define ifdebug(fac) if (0) | 76 | # define ifdebug(fac) if (0) |
| 58 | # define dfprintk(fac, args...) do ; while (0) | 77 | # define dfprintk(fac, args...) do {} while (0) |
| 78 | # define dfprintk_rcu(fac, args...) do {} while (0) | ||
| 59 | # define RPC_IFDEBUG(x) | 79 | # define RPC_IFDEBUG(x) |
| 60 | #endif | 80 | #endif |
| 61 | 81 | ||
diff --git a/include/linux/sunrpc/metrics.h b/include/linux/sunrpc/metrics.h index b6edbc0ea83d..1565bbe86d51 100644 --- a/include/linux/sunrpc/metrics.h +++ b/include/linux/sunrpc/metrics.h | |||
| @@ -74,14 +74,16 @@ struct rpc_clnt; | |||
| 74 | #ifdef CONFIG_PROC_FS | 74 | #ifdef CONFIG_PROC_FS |
| 75 | 75 | ||
| 76 | struct rpc_iostats * rpc_alloc_iostats(struct rpc_clnt *); | 76 | struct rpc_iostats * rpc_alloc_iostats(struct rpc_clnt *); |
| 77 | void rpc_count_iostats(struct rpc_task *); | 77 | void rpc_count_iostats(const struct rpc_task *, |
| 78 | struct rpc_iostats *); | ||
| 78 | void rpc_print_iostats(struct seq_file *, struct rpc_clnt *); | 79 | void rpc_print_iostats(struct seq_file *, struct rpc_clnt *); |
| 79 | void rpc_free_iostats(struct rpc_iostats *); | 80 | void rpc_free_iostats(struct rpc_iostats *); |
| 80 | 81 | ||
| 81 | #else /* CONFIG_PROC_FS */ | 82 | #else /* CONFIG_PROC_FS */ |
| 82 | 83 | ||
| 83 | static inline struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) { return NULL; } | 84 | static inline struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) { return NULL; } |
| 84 | static inline void rpc_count_iostats(struct rpc_task *task) {} | 85 | static inline void rpc_count_iostats(const struct rpc_task *task, |
| 86 | struct rpc_iostats *stats) {} | ||
| 85 | static inline void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) {} | 87 | static inline void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) {} |
| 86 | static inline void rpc_free_iostats(struct rpc_iostats *stats) {} | 88 | static inline void rpc_free_iostats(struct rpc_iostats *stats) {} |
| 87 | 89 | ||
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 2bb03d77375a..a7b422b33eda 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h | |||
| @@ -21,21 +21,26 @@ struct rpc_pipe_ops { | |||
| 21 | void (*destroy_msg)(struct rpc_pipe_msg *); | 21 | void (*destroy_msg)(struct rpc_pipe_msg *); |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | struct rpc_inode { | 24 | struct rpc_pipe { |
| 25 | struct inode vfs_inode; | ||
| 26 | void *private; | ||
| 27 | struct list_head pipe; | 25 | struct list_head pipe; |
| 28 | struct list_head in_upcall; | 26 | struct list_head in_upcall; |
| 29 | struct list_head in_downcall; | 27 | struct list_head in_downcall; |
| 30 | int pipelen; | 28 | int pipelen; |
| 31 | int nreaders; | 29 | int nreaders; |
| 32 | int nwriters; | 30 | int nwriters; |
| 33 | int nkern_readwriters; | ||
| 34 | wait_queue_head_t waitq; | ||
| 35 | #define RPC_PIPE_WAIT_FOR_OPEN 1 | 31 | #define RPC_PIPE_WAIT_FOR_OPEN 1 |
| 36 | int flags; | 32 | int flags; |
| 37 | struct delayed_work queue_timeout; | 33 | struct delayed_work queue_timeout; |
| 38 | const struct rpc_pipe_ops *ops; | 34 | const struct rpc_pipe_ops *ops; |
| 35 | spinlock_t lock; | ||
| 36 | struct dentry *dentry; | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct rpc_inode { | ||
| 40 | struct inode vfs_inode; | ||
| 41 | void *private; | ||
| 42 | struct rpc_pipe *pipe; | ||
| 43 | wait_queue_head_t waitq; | ||
| 39 | }; | 44 | }; |
| 40 | 45 | ||
| 41 | static inline struct rpc_inode * | 46 | static inline struct rpc_inode * |
| @@ -44,9 +49,28 @@ RPC_I(struct inode *inode) | |||
| 44 | return container_of(inode, struct rpc_inode, vfs_inode); | 49 | return container_of(inode, struct rpc_inode, vfs_inode); |
| 45 | } | 50 | } |
| 46 | 51 | ||
| 52 | enum { | ||
| 53 | SUNRPC_PIPEFS_NFS_PRIO, | ||
| 54 | SUNRPC_PIPEFS_RPC_PRIO, | ||
| 55 | }; | ||
| 56 | |||
| 57 | extern int rpc_pipefs_notifier_register(struct notifier_block *); | ||
| 58 | extern void rpc_pipefs_notifier_unregister(struct notifier_block *); | ||
| 59 | |||
| 60 | enum { | ||
| 61 | RPC_PIPEFS_MOUNT, | ||
| 62 | RPC_PIPEFS_UMOUNT, | ||
| 63 | }; | ||
| 64 | |||
| 65 | extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb, | ||
| 66 | const unsigned char *dir_name); | ||
| 67 | extern void rpc_pipefs_init_net(struct net *net); | ||
| 68 | extern struct super_block *rpc_get_sb_net(const struct net *net); | ||
| 69 | extern void rpc_put_sb_net(const struct net *net); | ||
| 70 | |||
| 47 | extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *, | 71 | extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *, |
| 48 | char __user *, size_t); | 72 | char __user *, size_t); |
| 49 | extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); | 73 | extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *); |
| 50 | 74 | ||
| 51 | struct rpc_clnt; | 75 | struct rpc_clnt; |
| 52 | extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *); | 76 | 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 *, | |||
| 59 | struct cache_detail *); | 83 | struct cache_detail *); |
| 60 | extern void rpc_remove_cache_dir(struct dentry *); | 84 | extern void rpc_remove_cache_dir(struct dentry *); |
| 61 | 85 | ||
| 62 | extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, | 86 | extern int rpc_rmdir(struct dentry *dentry); |
| 63 | const struct rpc_pipe_ops *, int flags); | 87 | |
| 88 | struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags); | ||
| 89 | void rpc_destroy_pipe_data(struct rpc_pipe *pipe); | ||
| 90 | extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *, | ||
| 91 | struct rpc_pipe *); | ||
| 64 | extern int rpc_unlink(struct dentry *); | 92 | extern int rpc_unlink(struct dentry *); |
| 65 | extern struct vfsmount *rpc_get_mount(void); | ||
| 66 | extern void rpc_put_mount(void); | ||
| 67 | extern int register_rpc_pipefs(void); | 93 | extern int register_rpc_pipefs(void); |
| 68 | extern void unregister_rpc_pipefs(void); | 94 | extern void unregister_rpc_pipefs(void); |
| 69 | 95 | ||
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index e7756896f3ca..dc0c3cc3ada3 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
| @@ -103,6 +103,7 @@ typedef void (*rpc_action)(struct rpc_task *); | |||
| 103 | struct rpc_call_ops { | 103 | struct rpc_call_ops { |
| 104 | void (*rpc_call_prepare)(struct rpc_task *, void *); | 104 | void (*rpc_call_prepare)(struct rpc_task *, void *); |
| 105 | void (*rpc_call_done)(struct rpc_task *, void *); | 105 | void (*rpc_call_done)(struct rpc_task *, void *); |
| 106 | void (*rpc_count_stats)(struct rpc_task *, void *); | ||
| 106 | void (*rpc_release)(void *); | 107 | void (*rpc_release)(void *); |
| 107 | }; | 108 | }; |
| 108 | 109 | ||
| @@ -195,7 +196,7 @@ struct rpc_wait_queue { | |||
| 195 | unsigned char nr; /* # tasks remaining for cookie */ | 196 | unsigned char nr; /* # tasks remaining for cookie */ |
| 196 | unsigned short qlen; /* total # tasks waiting in queue */ | 197 | unsigned short qlen; /* total # tasks waiting in queue */ |
| 197 | struct rpc_timer timer_list; | 198 | struct rpc_timer timer_list; |
| 198 | #ifdef RPC_DEBUG | 199 | #if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS) |
| 199 | const char * name; | 200 | const char * name; |
| 200 | #endif | 201 | #endif |
| 201 | }; | 202 | }; |
| @@ -235,6 +236,9 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *, | |||
| 235 | struct rpc_task *); | 236 | struct rpc_task *); |
| 236 | void rpc_wake_up(struct rpc_wait_queue *); | 237 | void rpc_wake_up(struct rpc_wait_queue *); |
| 237 | struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); | 238 | struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); |
| 239 | struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *, | ||
| 240 | bool (*)(struct rpc_task *, void *), | ||
| 241 | void *); | ||
| 238 | void rpc_wake_up_status(struct rpc_wait_queue *, int); | 242 | void rpc_wake_up_status(struct rpc_wait_queue *, int); |
| 239 | int rpc_queue_empty(struct rpc_wait_queue *); | 243 | int rpc_queue_empty(struct rpc_wait_queue *); |
| 240 | void rpc_delay(struct rpc_task *, unsigned long); | 244 | void rpc_delay(struct rpc_task *, unsigned long); |
| @@ -244,7 +248,8 @@ int rpciod_up(void); | |||
| 244 | void rpciod_down(void); | 248 | void rpciod_down(void); |
| 245 | int __rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *)); | 249 | int __rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *)); |
| 246 | #ifdef RPC_DEBUG | 250 | #ifdef RPC_DEBUG |
| 247 | void rpc_show_tasks(void); | 251 | struct net; |
| 252 | void rpc_show_tasks(struct net *); | ||
| 248 | #endif | 253 | #endif |
| 249 | int rpc_init_mempool(void); | 254 | int rpc_init_mempool(void); |
| 250 | void rpc_destroy_mempool(void); | 255 | void rpc_destroy_mempool(void); |
| @@ -266,11 +271,22 @@ static inline int rpc_task_has_priority(struct rpc_task *task, unsigned char pri | |||
| 266 | return (task->tk_priority + RPC_PRIORITY_LOW == prio); | 271 | return (task->tk_priority + RPC_PRIORITY_LOW == prio); |
| 267 | } | 272 | } |
| 268 | 273 | ||
| 269 | #ifdef RPC_DEBUG | 274 | #if defined(RPC_DEBUG) || defined (RPC_TRACEPOINTS) |
| 270 | static inline const char * rpc_qname(struct rpc_wait_queue *q) | 275 | static inline const char * rpc_qname(const struct rpc_wait_queue *q) |
| 271 | { | 276 | { |
| 272 | return ((q && q->name) ? q->name : "unknown"); | 277 | return ((q && q->name) ? q->name : "unknown"); |
| 273 | } | 278 | } |
| 279 | |||
| 280 | static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q, | ||
| 281 | const char *name) | ||
| 282 | { | ||
| 283 | q->name = name; | ||
| 284 | } | ||
| 285 | #else | ||
| 286 | static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q, | ||
| 287 | const char *name) | ||
| 288 | { | ||
| 289 | } | ||
| 274 | #endif | 290 | #endif |
| 275 | 291 | ||
| 276 | #endif /* _LINUX_SUNRPC_SCHED_H_ */ | 292 | #endif /* _LINUX_SUNRPC_SCHED_H_ */ |
diff --git a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h index 680471d1f28a..edc64219f92b 100644 --- a/include/linux/sunrpc/stats.h +++ b/include/linux/sunrpc/stats.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | #include <linux/proc_fs.h> | 12 | #include <linux/proc_fs.h> |
| 13 | 13 | ||
| 14 | struct rpc_stat { | 14 | struct rpc_stat { |
| 15 | struct rpc_program * program; | 15 | const struct rpc_program *program; |
| 16 | 16 | ||
| 17 | unsigned int netcnt, | 17 | unsigned int netcnt, |
| 18 | netudpcnt, | 18 | netudpcnt, |
| @@ -58,24 +58,24 @@ void rpc_modcount(struct inode *, int); | |||
| 58 | #endif | 58 | #endif |
| 59 | 59 | ||
| 60 | #ifdef CONFIG_PROC_FS | 60 | #ifdef CONFIG_PROC_FS |
| 61 | struct proc_dir_entry * rpc_proc_register(struct rpc_stat *); | 61 | struct proc_dir_entry * rpc_proc_register(struct net *,struct rpc_stat *); |
| 62 | void rpc_proc_unregister(const char *); | 62 | void rpc_proc_unregister(struct net *,const char *); |
| 63 | void rpc_proc_zero(struct rpc_program *); | 63 | void rpc_proc_zero(const struct rpc_program *); |
| 64 | struct proc_dir_entry * svc_proc_register(struct svc_stat *, | 64 | struct proc_dir_entry * svc_proc_register(struct net *, struct svc_stat *, |
| 65 | const struct file_operations *); | 65 | const struct file_operations *); |
| 66 | void svc_proc_unregister(const char *); | 66 | void svc_proc_unregister(struct net *, const char *); |
| 67 | 67 | ||
| 68 | void svc_seq_show(struct seq_file *, | 68 | void svc_seq_show(struct seq_file *, |
| 69 | const struct svc_stat *); | 69 | const struct svc_stat *); |
| 70 | #else | 70 | #else |
| 71 | 71 | ||
| 72 | static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; } | 72 | static inline struct proc_dir_entry *rpc_proc_register(struct net *net, struct rpc_stat *s) { return NULL; } |
| 73 | static inline void rpc_proc_unregister(const char *p) {} | 73 | static inline void rpc_proc_unregister(struct net *net, const char *p) {} |
| 74 | static inline void rpc_proc_zero(struct rpc_program *p) {} | 74 | static inline void rpc_proc_zero(const struct rpc_program *p) {} |
| 75 | 75 | ||
| 76 | static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s, | 76 | static inline struct proc_dir_entry *svc_proc_register(struct net *net, struct svc_stat *s, |
| 77 | const struct file_operations *f) { return NULL; } | 77 | const struct file_operations *f) { return NULL; } |
| 78 | static inline void svc_proc_unregister(const char *p) {} | 78 | static inline void svc_proc_unregister(struct net *net, const char *p) {} |
| 79 | 79 | ||
| 80 | static inline void svc_seq_show(struct seq_file *seq, | 80 | static inline void svc_seq_show(struct seq_file *seq, |
| 81 | const struct svc_stat *st) {} | 81 | const struct svc_stat *st) {} |
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 35b37b1e9299..51b29ac45a8e 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
| @@ -84,7 +84,8 @@ struct svc_serv { | |||
| 84 | unsigned int sv_nrpools; /* number of thread pools */ | 84 | unsigned int sv_nrpools; /* number of thread pools */ |
| 85 | struct svc_pool * sv_pools; /* array of thread pools */ | 85 | struct svc_pool * sv_pools; /* array of thread pools */ |
| 86 | 86 | ||
| 87 | void (*sv_shutdown)(struct svc_serv *serv); | 87 | void (*sv_shutdown)(struct svc_serv *serv, |
| 88 | struct net *net); | ||
| 88 | /* Callback to use when last thread | 89 | /* Callback to use when last thread |
| 89 | * exits. | 90 | * exits. |
| 90 | */ | 91 | */ |
| @@ -413,22 +414,24 @@ struct svc_procedure { | |||
| 413 | /* | 414 | /* |
| 414 | * Function prototypes. | 415 | * Function prototypes. |
| 415 | */ | 416 | */ |
| 416 | void svc_rpcb_cleanup(struct svc_serv *serv); | 417 | int svc_rpcb_setup(struct svc_serv *serv, struct net *net); |
| 418 | void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net); | ||
| 417 | struct svc_serv *svc_create(struct svc_program *, unsigned int, | 419 | struct svc_serv *svc_create(struct svc_program *, unsigned int, |
| 418 | void (*shutdown)(struct svc_serv *)); | 420 | void (*shutdown)(struct svc_serv *, struct net *net)); |
| 419 | struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, | 421 | struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, |
| 420 | struct svc_pool *pool, int node); | 422 | struct svc_pool *pool, int node); |
| 421 | void svc_exit_thread(struct svc_rqst *); | 423 | void svc_exit_thread(struct svc_rqst *); |
| 422 | struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, | 424 | struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, |
| 423 | void (*shutdown)(struct svc_serv *), | 425 | void (*shutdown)(struct svc_serv *, struct net *net), |
| 424 | svc_thread_fn, struct module *); | 426 | svc_thread_fn, struct module *); |
| 425 | int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); | 427 | int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); |
| 426 | int svc_pool_stats_open(struct svc_serv *serv, struct file *file); | 428 | int svc_pool_stats_open(struct svc_serv *serv, struct file *file); |
| 427 | void svc_destroy(struct svc_serv *); | 429 | void svc_destroy(struct svc_serv *); |
| 430 | void svc_shutdown_net(struct svc_serv *, struct net *); | ||
| 428 | int svc_process(struct svc_rqst *); | 431 | int svc_process(struct svc_rqst *); |
| 429 | int bc_svc_process(struct svc_serv *, struct rpc_rqst *, | 432 | int bc_svc_process(struct svc_serv *, struct rpc_rqst *, |
| 430 | struct svc_rqst *); | 433 | struct svc_rqst *); |
| 431 | int svc_register(const struct svc_serv *, const int, | 434 | int svc_register(const struct svc_serv *, struct net *, const int, |
| 432 | const unsigned short, const unsigned short); | 435 | const unsigned short, const unsigned short); |
| 433 | 436 | ||
| 434 | void svc_wake_up(struct svc_serv *); | 437 | void svc_wake_up(struct svc_serv *); |
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index dfa900948af7..b3f64b12f141 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h | |||
| @@ -121,7 +121,8 @@ void svc_close_xprt(struct svc_xprt *xprt); | |||
| 121 | int svc_port_is_privileged(struct sockaddr *sin); | 121 | int svc_port_is_privileged(struct sockaddr *sin); |
| 122 | int svc_print_xprts(char *buf, int maxlen); | 122 | int svc_print_xprts(char *buf, int maxlen); |
| 123 | struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, | 123 | struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, |
| 124 | const sa_family_t af, const unsigned short port); | 124 | struct net *net, const sa_family_t af, |
| 125 | const unsigned short port); | ||
| 125 | int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); | 126 | int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); |
| 126 | 127 | ||
| 127 | static inline void svc_xprt_get(struct svc_xprt *xprt) | 128 | static inline void svc_xprt_get(struct svc_xprt *xprt) |
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index 25d333c1b571..548790e9113b 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h | |||
| @@ -135,6 +135,9 @@ extern void svcauth_unix_purge(void); | |||
| 135 | extern void svcauth_unix_info_release(struct svc_xprt *xpt); | 135 | extern void svcauth_unix_info_release(struct svc_xprt *xpt); |
| 136 | extern int svcauth_unix_set_client(struct svc_rqst *rqstp); | 136 | extern int svcauth_unix_set_client(struct svc_rqst *rqstp); |
| 137 | 137 | ||
| 138 | extern int unix_gid_cache_create(struct net *net); | ||
| 139 | extern void unix_gid_cache_destroy(struct net *net); | ||
| 140 | |||
| 138 | static inline unsigned long hash_str(char *name, int bits) | 141 | static inline unsigned long hash_str(char *name, int bits) |
| 139 | { | 142 | { |
| 140 | unsigned long hash = 0; | 143 | unsigned long hash = 0; |
diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h index 83bbee3f089c..7c32daa025eb 100644 --- a/include/linux/sunrpc/svcauth_gss.h +++ b/include/linux/sunrpc/svcauth_gss.h | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | 18 | ||
| 19 | int gss_svc_init(void); | 19 | int gss_svc_init(void); |
| 20 | void gss_svc_shutdown(void); | 20 | void gss_svc_shutdown(void); |
| 21 | int gss_svc_init_net(struct net *net); | ||
| 22 | void gss_svc_shutdown_net(struct net *net); | ||
| 21 | int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); | 23 | int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); |
| 22 | u32 svcauth_gss_flavor(struct auth_domain *dom); | 24 | u32 svcauth_gss_flavor(struct auth_domain *dom); |
| 23 | char *svc_gss_principal(struct svc_rqst *); | 25 | char *svc_gss_principal(struct svc_rqst *); |
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index c84e9741cb2a..cb4ac69e1f33 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h | |||
| @@ -34,7 +34,7 @@ struct svc_sock { | |||
| 34 | /* | 34 | /* |
| 35 | * Function prototypes. | 35 | * Function prototypes. |
| 36 | */ | 36 | */ |
| 37 | void svc_close_all(struct svc_serv *); | 37 | void svc_close_net(struct svc_serv *, struct net *); |
| 38 | int svc_recv(struct svc_rqst *, long); | 38 | int svc_recv(struct svc_rqst *, long); |
| 39 | int svc_send(struct svc_rqst *); | 39 | int svc_send(struct svc_rqst *); |
| 40 | void svc_drop(struct svc_rqst *); | 40 | void svc_drop(struct svc_rqst *); |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 15518a152ac3..77d278defa70 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -21,8 +21,8 @@ | |||
| 21 | 21 | ||
| 22 | #define RPC_MIN_SLOT_TABLE (2U) | 22 | #define RPC_MIN_SLOT_TABLE (2U) |
| 23 | #define RPC_DEF_SLOT_TABLE (16U) | 23 | #define RPC_DEF_SLOT_TABLE (16U) |
| 24 | #define RPC_MAX_SLOT_TABLE (128U) | ||
| 25 | #define RPC_MAX_SLOT_TABLE_LIMIT (65536U) | 24 | #define RPC_MAX_SLOT_TABLE_LIMIT (65536U) |
| 25 | #define RPC_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE_LIMIT | ||
| 26 | 26 | ||
| 27 | /* | 27 | /* |
| 28 | * This describes a timeout strategy | 28 | * This describes a timeout strategy |
| @@ -219,13 +219,17 @@ struct rpc_xprt { | |||
| 219 | connect_time, /* jiffies waiting for connect */ | 219 | connect_time, /* jiffies waiting for connect */ |
| 220 | sends, /* how many complete requests */ | 220 | sends, /* how many complete requests */ |
| 221 | recvs, /* how many complete requests */ | 221 | recvs, /* how many complete requests */ |
| 222 | bad_xids; /* lookup_rqst didn't find XID */ | 222 | bad_xids, /* lookup_rqst didn't find XID */ |
| 223 | max_slots; /* max rpc_slots used */ | ||
| 223 | 224 | ||
| 224 | unsigned long long req_u, /* average requests on the wire */ | 225 | unsigned long long req_u, /* average requests on the wire */ |
| 225 | bklog_u; /* backlog queue utilization */ | 226 | bklog_u, /* backlog queue utilization */ |
| 227 | sending_u, /* send q utilization */ | ||
| 228 | pending_u; /* pend q utilization */ | ||
| 226 | } stat; | 229 | } stat; |
| 227 | 230 | ||
| 228 | struct net *xprt_net; | 231 | struct net *xprt_net; |
| 232 | const char *servername; | ||
| 229 | const char *address_strings[RPC_DISPLAY_MAX]; | 233 | const char *address_strings[RPC_DISPLAY_MAX]; |
| 230 | }; | 234 | }; |
| 231 | 235 | ||
| @@ -255,6 +259,7 @@ struct xprt_create { | |||
| 255 | struct sockaddr * srcaddr; /* optional local address */ | 259 | struct sockaddr * srcaddr; /* optional local address */ |
| 256 | struct sockaddr * dstaddr; /* remote peer address */ | 260 | struct sockaddr * dstaddr; /* remote peer address */ |
| 257 | size_t addrlen; | 261 | size_t addrlen; |
| 262 | const char *servername; | ||
| 258 | struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ | 263 | struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ |
| 259 | }; | 264 | }; |
| 260 | 265 | ||
diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h index 3f14a02e9cc0..1ad36cc25b2e 100644 --- a/include/linux/sunrpc/xprtsock.h +++ b/include/linux/sunrpc/xprtsock.h | |||
| @@ -12,18 +12,6 @@ | |||
| 12 | int init_socket_xprt(void); | 12 | int init_socket_xprt(void); |
| 13 | void cleanup_socket_xprt(void); | 13 | void cleanup_socket_xprt(void); |
| 14 | 14 | ||
| 15 | /* | ||
| 16 | * RPC slot table sizes for UDP, TCP transports | ||
| 17 | */ | ||
| 18 | extern unsigned int xprt_udp_slot_table_entries; | ||
| 19 | extern unsigned int xprt_tcp_slot_table_entries; | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Parameters for choosing a free port | ||
| 23 | */ | ||
| 24 | extern unsigned int xprt_min_resvport; | ||
| 25 | extern unsigned int xprt_max_resvport; | ||
| 26 | |||
| 27 | #define RPC_MIN_RESVPORT (1U) | 15 | #define RPC_MIN_RESVPORT (1U) |
| 28 | #define RPC_MAX_RESVPORT (65535U) | 16 | #define RPC_MAX_RESVPORT (65535U) |
| 29 | #define RPC_DEF_MIN_RESVPORT (665U) | 17 | #define RPC_DEF_MIN_RESVPORT (665U) |
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h new file mode 100644 index 000000000000..43be87d5dd58 --- /dev/null +++ b/include/trace/events/sunrpc.h | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM sunrpc | ||
| 3 | |||
| 4 | #if !defined(_TRACE_SUNRPC_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 5 | #define _TRACE_SUNRPC_H | ||
| 6 | |||
| 7 | #include <linux/sunrpc/sched.h> | ||
| 8 | #include <linux/sunrpc/clnt.h> | ||
| 9 | #include <linux/tracepoint.h> | ||
| 10 | |||
| 11 | DECLARE_EVENT_CLASS(rpc_task_status, | ||
| 12 | |||
| 13 | TP_PROTO(struct rpc_task *task), | ||
| 14 | |||
| 15 | TP_ARGS(task), | ||
| 16 | |||
| 17 | TP_STRUCT__entry( | ||
| 18 | __field(const struct rpc_task *, task) | ||
| 19 | __field(const struct rpc_clnt *, clnt) | ||
| 20 | __field(int, status) | ||
| 21 | ), | ||
| 22 | |||
| 23 | TP_fast_assign( | ||
| 24 | __entry->task = task; | ||
| 25 | __entry->clnt = task->tk_client; | ||
| 26 | __entry->status = task->tk_status; | ||
| 27 | ), | ||
| 28 | |||
| 29 | TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status) | ||
| 30 | ); | ||
| 31 | |||
| 32 | DEFINE_EVENT(rpc_task_status, rpc_call_status, | ||
| 33 | TP_PROTO(struct rpc_task *task), | ||
| 34 | |||
| 35 | TP_ARGS(task) | ||
| 36 | ); | ||
| 37 | |||
| 38 | DEFINE_EVENT(rpc_task_status, rpc_bind_status, | ||
| 39 | TP_PROTO(struct rpc_task *task), | ||
| 40 | |||
| 41 | TP_ARGS(task) | ||
| 42 | ); | ||
| 43 | |||
| 44 | TRACE_EVENT(rpc_connect_status, | ||
| 45 | TP_PROTO(struct rpc_task *task, int status), | ||
| 46 | |||
| 47 | TP_ARGS(task, status), | ||
| 48 | |||
| 49 | TP_STRUCT__entry( | ||
| 50 | __field(const struct rpc_task *, task) | ||
| 51 | __field(const struct rpc_clnt *, clnt) | ||
| 52 | __field(int, status) | ||
| 53 | ), | ||
| 54 | |||
| 55 | TP_fast_assign( | ||
| 56 | __entry->task = task; | ||
| 57 | __entry->clnt = task->tk_client; | ||
| 58 | __entry->status = status; | ||
| 59 | ), | ||
| 60 | |||
| 61 | TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status) | ||
| 62 | ); | ||
| 63 | |||
| 64 | DECLARE_EVENT_CLASS(rpc_task_running, | ||
| 65 | |||
| 66 | TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action), | ||
| 67 | |||
| 68 | TP_ARGS(clnt, task, action), | ||
| 69 | |||
| 70 | TP_STRUCT__entry( | ||
| 71 | __field(const struct rpc_clnt *, clnt) | ||
| 72 | __field(const struct rpc_task *, task) | ||
| 73 | __field(const void *, action) | ||
| 74 | __field(unsigned long, runstate) | ||
| 75 | __field(int, status) | ||
| 76 | __field(unsigned short, flags) | ||
| 77 | ), | ||
| 78 | |||
| 79 | TP_fast_assign( | ||
| 80 | __entry->clnt = clnt; | ||
| 81 | __entry->task = task; | ||
| 82 | __entry->action = action; | ||
| 83 | __entry->runstate = task->tk_runstate; | ||
| 84 | __entry->status = task->tk_status; | ||
| 85 | __entry->flags = task->tk_flags; | ||
| 86 | ), | ||
| 87 | |||
| 88 | TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d action=%pf", | ||
| 89 | __entry->task, | ||
| 90 | __entry->clnt, | ||
| 91 | __entry->flags, | ||
| 92 | __entry->runstate, | ||
| 93 | __entry->status, | ||
| 94 | __entry->action | ||
| 95 | ) | ||
| 96 | ); | ||
| 97 | |||
| 98 | DEFINE_EVENT(rpc_task_running, rpc_task_begin, | ||
| 99 | |||
| 100 | TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action), | ||
| 101 | |||
| 102 | TP_ARGS(clnt, task, action) | ||
| 103 | |||
| 104 | ); | ||
| 105 | |||
| 106 | DEFINE_EVENT(rpc_task_running, rpc_task_run_action, | ||
| 107 | |||
| 108 | TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action), | ||
| 109 | |||
| 110 | TP_ARGS(clnt, task, action) | ||
| 111 | |||
| 112 | ); | ||
| 113 | |||
| 114 | DEFINE_EVENT(rpc_task_running, rpc_task_complete, | ||
| 115 | |||
| 116 | TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action), | ||
| 117 | |||
| 118 | TP_ARGS(clnt, task, action) | ||
| 119 | |||
| 120 | ); | ||
| 121 | |||
| 122 | DECLARE_EVENT_CLASS(rpc_task_queued, | ||
| 123 | |||
| 124 | TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q), | ||
| 125 | |||
| 126 | TP_ARGS(clnt, task, q), | ||
| 127 | |||
| 128 | TP_STRUCT__entry( | ||
| 129 | __field(const struct rpc_clnt *, clnt) | ||
| 130 | __field(const struct rpc_task *, task) | ||
| 131 | __field(unsigned long, timeout) | ||
| 132 | __field(unsigned long, runstate) | ||
| 133 | __field(int, status) | ||
| 134 | __field(unsigned short, flags) | ||
| 135 | __string(q_name, rpc_qname(q)) | ||
| 136 | ), | ||
| 137 | |||
| 138 | TP_fast_assign( | ||
| 139 | __entry->clnt = clnt; | ||
| 140 | __entry->task = task; | ||
| 141 | __entry->timeout = task->tk_timeout; | ||
| 142 | __entry->runstate = task->tk_runstate; | ||
| 143 | __entry->status = task->tk_status; | ||
| 144 | __entry->flags = task->tk_flags; | ||
| 145 | __assign_str(q_name, rpc_qname(q)); | ||
| 146 | ), | ||
| 147 | |||
| 148 | TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d timeout=%lu queue=%s", | ||
| 149 | __entry->task, | ||
| 150 | __entry->clnt, | ||
| 151 | __entry->flags, | ||
| 152 | __entry->runstate, | ||
| 153 | __entry->status, | ||
| 154 | __entry->timeout, | ||
| 155 | __get_str(q_name) | ||
| 156 | ) | ||
| 157 | ); | ||
| 158 | |||
| 159 | DEFINE_EVENT(rpc_task_queued, rpc_task_sleep, | ||
| 160 | |||
| 161 | TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q), | ||
| 162 | |||
| 163 | TP_ARGS(clnt, task, q) | ||
| 164 | |||
| 165 | ); | ||
| 166 | |||
| 167 | DEFINE_EVENT(rpc_task_queued, rpc_task_wakeup, | ||
| 168 | |||
| 169 | TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q), | ||
| 170 | |||
| 171 | TP_ARGS(clnt, task, q) | ||
| 172 | |||
| 173 | ); | ||
| 174 | |||
| 175 | #endif /* _TRACE_SUNRPC_H */ | ||
| 176 | |||
| 177 | #include <trace/define_trace.h> | ||
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig index ffd243d09188..9fe8857d8d59 100644 --- a/net/sunrpc/Kconfig +++ b/net/sunrpc/Kconfig | |||
| @@ -39,3 +39,16 @@ config RPCSEC_GSS_KRB5 | |||
| 39 | Kerberos support should be installed. | 39 | Kerberos support should be installed. |
| 40 | 40 | ||
| 41 | If unsure, say Y. | 41 | If unsure, say Y. |
| 42 | |||
| 43 | config SUNRPC_DEBUG | ||
| 44 | bool "RPC: Enable dprintk debugging" | ||
| 45 | depends on SUNRPC && SYSCTL | ||
| 46 | help | ||
| 47 | This option enables a sysctl-based debugging interface | ||
| 48 | that is be used by the 'rpcdebug' utility to turn on or off | ||
| 49 | logging of different aspects of the kernel RPC activity. | ||
| 50 | |||
| 51 | Disabling this option will make your kernel slightly smaller, | ||
| 52 | but makes troubleshooting NFS issues significantly harder. | ||
| 53 | |||
| 54 | If unsure, say Y. | ||
diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index ee77742e0ed6..d11418f97f1f 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c | |||
| @@ -156,8 +156,9 @@ static size_t rpc_pton4(const char *buf, const size_t buflen, | |||
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | #if IS_ENABLED(CONFIG_IPV6) | 158 | #if IS_ENABLED(CONFIG_IPV6) |
| 159 | static int rpc_parse_scope_id(const char *buf, const size_t buflen, | 159 | static int rpc_parse_scope_id(struct net *net, const char *buf, |
| 160 | const char *delim, struct sockaddr_in6 *sin6) | 160 | const size_t buflen, const char *delim, |
| 161 | struct sockaddr_in6 *sin6) | ||
| 161 | { | 162 | { |
| 162 | char *p; | 163 | char *p; |
| 163 | size_t len; | 164 | size_t len; |
| @@ -177,7 +178,7 @@ static int rpc_parse_scope_id(const char *buf, const size_t buflen, | |||
| 177 | unsigned long scope_id = 0; | 178 | unsigned long scope_id = 0; |
| 178 | struct net_device *dev; | 179 | struct net_device *dev; |
| 179 | 180 | ||
| 180 | dev = dev_get_by_name(&init_net, p); | 181 | dev = dev_get_by_name(net, p); |
| 181 | if (dev != NULL) { | 182 | if (dev != NULL) { |
| 182 | scope_id = dev->ifindex; | 183 | scope_id = dev->ifindex; |
| 183 | dev_put(dev); | 184 | dev_put(dev); |
| @@ -197,7 +198,7 @@ static int rpc_parse_scope_id(const char *buf, const size_t buflen, | |||
| 197 | return 0; | 198 | return 0; |
| 198 | } | 199 | } |
| 199 | 200 | ||
| 200 | static size_t rpc_pton6(const char *buf, const size_t buflen, | 201 | static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen, |
| 201 | struct sockaddr *sap, const size_t salen) | 202 | struct sockaddr *sap, const size_t salen) |
| 202 | { | 203 | { |
| 203 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | 204 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; |
| @@ -213,14 +214,14 @@ static size_t rpc_pton6(const char *buf, const size_t buflen, | |||
| 213 | if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0) | 214 | if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0) |
| 214 | return 0; | 215 | return 0; |
| 215 | 216 | ||
| 216 | if (!rpc_parse_scope_id(buf, buflen, delim, sin6)) | 217 | if (!rpc_parse_scope_id(net, buf, buflen, delim, sin6)) |
| 217 | return 0; | 218 | return 0; |
| 218 | 219 | ||
| 219 | sin6->sin6_family = AF_INET6; | 220 | sin6->sin6_family = AF_INET6; |
| 220 | return sizeof(struct sockaddr_in6); | 221 | return sizeof(struct sockaddr_in6); |
| 221 | } | 222 | } |
| 222 | #else | 223 | #else |
| 223 | static size_t rpc_pton6(const char *buf, const size_t buflen, | 224 | static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen, |
| 224 | struct sockaddr *sap, const size_t salen) | 225 | struct sockaddr *sap, const size_t salen) |
| 225 | { | 226 | { |
| 226 | return 0; | 227 | return 0; |
| @@ -229,6 +230,7 @@ static size_t rpc_pton6(const char *buf, const size_t buflen, | |||
| 229 | 230 | ||
| 230 | /** | 231 | /** |
| 231 | * rpc_pton - Construct a sockaddr in @sap | 232 | * rpc_pton - Construct a sockaddr in @sap |
| 233 | * @net: applicable network namespace | ||
| 232 | * @buf: C string containing presentation format IP address | 234 | * @buf: C string containing presentation format IP address |
| 233 | * @buflen: length of presentation address in bytes | 235 | * @buflen: length of presentation address in bytes |
| 234 | * @sap: buffer into which to plant socket address | 236 | * @sap: buffer into which to plant socket address |
| @@ -241,14 +243,14 @@ static size_t rpc_pton6(const char *buf, const size_t buflen, | |||
| 241 | * socket address, if successful. Returns zero if an error | 243 | * socket address, if successful. Returns zero if an error |
| 242 | * occurred. | 244 | * occurred. |
| 243 | */ | 245 | */ |
| 244 | size_t rpc_pton(const char *buf, const size_t buflen, | 246 | size_t rpc_pton(struct net *net, const char *buf, const size_t buflen, |
| 245 | struct sockaddr *sap, const size_t salen) | 247 | struct sockaddr *sap, const size_t salen) |
| 246 | { | 248 | { |
| 247 | unsigned int i; | 249 | unsigned int i; |
| 248 | 250 | ||
| 249 | for (i = 0; i < buflen; i++) | 251 | for (i = 0; i < buflen; i++) |
| 250 | if (buf[i] == ':') | 252 | if (buf[i] == ':') |
| 251 | return rpc_pton6(buf, buflen, sap, salen); | 253 | return rpc_pton6(net, buf, buflen, sap, salen); |
| 252 | return rpc_pton4(buf, buflen, sap, salen); | 254 | return rpc_pton4(buf, buflen, sap, salen); |
| 253 | } | 255 | } |
| 254 | EXPORT_SYMBOL_GPL(rpc_pton); | 256 | EXPORT_SYMBOL_GPL(rpc_pton); |
| @@ -295,6 +297,7 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags) | |||
| 295 | 297 | ||
| 296 | /** | 298 | /** |
| 297 | * rpc_uaddr2sockaddr - convert a universal address to a socket address. | 299 | * rpc_uaddr2sockaddr - convert a universal address to a socket address. |
| 300 | * @net: applicable network namespace | ||
| 298 | * @uaddr: C string containing universal address to convert | 301 | * @uaddr: C string containing universal address to convert |
| 299 | * @uaddr_len: length of universal address string | 302 | * @uaddr_len: length of universal address string |
| 300 | * @sap: buffer into which to plant socket address | 303 | * @sap: buffer into which to plant socket address |
| @@ -306,8 +309,9 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags) | |||
| 306 | * Returns the size of the socket address if successful; otherwise | 309 | * Returns the size of the socket address if successful; otherwise |
| 307 | * zero is returned. | 310 | * zero is returned. |
| 308 | */ | 311 | */ |
| 309 | size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, | 312 | size_t rpc_uaddr2sockaddr(struct net *net, const char *uaddr, |
| 310 | struct sockaddr *sap, const size_t salen) | 313 | const size_t uaddr_len, struct sockaddr *sap, |
| 314 | const size_t salen) | ||
| 311 | { | 315 | { |
| 312 | char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; | 316 | char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; |
| 313 | unsigned long portlo, porthi; | 317 | unsigned long portlo, porthi; |
| @@ -339,7 +343,7 @@ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, | |||
| 339 | port = (unsigned short)((porthi << 8) | portlo); | 343 | port = (unsigned short)((porthi << 8) | portlo); |
| 340 | 344 | ||
| 341 | *c = '\0'; | 345 | *c = '\0'; |
| 342 | if (rpc_pton(buf, strlen(buf), sap, salen) == 0) | 346 | if (rpc_pton(net, buf, strlen(buf), sap, salen) == 0) |
| 343 | return 0; | 347 | return 0; |
| 344 | 348 | ||
| 345 | switch (sap->sa_family) { | 349 | switch (sap->sa_family) { |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index affa631ac1ab..d3ad81f8da5b 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -81,7 +81,7 @@ struct gss_auth { | |||
| 81 | * mechanism (for example, "krb5") and exists for | 81 | * mechanism (for example, "krb5") and exists for |
| 82 | * backwards-compatibility with older gssd's. | 82 | * backwards-compatibility with older gssd's. |
| 83 | */ | 83 | */ |
| 84 | struct dentry *dentry[2]; | 84 | struct rpc_pipe *pipe[2]; |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | /* pipe_version >= 0 if and only if someone has a pipe open. */ | 87 | /* pipe_version >= 0 if and only if someone has a pipe open. */ |
| @@ -112,7 +112,7 @@ gss_put_ctx(struct gss_cl_ctx *ctx) | |||
| 112 | /* gss_cred_set_ctx: | 112 | /* gss_cred_set_ctx: |
| 113 | * called by gss_upcall_callback and gss_create_upcall in order | 113 | * called by gss_upcall_callback and gss_create_upcall in order |
| 114 | * to set the gss context. The actual exchange of an old context | 114 | * to set the gss context. The actual exchange of an old context |
| 115 | * and a new one is protected by the inode->i_lock. | 115 | * and a new one is protected by the pipe->lock. |
| 116 | */ | 116 | */ |
| 117 | static void | 117 | static void |
| 118 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) | 118 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) |
| @@ -251,7 +251,7 @@ struct gss_upcall_msg { | |||
| 251 | struct rpc_pipe_msg msg; | 251 | struct rpc_pipe_msg msg; |
| 252 | struct list_head list; | 252 | struct list_head list; |
| 253 | struct gss_auth *auth; | 253 | struct gss_auth *auth; |
| 254 | struct rpc_inode *inode; | 254 | struct rpc_pipe *pipe; |
| 255 | struct rpc_wait_queue rpc_waitqueue; | 255 | struct rpc_wait_queue rpc_waitqueue; |
| 256 | wait_queue_head_t waitqueue; | 256 | wait_queue_head_t waitqueue; |
| 257 | struct gss_cl_ctx *ctx; | 257 | struct gss_cl_ctx *ctx; |
| @@ -294,10 +294,10 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) | |||
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | static struct gss_upcall_msg * | 296 | static struct gss_upcall_msg * |
| 297 | __gss_find_upcall(struct rpc_inode *rpci, uid_t uid) | 297 | __gss_find_upcall(struct rpc_pipe *pipe, uid_t uid) |
| 298 | { | 298 | { |
| 299 | struct gss_upcall_msg *pos; | 299 | struct gss_upcall_msg *pos; |
| 300 | list_for_each_entry(pos, &rpci->in_downcall, list) { | 300 | list_for_each_entry(pos, &pipe->in_downcall, list) { |
| 301 | if (pos->uid != uid) | 301 | if (pos->uid != uid) |
| 302 | continue; | 302 | continue; |
| 303 | atomic_inc(&pos->count); | 303 | atomic_inc(&pos->count); |
| @@ -315,18 +315,17 @@ __gss_find_upcall(struct rpc_inode *rpci, uid_t uid) | |||
| 315 | static inline struct gss_upcall_msg * | 315 | static inline struct gss_upcall_msg * |
| 316 | gss_add_msg(struct gss_upcall_msg *gss_msg) | 316 | gss_add_msg(struct gss_upcall_msg *gss_msg) |
| 317 | { | 317 | { |
| 318 | struct rpc_inode *rpci = gss_msg->inode; | 318 | struct rpc_pipe *pipe = gss_msg->pipe; |
| 319 | struct inode *inode = &rpci->vfs_inode; | ||
| 320 | struct gss_upcall_msg *old; | 319 | struct gss_upcall_msg *old; |
| 321 | 320 | ||
| 322 | spin_lock(&inode->i_lock); | 321 | spin_lock(&pipe->lock); |
| 323 | old = __gss_find_upcall(rpci, gss_msg->uid); | 322 | old = __gss_find_upcall(pipe, gss_msg->uid); |
| 324 | if (old == NULL) { | 323 | if (old == NULL) { |
| 325 | atomic_inc(&gss_msg->count); | 324 | atomic_inc(&gss_msg->count); |
| 326 | list_add(&gss_msg->list, &rpci->in_downcall); | 325 | list_add(&gss_msg->list, &pipe->in_downcall); |
| 327 | } else | 326 | } else |
| 328 | gss_msg = old; | 327 | gss_msg = old; |
| 329 | spin_unlock(&inode->i_lock); | 328 | spin_unlock(&pipe->lock); |
| 330 | return gss_msg; | 329 | return gss_msg; |
| 331 | } | 330 | } |
| 332 | 331 | ||
| @@ -342,14 +341,14 @@ __gss_unhash_msg(struct gss_upcall_msg *gss_msg) | |||
| 342 | static void | 341 | static void |
| 343 | gss_unhash_msg(struct gss_upcall_msg *gss_msg) | 342 | gss_unhash_msg(struct gss_upcall_msg *gss_msg) |
| 344 | { | 343 | { |
| 345 | struct inode *inode = &gss_msg->inode->vfs_inode; | 344 | struct rpc_pipe *pipe = gss_msg->pipe; |
| 346 | 345 | ||
| 347 | if (list_empty(&gss_msg->list)) | 346 | if (list_empty(&gss_msg->list)) |
| 348 | return; | 347 | return; |
| 349 | spin_lock(&inode->i_lock); | 348 | spin_lock(&pipe->lock); |
| 350 | if (!list_empty(&gss_msg->list)) | 349 | if (!list_empty(&gss_msg->list)) |
| 351 | __gss_unhash_msg(gss_msg); | 350 | __gss_unhash_msg(gss_msg); |
| 352 | spin_unlock(&inode->i_lock); | 351 | spin_unlock(&pipe->lock); |
| 353 | } | 352 | } |
| 354 | 353 | ||
| 355 | static void | 354 | static void |
| @@ -376,11 +375,11 @@ gss_upcall_callback(struct rpc_task *task) | |||
| 376 | struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred, | 375 | struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred, |
| 377 | struct gss_cred, gc_base); | 376 | struct gss_cred, gc_base); |
| 378 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; | 377 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; |
| 379 | struct inode *inode = &gss_msg->inode->vfs_inode; | 378 | struct rpc_pipe *pipe = gss_msg->pipe; |
| 380 | 379 | ||
| 381 | spin_lock(&inode->i_lock); | 380 | spin_lock(&pipe->lock); |
| 382 | gss_handle_downcall_result(gss_cred, gss_msg); | 381 | gss_handle_downcall_result(gss_cred, gss_msg); |
| 383 | spin_unlock(&inode->i_lock); | 382 | spin_unlock(&pipe->lock); |
| 384 | task->tk_status = gss_msg->msg.errno; | 383 | task->tk_status = gss_msg->msg.errno; |
| 385 | gss_release_msg(gss_msg); | 384 | gss_release_msg(gss_msg); |
| 386 | } | 385 | } |
| @@ -450,7 +449,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, | |||
| 450 | kfree(gss_msg); | 449 | kfree(gss_msg); |
| 451 | return ERR_PTR(vers); | 450 | return ERR_PTR(vers); |
| 452 | } | 451 | } |
| 453 | gss_msg->inode = RPC_I(gss_auth->dentry[vers]->d_inode); | 452 | gss_msg->pipe = gss_auth->pipe[vers]; |
| 454 | INIT_LIST_HEAD(&gss_msg->list); | 453 | INIT_LIST_HEAD(&gss_msg->list); |
| 455 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); | 454 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); |
| 456 | init_waitqueue_head(&gss_msg->waitqueue); | 455 | init_waitqueue_head(&gss_msg->waitqueue); |
| @@ -474,8 +473,7 @@ gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cr | |||
| 474 | return gss_new; | 473 | return gss_new; |
| 475 | gss_msg = gss_add_msg(gss_new); | 474 | gss_msg = gss_add_msg(gss_new); |
| 476 | if (gss_msg == gss_new) { | 475 | if (gss_msg == gss_new) { |
| 477 | struct inode *inode = &gss_new->inode->vfs_inode; | 476 | int res = rpc_queue_upcall(gss_new->pipe, &gss_new->msg); |
| 478 | int res = rpc_queue_upcall(inode, &gss_new->msg); | ||
| 479 | if (res) { | 477 | if (res) { |
| 480 | gss_unhash_msg(gss_new); | 478 | gss_unhash_msg(gss_new); |
| 481 | gss_msg = ERR_PTR(res); | 479 | gss_msg = ERR_PTR(res); |
| @@ -506,7 +504,7 @@ gss_refresh_upcall(struct rpc_task *task) | |||
| 506 | struct gss_cred *gss_cred = container_of(cred, | 504 | struct gss_cred *gss_cred = container_of(cred, |
| 507 | struct gss_cred, gc_base); | 505 | struct gss_cred, gc_base); |
| 508 | struct gss_upcall_msg *gss_msg; | 506 | struct gss_upcall_msg *gss_msg; |
| 509 | struct inode *inode; | 507 | struct rpc_pipe *pipe; |
| 510 | int err = 0; | 508 | int err = 0; |
| 511 | 509 | ||
| 512 | dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, | 510 | dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, |
| @@ -524,8 +522,8 @@ gss_refresh_upcall(struct rpc_task *task) | |||
| 524 | err = PTR_ERR(gss_msg); | 522 | err = PTR_ERR(gss_msg); |
| 525 | goto out; | 523 | goto out; |
| 526 | } | 524 | } |
| 527 | inode = &gss_msg->inode->vfs_inode; | 525 | pipe = gss_msg->pipe; |
| 528 | spin_lock(&inode->i_lock); | 526 | spin_lock(&pipe->lock); |
| 529 | if (gss_cred->gc_upcall != NULL) | 527 | if (gss_cred->gc_upcall != NULL) |
| 530 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); | 528 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); |
| 531 | else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { | 529 | else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { |
| @@ -538,7 +536,7 @@ gss_refresh_upcall(struct rpc_task *task) | |||
| 538 | gss_handle_downcall_result(gss_cred, gss_msg); | 536 | gss_handle_downcall_result(gss_cred, gss_msg); |
| 539 | err = gss_msg->msg.errno; | 537 | err = gss_msg->msg.errno; |
| 540 | } | 538 | } |
| 541 | spin_unlock(&inode->i_lock); | 539 | spin_unlock(&pipe->lock); |
| 542 | gss_release_msg(gss_msg); | 540 | gss_release_msg(gss_msg); |
| 543 | out: | 541 | out: |
| 544 | dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n", | 542 | dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n", |
| @@ -549,7 +547,7 @@ out: | |||
| 549 | static inline int | 547 | static inline int |
| 550 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | 548 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) |
| 551 | { | 549 | { |
| 552 | struct inode *inode; | 550 | struct rpc_pipe *pipe; |
| 553 | struct rpc_cred *cred = &gss_cred->gc_base; | 551 | struct rpc_cred *cred = &gss_cred->gc_base; |
| 554 | struct gss_upcall_msg *gss_msg; | 552 | struct gss_upcall_msg *gss_msg; |
| 555 | DEFINE_WAIT(wait); | 553 | DEFINE_WAIT(wait); |
| @@ -573,14 +571,14 @@ retry: | |||
| 573 | err = PTR_ERR(gss_msg); | 571 | err = PTR_ERR(gss_msg); |
| 574 | goto out; | 572 | goto out; |
| 575 | } | 573 | } |
| 576 | inode = &gss_msg->inode->vfs_inode; | 574 | pipe = gss_msg->pipe; |
| 577 | for (;;) { | 575 | for (;;) { |
| 578 | prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE); | 576 | prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE); |
| 579 | spin_lock(&inode->i_lock); | 577 | spin_lock(&pipe->lock); |
| 580 | if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { | 578 | if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { |
| 581 | break; | 579 | break; |
| 582 | } | 580 | } |
| 583 | spin_unlock(&inode->i_lock); | 581 | spin_unlock(&pipe->lock); |
| 584 | if (fatal_signal_pending(current)) { | 582 | if (fatal_signal_pending(current)) { |
| 585 | err = -ERESTARTSYS; | 583 | err = -ERESTARTSYS; |
| 586 | goto out_intr; | 584 | goto out_intr; |
| @@ -591,7 +589,7 @@ retry: | |||
| 591 | gss_cred_set_ctx(cred, gss_msg->ctx); | 589 | gss_cred_set_ctx(cred, gss_msg->ctx); |
| 592 | else | 590 | else |
| 593 | err = gss_msg->msg.errno; | 591 | err = gss_msg->msg.errno; |
| 594 | spin_unlock(&inode->i_lock); | 592 | spin_unlock(&pipe->lock); |
| 595 | out_intr: | 593 | out_intr: |
| 596 | finish_wait(&gss_msg->waitqueue, &wait); | 594 | finish_wait(&gss_msg->waitqueue, &wait); |
| 597 | gss_release_msg(gss_msg); | 595 | gss_release_msg(gss_msg); |
| @@ -609,7 +607,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
| 609 | const void *p, *end; | 607 | const void *p, *end; |
| 610 | void *buf; | 608 | void *buf; |
| 611 | struct gss_upcall_msg *gss_msg; | 609 | struct gss_upcall_msg *gss_msg; |
| 612 | struct inode *inode = filp->f_path.dentry->d_inode; | 610 | struct rpc_pipe *pipe = RPC_I(filp->f_dentry->d_inode)->pipe; |
| 613 | struct gss_cl_ctx *ctx; | 611 | struct gss_cl_ctx *ctx; |
| 614 | uid_t uid; | 612 | uid_t uid; |
| 615 | ssize_t err = -EFBIG; | 613 | ssize_t err = -EFBIG; |
| @@ -639,14 +637,14 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
| 639 | 637 | ||
| 640 | err = -ENOENT; | 638 | err = -ENOENT; |
| 641 | /* Find a matching upcall */ | 639 | /* Find a matching upcall */ |
| 642 | spin_lock(&inode->i_lock); | 640 | spin_lock(&pipe->lock); |
| 643 | gss_msg = __gss_find_upcall(RPC_I(inode), uid); | 641 | gss_msg = __gss_find_upcall(pipe, uid); |
| 644 | if (gss_msg == NULL) { | 642 | if (gss_msg == NULL) { |
| 645 | spin_unlock(&inode->i_lock); | 643 | spin_unlock(&pipe->lock); |
| 646 | goto err_put_ctx; | 644 | goto err_put_ctx; |
| 647 | } | 645 | } |
| 648 | list_del_init(&gss_msg->list); | 646 | list_del_init(&gss_msg->list); |
| 649 | spin_unlock(&inode->i_lock); | 647 | spin_unlock(&pipe->lock); |
| 650 | 648 | ||
| 651 | p = gss_fill_context(p, end, ctx, gss_msg->auth->mech); | 649 | p = gss_fill_context(p, end, ctx, gss_msg->auth->mech); |
| 652 | if (IS_ERR(p)) { | 650 | if (IS_ERR(p)) { |
| @@ -674,9 +672,9 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
| 674 | err = mlen; | 672 | err = mlen; |
| 675 | 673 | ||
| 676 | err_release_msg: | 674 | err_release_msg: |
| 677 | spin_lock(&inode->i_lock); | 675 | spin_lock(&pipe->lock); |
| 678 | __gss_unhash_msg(gss_msg); | 676 | __gss_unhash_msg(gss_msg); |
| 679 | spin_unlock(&inode->i_lock); | 677 | spin_unlock(&pipe->lock); |
| 680 | gss_release_msg(gss_msg); | 678 | gss_release_msg(gss_msg); |
| 681 | err_put_ctx: | 679 | err_put_ctx: |
| 682 | gss_put_ctx(ctx); | 680 | gss_put_ctx(ctx); |
| @@ -722,23 +720,23 @@ static int gss_pipe_open_v1(struct inode *inode) | |||
| 722 | static void | 720 | static void |
| 723 | gss_pipe_release(struct inode *inode) | 721 | gss_pipe_release(struct inode *inode) |
| 724 | { | 722 | { |
| 725 | struct rpc_inode *rpci = RPC_I(inode); | 723 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; |
| 726 | struct gss_upcall_msg *gss_msg; | 724 | struct gss_upcall_msg *gss_msg; |
| 727 | 725 | ||
| 728 | restart: | 726 | restart: |
| 729 | spin_lock(&inode->i_lock); | 727 | spin_lock(&pipe->lock); |
| 730 | list_for_each_entry(gss_msg, &rpci->in_downcall, list) { | 728 | list_for_each_entry(gss_msg, &pipe->in_downcall, list) { |
| 731 | 729 | ||
| 732 | if (!list_empty(&gss_msg->msg.list)) | 730 | if (!list_empty(&gss_msg->msg.list)) |
| 733 | continue; | 731 | continue; |
| 734 | gss_msg->msg.errno = -EPIPE; | 732 | gss_msg->msg.errno = -EPIPE; |
| 735 | atomic_inc(&gss_msg->count); | 733 | atomic_inc(&gss_msg->count); |
| 736 | __gss_unhash_msg(gss_msg); | 734 | __gss_unhash_msg(gss_msg); |
| 737 | spin_unlock(&inode->i_lock); | 735 | spin_unlock(&pipe->lock); |
| 738 | gss_release_msg(gss_msg); | 736 | gss_release_msg(gss_msg); |
| 739 | goto restart; | 737 | goto restart; |
| 740 | } | 738 | } |
| 741 | spin_unlock(&inode->i_lock); | 739 | spin_unlock(&pipe->lock); |
| 742 | 740 | ||
| 743 | put_pipe_version(); | 741 | put_pipe_version(); |
| 744 | } | 742 | } |
| @@ -759,6 +757,75 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg) | |||
| 759 | } | 757 | } |
| 760 | } | 758 | } |
| 761 | 759 | ||
| 760 | static void gss_pipes_dentries_destroy(struct rpc_auth *auth) | ||
| 761 | { | ||
| 762 | struct gss_auth *gss_auth; | ||
| 763 | |||
| 764 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | ||
| 765 | if (gss_auth->pipe[0]->dentry) | ||
| 766 | rpc_unlink(gss_auth->pipe[0]->dentry); | ||
| 767 | if (gss_auth->pipe[1]->dentry) | ||
| 768 | rpc_unlink(gss_auth->pipe[1]->dentry); | ||
| 769 | } | ||
| 770 | |||
| 771 | static int gss_pipes_dentries_create(struct rpc_auth *auth) | ||
| 772 | { | ||
| 773 | int err; | ||
| 774 | struct gss_auth *gss_auth; | ||
| 775 | struct rpc_clnt *clnt; | ||
| 776 | |||
| 777 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | ||
| 778 | clnt = gss_auth->client; | ||
| 779 | |||
| 780 | gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry, | ||
| 781 | "gssd", | ||
| 782 | clnt, gss_auth->pipe[1]); | ||
| 783 | if (IS_ERR(gss_auth->pipe[1]->dentry)) | ||
| 784 | return PTR_ERR(gss_auth->pipe[1]->dentry); | ||
| 785 | gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry, | ||
| 786 | gss_auth->mech->gm_name, | ||
| 787 | clnt, gss_auth->pipe[0]); | ||
| 788 | if (IS_ERR(gss_auth->pipe[0]->dentry)) { | ||
| 789 | err = PTR_ERR(gss_auth->pipe[0]->dentry); | ||
| 790 | goto err_unlink_pipe_1; | ||
| 791 | } | ||
| 792 | return 0; | ||
| 793 | |||
| 794 | err_unlink_pipe_1: | ||
| 795 | rpc_unlink(gss_auth->pipe[1]->dentry); | ||
| 796 | return err; | ||
| 797 | } | ||
| 798 | |||
| 799 | static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, | ||
| 800 | struct rpc_auth *auth) | ||
| 801 | { | ||
| 802 | struct net *net = rpc_net_ns(clnt); | ||
| 803 | struct super_block *sb; | ||
| 804 | |||
| 805 | sb = rpc_get_sb_net(net); | ||
| 806 | if (sb) { | ||
| 807 | if (clnt->cl_dentry) | ||
| 808 | gss_pipes_dentries_destroy(auth); | ||
| 809 | rpc_put_sb_net(net); | ||
| 810 | } | ||
| 811 | } | ||
| 812 | |||
| 813 | static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt, | ||
| 814 | struct rpc_auth *auth) | ||
| 815 | { | ||
| 816 | struct net *net = rpc_net_ns(clnt); | ||
| 817 | struct super_block *sb; | ||
| 818 | int err = 0; | ||
| 819 | |||
| 820 | sb = rpc_get_sb_net(net); | ||
| 821 | if (sb) { | ||
| 822 | if (clnt->cl_dentry) | ||
| 823 | err = gss_pipes_dentries_create(auth); | ||
| 824 | rpc_put_sb_net(net); | ||
| 825 | } | ||
| 826 | return err; | ||
| 827 | } | ||
| 828 | |||
| 762 | /* | 829 | /* |
| 763 | * NOTE: we have the opportunity to use different | 830 | * NOTE: we have the opportunity to use different |
| 764 | * parameters based on the input flavor (which must be a pseudoflavor) | 831 | * parameters based on the input flavor (which must be a pseudoflavor) |
| @@ -801,32 +868,33 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
| 801 | * that we supported only the old pipe. So we instead create | 868 | * that we supported only the old pipe. So we instead create |
| 802 | * the new pipe first. | 869 | * the new pipe first. |
| 803 | */ | 870 | */ |
| 804 | gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_path.dentry, | 871 | gss_auth->pipe[1] = rpc_mkpipe_data(&gss_upcall_ops_v1, |
| 805 | "gssd", | 872 | RPC_PIPE_WAIT_FOR_OPEN); |
| 806 | clnt, &gss_upcall_ops_v1, | 873 | if (IS_ERR(gss_auth->pipe[1])) { |
| 807 | RPC_PIPE_WAIT_FOR_OPEN); | 874 | err = PTR_ERR(gss_auth->pipe[1]); |
| 808 | if (IS_ERR(gss_auth->dentry[1])) { | ||
| 809 | err = PTR_ERR(gss_auth->dentry[1]); | ||
| 810 | goto err_put_mech; | 875 | goto err_put_mech; |
| 811 | } | 876 | } |
| 812 | 877 | ||
| 813 | gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_path.dentry, | 878 | gss_auth->pipe[0] = rpc_mkpipe_data(&gss_upcall_ops_v0, |
| 814 | gss_auth->mech->gm_name, | 879 | RPC_PIPE_WAIT_FOR_OPEN); |
| 815 | clnt, &gss_upcall_ops_v0, | 880 | if (IS_ERR(gss_auth->pipe[0])) { |
| 816 | RPC_PIPE_WAIT_FOR_OPEN); | 881 | err = PTR_ERR(gss_auth->pipe[0]); |
| 817 | if (IS_ERR(gss_auth->dentry[0])) { | 882 | goto err_destroy_pipe_1; |
| 818 | err = PTR_ERR(gss_auth->dentry[0]); | ||
| 819 | goto err_unlink_pipe_1; | ||
| 820 | } | 883 | } |
| 884 | err = gss_pipes_dentries_create_net(clnt, auth); | ||
| 885 | if (err) | ||
| 886 | goto err_destroy_pipe_0; | ||
| 821 | err = rpcauth_init_credcache(auth); | 887 | err = rpcauth_init_credcache(auth); |
| 822 | if (err) | 888 | if (err) |
| 823 | goto err_unlink_pipe_0; | 889 | goto err_unlink_pipes; |
| 824 | 890 | ||
| 825 | return auth; | 891 | return auth; |
| 826 | err_unlink_pipe_0: | 892 | err_unlink_pipes: |
| 827 | rpc_unlink(gss_auth->dentry[0]); | 893 | gss_pipes_dentries_destroy_net(clnt, auth); |
| 828 | err_unlink_pipe_1: | 894 | err_destroy_pipe_0: |
| 829 | rpc_unlink(gss_auth->dentry[1]); | 895 | rpc_destroy_pipe_data(gss_auth->pipe[0]); |
| 896 | err_destroy_pipe_1: | ||
| 897 | rpc_destroy_pipe_data(gss_auth->pipe[1]); | ||
| 830 | err_put_mech: | 898 | err_put_mech: |
| 831 | gss_mech_put(gss_auth->mech); | 899 | gss_mech_put(gss_auth->mech); |
| 832 | err_free: | 900 | err_free: |
| @@ -839,8 +907,9 @@ out_dec: | |||
| 839 | static void | 907 | static void |
| 840 | gss_free(struct gss_auth *gss_auth) | 908 | gss_free(struct gss_auth *gss_auth) |
| 841 | { | 909 | { |
| 842 | rpc_unlink(gss_auth->dentry[1]); | 910 | gss_pipes_dentries_destroy_net(gss_auth->client, &gss_auth->rpc_auth); |
| 843 | rpc_unlink(gss_auth->dentry[0]); | 911 | rpc_destroy_pipe_data(gss_auth->pipe[0]); |
| 912 | rpc_destroy_pipe_data(gss_auth->pipe[1]); | ||
| 844 | gss_mech_put(gss_auth->mech); | 913 | gss_mech_put(gss_auth->mech); |
| 845 | 914 | ||
| 846 | kfree(gss_auth); | 915 | kfree(gss_auth); |
| @@ -1547,7 +1616,9 @@ static const struct rpc_authops authgss_ops = { | |||
| 1547 | .create = gss_create, | 1616 | .create = gss_create, |
| 1548 | .destroy = gss_destroy, | 1617 | .destroy = gss_destroy, |
| 1549 | .lookup_cred = gss_lookup_cred, | 1618 | .lookup_cred = gss_lookup_cred, |
| 1550 | .crcreate = gss_create_cred | 1619 | .crcreate = gss_create_cred, |
| 1620 | .pipes_create = gss_pipes_dentries_create, | ||
| 1621 | .pipes_destroy = gss_pipes_dentries_destroy, | ||
| 1551 | }; | 1622 | }; |
| 1552 | 1623 | ||
| 1553 | static const struct rpc_credops gss_credops = { | 1624 | static const struct rpc_credops gss_credops = { |
| @@ -1591,6 +1662,21 @@ static const struct rpc_pipe_ops gss_upcall_ops_v1 = { | |||
| 1591 | .release_pipe = gss_pipe_release, | 1662 | .release_pipe = gss_pipe_release, |
| 1592 | }; | 1663 | }; |
| 1593 | 1664 | ||
| 1665 | static __net_init int rpcsec_gss_init_net(struct net *net) | ||
| 1666 | { | ||
| 1667 | return gss_svc_init_net(net); | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | static __net_exit void rpcsec_gss_exit_net(struct net *net) | ||
| 1671 | { | ||
| 1672 | gss_svc_shutdown_net(net); | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | static struct pernet_operations rpcsec_gss_net_ops = { | ||
| 1676 | .init = rpcsec_gss_init_net, | ||
| 1677 | .exit = rpcsec_gss_exit_net, | ||
| 1678 | }; | ||
| 1679 | |||
| 1594 | /* | 1680 | /* |
| 1595 | * Initialize RPCSEC_GSS module | 1681 | * Initialize RPCSEC_GSS module |
| 1596 | */ | 1682 | */ |
| @@ -1604,8 +1690,13 @@ static int __init init_rpcsec_gss(void) | |||
| 1604 | err = gss_svc_init(); | 1690 | err = gss_svc_init(); |
| 1605 | if (err) | 1691 | if (err) |
| 1606 | goto out_unregister; | 1692 | goto out_unregister; |
| 1693 | err = register_pernet_subsys(&rpcsec_gss_net_ops); | ||
| 1694 | if (err) | ||
| 1695 | goto out_svc_exit; | ||
| 1607 | rpc_init_wait_queue(&pipe_version_rpc_waitqueue, "gss pipe version"); | 1696 | rpc_init_wait_queue(&pipe_version_rpc_waitqueue, "gss pipe version"); |
| 1608 | return 0; | 1697 | return 0; |
| 1698 | out_svc_exit: | ||
| 1699 | gss_svc_shutdown(); | ||
| 1609 | out_unregister: | 1700 | out_unregister: |
| 1610 | rpcauth_unregister(&authgss_ops); | 1701 | rpcauth_unregister(&authgss_ops); |
| 1611 | out: | 1702 | out: |
| @@ -1614,6 +1705,7 @@ out: | |||
| 1614 | 1705 | ||
| 1615 | static void __exit exit_rpcsec_gss(void) | 1706 | static void __exit exit_rpcsec_gss(void) |
| 1616 | { | 1707 | { |
| 1708 | unregister_pernet_subsys(&rpcsec_gss_net_ops); | ||
| 1617 | gss_svc_shutdown(); | 1709 | gss_svc_shutdown(); |
| 1618 | rpcauth_unregister(&authgss_ops); | 1710 | rpcauth_unregister(&authgss_ops); |
| 1619 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 1711 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 9576f35ab701..0f43e894bc0a 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c | |||
| @@ -600,11 +600,14 @@ gss_krb5_cts_crypt(struct crypto_blkcipher *cipher, struct xdr_buf *buf, | |||
| 600 | u32 ret; | 600 | u32 ret; |
| 601 | struct scatterlist sg[1]; | 601 | struct scatterlist sg[1]; |
| 602 | struct blkcipher_desc desc = { .tfm = cipher, .info = iv }; | 602 | struct blkcipher_desc desc = { .tfm = cipher, .info = iv }; |
| 603 | u8 data[crypto_blkcipher_blocksize(cipher) * 2]; | 603 | u8 data[GSS_KRB5_MAX_BLOCKSIZE * 2]; |
| 604 | struct page **save_pages; | 604 | struct page **save_pages; |
| 605 | u32 len = buf->len - offset; | 605 | u32 len = buf->len - offset; |
| 606 | 606 | ||
| 607 | BUG_ON(len > crypto_blkcipher_blocksize(cipher) * 2); | 607 | if (len > ARRAY_SIZE(data)) { |
| 608 | WARN_ON(0); | ||
| 609 | return -ENOMEM; | ||
| 610 | } | ||
| 608 | 611 | ||
| 609 | /* | 612 | /* |
| 610 | * For encryption, we want to read from the cleartext | 613 | * For encryption, we want to read from the cleartext |
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 8c67890de427..8eff8c32d1b9 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |||
| @@ -344,7 +344,7 @@ out_err: | |||
| 344 | return PTR_ERR(p); | 344 | return PTR_ERR(p); |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | struct crypto_blkcipher * | 347 | static struct crypto_blkcipher * |
| 348 | context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key) | 348 | context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key) |
| 349 | { | 349 | { |
| 350 | struct crypto_blkcipher *cp; | 350 | struct crypto_blkcipher *cp; |
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index d7941eab7796..62ae3273186c 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c | |||
| @@ -159,7 +159,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text, | |||
| 159 | return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; | 159 | return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | u32 | 162 | static u32 |
| 163 | gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text, | 163 | gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text, |
| 164 | struct xdr_netobj *token) | 164 | struct xdr_netobj *token) |
| 165 | { | 165 | { |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 8d0f7d3c71c8..1600cfb1618c 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
| @@ -48,6 +48,8 @@ | |||
| 48 | #include <linux/sunrpc/svcauth_gss.h> | 48 | #include <linux/sunrpc/svcauth_gss.h> |
| 49 | #include <linux/sunrpc/cache.h> | 49 | #include <linux/sunrpc/cache.h> |
| 50 | 50 | ||
| 51 | #include "../netns.h" | ||
| 52 | |||
| 51 | #ifdef RPC_DEBUG | 53 | #ifdef RPC_DEBUG |
| 52 | # define RPCDBG_FACILITY RPCDBG_AUTH | 54 | # define RPCDBG_FACILITY RPCDBG_AUTH |
| 53 | #endif | 55 | #endif |
| @@ -75,10 +77,8 @@ struct rsi { | |||
| 75 | int major_status, minor_status; | 77 | int major_status, minor_status; |
| 76 | }; | 78 | }; |
| 77 | 79 | ||
| 78 | static struct cache_head *rsi_table[RSI_HASHMAX]; | 80 | static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old); |
| 79 | static struct cache_detail rsi_cache; | 81 | static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item); |
| 80 | static struct rsi *rsi_update(struct rsi *new, struct rsi *old); | ||
| 81 | static struct rsi *rsi_lookup(struct rsi *item); | ||
| 82 | 82 | ||
| 83 | static void rsi_free(struct rsi *rsii) | 83 | static void rsi_free(struct rsi *rsii) |
| 84 | { | 84 | { |
| @@ -216,7 +216,7 @@ static int rsi_parse(struct cache_detail *cd, | |||
| 216 | if (dup_to_netobj(&rsii.in_token, buf, len)) | 216 | if (dup_to_netobj(&rsii.in_token, buf, len)) |
| 217 | goto out; | 217 | goto out; |
| 218 | 218 | ||
| 219 | rsip = rsi_lookup(&rsii); | 219 | rsip = rsi_lookup(cd, &rsii); |
| 220 | if (!rsip) | 220 | if (!rsip) |
| 221 | goto out; | 221 | goto out; |
| 222 | 222 | ||
| @@ -258,21 +258,20 @@ static int rsi_parse(struct cache_detail *cd, | |||
| 258 | if (dup_to_netobj(&rsii.out_token, buf, len)) | 258 | if (dup_to_netobj(&rsii.out_token, buf, len)) |
| 259 | goto out; | 259 | goto out; |
| 260 | rsii.h.expiry_time = expiry; | 260 | rsii.h.expiry_time = expiry; |
| 261 | rsip = rsi_update(&rsii, rsip); | 261 | rsip = rsi_update(cd, &rsii, rsip); |
| 262 | status = 0; | 262 | status = 0; |
| 263 | out: | 263 | out: |
| 264 | rsi_free(&rsii); | 264 | rsi_free(&rsii); |
| 265 | if (rsip) | 265 | if (rsip) |
| 266 | cache_put(&rsip->h, &rsi_cache); | 266 | cache_put(&rsip->h, cd); |
| 267 | else | 267 | else |
| 268 | status = -ENOMEM; | 268 | status = -ENOMEM; |
| 269 | return status; | 269 | return status; |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | static struct cache_detail rsi_cache = { | 272 | static struct cache_detail rsi_cache_template = { |
| 273 | .owner = THIS_MODULE, | 273 | .owner = THIS_MODULE, |
| 274 | .hash_size = RSI_HASHMAX, | 274 | .hash_size = RSI_HASHMAX, |
| 275 | .hash_table = rsi_table, | ||
| 276 | .name = "auth.rpcsec.init", | 275 | .name = "auth.rpcsec.init", |
| 277 | .cache_put = rsi_put, | 276 | .cache_put = rsi_put, |
| 278 | .cache_upcall = rsi_upcall, | 277 | .cache_upcall = rsi_upcall, |
| @@ -283,24 +282,24 @@ static struct cache_detail rsi_cache = { | |||
| 283 | .alloc = rsi_alloc, | 282 | .alloc = rsi_alloc, |
| 284 | }; | 283 | }; |
| 285 | 284 | ||
| 286 | static struct rsi *rsi_lookup(struct rsi *item) | 285 | static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item) |
| 287 | { | 286 | { |
| 288 | struct cache_head *ch; | 287 | struct cache_head *ch; |
| 289 | int hash = rsi_hash(item); | 288 | int hash = rsi_hash(item); |
| 290 | 289 | ||
| 291 | ch = sunrpc_cache_lookup(&rsi_cache, &item->h, hash); | 290 | ch = sunrpc_cache_lookup(cd, &item->h, hash); |
| 292 | if (ch) | 291 | if (ch) |
| 293 | return container_of(ch, struct rsi, h); | 292 | return container_of(ch, struct rsi, h); |
| 294 | else | 293 | else |
| 295 | return NULL; | 294 | return NULL; |
| 296 | } | 295 | } |
| 297 | 296 | ||
| 298 | static struct rsi *rsi_update(struct rsi *new, struct rsi *old) | 297 | static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old) |
| 299 | { | 298 | { |
| 300 | struct cache_head *ch; | 299 | struct cache_head *ch; |
| 301 | int hash = rsi_hash(new); | 300 | int hash = rsi_hash(new); |
| 302 | 301 | ||
| 303 | ch = sunrpc_cache_update(&rsi_cache, &new->h, | 302 | ch = sunrpc_cache_update(cd, &new->h, |
| 304 | &old->h, hash); | 303 | &old->h, hash); |
| 305 | if (ch) | 304 | if (ch) |
| 306 | return container_of(ch, struct rsi, h); | 305 | return container_of(ch, struct rsi, h); |
| @@ -339,10 +338,8 @@ struct rsc { | |||
| 339 | char *client_name; | 338 | char *client_name; |
| 340 | }; | 339 | }; |
| 341 | 340 | ||
| 342 | static struct cache_head *rsc_table[RSC_HASHMAX]; | 341 | static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old); |
| 343 | static struct cache_detail rsc_cache; | 342 | static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item); |
| 344 | static struct rsc *rsc_update(struct rsc *new, struct rsc *old); | ||
| 345 | static struct rsc *rsc_lookup(struct rsc *item); | ||
| 346 | 343 | ||
| 347 | static void rsc_free(struct rsc *rsci) | 344 | static void rsc_free(struct rsc *rsci) |
| 348 | { | 345 | { |
| @@ -444,7 +441,7 @@ static int rsc_parse(struct cache_detail *cd, | |||
| 444 | if (expiry == 0) | 441 | if (expiry == 0) |
| 445 | goto out; | 442 | goto out; |
| 446 | 443 | ||
| 447 | rscp = rsc_lookup(&rsci); | 444 | rscp = rsc_lookup(cd, &rsci); |
| 448 | if (!rscp) | 445 | if (!rscp) |
| 449 | goto out; | 446 | goto out; |
| 450 | 447 | ||
| @@ -506,22 +503,21 @@ static int rsc_parse(struct cache_detail *cd, | |||
| 506 | 503 | ||
| 507 | } | 504 | } |
| 508 | rsci.h.expiry_time = expiry; | 505 | rsci.h.expiry_time = expiry; |
| 509 | rscp = rsc_update(&rsci, rscp); | 506 | rscp = rsc_update(cd, &rsci, rscp); |
| 510 | status = 0; | 507 | status = 0; |
| 511 | out: | 508 | out: |
| 512 | gss_mech_put(gm); | 509 | gss_mech_put(gm); |
| 513 | rsc_free(&rsci); | 510 | rsc_free(&rsci); |
| 514 | if (rscp) | 511 | if (rscp) |
| 515 | cache_put(&rscp->h, &rsc_cache); | 512 | cache_put(&rscp->h, cd); |
| 516 | else | 513 | else |
| 517 | status = -ENOMEM; | 514 | status = -ENOMEM; |
| 518 | return status; | 515 | return status; |
| 519 | } | 516 | } |
| 520 | 517 | ||
| 521 | static struct cache_detail rsc_cache = { | 518 | static struct cache_detail rsc_cache_template = { |
| 522 | .owner = THIS_MODULE, | 519 | .owner = THIS_MODULE, |
| 523 | .hash_size = RSC_HASHMAX, | 520 | .hash_size = RSC_HASHMAX, |
| 524 | .hash_table = rsc_table, | ||
| 525 | .name = "auth.rpcsec.context", | 521 | .name = "auth.rpcsec.context", |
| 526 | .cache_put = rsc_put, | 522 | .cache_put = rsc_put, |
| 527 | .cache_parse = rsc_parse, | 523 | .cache_parse = rsc_parse, |
| @@ -531,24 +527,24 @@ static struct cache_detail rsc_cache = { | |||
| 531 | .alloc = rsc_alloc, | 527 | .alloc = rsc_alloc, |
| 532 | }; | 528 | }; |
| 533 | 529 | ||
| 534 | static struct rsc *rsc_lookup(struct rsc *item) | 530 | static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item) |
| 535 | { | 531 | { |
| 536 | struct cache_head *ch; | 532 | struct cache_head *ch; |
| 537 | int hash = rsc_hash(item); | 533 | int hash = rsc_hash(item); |
| 538 | 534 | ||
| 539 | ch = sunrpc_cache_lookup(&rsc_cache, &item->h, hash); | 535 | ch = sunrpc_cache_lookup(cd, &item->h, hash); |
| 540 | if (ch) | 536 | if (ch) |
| 541 | return container_of(ch, struct rsc, h); | 537 | return container_of(ch, struct rsc, h); |
| 542 | else | 538 | else |
| 543 | return NULL; | 539 | return NULL; |
| 544 | } | 540 | } |
| 545 | 541 | ||
| 546 | static struct rsc *rsc_update(struct rsc *new, struct rsc *old) | 542 | static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old) |
| 547 | { | 543 | { |
| 548 | struct cache_head *ch; | 544 | struct cache_head *ch; |
| 549 | int hash = rsc_hash(new); | 545 | int hash = rsc_hash(new); |
| 550 | 546 | ||
| 551 | ch = sunrpc_cache_update(&rsc_cache, &new->h, | 547 | ch = sunrpc_cache_update(cd, &new->h, |
| 552 | &old->h, hash); | 548 | &old->h, hash); |
| 553 | if (ch) | 549 | if (ch) |
| 554 | return container_of(ch, struct rsc, h); | 550 | return container_of(ch, struct rsc, h); |
| @@ -558,7 +554,7 @@ static struct rsc *rsc_update(struct rsc *new, struct rsc *old) | |||
| 558 | 554 | ||
| 559 | 555 | ||
| 560 | static struct rsc * | 556 | static struct rsc * |
| 561 | gss_svc_searchbyctx(struct xdr_netobj *handle) | 557 | gss_svc_searchbyctx(struct cache_detail *cd, struct xdr_netobj *handle) |
| 562 | { | 558 | { |
| 563 | struct rsc rsci; | 559 | struct rsc rsci; |
| 564 | struct rsc *found; | 560 | struct rsc *found; |
| @@ -566,11 +562,11 @@ gss_svc_searchbyctx(struct xdr_netobj *handle) | |||
| 566 | memset(&rsci, 0, sizeof(rsci)); | 562 | memset(&rsci, 0, sizeof(rsci)); |
| 567 | if (dup_to_netobj(&rsci.handle, handle->data, handle->len)) | 563 | if (dup_to_netobj(&rsci.handle, handle->data, handle->len)) |
| 568 | return NULL; | 564 | return NULL; |
| 569 | found = rsc_lookup(&rsci); | 565 | found = rsc_lookup(cd, &rsci); |
| 570 | rsc_free(&rsci); | 566 | rsc_free(&rsci); |
| 571 | if (!found) | 567 | if (!found) |
| 572 | return NULL; | 568 | return NULL; |
| 573 | if (cache_check(&rsc_cache, &found->h, NULL)) | 569 | if (cache_check(cd, &found->h, NULL)) |
| 574 | return NULL; | 570 | return NULL; |
| 575 | return found; | 571 | return found; |
| 576 | } | 572 | } |
| @@ -968,20 +964,20 @@ svcauth_gss_set_client(struct svc_rqst *rqstp) | |||
| 968 | } | 964 | } |
| 969 | 965 | ||
| 970 | static inline int | 966 | static inline int |
| 971 | gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip) | 967 | gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi *rsip) |
| 972 | { | 968 | { |
| 973 | struct rsc *rsci; | 969 | struct rsc *rsci; |
| 974 | int rc; | 970 | int rc; |
| 975 | 971 | ||
| 976 | if (rsip->major_status != GSS_S_COMPLETE) | 972 | if (rsip->major_status != GSS_S_COMPLETE) |
| 977 | return gss_write_null_verf(rqstp); | 973 | return gss_write_null_verf(rqstp); |
| 978 | rsci = gss_svc_searchbyctx(&rsip->out_handle); | 974 | rsci = gss_svc_searchbyctx(cd, &rsip->out_handle); |
| 979 | if (rsci == NULL) { | 975 | if (rsci == NULL) { |
| 980 | rsip->major_status = GSS_S_NO_CONTEXT; | 976 | rsip->major_status = GSS_S_NO_CONTEXT; |
| 981 | return gss_write_null_verf(rqstp); | 977 | return gss_write_null_verf(rqstp); |
| 982 | } | 978 | } |
| 983 | rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN); | 979 | rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN); |
| 984 | cache_put(&rsci->h, &rsc_cache); | 980 | cache_put(&rsci->h, cd); |
| 985 | return rc; | 981 | return rc; |
| 986 | } | 982 | } |
| 987 | 983 | ||
| @@ -1000,6 +996,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp, | |||
| 1000 | struct xdr_netobj tmpobj; | 996 | struct xdr_netobj tmpobj; |
| 1001 | struct rsi *rsip, rsikey; | 997 | struct rsi *rsip, rsikey; |
| 1002 | int ret; | 998 | int ret; |
| 999 | struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id); | ||
| 1003 | 1000 | ||
| 1004 | /* Read the verifier; should be NULL: */ | 1001 | /* Read the verifier; should be NULL: */ |
| 1005 | *authp = rpc_autherr_badverf; | 1002 | *authp = rpc_autherr_badverf; |
| @@ -1028,17 +1025,17 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp, | |||
| 1028 | } | 1025 | } |
| 1029 | 1026 | ||
| 1030 | /* Perform upcall, or find upcall result: */ | 1027 | /* Perform upcall, or find upcall result: */ |
| 1031 | rsip = rsi_lookup(&rsikey); | 1028 | rsip = rsi_lookup(sn->rsi_cache, &rsikey); |
| 1032 | rsi_free(&rsikey); | 1029 | rsi_free(&rsikey); |
| 1033 | if (!rsip) | 1030 | if (!rsip) |
| 1034 | return SVC_CLOSE; | 1031 | return SVC_CLOSE; |
| 1035 | if (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0) | 1032 | if (cache_check(sn->rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0) |
| 1036 | /* No upcall result: */ | 1033 | /* No upcall result: */ |
| 1037 | return SVC_CLOSE; | 1034 | return SVC_CLOSE; |
| 1038 | 1035 | ||
| 1039 | ret = SVC_CLOSE; | 1036 | ret = SVC_CLOSE; |
| 1040 | /* Got an answer to the upcall; use it: */ | 1037 | /* Got an answer to the upcall; use it: */ |
| 1041 | if (gss_write_init_verf(rqstp, rsip)) | 1038 | if (gss_write_init_verf(sn->rsc_cache, rqstp, rsip)) |
| 1042 | goto out; | 1039 | goto out; |
| 1043 | if (resv->iov_len + 4 > PAGE_SIZE) | 1040 | if (resv->iov_len + 4 > PAGE_SIZE) |
| 1044 | goto out; | 1041 | goto out; |
| @@ -1055,7 +1052,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp, | |||
| 1055 | 1052 | ||
| 1056 | ret = SVC_COMPLETE; | 1053 | ret = SVC_COMPLETE; |
| 1057 | out: | 1054 | out: |
| 1058 | cache_put(&rsip->h, &rsi_cache); | 1055 | cache_put(&rsip->h, sn->rsi_cache); |
| 1059 | return ret; | 1056 | return ret; |
| 1060 | } | 1057 | } |
| 1061 | 1058 | ||
| @@ -1079,6 +1076,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
| 1079 | __be32 *rpcstart; | 1076 | __be32 *rpcstart; |
| 1080 | __be32 *reject_stat = resv->iov_base + resv->iov_len; | 1077 | __be32 *reject_stat = resv->iov_base + resv->iov_len; |
| 1081 | int ret; | 1078 | int ret; |
| 1079 | struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id); | ||
| 1082 | 1080 | ||
| 1083 | dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n", | 1081 | dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n", |
| 1084 | argv->iov_len); | 1082 | argv->iov_len); |
| @@ -1129,7 +1127,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
| 1129 | case RPC_GSS_PROC_DESTROY: | 1127 | case RPC_GSS_PROC_DESTROY: |
| 1130 | /* Look up the context, and check the verifier: */ | 1128 | /* Look up the context, and check the verifier: */ |
| 1131 | *authp = rpcsec_gsserr_credproblem; | 1129 | *authp = rpcsec_gsserr_credproblem; |
| 1132 | rsci = gss_svc_searchbyctx(&gc->gc_ctx); | 1130 | rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx); |
| 1133 | if (!rsci) | 1131 | if (!rsci) |
| 1134 | goto auth_err; | 1132 | goto auth_err; |
| 1135 | switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) { | 1133 | switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) { |
| @@ -1209,7 +1207,7 @@ drop: | |||
| 1209 | ret = SVC_DROP; | 1207 | ret = SVC_DROP; |
| 1210 | out: | 1208 | out: |
| 1211 | if (rsci) | 1209 | if (rsci) |
| 1212 | cache_put(&rsci->h, &rsc_cache); | 1210 | cache_put(&rsci->h, sn->rsc_cache); |
| 1213 | return ret; | 1211 | return ret; |
| 1214 | } | 1212 | } |
| 1215 | 1213 | ||
| @@ -1362,6 +1360,7 @@ svcauth_gss_release(struct svc_rqst *rqstp) | |||
| 1362 | struct rpc_gss_wire_cred *gc = &gsd->clcred; | 1360 | struct rpc_gss_wire_cred *gc = &gsd->clcred; |
| 1363 | struct xdr_buf *resbuf = &rqstp->rq_res; | 1361 | struct xdr_buf *resbuf = &rqstp->rq_res; |
| 1364 | int stat = -EINVAL; | 1362 | int stat = -EINVAL; |
| 1363 | struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id); | ||
| 1365 | 1364 | ||
| 1366 | if (gc->gc_proc != RPC_GSS_PROC_DATA) | 1365 | if (gc->gc_proc != RPC_GSS_PROC_DATA) |
| 1367 | goto out; | 1366 | goto out; |
| @@ -1404,7 +1403,7 @@ out_err: | |||
| 1404 | put_group_info(rqstp->rq_cred.cr_group_info); | 1403 | put_group_info(rqstp->rq_cred.cr_group_info); |
| 1405 | rqstp->rq_cred.cr_group_info = NULL; | 1404 | rqstp->rq_cred.cr_group_info = NULL; |
| 1406 | if (gsd->rsci) | 1405 | if (gsd->rsci) |
| 1407 | cache_put(&gsd->rsci->h, &rsc_cache); | 1406 | cache_put(&gsd->rsci->h, sn->rsc_cache); |
| 1408 | gsd->rsci = NULL; | 1407 | gsd->rsci = NULL; |
| 1409 | 1408 | ||
| 1410 | return stat; | 1409 | return stat; |
| @@ -1429,30 +1428,96 @@ static struct auth_ops svcauthops_gss = { | |||
| 1429 | .set_client = svcauth_gss_set_client, | 1428 | .set_client = svcauth_gss_set_client, |
| 1430 | }; | 1429 | }; |
| 1431 | 1430 | ||
| 1431 | static int rsi_cache_create_net(struct net *net) | ||
| 1432 | { | ||
| 1433 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1434 | struct cache_detail *cd; | ||
| 1435 | int err; | ||
| 1436 | |||
| 1437 | cd = cache_create_net(&rsi_cache_template, net); | ||
| 1438 | if (IS_ERR(cd)) | ||
| 1439 | return PTR_ERR(cd); | ||
| 1440 | err = cache_register_net(cd, net); | ||
| 1441 | if (err) { | ||
| 1442 | cache_destroy_net(cd, net); | ||
| 1443 | return err; | ||
| 1444 | } | ||
| 1445 | sn->rsi_cache = cd; | ||
| 1446 | return 0; | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | static void rsi_cache_destroy_net(struct net *net) | ||
| 1450 | { | ||
| 1451 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1452 | struct cache_detail *cd = sn->rsi_cache; | ||
| 1453 | |||
| 1454 | sn->rsi_cache = NULL; | ||
| 1455 | cache_purge(cd); | ||
| 1456 | cache_unregister_net(cd, net); | ||
| 1457 | cache_destroy_net(cd, net); | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | static int rsc_cache_create_net(struct net *net) | ||
| 1461 | { | ||
| 1462 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1463 | struct cache_detail *cd; | ||
| 1464 | int err; | ||
| 1465 | |||
| 1466 | cd = cache_create_net(&rsc_cache_template, net); | ||
| 1467 | if (IS_ERR(cd)) | ||
| 1468 | return PTR_ERR(cd); | ||
| 1469 | err = cache_register_net(cd, net); | ||
| 1470 | if (err) { | ||
| 1471 | cache_destroy_net(cd, net); | ||
| 1472 | return err; | ||
| 1473 | } | ||
| 1474 | sn->rsc_cache = cd; | ||
| 1475 | return 0; | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | static void rsc_cache_destroy_net(struct net *net) | ||
| 1479 | { | ||
| 1480 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1481 | struct cache_detail *cd = sn->rsc_cache; | ||
| 1482 | |||
| 1483 | sn->rsc_cache = NULL; | ||
| 1484 | cache_purge(cd); | ||
| 1485 | cache_unregister_net(cd, net); | ||
| 1486 | cache_destroy_net(cd, net); | ||
| 1487 | } | ||
| 1488 | |||
| 1432 | int | 1489 | int |
| 1433 | gss_svc_init(void) | 1490 | gss_svc_init_net(struct net *net) |
| 1434 | { | 1491 | { |
| 1435 | int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); | 1492 | int rv; |
| 1493 | |||
| 1494 | rv = rsc_cache_create_net(net); | ||
| 1436 | if (rv) | 1495 | if (rv) |
| 1437 | return rv; | 1496 | return rv; |
| 1438 | rv = cache_register(&rsc_cache); | 1497 | rv = rsi_cache_create_net(net); |
| 1439 | if (rv) | 1498 | if (rv) |
| 1440 | goto out1; | 1499 | goto out1; |
| 1441 | rv = cache_register(&rsi_cache); | ||
| 1442 | if (rv) | ||
| 1443 | goto out2; | ||
| 1444 | return 0; | 1500 | return 0; |
| 1445 | out2: | ||
| 1446 | cache_unregister(&rsc_cache); | ||
| 1447 | out1: | 1501 | out1: |
| 1448 | svc_auth_unregister(RPC_AUTH_GSS); | 1502 | rsc_cache_destroy_net(net); |
| 1449 | return rv; | 1503 | return rv; |
| 1450 | } | 1504 | } |
| 1451 | 1505 | ||
| 1452 | void | 1506 | void |
| 1507 | gss_svc_shutdown_net(struct net *net) | ||
| 1508 | { | ||
| 1509 | rsi_cache_destroy_net(net); | ||
| 1510 | rsc_cache_destroy_net(net); | ||
| 1511 | } | ||
| 1512 | |||
| 1513 | int | ||
| 1514 | gss_svc_init(void) | ||
| 1515 | { | ||
| 1516 | return svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss); | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | void | ||
| 1453 | gss_svc_shutdown(void) | 1520 | gss_svc_shutdown(void) |
| 1454 | { | 1521 | { |
| 1455 | cache_unregister(&rsc_cache); | ||
| 1456 | cache_unregister(&rsi_cache); | ||
| 1457 | svc_auth_unregister(RPC_AUTH_GSS); | 1522 | svc_auth_unregister(RPC_AUTH_GSS); |
| 1458 | } | 1523 | } |
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 3ad435a14ada..31def68a0f6e 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c | |||
| @@ -25,6 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/sunrpc/xprt.h> | 26 | #include <linux/sunrpc/xprt.h> |
| 27 | #include <linux/export.h> | 27 | #include <linux/export.h> |
| 28 | #include <linux/sunrpc/bc_xprt.h> | ||
| 28 | 29 | ||
| 29 | #ifdef RPC_DEBUG | 30 | #ifdef RPC_DEBUG |
| 30 | #define RPCDBG_FACILITY RPCDBG_TRANS | 31 | #define RPCDBG_FACILITY RPCDBG_TRANS |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 465df9ae1046..f21ece088764 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -344,7 +344,7 @@ static int current_index; | |||
| 344 | static void do_cache_clean(struct work_struct *work); | 344 | static void do_cache_clean(struct work_struct *work); |
| 345 | static struct delayed_work cache_cleaner; | 345 | static struct delayed_work cache_cleaner; |
| 346 | 346 | ||
| 347 | static void sunrpc_init_cache_detail(struct cache_detail *cd) | 347 | void sunrpc_init_cache_detail(struct cache_detail *cd) |
| 348 | { | 348 | { |
| 349 | rwlock_init(&cd->hash_lock); | 349 | rwlock_init(&cd->hash_lock); |
| 350 | INIT_LIST_HEAD(&cd->queue); | 350 | INIT_LIST_HEAD(&cd->queue); |
| @@ -360,8 +360,9 @@ static void sunrpc_init_cache_detail(struct cache_detail *cd) | |||
| 360 | /* start the cleaning process */ | 360 | /* start the cleaning process */ |
| 361 | schedule_delayed_work(&cache_cleaner, 0); | 361 | schedule_delayed_work(&cache_cleaner, 0); |
| 362 | } | 362 | } |
| 363 | EXPORT_SYMBOL_GPL(sunrpc_init_cache_detail); | ||
| 363 | 364 | ||
| 364 | static void sunrpc_destroy_cache_detail(struct cache_detail *cd) | 365 | void sunrpc_destroy_cache_detail(struct cache_detail *cd) |
| 365 | { | 366 | { |
| 366 | cache_purge(cd); | 367 | cache_purge(cd); |
| 367 | spin_lock(&cache_list_lock); | 368 | spin_lock(&cache_list_lock); |
| @@ -384,6 +385,7 @@ static void sunrpc_destroy_cache_detail(struct cache_detail *cd) | |||
| 384 | out: | 385 | out: |
| 385 | printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name); | 386 | printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name); |
| 386 | } | 387 | } |
| 388 | EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail); | ||
| 387 | 389 | ||
| 388 | /* clean cache tries to find something to clean | 390 | /* clean cache tries to find something to clean |
| 389 | * and cleans it. | 391 | * and cleans it. |
| @@ -1643,12 +1645,6 @@ int cache_register_net(struct cache_detail *cd, struct net *net) | |||
| 1643 | } | 1645 | } |
| 1644 | EXPORT_SYMBOL_GPL(cache_register_net); | 1646 | EXPORT_SYMBOL_GPL(cache_register_net); |
| 1645 | 1647 | ||
| 1646 | int cache_register(struct cache_detail *cd) | ||
| 1647 | { | ||
| 1648 | return cache_register_net(cd, &init_net); | ||
| 1649 | } | ||
| 1650 | EXPORT_SYMBOL_GPL(cache_register); | ||
| 1651 | |||
| 1652 | void cache_unregister_net(struct cache_detail *cd, struct net *net) | 1648 | void cache_unregister_net(struct cache_detail *cd, struct net *net) |
| 1653 | { | 1649 | { |
| 1654 | remove_cache_proc_entries(cd, net); | 1650 | remove_cache_proc_entries(cd, net); |
| @@ -1656,11 +1652,31 @@ void cache_unregister_net(struct cache_detail *cd, struct net *net) | |||
| 1656 | } | 1652 | } |
| 1657 | EXPORT_SYMBOL_GPL(cache_unregister_net); | 1653 | EXPORT_SYMBOL_GPL(cache_unregister_net); |
| 1658 | 1654 | ||
| 1659 | void cache_unregister(struct cache_detail *cd) | 1655 | struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net) |
| 1656 | { | ||
| 1657 | struct cache_detail *cd; | ||
| 1658 | |||
| 1659 | cd = kmemdup(tmpl, sizeof(struct cache_detail), GFP_KERNEL); | ||
| 1660 | if (cd == NULL) | ||
| 1661 | return ERR_PTR(-ENOMEM); | ||
| 1662 | |||
| 1663 | cd->hash_table = kzalloc(cd->hash_size * sizeof(struct cache_head *), | ||
| 1664 | GFP_KERNEL); | ||
| 1665 | if (cd->hash_table == NULL) { | ||
| 1666 | kfree(cd); | ||
| 1667 | return ERR_PTR(-ENOMEM); | ||
| 1668 | } | ||
| 1669 | cd->net = net; | ||
| 1670 | return cd; | ||
| 1671 | } | ||
| 1672 | EXPORT_SYMBOL_GPL(cache_create_net); | ||
| 1673 | |||
| 1674 | void cache_destroy_net(struct cache_detail *cd, struct net *net) | ||
| 1660 | { | 1675 | { |
| 1661 | cache_unregister_net(cd, &init_net); | 1676 | kfree(cd->hash_table); |
| 1677 | kfree(cd); | ||
| 1662 | } | 1678 | } |
| 1663 | EXPORT_SYMBOL_GPL(cache_unregister); | 1679 | EXPORT_SYMBOL_GPL(cache_destroy_net); |
| 1664 | 1680 | ||
| 1665 | static ssize_t cache_read_pipefs(struct file *filp, char __user *buf, | 1681 | static ssize_t cache_read_pipefs(struct file *filp, char __user *buf, |
| 1666 | size_t count, loff_t *ppos) | 1682 | size_t count, loff_t *ppos) |
| @@ -1787,17 +1803,14 @@ int sunrpc_cache_register_pipefs(struct dentry *parent, | |||
| 1787 | struct dentry *dir; | 1803 | struct dentry *dir; |
| 1788 | int ret = 0; | 1804 | int ret = 0; |
| 1789 | 1805 | ||
| 1790 | sunrpc_init_cache_detail(cd); | ||
| 1791 | q.name = name; | 1806 | q.name = name; |
| 1792 | q.len = strlen(name); | 1807 | q.len = strlen(name); |
| 1793 | q.hash = full_name_hash(q.name, q.len); | 1808 | q.hash = full_name_hash(q.name, q.len); |
| 1794 | dir = rpc_create_cache_dir(parent, &q, umode, cd); | 1809 | dir = rpc_create_cache_dir(parent, &q, umode, cd); |
| 1795 | if (!IS_ERR(dir)) | 1810 | if (!IS_ERR(dir)) |
| 1796 | cd->u.pipefs.dir = dir; | 1811 | cd->u.pipefs.dir = dir; |
| 1797 | else { | 1812 | else |
| 1798 | sunrpc_destroy_cache_detail(cd); | ||
| 1799 | ret = PTR_ERR(dir); | 1813 | ret = PTR_ERR(dir); |
| 1800 | } | ||
| 1801 | return ret; | 1814 | return ret; |
| 1802 | } | 1815 | } |
| 1803 | EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs); | 1816 | EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs); |
| @@ -1806,7 +1819,6 @@ void sunrpc_cache_unregister_pipefs(struct cache_detail *cd) | |||
| 1806 | { | 1819 | { |
| 1807 | rpc_remove_cache_dir(cd->u.pipefs.dir); | 1820 | rpc_remove_cache_dir(cd->u.pipefs.dir); |
| 1808 | cd->u.pipefs.dir = NULL; | 1821 | cd->u.pipefs.dir = NULL; |
| 1809 | sunrpc_destroy_cache_detail(cd); | ||
| 1810 | } | 1822 | } |
| 1811 | EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs); | 1823 | EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs); |
| 1812 | 1824 | ||
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f0268ea7e711..7a4cb5fdc212 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -31,13 +31,16 @@ | |||
| 31 | #include <linux/in.h> | 31 | #include <linux/in.h> |
| 32 | #include <linux/in6.h> | 32 | #include <linux/in6.h> |
| 33 | #include <linux/un.h> | 33 | #include <linux/un.h> |
| 34 | #include <linux/rcupdate.h> | ||
| 34 | 35 | ||
| 35 | #include <linux/sunrpc/clnt.h> | 36 | #include <linux/sunrpc/clnt.h> |
| 36 | #include <linux/sunrpc/rpc_pipe_fs.h> | 37 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 37 | #include <linux/sunrpc/metrics.h> | 38 | #include <linux/sunrpc/metrics.h> |
| 38 | #include <linux/sunrpc/bc_xprt.h> | 39 | #include <linux/sunrpc/bc_xprt.h> |
| 40 | #include <trace/events/sunrpc.h> | ||
| 39 | 41 | ||
| 40 | #include "sunrpc.h" | 42 | #include "sunrpc.h" |
| 43 | #include "netns.h" | ||
| 41 | 44 | ||
| 42 | #ifdef RPC_DEBUG | 45 | #ifdef RPC_DEBUG |
| 43 | # define RPCDBG_FACILITY RPCDBG_CALL | 46 | # define RPCDBG_FACILITY RPCDBG_CALL |
| @@ -50,8 +53,6 @@ | |||
| 50 | /* | 53 | /* |
| 51 | * All RPC clients are linked into this list | 54 | * All RPC clients are linked into this list |
| 52 | */ | 55 | */ |
| 53 | static LIST_HEAD(all_clients); | ||
| 54 | static DEFINE_SPINLOCK(rpc_client_lock); | ||
| 55 | 56 | ||
| 56 | static DECLARE_WAIT_QUEUE_HEAD(destroy_wait); | 57 | static DECLARE_WAIT_QUEUE_HEAD(destroy_wait); |
| 57 | 58 | ||
| @@ -81,82 +82,191 @@ static int rpc_ping(struct rpc_clnt *clnt); | |||
| 81 | 82 | ||
| 82 | static void rpc_register_client(struct rpc_clnt *clnt) | 83 | static void rpc_register_client(struct rpc_clnt *clnt) |
| 83 | { | 84 | { |
| 84 | spin_lock(&rpc_client_lock); | 85 | struct net *net = rpc_net_ns(clnt); |
| 85 | list_add(&clnt->cl_clients, &all_clients); | 86 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
| 86 | spin_unlock(&rpc_client_lock); | 87 | |
| 88 | spin_lock(&sn->rpc_client_lock); | ||
| 89 | list_add(&clnt->cl_clients, &sn->all_clients); | ||
| 90 | spin_unlock(&sn->rpc_client_lock); | ||
| 87 | } | 91 | } |
| 88 | 92 | ||
| 89 | static void rpc_unregister_client(struct rpc_clnt *clnt) | 93 | static void rpc_unregister_client(struct rpc_clnt *clnt) |
| 90 | { | 94 | { |
| 91 | spin_lock(&rpc_client_lock); | 95 | struct net *net = rpc_net_ns(clnt); |
| 96 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 97 | |||
| 98 | spin_lock(&sn->rpc_client_lock); | ||
| 92 | list_del(&clnt->cl_clients); | 99 | list_del(&clnt->cl_clients); |
| 93 | spin_unlock(&rpc_client_lock); | 100 | spin_unlock(&sn->rpc_client_lock); |
| 94 | } | 101 | } |
| 95 | 102 | ||
| 96 | static int | 103 | static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) |
| 97 | rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) | 104 | { |
| 105 | if (clnt->cl_dentry) { | ||
| 106 | if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy) | ||
| 107 | clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth); | ||
| 108 | rpc_remove_client_dir(clnt->cl_dentry); | ||
| 109 | } | ||
| 110 | clnt->cl_dentry = NULL; | ||
| 111 | } | ||
| 112 | |||
| 113 | static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) | ||
| 114 | { | ||
| 115 | struct net *net = rpc_net_ns(clnt); | ||
| 116 | struct super_block *pipefs_sb; | ||
| 117 | |||
| 118 | pipefs_sb = rpc_get_sb_net(net); | ||
| 119 | if (pipefs_sb) { | ||
| 120 | __rpc_clnt_remove_pipedir(clnt); | ||
| 121 | rpc_put_sb_net(net); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, | ||
| 126 | struct rpc_clnt *clnt, | ||
| 127 | const char *dir_name) | ||
| 98 | { | 128 | { |
| 99 | static uint32_t clntid; | 129 | static uint32_t clntid; |
| 100 | struct path path, dir; | ||
| 101 | char name[15]; | 130 | char name[15]; |
| 102 | struct qstr q = { | 131 | struct qstr q = { |
| 103 | .name = name, | 132 | .name = name, |
| 104 | }; | 133 | }; |
| 134 | struct dentry *dir, *dentry; | ||
| 105 | int error; | 135 | int error; |
| 106 | 136 | ||
| 107 | clnt->cl_path.mnt = ERR_PTR(-ENOENT); | 137 | dir = rpc_d_lookup_sb(sb, dir_name); |
| 108 | clnt->cl_path.dentry = ERR_PTR(-ENOENT); | 138 | if (dir == NULL) |
| 109 | if (dir_name == NULL) | 139 | return dir; |
| 110 | return 0; | ||
| 111 | |||
| 112 | path.mnt = rpc_get_mount(); | ||
| 113 | if (IS_ERR(path.mnt)) | ||
| 114 | return PTR_ERR(path.mnt); | ||
| 115 | error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &dir); | ||
| 116 | if (error) | ||
| 117 | goto err; | ||
| 118 | |||
| 119 | for (;;) { | 140 | for (;;) { |
| 120 | q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); | 141 | q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); |
| 121 | name[sizeof(name) - 1] = '\0'; | 142 | name[sizeof(name) - 1] = '\0'; |
| 122 | q.hash = full_name_hash(q.name, q.len); | 143 | q.hash = full_name_hash(q.name, q.len); |
| 123 | path.dentry = rpc_create_client_dir(dir.dentry, &q, clnt); | 144 | dentry = rpc_create_client_dir(dir, &q, clnt); |
| 124 | if (!IS_ERR(path.dentry)) | 145 | if (!IS_ERR(dentry)) |
| 125 | break; | 146 | break; |
| 126 | error = PTR_ERR(path.dentry); | 147 | error = PTR_ERR(dentry); |
| 127 | if (error != -EEXIST) { | 148 | if (error != -EEXIST) { |
| 128 | printk(KERN_INFO "RPC: Couldn't create pipefs entry" | 149 | printk(KERN_INFO "RPC: Couldn't create pipefs entry" |
| 129 | " %s/%s, error %d\n", | 150 | " %s/%s, error %d\n", |
| 130 | dir_name, name, error); | 151 | dir_name, name, error); |
| 131 | goto err_path_put; | 152 | break; |
| 132 | } | 153 | } |
| 133 | } | 154 | } |
| 134 | path_put(&dir); | 155 | dput(dir); |
| 135 | clnt->cl_path = path; | 156 | return dentry; |
| 157 | } | ||
| 158 | |||
| 159 | static int | ||
| 160 | rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name) | ||
| 161 | { | ||
| 162 | struct net *net = rpc_net_ns(clnt); | ||
| 163 | struct super_block *pipefs_sb; | ||
| 164 | struct dentry *dentry; | ||
| 165 | |||
| 166 | clnt->cl_dentry = NULL; | ||
| 167 | if (dir_name == NULL) | ||
| 168 | return 0; | ||
| 169 | pipefs_sb = rpc_get_sb_net(net); | ||
| 170 | if (!pipefs_sb) | ||
| 171 | return 0; | ||
| 172 | dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); | ||
| 173 | rpc_put_sb_net(net); | ||
| 174 | if (IS_ERR(dentry)) | ||
| 175 | return PTR_ERR(dentry); | ||
| 176 | clnt->cl_dentry = dentry; | ||
| 136 | return 0; | 177 | return 0; |
| 137 | err_path_put: | 178 | } |
| 138 | path_put(&dir); | 179 | |
| 139 | err: | 180 | static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, |
| 140 | rpc_put_mount(); | 181 | struct super_block *sb) |
| 182 | { | ||
| 183 | struct dentry *dentry; | ||
| 184 | int err = 0; | ||
| 185 | |||
| 186 | switch (event) { | ||
| 187 | case RPC_PIPEFS_MOUNT: | ||
| 188 | if (clnt->cl_program->pipe_dir_name == NULL) | ||
| 189 | break; | ||
| 190 | dentry = rpc_setup_pipedir_sb(sb, clnt, | ||
| 191 | clnt->cl_program->pipe_dir_name); | ||
| 192 | BUG_ON(dentry == NULL); | ||
| 193 | if (IS_ERR(dentry)) | ||
| 194 | return PTR_ERR(dentry); | ||
| 195 | clnt->cl_dentry = dentry; | ||
| 196 | if (clnt->cl_auth->au_ops->pipes_create) { | ||
| 197 | err = clnt->cl_auth->au_ops->pipes_create(clnt->cl_auth); | ||
| 198 | if (err) | ||
| 199 | __rpc_clnt_remove_pipedir(clnt); | ||
| 200 | } | ||
| 201 | break; | ||
| 202 | case RPC_PIPEFS_UMOUNT: | ||
| 203 | __rpc_clnt_remove_pipedir(clnt); | ||
| 204 | break; | ||
| 205 | default: | ||
| 206 | printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event); | ||
| 207 | return -ENOTSUPP; | ||
| 208 | } | ||
| 209 | return err; | ||
| 210 | } | ||
| 211 | |||
| 212 | static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) | ||
| 213 | { | ||
| 214 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 215 | struct rpc_clnt *clnt; | ||
| 216 | |||
| 217 | spin_lock(&sn->rpc_client_lock); | ||
| 218 | list_for_each_entry(clnt, &sn->all_clients, cl_clients) { | ||
| 219 | if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) || | ||
| 220 | ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry)) | ||
| 221 | continue; | ||
| 222 | atomic_inc(&clnt->cl_count); | ||
| 223 | spin_unlock(&sn->rpc_client_lock); | ||
| 224 | return clnt; | ||
| 225 | } | ||
| 226 | spin_unlock(&sn->rpc_client_lock); | ||
| 227 | return NULL; | ||
| 228 | } | ||
| 229 | |||
| 230 | static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, | ||
| 231 | void *ptr) | ||
| 232 | { | ||
| 233 | struct super_block *sb = ptr; | ||
| 234 | struct rpc_clnt *clnt; | ||
| 235 | int error = 0; | ||
| 236 | |||
| 237 | while ((clnt = rpc_get_client_for_event(sb->s_fs_info, event))) { | ||
| 238 | error = __rpc_pipefs_event(clnt, event, sb); | ||
| 239 | rpc_release_client(clnt); | ||
| 240 | if (error) | ||
| 241 | break; | ||
| 242 | } | ||
| 141 | return error; | 243 | return error; |
| 142 | } | 244 | } |
| 143 | 245 | ||
| 246 | static struct notifier_block rpc_clients_block = { | ||
| 247 | .notifier_call = rpc_pipefs_event, | ||
| 248 | .priority = SUNRPC_PIPEFS_RPC_PRIO, | ||
| 249 | }; | ||
| 250 | |||
| 251 | int rpc_clients_notifier_register(void) | ||
| 252 | { | ||
| 253 | return rpc_pipefs_notifier_register(&rpc_clients_block); | ||
| 254 | } | ||
| 255 | |||
| 256 | void rpc_clients_notifier_unregister(void) | ||
| 257 | { | ||
| 258 | return rpc_pipefs_notifier_unregister(&rpc_clients_block); | ||
| 259 | } | ||
| 260 | |||
| 144 | static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) | 261 | static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) |
| 145 | { | 262 | { |
| 146 | struct rpc_program *program = args->program; | 263 | const struct rpc_program *program = args->program; |
| 147 | struct rpc_version *version; | 264 | const struct rpc_version *version; |
| 148 | struct rpc_clnt *clnt = NULL; | 265 | struct rpc_clnt *clnt = NULL; |
| 149 | struct rpc_auth *auth; | 266 | struct rpc_auth *auth; |
| 150 | int err; | 267 | int err; |
| 151 | size_t len; | ||
| 152 | 268 | ||
| 153 | /* sanity check the name before trying to print it */ | 269 | /* sanity check the name before trying to print it */ |
| 154 | err = -EINVAL; | ||
| 155 | len = strlen(args->servername); | ||
| 156 | if (len > RPC_MAXNETNAMELEN) | ||
| 157 | goto out_no_rpciod; | ||
| 158 | len++; | ||
| 159 | |||
| 160 | dprintk("RPC: creating %s client for %s (xprt %p)\n", | 270 | dprintk("RPC: creating %s client for %s (xprt %p)\n", |
| 161 | program->name, args->servername, xprt); | 271 | program->name, args->servername, xprt); |
| 162 | 272 | ||
| @@ -179,17 +289,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
| 179 | goto out_err; | 289 | goto out_err; |
| 180 | clnt->cl_parent = clnt; | 290 | clnt->cl_parent = clnt; |
| 181 | 291 | ||
| 182 | clnt->cl_server = clnt->cl_inline_name; | 292 | rcu_assign_pointer(clnt->cl_xprt, xprt); |
| 183 | if (len > sizeof(clnt->cl_inline_name)) { | ||
| 184 | char *buf = kmalloc(len, GFP_KERNEL); | ||
| 185 | if (buf != NULL) | ||
| 186 | clnt->cl_server = buf; | ||
| 187 | else | ||
| 188 | len = sizeof(clnt->cl_inline_name); | ||
| 189 | } | ||
| 190 | strlcpy(clnt->cl_server, args->servername, len); | ||
| 191 | |||
| 192 | clnt->cl_xprt = xprt; | ||
| 193 | clnt->cl_procinfo = version->procs; | 293 | clnt->cl_procinfo = version->procs; |
| 194 | clnt->cl_maxproc = version->nrprocs; | 294 | clnt->cl_maxproc = version->nrprocs; |
| 195 | clnt->cl_protname = program->name; | 295 | clnt->cl_protname = program->name; |
| @@ -204,7 +304,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
| 204 | INIT_LIST_HEAD(&clnt->cl_tasks); | 304 | INIT_LIST_HEAD(&clnt->cl_tasks); |
| 205 | spin_lock_init(&clnt->cl_lock); | 305 | spin_lock_init(&clnt->cl_lock); |
| 206 | 306 | ||
| 207 | if (!xprt_bound(clnt->cl_xprt)) | 307 | if (!xprt_bound(xprt)) |
| 208 | clnt->cl_autobind = 1; | 308 | clnt->cl_autobind = 1; |
| 209 | 309 | ||
| 210 | clnt->cl_timeout = xprt->timeout; | 310 | clnt->cl_timeout = xprt->timeout; |
| @@ -246,17 +346,12 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
| 246 | return clnt; | 346 | return clnt; |
| 247 | 347 | ||
| 248 | out_no_auth: | 348 | out_no_auth: |
| 249 | if (!IS_ERR(clnt->cl_path.dentry)) { | 349 | rpc_clnt_remove_pipedir(clnt); |
| 250 | rpc_remove_client_dir(clnt->cl_path.dentry); | ||
| 251 | rpc_put_mount(); | ||
| 252 | } | ||
| 253 | out_no_path: | 350 | out_no_path: |
| 254 | kfree(clnt->cl_principal); | 351 | kfree(clnt->cl_principal); |
| 255 | out_no_principal: | 352 | out_no_principal: |
| 256 | rpc_free_iostats(clnt->cl_metrics); | 353 | rpc_free_iostats(clnt->cl_metrics); |
| 257 | out_no_stats: | 354 | out_no_stats: |
| 258 | if (clnt->cl_server != clnt->cl_inline_name) | ||
| 259 | kfree(clnt->cl_server); | ||
| 260 | kfree(clnt); | 355 | kfree(clnt); |
| 261 | out_err: | 356 | out_err: |
| 262 | xprt_put(xprt); | 357 | xprt_put(xprt); |
| @@ -286,6 +381,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
| 286 | .srcaddr = args->saddress, | 381 | .srcaddr = args->saddress, |
| 287 | .dstaddr = args->address, | 382 | .dstaddr = args->address, |
| 288 | .addrlen = args->addrsize, | 383 | .addrlen = args->addrsize, |
| 384 | .servername = args->servername, | ||
| 289 | .bc_xprt = args->bc_xprt, | 385 | .bc_xprt = args->bc_xprt, |
| 290 | }; | 386 | }; |
| 291 | char servername[48]; | 387 | char servername[48]; |
| @@ -294,7 +390,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
| 294 | * If the caller chooses not to specify a hostname, whip | 390 | * If the caller chooses not to specify a hostname, whip |
| 295 | * up a string representation of the passed-in address. | 391 | * up a string representation of the passed-in address. |
| 296 | */ | 392 | */ |
| 297 | if (args->servername == NULL) { | 393 | if (xprtargs.servername == NULL) { |
| 298 | struct sockaddr_un *sun = | 394 | struct sockaddr_un *sun = |
| 299 | (struct sockaddr_un *)args->address; | 395 | (struct sockaddr_un *)args->address; |
| 300 | struct sockaddr_in *sin = | 396 | struct sockaddr_in *sin = |
| @@ -321,7 +417,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
| 321 | * address family isn't recognized. */ | 417 | * address family isn't recognized. */ |
| 322 | return ERR_PTR(-EINVAL); | 418 | return ERR_PTR(-EINVAL); |
| 323 | } | 419 | } |
| 324 | args->servername = servername; | 420 | xprtargs.servername = servername; |
| 325 | } | 421 | } |
| 326 | 422 | ||
| 327 | xprt = xprt_create_transport(&xprtargs); | 423 | xprt = xprt_create_transport(&xprtargs); |
| @@ -374,6 +470,7 @@ struct rpc_clnt * | |||
| 374 | rpc_clone_client(struct rpc_clnt *clnt) | 470 | rpc_clone_client(struct rpc_clnt *clnt) |
| 375 | { | 471 | { |
| 376 | struct rpc_clnt *new; | 472 | struct rpc_clnt *new; |
| 473 | struct rpc_xprt *xprt; | ||
| 377 | int err = -ENOMEM; | 474 | int err = -ENOMEM; |
| 378 | 475 | ||
| 379 | new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); | 476 | new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); |
| @@ -393,18 +490,25 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
| 393 | if (new->cl_principal == NULL) | 490 | if (new->cl_principal == NULL) |
| 394 | goto out_no_principal; | 491 | goto out_no_principal; |
| 395 | } | 492 | } |
| 493 | rcu_read_lock(); | ||
| 494 | xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); | ||
| 495 | rcu_read_unlock(); | ||
| 496 | if (xprt == NULL) | ||
| 497 | goto out_no_transport; | ||
| 498 | rcu_assign_pointer(new->cl_xprt, xprt); | ||
| 396 | atomic_set(&new->cl_count, 1); | 499 | atomic_set(&new->cl_count, 1); |
| 397 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); | 500 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); |
| 398 | if (err != 0) | 501 | if (err != 0) |
| 399 | goto out_no_path; | 502 | goto out_no_path; |
| 400 | if (new->cl_auth) | 503 | if (new->cl_auth) |
| 401 | atomic_inc(&new->cl_auth->au_count); | 504 | atomic_inc(&new->cl_auth->au_count); |
| 402 | xprt_get(clnt->cl_xprt); | ||
| 403 | atomic_inc(&clnt->cl_count); | 505 | atomic_inc(&clnt->cl_count); |
| 404 | rpc_register_client(new); | 506 | rpc_register_client(new); |
| 405 | rpciod_up(); | 507 | rpciod_up(); |
| 406 | return new; | 508 | return new; |
| 407 | out_no_path: | 509 | out_no_path: |
| 510 | xprt_put(xprt); | ||
| 511 | out_no_transport: | ||
| 408 | kfree(new->cl_principal); | 512 | kfree(new->cl_principal); |
| 409 | out_no_principal: | 513 | out_no_principal: |
| 410 | rpc_free_iostats(new->cl_metrics); | 514 | rpc_free_iostats(new->cl_metrics); |
| @@ -453,8 +557,9 @@ EXPORT_SYMBOL_GPL(rpc_killall_tasks); | |||
| 453 | */ | 557 | */ |
| 454 | void rpc_shutdown_client(struct rpc_clnt *clnt) | 558 | void rpc_shutdown_client(struct rpc_clnt *clnt) |
| 455 | { | 559 | { |
| 456 | dprintk("RPC: shutting down %s client for %s\n", | 560 | dprintk_rcu("RPC: shutting down %s client for %s\n", |
| 457 | clnt->cl_protname, clnt->cl_server); | 561 | clnt->cl_protname, |
| 562 | rcu_dereference(clnt->cl_xprt)->servername); | ||
| 458 | 563 | ||
| 459 | while (!list_empty(&clnt->cl_tasks)) { | 564 | while (!list_empty(&clnt->cl_tasks)) { |
| 460 | rpc_killall_tasks(clnt); | 565 | rpc_killall_tasks(clnt); |
| @@ -472,24 +577,17 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client); | |||
| 472 | static void | 577 | static void |
| 473 | rpc_free_client(struct rpc_clnt *clnt) | 578 | rpc_free_client(struct rpc_clnt *clnt) |
| 474 | { | 579 | { |
| 475 | dprintk("RPC: destroying %s client for %s\n", | 580 | dprintk_rcu("RPC: destroying %s client for %s\n", |
| 476 | clnt->cl_protname, clnt->cl_server); | 581 | clnt->cl_protname, |
| 477 | if (!IS_ERR(clnt->cl_path.dentry)) { | 582 | rcu_dereference(clnt->cl_xprt)->servername); |
| 478 | rpc_remove_client_dir(clnt->cl_path.dentry); | 583 | if (clnt->cl_parent != clnt) |
| 479 | rpc_put_mount(); | ||
| 480 | } | ||
| 481 | if (clnt->cl_parent != clnt) { | ||
| 482 | rpc_release_client(clnt->cl_parent); | 584 | rpc_release_client(clnt->cl_parent); |
| 483 | goto out_free; | ||
| 484 | } | ||
| 485 | if (clnt->cl_server != clnt->cl_inline_name) | ||
| 486 | kfree(clnt->cl_server); | ||
| 487 | out_free: | ||
| 488 | rpc_unregister_client(clnt); | 585 | rpc_unregister_client(clnt); |
| 586 | rpc_clnt_remove_pipedir(clnt); | ||
| 489 | rpc_free_iostats(clnt->cl_metrics); | 587 | rpc_free_iostats(clnt->cl_metrics); |
| 490 | kfree(clnt->cl_principal); | 588 | kfree(clnt->cl_principal); |
| 491 | clnt->cl_metrics = NULL; | 589 | clnt->cl_metrics = NULL; |
| 492 | xprt_put(clnt->cl_xprt); | 590 | xprt_put(rcu_dereference_raw(clnt->cl_xprt)); |
| 493 | rpciod_down(); | 591 | rpciod_down(); |
| 494 | kfree(clnt); | 592 | kfree(clnt); |
| 495 | } | 593 | } |
| @@ -542,11 +640,11 @@ rpc_release_client(struct rpc_clnt *clnt) | |||
| 542 | * The Sun NFSv2/v3 ACL protocol can do this. | 640 | * The Sun NFSv2/v3 ACL protocol can do this. |
| 543 | */ | 641 | */ |
| 544 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, | 642 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, |
| 545 | struct rpc_program *program, | 643 | const struct rpc_program *program, |
| 546 | u32 vers) | 644 | u32 vers) |
| 547 | { | 645 | { |
| 548 | struct rpc_clnt *clnt; | 646 | struct rpc_clnt *clnt; |
| 549 | struct rpc_version *version; | 647 | const struct rpc_version *version; |
| 550 | int err; | 648 | int err; |
| 551 | 649 | ||
| 552 | BUG_ON(vers >= program->nrvers || !program->version[vers]); | 650 | BUG_ON(vers >= program->nrvers || !program->version[vers]); |
| @@ -778,13 +876,18 @@ EXPORT_SYMBOL_GPL(rpc_call_start); | |||
| 778 | size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize) | 876 | size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize) |
| 779 | { | 877 | { |
| 780 | size_t bytes; | 878 | size_t bytes; |
| 781 | struct rpc_xprt *xprt = clnt->cl_xprt; | 879 | struct rpc_xprt *xprt; |
| 782 | 880 | ||
| 783 | bytes = sizeof(xprt->addr); | 881 | rcu_read_lock(); |
| 882 | xprt = rcu_dereference(clnt->cl_xprt); | ||
| 883 | |||
| 884 | bytes = xprt->addrlen; | ||
| 784 | if (bytes > bufsize) | 885 | if (bytes > bufsize) |
| 785 | bytes = bufsize; | 886 | bytes = bufsize; |
| 786 | memcpy(buf, &clnt->cl_xprt->addr, bytes); | 887 | memcpy(buf, &xprt->addr, bytes); |
| 787 | return xprt->addrlen; | 888 | rcu_read_unlock(); |
| 889 | |||
| 890 | return bytes; | ||
| 788 | } | 891 | } |
| 789 | EXPORT_SYMBOL_GPL(rpc_peeraddr); | 892 | EXPORT_SYMBOL_GPL(rpc_peeraddr); |
| 790 | 893 | ||
| @@ -793,11 +896,16 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr); | |||
| 793 | * @clnt: RPC client structure | 896 | * @clnt: RPC client structure |
| 794 | * @format: address format | 897 | * @format: address format |
| 795 | * | 898 | * |
| 899 | * NB: the lifetime of the memory referenced by the returned pointer is | ||
| 900 | * the same as the rpc_xprt itself. As long as the caller uses this | ||
| 901 | * pointer, it must hold the RCU read lock. | ||
| 796 | */ | 902 | */ |
| 797 | const char *rpc_peeraddr2str(struct rpc_clnt *clnt, | 903 | const char *rpc_peeraddr2str(struct rpc_clnt *clnt, |
| 798 | enum rpc_display_format_t format) | 904 | enum rpc_display_format_t format) |
| 799 | { | 905 | { |
| 800 | struct rpc_xprt *xprt = clnt->cl_xprt; | 906 | struct rpc_xprt *xprt; |
| 907 | |||
| 908 | xprt = rcu_dereference(clnt->cl_xprt); | ||
| 801 | 909 | ||
| 802 | if (xprt->address_strings[format] != NULL) | 910 | if (xprt->address_strings[format] != NULL) |
| 803 | return xprt->address_strings[format]; | 911 | return xprt->address_strings[format]; |
| @@ -806,17 +914,203 @@ const char *rpc_peeraddr2str(struct rpc_clnt *clnt, | |||
| 806 | } | 914 | } |
| 807 | EXPORT_SYMBOL_GPL(rpc_peeraddr2str); | 915 | EXPORT_SYMBOL_GPL(rpc_peeraddr2str); |
| 808 | 916 | ||
| 917 | static const struct sockaddr_in rpc_inaddr_loopback = { | ||
| 918 | .sin_family = AF_INET, | ||
| 919 | .sin_addr.s_addr = htonl(INADDR_ANY), | ||
| 920 | }; | ||
| 921 | |||
| 922 | static const struct sockaddr_in6 rpc_in6addr_loopback = { | ||
| 923 | .sin6_family = AF_INET6, | ||
| 924 | .sin6_addr = IN6ADDR_ANY_INIT, | ||
| 925 | }; | ||
| 926 | |||
| 927 | /* | ||
| 928 | * Try a getsockname() on a connected datagram socket. Using a | ||
| 929 | * connected datagram socket prevents leaving a socket in TIME_WAIT. | ||
| 930 | * This conserves the ephemeral port number space. | ||
| 931 | * | ||
| 932 | * Returns zero and fills in "buf" if successful; otherwise, a | ||
| 933 | * negative errno is returned. | ||
| 934 | */ | ||
| 935 | static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen, | ||
| 936 | struct sockaddr *buf, int buflen) | ||
| 937 | { | ||
| 938 | struct socket *sock; | ||
| 939 | int err; | ||
| 940 | |||
| 941 | err = __sock_create(net, sap->sa_family, | ||
| 942 | SOCK_DGRAM, IPPROTO_UDP, &sock, 1); | ||
| 943 | if (err < 0) { | ||
| 944 | dprintk("RPC: can't create UDP socket (%d)\n", err); | ||
| 945 | goto out; | ||
| 946 | } | ||
| 947 | |||
| 948 | switch (sap->sa_family) { | ||
| 949 | case AF_INET: | ||
| 950 | err = kernel_bind(sock, | ||
| 951 | (struct sockaddr *)&rpc_inaddr_loopback, | ||
| 952 | sizeof(rpc_inaddr_loopback)); | ||
| 953 | break; | ||
| 954 | case AF_INET6: | ||
| 955 | err = kernel_bind(sock, | ||
| 956 | (struct sockaddr *)&rpc_in6addr_loopback, | ||
| 957 | sizeof(rpc_in6addr_loopback)); | ||
| 958 | break; | ||
| 959 | default: | ||
| 960 | err = -EAFNOSUPPORT; | ||
| 961 | goto out; | ||
| 962 | } | ||
| 963 | if (err < 0) { | ||
| 964 | dprintk("RPC: can't bind UDP socket (%d)\n", err); | ||
| 965 | goto out_release; | ||
| 966 | } | ||
| 967 | |||
| 968 | err = kernel_connect(sock, sap, salen, 0); | ||
| 969 | if (err < 0) { | ||
| 970 | dprintk("RPC: can't connect UDP socket (%d)\n", err); | ||
| 971 | goto out_release; | ||
| 972 | } | ||
| 973 | |||
| 974 | err = kernel_getsockname(sock, buf, &buflen); | ||
| 975 | if (err < 0) { | ||
| 976 | dprintk("RPC: getsockname failed (%d)\n", err); | ||
| 977 | goto out_release; | ||
| 978 | } | ||
| 979 | |||
| 980 | err = 0; | ||
| 981 | if (buf->sa_family == AF_INET6) { | ||
| 982 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf; | ||
| 983 | sin6->sin6_scope_id = 0; | ||
| 984 | } | ||
| 985 | dprintk("RPC: %s succeeded\n", __func__); | ||
| 986 | |||
| 987 | out_release: | ||
| 988 | sock_release(sock); | ||
| 989 | out: | ||
| 990 | return err; | ||
| 991 | } | ||
| 992 | |||
| 993 | /* | ||
| 994 | * Scraping a connected socket failed, so we don't have a useable | ||
| 995 | * local address. Fallback: generate an address that will prevent | ||
| 996 | * the server from calling us back. | ||
| 997 | * | ||
| 998 | * Returns zero and fills in "buf" if successful; otherwise, a | ||
| 999 | * negative errno is returned. | ||
| 1000 | */ | ||
| 1001 | static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen) | ||
| 1002 | { | ||
| 1003 | switch (family) { | ||
| 1004 | case AF_INET: | ||
| 1005 | if (buflen < sizeof(rpc_inaddr_loopback)) | ||
| 1006 | return -EINVAL; | ||
| 1007 | memcpy(buf, &rpc_inaddr_loopback, | ||
| 1008 | sizeof(rpc_inaddr_loopback)); | ||
| 1009 | break; | ||
| 1010 | case AF_INET6: | ||
| 1011 | if (buflen < sizeof(rpc_in6addr_loopback)) | ||
| 1012 | return -EINVAL; | ||
| 1013 | memcpy(buf, &rpc_in6addr_loopback, | ||
| 1014 | sizeof(rpc_in6addr_loopback)); | ||
| 1015 | default: | ||
| 1016 | dprintk("RPC: %s: address family not supported\n", | ||
| 1017 | __func__); | ||
| 1018 | return -EAFNOSUPPORT; | ||
| 1019 | } | ||
| 1020 | dprintk("RPC: %s: succeeded\n", __func__); | ||
| 1021 | return 0; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | /** | ||
| 1025 | * rpc_localaddr - discover local endpoint address for an RPC client | ||
| 1026 | * @clnt: RPC client structure | ||
| 1027 | * @buf: target buffer | ||
| 1028 | * @buflen: size of target buffer, in bytes | ||
| 1029 | * | ||
| 1030 | * Returns zero and fills in "buf" and "buflen" if successful; | ||
| 1031 | * otherwise, a negative errno is returned. | ||
| 1032 | * | ||
| 1033 | * This works even if the underlying transport is not currently connected, | ||
| 1034 | * or if the upper layer never previously provided a source address. | ||
| 1035 | * | ||
| 1036 | * The result of this function call is transient: multiple calls in | ||
| 1037 | * succession may give different results, depending on how local | ||
| 1038 | * networking configuration changes over time. | ||
| 1039 | */ | ||
| 1040 | int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen) | ||
| 1041 | { | ||
| 1042 | struct sockaddr_storage address; | ||
| 1043 | struct sockaddr *sap = (struct sockaddr *)&address; | ||
| 1044 | struct rpc_xprt *xprt; | ||
| 1045 | struct net *net; | ||
| 1046 | size_t salen; | ||
| 1047 | int err; | ||
| 1048 | |||
| 1049 | rcu_read_lock(); | ||
| 1050 | xprt = rcu_dereference(clnt->cl_xprt); | ||
| 1051 | salen = xprt->addrlen; | ||
| 1052 | memcpy(sap, &xprt->addr, salen); | ||
| 1053 | net = get_net(xprt->xprt_net); | ||
| 1054 | rcu_read_unlock(); | ||
| 1055 | |||
| 1056 | rpc_set_port(sap, 0); | ||
| 1057 | err = rpc_sockname(net, sap, salen, buf, buflen); | ||
| 1058 | put_net(net); | ||
| 1059 | if (err != 0) | ||
| 1060 | /* Couldn't discover local address, return ANYADDR */ | ||
| 1061 | return rpc_anyaddr(sap->sa_family, buf, buflen); | ||
| 1062 | return 0; | ||
| 1063 | } | ||
| 1064 | EXPORT_SYMBOL_GPL(rpc_localaddr); | ||
| 1065 | |||
| 809 | void | 1066 | void |
| 810 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) | 1067 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) |
| 811 | { | 1068 | { |
| 812 | struct rpc_xprt *xprt = clnt->cl_xprt; | 1069 | struct rpc_xprt *xprt; |
| 1070 | |||
| 1071 | rcu_read_lock(); | ||
| 1072 | xprt = rcu_dereference(clnt->cl_xprt); | ||
| 813 | if (xprt->ops->set_buffer_size) | 1073 | if (xprt->ops->set_buffer_size) |
| 814 | xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); | 1074 | xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); |
| 1075 | rcu_read_unlock(); | ||
| 815 | } | 1076 | } |
| 816 | EXPORT_SYMBOL_GPL(rpc_setbufsize); | 1077 | EXPORT_SYMBOL_GPL(rpc_setbufsize); |
| 817 | 1078 | ||
| 818 | /* | 1079 | /** |
| 819 | * Return size of largest payload RPC client can support, in bytes | 1080 | * rpc_protocol - Get transport protocol number for an RPC client |
| 1081 | * @clnt: RPC client to query | ||
| 1082 | * | ||
| 1083 | */ | ||
| 1084 | int rpc_protocol(struct rpc_clnt *clnt) | ||
| 1085 | { | ||
| 1086 | int protocol; | ||
| 1087 | |||
| 1088 | rcu_read_lock(); | ||
| 1089 | protocol = rcu_dereference(clnt->cl_xprt)->prot; | ||
| 1090 | rcu_read_unlock(); | ||
| 1091 | return protocol; | ||
| 1092 | } | ||
| 1093 | EXPORT_SYMBOL_GPL(rpc_protocol); | ||
| 1094 | |||
| 1095 | /** | ||
| 1096 | * rpc_net_ns - Get the network namespace for this RPC client | ||
| 1097 | * @clnt: RPC client to query | ||
| 1098 | * | ||
| 1099 | */ | ||
| 1100 | struct net *rpc_net_ns(struct rpc_clnt *clnt) | ||
| 1101 | { | ||
| 1102 | struct net *ret; | ||
| 1103 | |||
| 1104 | rcu_read_lock(); | ||
| 1105 | ret = rcu_dereference(clnt->cl_xprt)->xprt_net; | ||
| 1106 | rcu_read_unlock(); | ||
| 1107 | return ret; | ||
| 1108 | } | ||
| 1109 | EXPORT_SYMBOL_GPL(rpc_net_ns); | ||
| 1110 | |||
| 1111 | /** | ||
| 1112 | * rpc_max_payload - Get maximum payload size for a transport, in bytes | ||
| 1113 | * @clnt: RPC client to query | ||
| 820 | * | 1114 | * |
| 821 | * For stream transports, this is one RPC record fragment (see RFC | 1115 | * For stream transports, this is one RPC record fragment (see RFC |
| 822 | * 1831), as we don't support multi-record requests yet. For datagram | 1116 | * 1831), as we don't support multi-record requests yet. For datagram |
| @@ -825,7 +1119,12 @@ EXPORT_SYMBOL_GPL(rpc_setbufsize); | |||
| 825 | */ | 1119 | */ |
| 826 | size_t rpc_max_payload(struct rpc_clnt *clnt) | 1120 | size_t rpc_max_payload(struct rpc_clnt *clnt) |
| 827 | { | 1121 | { |
| 828 | return clnt->cl_xprt->max_payload; | 1122 | size_t ret; |
| 1123 | |||
| 1124 | rcu_read_lock(); | ||
| 1125 | ret = rcu_dereference(clnt->cl_xprt)->max_payload; | ||
| 1126 | rcu_read_unlock(); | ||
| 1127 | return ret; | ||
| 829 | } | 1128 | } |
| 830 | EXPORT_SYMBOL_GPL(rpc_max_payload); | 1129 | EXPORT_SYMBOL_GPL(rpc_max_payload); |
| 831 | 1130 | ||
| @@ -836,8 +1135,11 @@ EXPORT_SYMBOL_GPL(rpc_max_payload); | |||
| 836 | */ | 1135 | */ |
| 837 | void rpc_force_rebind(struct rpc_clnt *clnt) | 1136 | void rpc_force_rebind(struct rpc_clnt *clnt) |
| 838 | { | 1137 | { |
| 839 | if (clnt->cl_autobind) | 1138 | if (clnt->cl_autobind) { |
| 840 | xprt_clear_bound(clnt->cl_xprt); | 1139 | rcu_read_lock(); |
| 1140 | xprt_clear_bound(rcu_dereference(clnt->cl_xprt)); | ||
| 1141 | rcu_read_unlock(); | ||
| 1142 | } | ||
| 841 | } | 1143 | } |
| 842 | EXPORT_SYMBOL_GPL(rpc_force_rebind); | 1144 | EXPORT_SYMBOL_GPL(rpc_force_rebind); |
| 843 | 1145 | ||
| @@ -1163,6 +1465,7 @@ call_bind_status(struct rpc_task *task) | |||
| 1163 | return; | 1465 | return; |
| 1164 | } | 1466 | } |
| 1165 | 1467 | ||
| 1468 | trace_rpc_bind_status(task); | ||
| 1166 | switch (task->tk_status) { | 1469 | switch (task->tk_status) { |
| 1167 | case -ENOMEM: | 1470 | case -ENOMEM: |
| 1168 | dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid); | 1471 | dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid); |
| @@ -1262,6 +1565,7 @@ call_connect_status(struct rpc_task *task) | |||
| 1262 | return; | 1565 | return; |
| 1263 | } | 1566 | } |
| 1264 | 1567 | ||
| 1568 | trace_rpc_connect_status(task, status); | ||
| 1265 | switch (status) { | 1569 | switch (status) { |
| 1266 | /* if soft mounted, test if we've timed out */ | 1570 | /* if soft mounted, test if we've timed out */ |
| 1267 | case -ETIMEDOUT: | 1571 | case -ETIMEDOUT: |
| @@ -1450,6 +1754,7 @@ call_status(struct rpc_task *task) | |||
| 1450 | return; | 1754 | return; |
| 1451 | } | 1755 | } |
| 1452 | 1756 | ||
| 1757 | trace_rpc_call_status(task); | ||
| 1453 | task->tk_status = 0; | 1758 | task->tk_status = 0; |
| 1454 | switch(status) { | 1759 | switch(status) { |
| 1455 | case -EHOSTDOWN: | 1760 | case -EHOSTDOWN: |
| @@ -1513,8 +1818,11 @@ call_timeout(struct rpc_task *task) | |||
| 1513 | } | 1818 | } |
| 1514 | if (RPC_IS_SOFT(task)) { | 1819 | if (RPC_IS_SOFT(task)) { |
| 1515 | if (clnt->cl_chatty) | 1820 | if (clnt->cl_chatty) |
| 1821 | rcu_read_lock(); | ||
| 1516 | printk(KERN_NOTICE "%s: server %s not responding, timed out\n", | 1822 | printk(KERN_NOTICE "%s: server %s not responding, timed out\n", |
| 1517 | clnt->cl_protname, clnt->cl_server); | 1823 | clnt->cl_protname, |
| 1824 | rcu_dereference(clnt->cl_xprt)->servername); | ||
| 1825 | rcu_read_unlock(); | ||
| 1518 | if (task->tk_flags & RPC_TASK_TIMEOUT) | 1826 | if (task->tk_flags & RPC_TASK_TIMEOUT) |
| 1519 | rpc_exit(task, -ETIMEDOUT); | 1827 | rpc_exit(task, -ETIMEDOUT); |
| 1520 | else | 1828 | else |
| @@ -1524,9 +1832,13 @@ call_timeout(struct rpc_task *task) | |||
| 1524 | 1832 | ||
| 1525 | if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) { | 1833 | if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) { |
| 1526 | task->tk_flags |= RPC_CALL_MAJORSEEN; | 1834 | task->tk_flags |= RPC_CALL_MAJORSEEN; |
| 1527 | if (clnt->cl_chatty) | 1835 | if (clnt->cl_chatty) { |
| 1836 | rcu_read_lock(); | ||
| 1528 | printk(KERN_NOTICE "%s: server %s not responding, still trying\n", | 1837 | printk(KERN_NOTICE "%s: server %s not responding, still trying\n", |
| 1529 | clnt->cl_protname, clnt->cl_server); | 1838 | clnt->cl_protname, |
| 1839 | rcu_dereference(clnt->cl_xprt)->servername); | ||
| 1840 | rcu_read_unlock(); | ||
| 1841 | } | ||
| 1530 | } | 1842 | } |
| 1531 | rpc_force_rebind(clnt); | 1843 | rpc_force_rebind(clnt); |
| 1532 | /* | 1844 | /* |
| @@ -1555,9 +1867,13 @@ call_decode(struct rpc_task *task) | |||
| 1555 | dprint_status(task); | 1867 | dprint_status(task); |
| 1556 | 1868 | ||
| 1557 | if (task->tk_flags & RPC_CALL_MAJORSEEN) { | 1869 | if (task->tk_flags & RPC_CALL_MAJORSEEN) { |
| 1558 | if (clnt->cl_chatty) | 1870 | if (clnt->cl_chatty) { |
| 1871 | rcu_read_lock(); | ||
| 1559 | printk(KERN_NOTICE "%s: server %s OK\n", | 1872 | printk(KERN_NOTICE "%s: server %s OK\n", |
| 1560 | clnt->cl_protname, clnt->cl_server); | 1873 | clnt->cl_protname, |
| 1874 | rcu_dereference(clnt->cl_xprt)->servername); | ||
| 1875 | rcu_read_unlock(); | ||
| 1876 | } | ||
| 1561 | task->tk_flags &= ~RPC_CALL_MAJORSEEN; | 1877 | task->tk_flags &= ~RPC_CALL_MAJORSEEN; |
| 1562 | } | 1878 | } |
| 1563 | 1879 | ||
| @@ -1635,6 +1951,7 @@ rpc_encode_header(struct rpc_task *task) | |||
| 1635 | static __be32 * | 1951 | static __be32 * |
| 1636 | rpc_verify_header(struct rpc_task *task) | 1952 | rpc_verify_header(struct rpc_task *task) |
| 1637 | { | 1953 | { |
| 1954 | struct rpc_clnt *clnt = task->tk_client; | ||
| 1638 | struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0]; | 1955 | struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0]; |
| 1639 | int len = task->tk_rqstp->rq_rcv_buf.len >> 2; | 1956 | int len = task->tk_rqstp->rq_rcv_buf.len >> 2; |
| 1640 | __be32 *p = iov->iov_base; | 1957 | __be32 *p = iov->iov_base; |
| @@ -1707,8 +2024,11 @@ rpc_verify_header(struct rpc_task *task) | |||
| 1707 | task->tk_action = call_bind; | 2024 | task->tk_action = call_bind; |
| 1708 | goto out_retry; | 2025 | goto out_retry; |
| 1709 | case RPC_AUTH_TOOWEAK: | 2026 | case RPC_AUTH_TOOWEAK: |
| 2027 | rcu_read_lock(); | ||
| 1710 | printk(KERN_NOTICE "RPC: server %s requires stronger " | 2028 | printk(KERN_NOTICE "RPC: server %s requires stronger " |
| 1711 | "authentication.\n", task->tk_client->cl_server); | 2029 | "authentication.\n", |
| 2030 | rcu_dereference(clnt->cl_xprt)->servername); | ||
| 2031 | rcu_read_unlock(); | ||
| 1712 | break; | 2032 | break; |
| 1713 | default: | 2033 | default: |
| 1714 | dprintk("RPC: %5u %s: unknown auth error: %x\n", | 2034 | dprintk("RPC: %5u %s: unknown auth error: %x\n", |
| @@ -1731,28 +2051,27 @@ rpc_verify_header(struct rpc_task *task) | |||
| 1731 | case RPC_SUCCESS: | 2051 | case RPC_SUCCESS: |
| 1732 | return p; | 2052 | return p; |
| 1733 | case RPC_PROG_UNAVAIL: | 2053 | case RPC_PROG_UNAVAIL: |
| 1734 | dprintk("RPC: %5u %s: program %u is unsupported by server %s\n", | 2054 | dprintk_rcu("RPC: %5u %s: program %u is unsupported " |
| 1735 | task->tk_pid, __func__, | 2055 | "by server %s\n", task->tk_pid, __func__, |
| 1736 | (unsigned int)task->tk_client->cl_prog, | 2056 | (unsigned int)clnt->cl_prog, |
| 1737 | task->tk_client->cl_server); | 2057 | rcu_dereference(clnt->cl_xprt)->servername); |
| 1738 | error = -EPFNOSUPPORT; | 2058 | error = -EPFNOSUPPORT; |
| 1739 | goto out_err; | 2059 | goto out_err; |
| 1740 | case RPC_PROG_MISMATCH: | 2060 | case RPC_PROG_MISMATCH: |
| 1741 | dprintk("RPC: %5u %s: program %u, version %u unsupported by " | 2061 | dprintk_rcu("RPC: %5u %s: program %u, version %u unsupported " |
| 1742 | "server %s\n", task->tk_pid, __func__, | 2062 | "by server %s\n", task->tk_pid, __func__, |
| 1743 | (unsigned int)task->tk_client->cl_prog, | 2063 | (unsigned int)clnt->cl_prog, |
| 1744 | (unsigned int)task->tk_client->cl_vers, | 2064 | (unsigned int)clnt->cl_vers, |
| 1745 | task->tk_client->cl_server); | 2065 | rcu_dereference(clnt->cl_xprt)->servername); |
| 1746 | error = -EPROTONOSUPPORT; | 2066 | error = -EPROTONOSUPPORT; |
| 1747 | goto out_err; | 2067 | goto out_err; |
| 1748 | case RPC_PROC_UNAVAIL: | 2068 | case RPC_PROC_UNAVAIL: |
| 1749 | dprintk("RPC: %5u %s: proc %s unsupported by program %u, " | 2069 | dprintk_rcu("RPC: %5u %s: proc %s unsupported by program %u, " |
| 1750 | "version %u on server %s\n", | 2070 | "version %u on server %s\n", |
| 1751 | task->tk_pid, __func__, | 2071 | task->tk_pid, __func__, |
| 1752 | rpc_proc_name(task), | 2072 | rpc_proc_name(task), |
| 1753 | task->tk_client->cl_prog, | 2073 | clnt->cl_prog, clnt->cl_vers, |
| 1754 | task->tk_client->cl_vers, | 2074 | rcu_dereference(clnt->cl_xprt)->servername); |
| 1755 | task->tk_client->cl_server); | ||
| 1756 | error = -EOPNOTSUPP; | 2075 | error = -EOPNOTSUPP; |
| 1757 | goto out_err; | 2076 | goto out_err; |
| 1758 | case RPC_GARBAGE_ARGS: | 2077 | case RPC_GARBAGE_ARGS: |
| @@ -1766,7 +2085,7 @@ rpc_verify_header(struct rpc_task *task) | |||
| 1766 | } | 2085 | } |
| 1767 | 2086 | ||
| 1768 | out_garbage: | 2087 | out_garbage: |
| 1769 | task->tk_client->cl_stats->rpcgarbage++; | 2088 | clnt->cl_stats->rpcgarbage++; |
| 1770 | if (task->tk_garb_retry) { | 2089 | if (task->tk_garb_retry) { |
| 1771 | task->tk_garb_retry--; | 2090 | task->tk_garb_retry--; |
| 1772 | dprintk("RPC: %5u %s: retrying\n", | 2091 | dprintk("RPC: %5u %s: retrying\n", |
| @@ -1852,14 +2171,15 @@ static void rpc_show_task(const struct rpc_clnt *clnt, | |||
| 1852 | task->tk_action, rpc_waitq); | 2171 | task->tk_action, rpc_waitq); |
| 1853 | } | 2172 | } |
| 1854 | 2173 | ||
| 1855 | void rpc_show_tasks(void) | 2174 | void rpc_show_tasks(struct net *net) |
| 1856 | { | 2175 | { |
| 1857 | struct rpc_clnt *clnt; | 2176 | struct rpc_clnt *clnt; |
| 1858 | struct rpc_task *task; | 2177 | struct rpc_task *task; |
| 1859 | int header = 0; | 2178 | int header = 0; |
| 2179 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1860 | 2180 | ||
| 1861 | spin_lock(&rpc_client_lock); | 2181 | spin_lock(&sn->rpc_client_lock); |
| 1862 | list_for_each_entry(clnt, &all_clients, cl_clients) { | 2182 | list_for_each_entry(clnt, &sn->all_clients, cl_clients) { |
| 1863 | spin_lock(&clnt->cl_lock); | 2183 | spin_lock(&clnt->cl_lock); |
| 1864 | list_for_each_entry(task, &clnt->cl_tasks, tk_task) { | 2184 | list_for_each_entry(task, &clnt->cl_tasks, tk_task) { |
| 1865 | if (!header) { | 2185 | if (!header) { |
| @@ -1870,6 +2190,6 @@ void rpc_show_tasks(void) | |||
| 1870 | } | 2190 | } |
| 1871 | spin_unlock(&clnt->cl_lock); | 2191 | spin_unlock(&clnt->cl_lock); |
| 1872 | } | 2192 | } |
| 1873 | spin_unlock(&rpc_client_lock); | 2193 | spin_unlock(&sn->rpc_client_lock); |
| 1874 | } | 2194 | } |
| 1875 | #endif | 2195 | #endif |
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index d013bf211cae..ce7bd449173d 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h | |||
| @@ -9,6 +9,20 @@ struct cache_detail; | |||
| 9 | struct sunrpc_net { | 9 | struct sunrpc_net { |
| 10 | struct proc_dir_entry *proc_net_rpc; | 10 | struct proc_dir_entry *proc_net_rpc; |
| 11 | struct cache_detail *ip_map_cache; | 11 | struct cache_detail *ip_map_cache; |
| 12 | struct cache_detail *unix_gid_cache; | ||
| 13 | struct cache_detail *rsc_cache; | ||
| 14 | struct cache_detail *rsi_cache; | ||
| 15 | |||
| 16 | struct super_block *pipefs_sb; | ||
| 17 | struct mutex pipefs_sb_lock; | ||
| 18 | |||
| 19 | struct list_head all_clients; | ||
| 20 | spinlock_t rpc_client_lock; | ||
| 21 | |||
| 22 | struct rpc_clnt *rpcb_local_clnt; | ||
| 23 | struct rpc_clnt *rpcb_local_clnt4; | ||
| 24 | spinlock_t rpcb_clnt_lock; | ||
| 25 | unsigned int rpcb_users; | ||
| 12 | }; | 26 | }; |
| 13 | 27 | ||
| 14 | extern int sunrpc_net_id; | 28 | extern int sunrpc_net_id; |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 7d6dd6efbdbe..c84c0e0c41cb 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
| @@ -16,9 +16,9 @@ | |||
| 16 | #include <linux/namei.h> | 16 | #include <linux/namei.h> |
| 17 | #include <linux/fsnotify.h> | 17 | #include <linux/fsnotify.h> |
| 18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 19 | #include <linux/rcupdate.h> | ||
| 19 | 20 | ||
| 20 | #include <asm/ioctls.h> | 21 | #include <asm/ioctls.h> |
| 21 | #include <linux/fs.h> | ||
| 22 | #include <linux/poll.h> | 22 | #include <linux/poll.h> |
| 23 | #include <linux/wait.h> | 23 | #include <linux/wait.h> |
| 24 | #include <linux/seq_file.h> | 24 | #include <linux/seq_file.h> |
| @@ -27,9 +27,15 @@ | |||
| 27 | #include <linux/workqueue.h> | 27 | #include <linux/workqueue.h> |
| 28 | #include <linux/sunrpc/rpc_pipe_fs.h> | 28 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 29 | #include <linux/sunrpc/cache.h> | 29 | #include <linux/sunrpc/cache.h> |
| 30 | #include <linux/nsproxy.h> | ||
| 31 | #include <linux/notifier.h> | ||
| 30 | 32 | ||
| 31 | static struct vfsmount *rpc_mnt __read_mostly; | 33 | #include "netns.h" |
| 32 | static int rpc_mount_count; | 34 | #include "sunrpc.h" |
| 35 | |||
| 36 | #define RPCDBG_FACILITY RPCDBG_DEBUG | ||
| 37 | |||
| 38 | #define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") | ||
| 33 | 39 | ||
| 34 | static struct file_system_type rpc_pipe_fs_type; | 40 | static struct file_system_type rpc_pipe_fs_type; |
| 35 | 41 | ||
| @@ -38,7 +44,21 @@ static struct kmem_cache *rpc_inode_cachep __read_mostly; | |||
| 38 | 44 | ||
| 39 | #define RPC_UPCALL_TIMEOUT (30*HZ) | 45 | #define RPC_UPCALL_TIMEOUT (30*HZ) |
| 40 | 46 | ||
| 41 | static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, | 47 | static BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list); |
| 48 | |||
| 49 | int rpc_pipefs_notifier_register(struct notifier_block *nb) | ||
| 50 | { | ||
| 51 | return blocking_notifier_chain_cond_register(&rpc_pipefs_notifier_list, nb); | ||
| 52 | } | ||
| 53 | EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register); | ||
| 54 | |||
| 55 | void rpc_pipefs_notifier_unregister(struct notifier_block *nb) | ||
| 56 | { | ||
| 57 | blocking_notifier_chain_unregister(&rpc_pipefs_notifier_list, nb); | ||
| 58 | } | ||
| 59 | EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister); | ||
| 60 | |||
| 61 | static void rpc_purge_list(wait_queue_head_t *waitq, struct list_head *head, | ||
| 42 | void (*destroy_msg)(struct rpc_pipe_msg *), int err) | 62 | void (*destroy_msg)(struct rpc_pipe_msg *), int err) |
| 43 | { | 63 | { |
| 44 | struct rpc_pipe_msg *msg; | 64 | struct rpc_pipe_msg *msg; |
| @@ -51,30 +71,31 @@ static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, | |||
| 51 | msg->errno = err; | 71 | msg->errno = err; |
| 52 | destroy_msg(msg); | 72 | destroy_msg(msg); |
| 53 | } while (!list_empty(head)); | 73 | } while (!list_empty(head)); |
| 54 | wake_up(&rpci->waitq); | 74 | wake_up(waitq); |
| 55 | } | 75 | } |
| 56 | 76 | ||
| 57 | static void | 77 | static void |
| 58 | rpc_timeout_upcall_queue(struct work_struct *work) | 78 | rpc_timeout_upcall_queue(struct work_struct *work) |
| 59 | { | 79 | { |
| 60 | LIST_HEAD(free_list); | 80 | LIST_HEAD(free_list); |
| 61 | struct rpc_inode *rpci = | 81 | struct rpc_pipe *pipe = |
| 62 | container_of(work, struct rpc_inode, queue_timeout.work); | 82 | container_of(work, struct rpc_pipe, queue_timeout.work); |
| 63 | struct inode *inode = &rpci->vfs_inode; | ||
| 64 | void (*destroy_msg)(struct rpc_pipe_msg *); | 83 | void (*destroy_msg)(struct rpc_pipe_msg *); |
| 84 | struct dentry *dentry; | ||
| 65 | 85 | ||
| 66 | spin_lock(&inode->i_lock); | 86 | spin_lock(&pipe->lock); |
| 67 | if (rpci->ops == NULL) { | 87 | destroy_msg = pipe->ops->destroy_msg; |
| 68 | spin_unlock(&inode->i_lock); | 88 | if (pipe->nreaders == 0) { |
| 69 | return; | 89 | list_splice_init(&pipe->pipe, &free_list); |
| 90 | pipe->pipelen = 0; | ||
| 70 | } | 91 | } |
| 71 | destroy_msg = rpci->ops->destroy_msg; | 92 | dentry = dget(pipe->dentry); |
| 72 | if (rpci->nreaders == 0) { | 93 | spin_unlock(&pipe->lock); |
| 73 | list_splice_init(&rpci->pipe, &free_list); | 94 | if (dentry) { |
| 74 | rpci->pipelen = 0; | 95 | rpc_purge_list(&RPC_I(dentry->d_inode)->waitq, |
| 96 | &free_list, destroy_msg, -ETIMEDOUT); | ||
| 97 | dput(dentry); | ||
| 75 | } | 98 | } |
| 76 | spin_unlock(&inode->i_lock); | ||
| 77 | rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT); | ||
| 78 | } | 99 | } |
| 79 | 100 | ||
| 80 | ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg, | 101 | ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg, |
| @@ -108,30 +129,31 @@ EXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall); | |||
| 108 | * initialize the fields of @msg (other than @msg->list) appropriately. | 129 | * initialize the fields of @msg (other than @msg->list) appropriately. |
| 109 | */ | 130 | */ |
| 110 | int | 131 | int |
| 111 | rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg) | 132 | rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg) |
| 112 | { | 133 | { |
| 113 | struct rpc_inode *rpci = RPC_I(inode); | ||
| 114 | int res = -EPIPE; | 134 | int res = -EPIPE; |
| 135 | struct dentry *dentry; | ||
| 115 | 136 | ||
| 116 | spin_lock(&inode->i_lock); | 137 | spin_lock(&pipe->lock); |
| 117 | if (rpci->ops == NULL) | 138 | if (pipe->nreaders) { |
| 118 | goto out; | 139 | list_add_tail(&msg->list, &pipe->pipe); |
| 119 | if (rpci->nreaders) { | 140 | pipe->pipelen += msg->len; |
| 120 | list_add_tail(&msg->list, &rpci->pipe); | ||
| 121 | rpci->pipelen += msg->len; | ||
| 122 | res = 0; | 141 | res = 0; |
| 123 | } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) { | 142 | } else if (pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) { |
| 124 | if (list_empty(&rpci->pipe)) | 143 | if (list_empty(&pipe->pipe)) |
| 125 | queue_delayed_work(rpciod_workqueue, | 144 | queue_delayed_work(rpciod_workqueue, |
| 126 | &rpci->queue_timeout, | 145 | &pipe->queue_timeout, |
| 127 | RPC_UPCALL_TIMEOUT); | 146 | RPC_UPCALL_TIMEOUT); |
| 128 | list_add_tail(&msg->list, &rpci->pipe); | 147 | list_add_tail(&msg->list, &pipe->pipe); |
| 129 | rpci->pipelen += msg->len; | 148 | pipe->pipelen += msg->len; |
| 130 | res = 0; | 149 | res = 0; |
| 131 | } | 150 | } |
| 132 | out: | 151 | dentry = dget(pipe->dentry); |
| 133 | spin_unlock(&inode->i_lock); | 152 | spin_unlock(&pipe->lock); |
| 134 | wake_up(&rpci->waitq); | 153 | if (dentry) { |
| 154 | wake_up(&RPC_I(dentry->d_inode)->waitq); | ||
| 155 | dput(dentry); | ||
| 156 | } | ||
| 135 | return res; | 157 | return res; |
| 136 | } | 158 | } |
| 137 | EXPORT_SYMBOL_GPL(rpc_queue_upcall); | 159 | EXPORT_SYMBOL_GPL(rpc_queue_upcall); |
| @@ -145,29 +167,26 @@ rpc_inode_setowner(struct inode *inode, void *private) | |||
| 145 | static void | 167 | static void |
| 146 | rpc_close_pipes(struct inode *inode) | 168 | rpc_close_pipes(struct inode *inode) |
| 147 | { | 169 | { |
| 148 | struct rpc_inode *rpci = RPC_I(inode); | 170 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; |
| 149 | const struct rpc_pipe_ops *ops; | ||
| 150 | int need_release; | 171 | int need_release; |
| 172 | LIST_HEAD(free_list); | ||
| 151 | 173 | ||
| 152 | mutex_lock(&inode->i_mutex); | 174 | mutex_lock(&inode->i_mutex); |
| 153 | ops = rpci->ops; | 175 | spin_lock(&pipe->lock); |
| 154 | if (ops != NULL) { | 176 | need_release = pipe->nreaders != 0 || pipe->nwriters != 0; |
| 155 | LIST_HEAD(free_list); | 177 | pipe->nreaders = 0; |
| 156 | spin_lock(&inode->i_lock); | 178 | list_splice_init(&pipe->in_upcall, &free_list); |
| 157 | need_release = rpci->nreaders != 0 || rpci->nwriters != 0; | 179 | list_splice_init(&pipe->pipe, &free_list); |
| 158 | rpci->nreaders = 0; | 180 | pipe->pipelen = 0; |
| 159 | list_splice_init(&rpci->in_upcall, &free_list); | 181 | pipe->dentry = NULL; |
| 160 | list_splice_init(&rpci->pipe, &free_list); | 182 | spin_unlock(&pipe->lock); |
| 161 | rpci->pipelen = 0; | 183 | rpc_purge_list(&RPC_I(inode)->waitq, &free_list, pipe->ops->destroy_msg, -EPIPE); |
| 162 | rpci->ops = NULL; | 184 | pipe->nwriters = 0; |
| 163 | spin_unlock(&inode->i_lock); | 185 | if (need_release && pipe->ops->release_pipe) |
| 164 | rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE); | 186 | pipe->ops->release_pipe(inode); |
| 165 | rpci->nwriters = 0; | 187 | cancel_delayed_work_sync(&pipe->queue_timeout); |
| 166 | if (need_release && ops->release_pipe) | ||
| 167 | ops->release_pipe(inode); | ||
| 168 | cancel_delayed_work_sync(&rpci->queue_timeout); | ||
| 169 | } | ||
| 170 | rpc_inode_setowner(inode, NULL); | 188 | rpc_inode_setowner(inode, NULL); |
| 189 | RPC_I(inode)->pipe = NULL; | ||
| 171 | mutex_unlock(&inode->i_mutex); | 190 | mutex_unlock(&inode->i_mutex); |
| 172 | } | 191 | } |
| 173 | 192 | ||
| @@ -197,23 +216,24 @@ rpc_destroy_inode(struct inode *inode) | |||
| 197 | static int | 216 | static int |
| 198 | rpc_pipe_open(struct inode *inode, struct file *filp) | 217 | rpc_pipe_open(struct inode *inode, struct file *filp) |
| 199 | { | 218 | { |
| 200 | struct rpc_inode *rpci = RPC_I(inode); | 219 | struct rpc_pipe *pipe; |
| 201 | int first_open; | 220 | int first_open; |
| 202 | int res = -ENXIO; | 221 | int res = -ENXIO; |
| 203 | 222 | ||
| 204 | mutex_lock(&inode->i_mutex); | 223 | mutex_lock(&inode->i_mutex); |
| 205 | if (rpci->ops == NULL) | 224 | pipe = RPC_I(inode)->pipe; |
| 225 | if (pipe == NULL) | ||
| 206 | goto out; | 226 | goto out; |
| 207 | first_open = rpci->nreaders == 0 && rpci->nwriters == 0; | 227 | first_open = pipe->nreaders == 0 && pipe->nwriters == 0; |
| 208 | if (first_open && rpci->ops->open_pipe) { | 228 | if (first_open && pipe->ops->open_pipe) { |
| 209 | res = rpci->ops->open_pipe(inode); | 229 | res = pipe->ops->open_pipe(inode); |
| 210 | if (res) | 230 | if (res) |
| 211 | goto out; | 231 | goto out; |
| 212 | } | 232 | } |
| 213 | if (filp->f_mode & FMODE_READ) | 233 | if (filp->f_mode & FMODE_READ) |
| 214 | rpci->nreaders++; | 234 | pipe->nreaders++; |
| 215 | if (filp->f_mode & FMODE_WRITE) | 235 | if (filp->f_mode & FMODE_WRITE) |
| 216 | rpci->nwriters++; | 236 | pipe->nwriters++; |
| 217 | res = 0; | 237 | res = 0; |
| 218 | out: | 238 | out: |
| 219 | mutex_unlock(&inode->i_mutex); | 239 | mutex_unlock(&inode->i_mutex); |
| @@ -223,38 +243,39 @@ out: | |||
| 223 | static int | 243 | static int |
| 224 | rpc_pipe_release(struct inode *inode, struct file *filp) | 244 | rpc_pipe_release(struct inode *inode, struct file *filp) |
| 225 | { | 245 | { |
| 226 | struct rpc_inode *rpci = RPC_I(inode); | 246 | struct rpc_pipe *pipe; |
| 227 | struct rpc_pipe_msg *msg; | 247 | struct rpc_pipe_msg *msg; |
| 228 | int last_close; | 248 | int last_close; |
| 229 | 249 | ||
| 230 | mutex_lock(&inode->i_mutex); | 250 | mutex_lock(&inode->i_mutex); |
| 231 | if (rpci->ops == NULL) | 251 | pipe = RPC_I(inode)->pipe; |
| 252 | if (pipe == NULL) | ||
| 232 | goto out; | 253 | goto out; |
| 233 | msg = filp->private_data; | 254 | msg = filp->private_data; |
| 234 | if (msg != NULL) { | 255 | if (msg != NULL) { |
| 235 | spin_lock(&inode->i_lock); | 256 | spin_lock(&pipe->lock); |
| 236 | msg->errno = -EAGAIN; | 257 | msg->errno = -EAGAIN; |
| 237 | list_del_init(&msg->list); | 258 | list_del_init(&msg->list); |
| 238 | spin_unlock(&inode->i_lock); | 259 | spin_unlock(&pipe->lock); |
| 239 | rpci->ops->destroy_msg(msg); | 260 | pipe->ops->destroy_msg(msg); |
| 240 | } | 261 | } |
| 241 | if (filp->f_mode & FMODE_WRITE) | 262 | if (filp->f_mode & FMODE_WRITE) |
| 242 | rpci->nwriters --; | 263 | pipe->nwriters --; |
| 243 | if (filp->f_mode & FMODE_READ) { | 264 | if (filp->f_mode & FMODE_READ) { |
| 244 | rpci->nreaders --; | 265 | pipe->nreaders --; |
| 245 | if (rpci->nreaders == 0) { | 266 | if (pipe->nreaders == 0) { |
| 246 | LIST_HEAD(free_list); | 267 | LIST_HEAD(free_list); |
| 247 | spin_lock(&inode->i_lock); | 268 | spin_lock(&pipe->lock); |
| 248 | list_splice_init(&rpci->pipe, &free_list); | 269 | list_splice_init(&pipe->pipe, &free_list); |
| 249 | rpci->pipelen = 0; | 270 | pipe->pipelen = 0; |
| 250 | spin_unlock(&inode->i_lock); | 271 | spin_unlock(&pipe->lock); |
| 251 | rpc_purge_list(rpci, &free_list, | 272 | rpc_purge_list(&RPC_I(inode)->waitq, &free_list, |
| 252 | rpci->ops->destroy_msg, -EAGAIN); | 273 | pipe->ops->destroy_msg, -EAGAIN); |
| 253 | } | 274 | } |
| 254 | } | 275 | } |
| 255 | last_close = rpci->nwriters == 0 && rpci->nreaders == 0; | 276 | last_close = pipe->nwriters == 0 && pipe->nreaders == 0; |
| 256 | if (last_close && rpci->ops->release_pipe) | 277 | if (last_close && pipe->ops->release_pipe) |
| 257 | rpci->ops->release_pipe(inode); | 278 | pipe->ops->release_pipe(inode); |
| 258 | out: | 279 | out: |
| 259 | mutex_unlock(&inode->i_mutex); | 280 | mutex_unlock(&inode->i_mutex); |
| 260 | return 0; | 281 | return 0; |
| @@ -264,39 +285,40 @@ static ssize_t | |||
| 264 | rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) | 285 | rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) |
| 265 | { | 286 | { |
| 266 | struct inode *inode = filp->f_path.dentry->d_inode; | 287 | struct inode *inode = filp->f_path.dentry->d_inode; |
| 267 | struct rpc_inode *rpci = RPC_I(inode); | 288 | struct rpc_pipe *pipe; |
| 268 | struct rpc_pipe_msg *msg; | 289 | struct rpc_pipe_msg *msg; |
| 269 | int res = 0; | 290 | int res = 0; |
| 270 | 291 | ||
| 271 | mutex_lock(&inode->i_mutex); | 292 | mutex_lock(&inode->i_mutex); |
| 272 | if (rpci->ops == NULL) { | 293 | pipe = RPC_I(inode)->pipe; |
| 294 | if (pipe == NULL) { | ||
| 273 | res = -EPIPE; | 295 | res = -EPIPE; |
| 274 | goto out_unlock; | 296 | goto out_unlock; |
| 275 | } | 297 | } |
| 276 | msg = filp->private_data; | 298 | msg = filp->private_data; |
| 277 | if (msg == NULL) { | 299 | if (msg == NULL) { |
| 278 | spin_lock(&inode->i_lock); | 300 | spin_lock(&pipe->lock); |
| 279 | if (!list_empty(&rpci->pipe)) { | 301 | if (!list_empty(&pipe->pipe)) { |
| 280 | msg = list_entry(rpci->pipe.next, | 302 | msg = list_entry(pipe->pipe.next, |
| 281 | struct rpc_pipe_msg, | 303 | struct rpc_pipe_msg, |
| 282 | list); | 304 | list); |
| 283 | list_move(&msg->list, &rpci->in_upcall); | 305 | list_move(&msg->list, &pipe->in_upcall); |
| 284 | rpci->pipelen -= msg->len; | 306 | pipe->pipelen -= msg->len; |
| 285 | filp->private_data = msg; | 307 | filp->private_data = msg; |
| 286 | msg->copied = 0; | 308 | msg->copied = 0; |
| 287 | } | 309 | } |
| 288 | spin_unlock(&inode->i_lock); | 310 | spin_unlock(&pipe->lock); |
| 289 | if (msg == NULL) | 311 | if (msg == NULL) |
| 290 | goto out_unlock; | 312 | goto out_unlock; |
| 291 | } | 313 | } |
| 292 | /* NOTE: it is up to the callback to update msg->copied */ | 314 | /* NOTE: it is up to the callback to update msg->copied */ |
| 293 | res = rpci->ops->upcall(filp, msg, buf, len); | 315 | res = pipe->ops->upcall(filp, msg, buf, len); |
| 294 | if (res < 0 || msg->len == msg->copied) { | 316 | if (res < 0 || msg->len == msg->copied) { |
| 295 | filp->private_data = NULL; | 317 | filp->private_data = NULL; |
| 296 | spin_lock(&inode->i_lock); | 318 | spin_lock(&pipe->lock); |
| 297 | list_del_init(&msg->list); | 319 | list_del_init(&msg->list); |
| 298 | spin_unlock(&inode->i_lock); | 320 | spin_unlock(&pipe->lock); |
| 299 | rpci->ops->destroy_msg(msg); | 321 | pipe->ops->destroy_msg(msg); |
| 300 | } | 322 | } |
| 301 | out_unlock: | 323 | out_unlock: |
| 302 | mutex_unlock(&inode->i_mutex); | 324 | mutex_unlock(&inode->i_mutex); |
| @@ -307,13 +329,12 @@ static ssize_t | |||
| 307 | rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) | 329 | rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) |
| 308 | { | 330 | { |
| 309 | struct inode *inode = filp->f_path.dentry->d_inode; | 331 | struct inode *inode = filp->f_path.dentry->d_inode; |
| 310 | struct rpc_inode *rpci = RPC_I(inode); | ||
| 311 | int res; | 332 | int res; |
| 312 | 333 | ||
| 313 | mutex_lock(&inode->i_mutex); | 334 | mutex_lock(&inode->i_mutex); |
| 314 | res = -EPIPE; | 335 | res = -EPIPE; |
| 315 | if (rpci->ops != NULL) | 336 | if (RPC_I(inode)->pipe != NULL) |
| 316 | res = rpci->ops->downcall(filp, buf, len); | 337 | res = RPC_I(inode)->pipe->ops->downcall(filp, buf, len); |
| 317 | mutex_unlock(&inode->i_mutex); | 338 | mutex_unlock(&inode->i_mutex); |
| 318 | return res; | 339 | return res; |
| 319 | } | 340 | } |
| @@ -321,17 +342,18 @@ rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *of | |||
| 321 | static unsigned int | 342 | static unsigned int |
| 322 | rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) | 343 | rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait) |
| 323 | { | 344 | { |
| 324 | struct rpc_inode *rpci; | 345 | struct inode *inode = filp->f_path.dentry->d_inode; |
| 325 | unsigned int mask = 0; | 346 | struct rpc_inode *rpci = RPC_I(inode); |
| 347 | unsigned int mask = POLLOUT | POLLWRNORM; | ||
| 326 | 348 | ||
| 327 | rpci = RPC_I(filp->f_path.dentry->d_inode); | ||
| 328 | poll_wait(filp, &rpci->waitq, wait); | 349 | poll_wait(filp, &rpci->waitq, wait); |
| 329 | 350 | ||
| 330 | mask = POLLOUT | POLLWRNORM; | 351 | mutex_lock(&inode->i_mutex); |
| 331 | if (rpci->ops == NULL) | 352 | if (rpci->pipe == NULL) |
| 332 | mask |= POLLERR | POLLHUP; | 353 | mask |= POLLERR | POLLHUP; |
| 333 | if (filp->private_data || !list_empty(&rpci->pipe)) | 354 | else if (filp->private_data || !list_empty(&rpci->pipe->pipe)) |
| 334 | mask |= POLLIN | POLLRDNORM; | 355 | mask |= POLLIN | POLLRDNORM; |
| 356 | mutex_unlock(&inode->i_mutex); | ||
| 335 | return mask; | 357 | return mask; |
| 336 | } | 358 | } |
| 337 | 359 | ||
| @@ -339,23 +361,26 @@ static long | |||
| 339 | rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 361 | rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 340 | { | 362 | { |
| 341 | struct inode *inode = filp->f_path.dentry->d_inode; | 363 | struct inode *inode = filp->f_path.dentry->d_inode; |
| 342 | struct rpc_inode *rpci = RPC_I(inode); | 364 | struct rpc_pipe *pipe; |
| 343 | int len; | 365 | int len; |
| 344 | 366 | ||
| 345 | switch (cmd) { | 367 | switch (cmd) { |
| 346 | case FIONREAD: | 368 | case FIONREAD: |
| 347 | spin_lock(&inode->i_lock); | 369 | mutex_lock(&inode->i_mutex); |
| 348 | if (rpci->ops == NULL) { | 370 | pipe = RPC_I(inode)->pipe; |
| 349 | spin_unlock(&inode->i_lock); | 371 | if (pipe == NULL) { |
| 372 | mutex_unlock(&inode->i_mutex); | ||
| 350 | return -EPIPE; | 373 | return -EPIPE; |
| 351 | } | 374 | } |
| 352 | len = rpci->pipelen; | 375 | spin_lock(&pipe->lock); |
| 376 | len = pipe->pipelen; | ||
| 353 | if (filp->private_data) { | 377 | if (filp->private_data) { |
| 354 | struct rpc_pipe_msg *msg; | 378 | struct rpc_pipe_msg *msg; |
| 355 | msg = filp->private_data; | 379 | msg = filp->private_data; |
| 356 | len += msg->len - msg->copied; | 380 | len += msg->len - msg->copied; |
| 357 | } | 381 | } |
| 358 | spin_unlock(&inode->i_lock); | 382 | spin_unlock(&pipe->lock); |
| 383 | mutex_unlock(&inode->i_mutex); | ||
| 359 | return put_user(len, (int __user *)arg); | 384 | return put_user(len, (int __user *)arg); |
| 360 | default: | 385 | default: |
| 361 | return -EINVAL; | 386 | return -EINVAL; |
| @@ -378,12 +403,15 @@ rpc_show_info(struct seq_file *m, void *v) | |||
| 378 | { | 403 | { |
| 379 | struct rpc_clnt *clnt = m->private; | 404 | struct rpc_clnt *clnt = m->private; |
| 380 | 405 | ||
| 381 | seq_printf(m, "RPC server: %s\n", clnt->cl_server); | 406 | rcu_read_lock(); |
| 407 | seq_printf(m, "RPC server: %s\n", | ||
| 408 | rcu_dereference(clnt->cl_xprt)->servername); | ||
| 382 | seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, | 409 | seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, |
| 383 | clnt->cl_prog, clnt->cl_vers); | 410 | clnt->cl_prog, clnt->cl_vers); |
| 384 | seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); | 411 | seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); |
| 385 | seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); | 412 | seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); |
| 386 | seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); | 413 | seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); |
| 414 | rcu_read_unlock(); | ||
| 387 | return 0; | 415 | return 0; |
| 388 | } | 416 | } |
| 389 | 417 | ||
| @@ -440,23 +468,6 @@ struct rpc_filelist { | |||
| 440 | umode_t mode; | 468 | umode_t mode; |
| 441 | }; | 469 | }; |
| 442 | 470 | ||
| 443 | struct vfsmount *rpc_get_mount(void) | ||
| 444 | { | ||
| 445 | int err; | ||
| 446 | |||
| 447 | err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mnt, &rpc_mount_count); | ||
| 448 | if (err != 0) | ||
| 449 | return ERR_PTR(err); | ||
| 450 | return rpc_mnt; | ||
| 451 | } | ||
| 452 | EXPORT_SYMBOL_GPL(rpc_get_mount); | ||
| 453 | |||
| 454 | void rpc_put_mount(void) | ||
| 455 | { | ||
| 456 | simple_release_fs(&rpc_mnt, &rpc_mount_count); | ||
| 457 | } | ||
| 458 | EXPORT_SYMBOL_GPL(rpc_put_mount); | ||
| 459 | |||
| 460 | static int rpc_delete_dentry(const struct dentry *dentry) | 471 | static int rpc_delete_dentry(const struct dentry *dentry) |
| 461 | { | 472 | { |
| 462 | return 1; | 473 | return 1; |
| @@ -540,12 +551,47 @@ static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, | |||
| 540 | return 0; | 551 | return 0; |
| 541 | } | 552 | } |
| 542 | 553 | ||
| 543 | static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, | 554 | static void |
| 544 | umode_t mode, | 555 | init_pipe(struct rpc_pipe *pipe) |
| 545 | const struct file_operations *i_fop, | 556 | { |
| 546 | void *private, | 557 | pipe->nreaders = 0; |
| 547 | const struct rpc_pipe_ops *ops, | 558 | pipe->nwriters = 0; |
| 548 | int flags) | 559 | INIT_LIST_HEAD(&pipe->in_upcall); |
| 560 | INIT_LIST_HEAD(&pipe->in_downcall); | ||
| 561 | INIT_LIST_HEAD(&pipe->pipe); | ||
| 562 | pipe->pipelen = 0; | ||
| 563 | INIT_DELAYED_WORK(&pipe->queue_timeout, | ||
| 564 | rpc_timeout_upcall_queue); | ||
| 565 | pipe->ops = NULL; | ||
| 566 | spin_lock_init(&pipe->lock); | ||
| 567 | pipe->dentry = NULL; | ||
| 568 | } | ||
| 569 | |||
| 570 | void rpc_destroy_pipe_data(struct rpc_pipe *pipe) | ||
| 571 | { | ||
| 572 | kfree(pipe); | ||
| 573 | } | ||
| 574 | EXPORT_SYMBOL_GPL(rpc_destroy_pipe_data); | ||
| 575 | |||
| 576 | struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags) | ||
| 577 | { | ||
| 578 | struct rpc_pipe *pipe; | ||
| 579 | |||
| 580 | pipe = kzalloc(sizeof(struct rpc_pipe), GFP_KERNEL); | ||
| 581 | if (!pipe) | ||
| 582 | return ERR_PTR(-ENOMEM); | ||
| 583 | init_pipe(pipe); | ||
| 584 | pipe->ops = ops; | ||
| 585 | pipe->flags = flags; | ||
| 586 | return pipe; | ||
| 587 | } | ||
| 588 | EXPORT_SYMBOL_GPL(rpc_mkpipe_data); | ||
| 589 | |||
| 590 | static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry, | ||
| 591 | umode_t mode, | ||
| 592 | const struct file_operations *i_fop, | ||
| 593 | void *private, | ||
| 594 | struct rpc_pipe *pipe) | ||
| 549 | { | 595 | { |
| 550 | struct rpc_inode *rpci; | 596 | struct rpc_inode *rpci; |
| 551 | int err; | 597 | int err; |
| @@ -554,10 +600,8 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, | |||
| 554 | if (err) | 600 | if (err) |
| 555 | return err; | 601 | return err; |
| 556 | rpci = RPC_I(dentry->d_inode); | 602 | rpci = RPC_I(dentry->d_inode); |
| 557 | rpci->nkern_readwriters = 1; | ||
| 558 | rpci->private = private; | 603 | rpci->private = private; |
| 559 | rpci->flags = flags; | 604 | rpci->pipe = pipe; |
| 560 | rpci->ops = ops; | ||
| 561 | fsnotify_create(dir, dentry); | 605 | fsnotify_create(dir, dentry); |
| 562 | return 0; | 606 | return 0; |
| 563 | } | 607 | } |
| @@ -573,6 +617,22 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 573 | return ret; | 617 | return ret; |
| 574 | } | 618 | } |
| 575 | 619 | ||
| 620 | int rpc_rmdir(struct dentry *dentry) | ||
| 621 | { | ||
| 622 | struct dentry *parent; | ||
| 623 | struct inode *dir; | ||
| 624 | int error; | ||
| 625 | |||
| 626 | parent = dget_parent(dentry); | ||
| 627 | dir = parent->d_inode; | ||
| 628 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | ||
| 629 | error = __rpc_rmdir(dir, dentry); | ||
| 630 | mutex_unlock(&dir->i_mutex); | ||
| 631 | dput(parent); | ||
| 632 | return error; | ||
| 633 | } | ||
| 634 | EXPORT_SYMBOL_GPL(rpc_rmdir); | ||
| 635 | |||
| 576 | static int __rpc_unlink(struct inode *dir, struct dentry *dentry) | 636 | static int __rpc_unlink(struct inode *dir, struct dentry *dentry) |
| 577 | { | 637 | { |
| 578 | int ret; | 638 | int ret; |
| @@ -587,16 +647,12 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry) | |||
| 587 | static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) | 647 | static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) |
| 588 | { | 648 | { |
| 589 | struct inode *inode = dentry->d_inode; | 649 | struct inode *inode = dentry->d_inode; |
| 590 | struct rpc_inode *rpci = RPC_I(inode); | ||
| 591 | 650 | ||
| 592 | rpci->nkern_readwriters--; | ||
| 593 | if (rpci->nkern_readwriters != 0) | ||
| 594 | return 0; | ||
| 595 | rpc_close_pipes(inode); | 651 | rpc_close_pipes(inode); |
| 596 | return __rpc_unlink(dir, dentry); | 652 | return __rpc_unlink(dir, dentry); |
| 597 | } | 653 | } |
| 598 | 654 | ||
| 599 | static struct dentry *__rpc_lookup_create(struct dentry *parent, | 655 | static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, |
| 600 | struct qstr *name) | 656 | struct qstr *name) |
| 601 | { | 657 | { |
| 602 | struct dentry *dentry; | 658 | struct dentry *dentry; |
| @@ -604,27 +660,13 @@ static struct dentry *__rpc_lookup_create(struct dentry *parent, | |||
| 604 | dentry = d_lookup(parent, name); | 660 | dentry = d_lookup(parent, name); |
| 605 | if (!dentry) { | 661 | if (!dentry) { |
| 606 | dentry = d_alloc(parent, name); | 662 | dentry = d_alloc(parent, name); |
| 607 | if (!dentry) { | 663 | if (!dentry) |
| 608 | dentry = ERR_PTR(-ENOMEM); | 664 | return ERR_PTR(-ENOMEM); |
| 609 | goto out_err; | ||
| 610 | } | ||
| 611 | } | 665 | } |
| 612 | if (!dentry->d_inode) | 666 | if (dentry->d_inode == NULL) { |
| 613 | d_set_d_op(dentry, &rpc_dentry_operations); | 667 | d_set_d_op(dentry, &rpc_dentry_operations); |
| 614 | out_err: | ||
| 615 | return dentry; | ||
| 616 | } | ||
| 617 | |||
| 618 | static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, | ||
| 619 | struct qstr *name) | ||
| 620 | { | ||
| 621 | struct dentry *dentry; | ||
| 622 | |||
| 623 | dentry = __rpc_lookup_create(parent, name); | ||
| 624 | if (IS_ERR(dentry)) | ||
| 625 | return dentry; | ||
| 626 | if (dentry->d_inode == NULL) | ||
| 627 | return dentry; | 668 | return dentry; |
| 669 | } | ||
| 628 | dput(dentry); | 670 | dput(dentry); |
| 629 | return ERR_PTR(-EEXIST); | 671 | return ERR_PTR(-EEXIST); |
| 630 | } | 672 | } |
| @@ -779,7 +821,7 @@ static int rpc_rmdir_depopulate(struct dentry *dentry, | |||
| 779 | * @private: private data to associate with the pipe, for the caller's use | 821 | * @private: private data to associate with the pipe, for the caller's use |
| 780 | * @ops: operations defining the behavior of the pipe: upcall, downcall, | 822 | * @ops: operations defining the behavior of the pipe: upcall, downcall, |
| 781 | * release_pipe, open_pipe, and destroy_msg. | 823 | * release_pipe, open_pipe, and destroy_msg. |
| 782 | * @flags: rpc_inode flags | 824 | * @flags: rpc_pipe flags |
| 783 | * | 825 | * |
| 784 | * Data is made available for userspace to read by calls to | 826 | * Data is made available for userspace to read by calls to |
| 785 | * rpc_queue_upcall(). The actual reads will result in calls to | 827 | * rpc_queue_upcall(). The actual reads will result in calls to |
| @@ -792,9 +834,8 @@ static int rpc_rmdir_depopulate(struct dentry *dentry, | |||
| 792 | * The @private argument passed here will be available to all these methods | 834 | * The @private argument passed here will be available to all these methods |
| 793 | * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. | 835 | * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. |
| 794 | */ | 836 | */ |
| 795 | struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, | 837 | struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name, |
| 796 | void *private, const struct rpc_pipe_ops *ops, | 838 | void *private, struct rpc_pipe *pipe) |
| 797 | int flags) | ||
| 798 | { | 839 | { |
| 799 | struct dentry *dentry; | 840 | struct dentry *dentry; |
| 800 | struct inode *dir = parent->d_inode; | 841 | struct inode *dir = parent->d_inode; |
| @@ -802,9 +843,9 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, | |||
| 802 | struct qstr q; | 843 | struct qstr q; |
| 803 | int err; | 844 | int err; |
| 804 | 845 | ||
| 805 | if (ops->upcall == NULL) | 846 | if (pipe->ops->upcall == NULL) |
| 806 | umode &= ~S_IRUGO; | 847 | umode &= ~S_IRUGO; |
| 807 | if (ops->downcall == NULL) | 848 | if (pipe->ops->downcall == NULL) |
| 808 | umode &= ~S_IWUGO; | 849 | umode &= ~S_IWUGO; |
| 809 | 850 | ||
| 810 | q.name = name; | 851 | q.name = name; |
| @@ -812,24 +853,11 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, | |||
| 812 | q.hash = full_name_hash(q.name, q.len), | 853 | q.hash = full_name_hash(q.name, q.len), |
| 813 | 854 | ||
| 814 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 855 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
| 815 | dentry = __rpc_lookup_create(parent, &q); | 856 | dentry = __rpc_lookup_create_exclusive(parent, &q); |
| 816 | if (IS_ERR(dentry)) | 857 | if (IS_ERR(dentry)) |
| 817 | goto out; | 858 | goto out; |
| 818 | if (dentry->d_inode) { | 859 | err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops, |
| 819 | struct rpc_inode *rpci = RPC_I(dentry->d_inode); | 860 | private, pipe); |
| 820 | if (rpci->private != private || | ||
| 821 | rpci->ops != ops || | ||
| 822 | rpci->flags != flags) { | ||
| 823 | dput (dentry); | ||
| 824 | err = -EBUSY; | ||
| 825 | goto out_err; | ||
| 826 | } | ||
| 827 | rpci->nkern_readwriters++; | ||
| 828 | goto out; | ||
| 829 | } | ||
| 830 | |||
| 831 | err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, | ||
| 832 | private, ops, flags); | ||
| 833 | if (err) | 861 | if (err) |
| 834 | goto out_err; | 862 | goto out_err; |
| 835 | out: | 863 | out: |
| @@ -842,7 +870,7 @@ out_err: | |||
| 842 | err); | 870 | err); |
| 843 | goto out; | 871 | goto out; |
| 844 | } | 872 | } |
| 845 | EXPORT_SYMBOL_GPL(rpc_mkpipe); | 873 | EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry); |
| 846 | 874 | ||
| 847 | /** | 875 | /** |
| 848 | * rpc_unlink - remove a pipe | 876 | * rpc_unlink - remove a pipe |
| @@ -915,7 +943,7 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry, | |||
| 915 | 943 | ||
| 916 | /** | 944 | /** |
| 917 | * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() | 945 | * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() |
| 918 | * @dentry: directory to remove | 946 | * @clnt: rpc client |
| 919 | */ | 947 | */ |
| 920 | int rpc_remove_client_dir(struct dentry *dentry) | 948 | int rpc_remove_client_dir(struct dentry *dentry) |
| 921 | { | 949 | { |
| @@ -1020,11 +1048,64 @@ static const struct rpc_filelist files[] = { | |||
| 1020 | }, | 1048 | }, |
| 1021 | }; | 1049 | }; |
| 1022 | 1050 | ||
| 1051 | /* | ||
| 1052 | * This call can be used only in RPC pipefs mount notification hooks. | ||
| 1053 | */ | ||
| 1054 | struct dentry *rpc_d_lookup_sb(const struct super_block *sb, | ||
| 1055 | const unsigned char *dir_name) | ||
| 1056 | { | ||
| 1057 | struct qstr dir = { | ||
| 1058 | .name = dir_name, | ||
| 1059 | .len = strlen(dir_name), | ||
| 1060 | .hash = full_name_hash(dir_name, strlen(dir_name)), | ||
| 1061 | }; | ||
| 1062 | |||
| 1063 | return d_lookup(sb->s_root, &dir); | ||
| 1064 | } | ||
| 1065 | EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); | ||
| 1066 | |||
| 1067 | void rpc_pipefs_init_net(struct net *net) | ||
| 1068 | { | ||
| 1069 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1070 | |||
| 1071 | mutex_init(&sn->pipefs_sb_lock); | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | /* | ||
| 1075 | * This call will be used for per network namespace operations calls. | ||
| 1076 | * Note: Function will be returned with pipefs_sb_lock taken if superblock was | ||
| 1077 | * found. This lock have to be released by rpc_put_sb_net() when all operations | ||
| 1078 | * will be completed. | ||
| 1079 | */ | ||
| 1080 | struct super_block *rpc_get_sb_net(const struct net *net) | ||
| 1081 | { | ||
| 1082 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1083 | |||
| 1084 | mutex_lock(&sn->pipefs_sb_lock); | ||
| 1085 | if (sn->pipefs_sb) | ||
| 1086 | return sn->pipefs_sb; | ||
| 1087 | mutex_unlock(&sn->pipefs_sb_lock); | ||
| 1088 | return NULL; | ||
| 1089 | } | ||
| 1090 | EXPORT_SYMBOL_GPL(rpc_get_sb_net); | ||
| 1091 | |||
| 1092 | void rpc_put_sb_net(const struct net *net) | ||
| 1093 | { | ||
| 1094 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1095 | |||
| 1096 | BUG_ON(sn->pipefs_sb == NULL); | ||
| 1097 | mutex_unlock(&sn->pipefs_sb_lock); | ||
| 1098 | } | ||
| 1099 | EXPORT_SYMBOL_GPL(rpc_put_sb_net); | ||
| 1100 | |||
| 1023 | static int | 1101 | static int |
| 1024 | rpc_fill_super(struct super_block *sb, void *data, int silent) | 1102 | rpc_fill_super(struct super_block *sb, void *data, int silent) |
| 1025 | { | 1103 | { |
| 1026 | struct inode *inode; | 1104 | struct inode *inode; |
| 1027 | struct dentry *root; | 1105 | struct dentry *root; |
| 1106 | struct net *net = data; | ||
| 1107 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1108 | int err; | ||
| 1028 | 1109 | ||
| 1029 | sb->s_blocksize = PAGE_CACHE_SIZE; | 1110 | sb->s_blocksize = PAGE_CACHE_SIZE; |
| 1030 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 1111 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
| @@ -1038,21 +1119,54 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1038 | return -ENOMEM; | 1119 | return -ENOMEM; |
| 1039 | if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) | 1120 | if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) |
| 1040 | return -ENOMEM; | 1121 | return -ENOMEM; |
| 1122 | dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", net, | ||
| 1123 | NET_NAME(net)); | ||
| 1124 | err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list, | ||
| 1125 | RPC_PIPEFS_MOUNT, | ||
| 1126 | sb); | ||
| 1127 | if (err) | ||
| 1128 | goto err_depopulate; | ||
| 1129 | sb->s_fs_info = get_net(net); | ||
| 1130 | sn->pipefs_sb = sb; | ||
| 1041 | return 0; | 1131 | return 0; |
| 1132 | |||
| 1133 | err_depopulate: | ||
| 1134 | blocking_notifier_call_chain(&rpc_pipefs_notifier_list, | ||
| 1135 | RPC_PIPEFS_UMOUNT, | ||
| 1136 | sb); | ||
| 1137 | __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); | ||
| 1138 | return err; | ||
| 1042 | } | 1139 | } |
| 1043 | 1140 | ||
| 1044 | static struct dentry * | 1141 | static struct dentry * |
| 1045 | rpc_mount(struct file_system_type *fs_type, | 1142 | rpc_mount(struct file_system_type *fs_type, |
| 1046 | int flags, const char *dev_name, void *data) | 1143 | int flags, const char *dev_name, void *data) |
| 1047 | { | 1144 | { |
| 1048 | return mount_single(fs_type, flags, data, rpc_fill_super); | 1145 | return mount_ns(fs_type, flags, current->nsproxy->net_ns, rpc_fill_super); |
| 1146 | } | ||
| 1147 | |||
| 1148 | static void rpc_kill_sb(struct super_block *sb) | ||
| 1149 | { | ||
| 1150 | struct net *net = sb->s_fs_info; | ||
| 1151 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 1152 | |||
| 1153 | mutex_lock(&sn->pipefs_sb_lock); | ||
| 1154 | sn->pipefs_sb = NULL; | ||
| 1155 | mutex_unlock(&sn->pipefs_sb_lock); | ||
| 1156 | put_net(net); | ||
| 1157 | dprintk("RPC: sending pipefs UMOUNT notification for net %p%s\n", net, | ||
| 1158 | NET_NAME(net)); | ||
| 1159 | blocking_notifier_call_chain(&rpc_pipefs_notifier_list, | ||
| 1160 | RPC_PIPEFS_UMOUNT, | ||
| 1161 | sb); | ||
| 1162 | kill_litter_super(sb); | ||
| 1049 | } | 1163 | } |
| 1050 | 1164 | ||
| 1051 | static struct file_system_type rpc_pipe_fs_type = { | 1165 | static struct file_system_type rpc_pipe_fs_type = { |
| 1052 | .owner = THIS_MODULE, | 1166 | .owner = THIS_MODULE, |
| 1053 | .name = "rpc_pipefs", | 1167 | .name = "rpc_pipefs", |
| 1054 | .mount = rpc_mount, | 1168 | .mount = rpc_mount, |
| 1055 | .kill_sb = kill_litter_super, | 1169 | .kill_sb = rpc_kill_sb, |
| 1056 | }; | 1170 | }; |
| 1057 | 1171 | ||
| 1058 | static void | 1172 | static void |
| @@ -1062,16 +1176,8 @@ init_once(void *foo) | |||
| 1062 | 1176 | ||
| 1063 | inode_init_once(&rpci->vfs_inode); | 1177 | inode_init_once(&rpci->vfs_inode); |
| 1064 | rpci->private = NULL; | 1178 | rpci->private = NULL; |
| 1065 | rpci->nreaders = 0; | 1179 | rpci->pipe = NULL; |
| 1066 | rpci->nwriters = 0; | ||
| 1067 | INIT_LIST_HEAD(&rpci->in_upcall); | ||
| 1068 | INIT_LIST_HEAD(&rpci->in_downcall); | ||
| 1069 | INIT_LIST_HEAD(&rpci->pipe); | ||
| 1070 | rpci->pipelen = 0; | ||
| 1071 | init_waitqueue_head(&rpci->waitq); | 1180 | init_waitqueue_head(&rpci->waitq); |
| 1072 | INIT_DELAYED_WORK(&rpci->queue_timeout, | ||
| 1073 | rpc_timeout_upcall_queue); | ||
| 1074 | rpci->ops = NULL; | ||
| 1075 | } | 1181 | } |
| 1076 | 1182 | ||
| 1077 | int register_rpc_pipefs(void) | 1183 | int register_rpc_pipefs(void) |
| @@ -1085,17 +1191,24 @@ int register_rpc_pipefs(void) | |||
| 1085 | init_once); | 1191 | init_once); |
| 1086 | if (!rpc_inode_cachep) | 1192 | if (!rpc_inode_cachep) |
| 1087 | return -ENOMEM; | 1193 | return -ENOMEM; |
| 1194 | err = rpc_clients_notifier_register(); | ||
| 1195 | if (err) | ||
| 1196 | goto err_notifier; | ||
| 1088 | err = register_filesystem(&rpc_pipe_fs_type); | 1197 | err = register_filesystem(&rpc_pipe_fs_type); |
| 1089 | if (err) { | 1198 | if (err) |
| 1090 | kmem_cache_destroy(rpc_inode_cachep); | 1199 | goto err_register; |
| 1091 | return err; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | return 0; | 1200 | return 0; |
| 1201 | |||
| 1202 | err_register: | ||
| 1203 | rpc_clients_notifier_unregister(); | ||
| 1204 | err_notifier: | ||
| 1205 | kmem_cache_destroy(rpc_inode_cachep); | ||
| 1206 | return err; | ||
| 1095 | } | 1207 | } |
| 1096 | 1208 | ||
| 1097 | void unregister_rpc_pipefs(void) | 1209 | void unregister_rpc_pipefs(void) |
| 1098 | { | 1210 | { |
| 1211 | rpc_clients_notifier_unregister(); | ||
| 1099 | kmem_cache_destroy(rpc_inode_cachep); | 1212 | kmem_cache_destroy(rpc_inode_cachep); |
| 1100 | unregister_filesystem(&rpc_pipe_fs_type); | 1213 | unregister_filesystem(&rpc_pipe_fs_type); |
| 1101 | } | 1214 | } |
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 8761bf8e36fc..207a74696c9f 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
| @@ -23,12 +23,15 @@ | |||
| 23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
| 24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/nsproxy.h> | ||
| 26 | #include <net/ipv6.h> | 27 | #include <net/ipv6.h> |
| 27 | 28 | ||
| 28 | #include <linux/sunrpc/clnt.h> | 29 | #include <linux/sunrpc/clnt.h> |
| 29 | #include <linux/sunrpc/sched.h> | 30 | #include <linux/sunrpc/sched.h> |
| 30 | #include <linux/sunrpc/xprtsock.h> | 31 | #include <linux/sunrpc/xprtsock.h> |
| 31 | 32 | ||
| 33 | #include "netns.h" | ||
| 34 | |||
| 32 | #ifdef RPC_DEBUG | 35 | #ifdef RPC_DEBUG |
| 33 | # define RPCDBG_FACILITY RPCDBG_BIND | 36 | # define RPCDBG_FACILITY RPCDBG_BIND |
| 34 | #endif | 37 | #endif |
| @@ -109,13 +112,7 @@ enum { | |||
| 109 | 112 | ||
| 110 | static void rpcb_getport_done(struct rpc_task *, void *); | 113 | static void rpcb_getport_done(struct rpc_task *, void *); |
| 111 | static void rpcb_map_release(void *data); | 114 | static void rpcb_map_release(void *data); |
| 112 | static struct rpc_program rpcb_program; | 115 | static const struct rpc_program rpcb_program; |
| 113 | |||
| 114 | static struct rpc_clnt * rpcb_local_clnt; | ||
| 115 | static struct rpc_clnt * rpcb_local_clnt4; | ||
| 116 | |||
| 117 | DEFINE_SPINLOCK(rpcb_clnt_lock); | ||
| 118 | unsigned int rpcb_users; | ||
| 119 | 116 | ||
| 120 | struct rpcbind_args { | 117 | struct rpcbind_args { |
| 121 | struct rpc_xprt * r_xprt; | 118 | struct rpc_xprt * r_xprt; |
| @@ -140,8 +137,8 @@ struct rpcb_info { | |||
| 140 | struct rpc_procinfo * rpc_proc; | 137 | struct rpc_procinfo * rpc_proc; |
| 141 | }; | 138 | }; |
| 142 | 139 | ||
| 143 | static struct rpcb_info rpcb_next_version[]; | 140 | static const struct rpcb_info rpcb_next_version[]; |
| 144 | static struct rpcb_info rpcb_next_version6[]; | 141 | static const struct rpcb_info rpcb_next_version6[]; |
| 145 | 142 | ||
| 146 | static const struct rpc_call_ops rpcb_getport_ops = { | 143 | static const struct rpc_call_ops rpcb_getport_ops = { |
| 147 | .rpc_call_done = rpcb_getport_done, | 144 | .rpc_call_done = rpcb_getport_done, |
| @@ -164,32 +161,34 @@ static void rpcb_map_release(void *data) | |||
| 164 | kfree(map); | 161 | kfree(map); |
| 165 | } | 162 | } |
| 166 | 163 | ||
| 167 | static int rpcb_get_local(void) | 164 | static int rpcb_get_local(struct net *net) |
| 168 | { | 165 | { |
| 169 | int cnt; | 166 | int cnt; |
| 167 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 170 | 168 | ||
| 171 | spin_lock(&rpcb_clnt_lock); | 169 | spin_lock(&sn->rpcb_clnt_lock); |
| 172 | if (rpcb_users) | 170 | if (sn->rpcb_users) |
| 173 | rpcb_users++; | 171 | sn->rpcb_users++; |
| 174 | cnt = rpcb_users; | 172 | cnt = sn->rpcb_users; |
| 175 | spin_unlock(&rpcb_clnt_lock); | 173 | spin_unlock(&sn->rpcb_clnt_lock); |
| 176 | 174 | ||
| 177 | return cnt; | 175 | return cnt; |
| 178 | } | 176 | } |
| 179 | 177 | ||
| 180 | void rpcb_put_local(void) | 178 | void rpcb_put_local(struct net *net) |
| 181 | { | 179 | { |
| 182 | struct rpc_clnt *clnt = rpcb_local_clnt; | 180 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
| 183 | struct rpc_clnt *clnt4 = rpcb_local_clnt4; | 181 | struct rpc_clnt *clnt = sn->rpcb_local_clnt; |
| 182 | struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; | ||
| 184 | int shutdown; | 183 | int shutdown; |
| 185 | 184 | ||
| 186 | spin_lock(&rpcb_clnt_lock); | 185 | spin_lock(&sn->rpcb_clnt_lock); |
| 187 | if (--rpcb_users == 0) { | 186 | if (--sn->rpcb_users == 0) { |
| 188 | rpcb_local_clnt = NULL; | 187 | sn->rpcb_local_clnt = NULL; |
| 189 | rpcb_local_clnt4 = NULL; | 188 | sn->rpcb_local_clnt4 = NULL; |
| 190 | } | 189 | } |
| 191 | shutdown = !rpcb_users; | 190 | shutdown = !sn->rpcb_users; |
| 192 | spin_unlock(&rpcb_clnt_lock); | 191 | spin_unlock(&sn->rpcb_clnt_lock); |
| 193 | 192 | ||
| 194 | if (shutdown) { | 193 | if (shutdown) { |
| 195 | /* | 194 | /* |
| @@ -202,30 +201,34 @@ void rpcb_put_local(void) | |||
| 202 | } | 201 | } |
| 203 | } | 202 | } |
| 204 | 203 | ||
| 205 | static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4) | 204 | static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt, |
| 205 | struct rpc_clnt *clnt4) | ||
| 206 | { | 206 | { |
| 207 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 208 | |||
| 207 | /* Protected by rpcb_create_local_mutex */ | 209 | /* Protected by rpcb_create_local_mutex */ |
| 208 | rpcb_local_clnt = clnt; | 210 | sn->rpcb_local_clnt = clnt; |
| 209 | rpcb_local_clnt4 = clnt4; | 211 | sn->rpcb_local_clnt4 = clnt4; |
| 210 | smp_wmb(); | 212 | smp_wmb(); |
| 211 | rpcb_users = 1; | 213 | sn->rpcb_users = 1; |
| 212 | dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " | 214 | dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " |
| 213 | "%p, rpcb_local_clnt4: %p)\n", rpcb_local_clnt, | 215 | "%p, rpcb_local_clnt4: %p) for net %p%s\n", |
| 214 | rpcb_local_clnt4); | 216 | sn->rpcb_local_clnt, sn->rpcb_local_clnt4, |
| 217 | net, (net == &init_net) ? " (init_net)" : ""); | ||
| 215 | } | 218 | } |
| 216 | 219 | ||
| 217 | /* | 220 | /* |
| 218 | * Returns zero on success, otherwise a negative errno value | 221 | * Returns zero on success, otherwise a negative errno value |
| 219 | * is returned. | 222 | * is returned. |
| 220 | */ | 223 | */ |
| 221 | static int rpcb_create_local_unix(void) | 224 | static int rpcb_create_local_unix(struct net *net) |
| 222 | { | 225 | { |
| 223 | static const struct sockaddr_un rpcb_localaddr_rpcbind = { | 226 | static const struct sockaddr_un rpcb_localaddr_rpcbind = { |
| 224 | .sun_family = AF_LOCAL, | 227 | .sun_family = AF_LOCAL, |
| 225 | .sun_path = RPCBIND_SOCK_PATHNAME, | 228 | .sun_path = RPCBIND_SOCK_PATHNAME, |
| 226 | }; | 229 | }; |
| 227 | struct rpc_create_args args = { | 230 | struct rpc_create_args args = { |
| 228 | .net = &init_net, | 231 | .net = net, |
| 229 | .protocol = XPRT_TRANSPORT_LOCAL, | 232 | .protocol = XPRT_TRANSPORT_LOCAL, |
| 230 | .address = (struct sockaddr *)&rpcb_localaddr_rpcbind, | 233 | .address = (struct sockaddr *)&rpcb_localaddr_rpcbind, |
| 231 | .addrsize = sizeof(rpcb_localaddr_rpcbind), | 234 | .addrsize = sizeof(rpcb_localaddr_rpcbind), |
| @@ -258,7 +261,7 @@ static int rpcb_create_local_unix(void) | |||
| 258 | clnt4 = NULL; | 261 | clnt4 = NULL; |
| 259 | } | 262 | } |
| 260 | 263 | ||
| 261 | rpcb_set_local(clnt, clnt4); | 264 | rpcb_set_local(net, clnt, clnt4); |
| 262 | 265 | ||
| 263 | out: | 266 | out: |
| 264 | return result; | 267 | return result; |
| @@ -268,7 +271,7 @@ out: | |||
| 268 | * Returns zero on success, otherwise a negative errno value | 271 | * Returns zero on success, otherwise a negative errno value |
| 269 | * is returned. | 272 | * is returned. |
| 270 | */ | 273 | */ |
| 271 | static int rpcb_create_local_net(void) | 274 | static int rpcb_create_local_net(struct net *net) |
| 272 | { | 275 | { |
| 273 | static const struct sockaddr_in rpcb_inaddr_loopback = { | 276 | static const struct sockaddr_in rpcb_inaddr_loopback = { |
| 274 | .sin_family = AF_INET, | 277 | .sin_family = AF_INET, |
| @@ -276,7 +279,7 @@ static int rpcb_create_local_net(void) | |||
| 276 | .sin_port = htons(RPCBIND_PORT), | 279 | .sin_port = htons(RPCBIND_PORT), |
| 277 | }; | 280 | }; |
| 278 | struct rpc_create_args args = { | 281 | struct rpc_create_args args = { |
| 279 | .net = &init_net, | 282 | .net = net, |
| 280 | .protocol = XPRT_TRANSPORT_TCP, | 283 | .protocol = XPRT_TRANSPORT_TCP, |
| 281 | .address = (struct sockaddr *)&rpcb_inaddr_loopback, | 284 | .address = (struct sockaddr *)&rpcb_inaddr_loopback, |
| 282 | .addrsize = sizeof(rpcb_inaddr_loopback), | 285 | .addrsize = sizeof(rpcb_inaddr_loopback), |
| @@ -310,7 +313,7 @@ static int rpcb_create_local_net(void) | |||
| 310 | clnt4 = NULL; | 313 | clnt4 = NULL; |
| 311 | } | 314 | } |
| 312 | 315 | ||
| 313 | rpcb_set_local(clnt, clnt4); | 316 | rpcb_set_local(net, clnt, clnt4); |
| 314 | 317 | ||
| 315 | out: | 318 | out: |
| 316 | return result; | 319 | return result; |
| @@ -320,31 +323,32 @@ out: | |||
| 320 | * Returns zero on success, otherwise a negative errno value | 323 | * Returns zero on success, otherwise a negative errno value |
| 321 | * is returned. | 324 | * is returned. |
| 322 | */ | 325 | */ |
| 323 | int rpcb_create_local(void) | 326 | int rpcb_create_local(struct net *net) |
| 324 | { | 327 | { |
| 325 | static DEFINE_MUTEX(rpcb_create_local_mutex); | 328 | static DEFINE_MUTEX(rpcb_create_local_mutex); |
| 326 | int result = 0; | 329 | int result = 0; |
| 327 | 330 | ||
| 328 | if (rpcb_get_local()) | 331 | if (rpcb_get_local(net)) |
| 329 | return result; | 332 | return result; |
| 330 | 333 | ||
| 331 | mutex_lock(&rpcb_create_local_mutex); | 334 | mutex_lock(&rpcb_create_local_mutex); |
| 332 | if (rpcb_get_local()) | 335 | if (rpcb_get_local(net)) |
| 333 | goto out; | 336 | goto out; |
| 334 | 337 | ||
| 335 | if (rpcb_create_local_unix() != 0) | 338 | if (rpcb_create_local_unix(net) != 0) |
| 336 | result = rpcb_create_local_net(); | 339 | result = rpcb_create_local_net(net); |
| 337 | 340 | ||
| 338 | out: | 341 | out: |
| 339 | mutex_unlock(&rpcb_create_local_mutex); | 342 | mutex_unlock(&rpcb_create_local_mutex); |
| 340 | return result; | 343 | return result; |
| 341 | } | 344 | } |
| 342 | 345 | ||
| 343 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | 346 | static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname, |
| 344 | size_t salen, int proto, u32 version) | 347 | struct sockaddr *srvaddr, size_t salen, |
| 348 | int proto, u32 version) | ||
| 345 | { | 349 | { |
| 346 | struct rpc_create_args args = { | 350 | struct rpc_create_args args = { |
| 347 | .net = &init_net, | 351 | .net = net, |
| 348 | .protocol = proto, | 352 | .protocol = proto, |
| 349 | .address = srvaddr, | 353 | .address = srvaddr, |
| 350 | .addrsize = salen, | 354 | .addrsize = salen, |
| @@ -420,7 +424,7 @@ static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg) | |||
| 420 | * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 | 424 | * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 |
| 421 | * addresses). | 425 | * addresses). |
| 422 | */ | 426 | */ |
| 423 | int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) | 427 | int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short port) |
| 424 | { | 428 | { |
| 425 | struct rpcbind_args map = { | 429 | struct rpcbind_args map = { |
| 426 | .r_prog = prog, | 430 | .r_prog = prog, |
| @@ -431,6 +435,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) | |||
| 431 | struct rpc_message msg = { | 435 | struct rpc_message msg = { |
| 432 | .rpc_argp = &map, | 436 | .rpc_argp = &map, |
| 433 | }; | 437 | }; |
| 438 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 434 | 439 | ||
| 435 | dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " | 440 | dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " |
| 436 | "rpcbind\n", (port ? "" : "un"), | 441 | "rpcbind\n", (port ? "" : "un"), |
| @@ -440,13 +445,14 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) | |||
| 440 | if (port) | 445 | if (port) |
| 441 | msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; | 446 | msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; |
| 442 | 447 | ||
| 443 | return rpcb_register_call(rpcb_local_clnt, &msg); | 448 | return rpcb_register_call(sn->rpcb_local_clnt, &msg); |
| 444 | } | 449 | } |
| 445 | 450 | ||
| 446 | /* | 451 | /* |
| 447 | * Fill in AF_INET family-specific arguments to register | 452 | * Fill in AF_INET family-specific arguments to register |
| 448 | */ | 453 | */ |
| 449 | static int rpcb_register_inet4(const struct sockaddr *sap, | 454 | static int rpcb_register_inet4(struct sunrpc_net *sn, |
| 455 | const struct sockaddr *sap, | ||
| 450 | struct rpc_message *msg) | 456 | struct rpc_message *msg) |
| 451 | { | 457 | { |
| 452 | const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; | 458 | const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; |
| @@ -465,7 +471,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap, | |||
| 465 | if (port) | 471 | if (port) |
| 466 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; | 472 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; |
| 467 | 473 | ||
| 468 | result = rpcb_register_call(rpcb_local_clnt4, msg); | 474 | result = rpcb_register_call(sn->rpcb_local_clnt4, msg); |
| 469 | kfree(map->r_addr); | 475 | kfree(map->r_addr); |
| 470 | return result; | 476 | return result; |
| 471 | } | 477 | } |
| @@ -473,7 +479,8 @@ static int rpcb_register_inet4(const struct sockaddr *sap, | |||
| 473 | /* | 479 | /* |
| 474 | * Fill in AF_INET6 family-specific arguments to register | 480 | * Fill in AF_INET6 family-specific arguments to register |
| 475 | */ | 481 | */ |
| 476 | static int rpcb_register_inet6(const struct sockaddr *sap, | 482 | static int rpcb_register_inet6(struct sunrpc_net *sn, |
| 483 | const struct sockaddr *sap, | ||
| 477 | struct rpc_message *msg) | 484 | struct rpc_message *msg) |
| 478 | { | 485 | { |
| 479 | const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; | 486 | const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; |
| @@ -492,12 +499,13 @@ static int rpcb_register_inet6(const struct sockaddr *sap, | |||
| 492 | if (port) | 499 | if (port) |
| 493 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; | 500 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; |
| 494 | 501 | ||
| 495 | result = rpcb_register_call(rpcb_local_clnt4, msg); | 502 | result = rpcb_register_call(sn->rpcb_local_clnt4, msg); |
| 496 | kfree(map->r_addr); | 503 | kfree(map->r_addr); |
| 497 | return result; | 504 | return result; |
| 498 | } | 505 | } |
| 499 | 506 | ||
| 500 | static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) | 507 | static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn, |
| 508 | struct rpc_message *msg) | ||
| 501 | { | 509 | { |
| 502 | struct rpcbind_args *map = msg->rpc_argp; | 510 | struct rpcbind_args *map = msg->rpc_argp; |
| 503 | 511 | ||
| @@ -508,7 +516,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) | |||
| 508 | map->r_addr = ""; | 516 | map->r_addr = ""; |
| 509 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; | 517 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; |
| 510 | 518 | ||
| 511 | return rpcb_register_call(rpcb_local_clnt4, msg); | 519 | return rpcb_register_call(sn->rpcb_local_clnt4, msg); |
| 512 | } | 520 | } |
| 513 | 521 | ||
| 514 | /** | 522 | /** |
| @@ -554,7 +562,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) | |||
| 554 | * service on any IPv4 address, but not on IPv6. The latter | 562 | * service on any IPv4 address, but not on IPv6. The latter |
| 555 | * advertises the service on all IPv4 and IPv6 addresses. | 563 | * advertises the service on all IPv4 and IPv6 addresses. |
| 556 | */ | 564 | */ |
| 557 | int rpcb_v4_register(const u32 program, const u32 version, | 565 | int rpcb_v4_register(struct net *net, const u32 program, const u32 version, |
| 558 | const struct sockaddr *address, const char *netid) | 566 | const struct sockaddr *address, const char *netid) |
| 559 | { | 567 | { |
| 560 | struct rpcbind_args map = { | 568 | struct rpcbind_args map = { |
| @@ -566,18 +574,19 @@ int rpcb_v4_register(const u32 program, const u32 version, | |||
| 566 | struct rpc_message msg = { | 574 | struct rpc_message msg = { |
| 567 | .rpc_argp = &map, | 575 | .rpc_argp = &map, |
| 568 | }; | 576 | }; |
| 577 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 569 | 578 | ||
| 570 | if (rpcb_local_clnt4 == NULL) | 579 | if (sn->rpcb_local_clnt4 == NULL) |
| 571 | return -EPROTONOSUPPORT; | 580 | return -EPROTONOSUPPORT; |
| 572 | 581 | ||
| 573 | if (address == NULL) | 582 | if (address == NULL) |
| 574 | return rpcb_unregister_all_protofamilies(&msg); | 583 | return rpcb_unregister_all_protofamilies(sn, &msg); |
| 575 | 584 | ||
| 576 | switch (address->sa_family) { | 585 | switch (address->sa_family) { |
| 577 | case AF_INET: | 586 | case AF_INET: |
| 578 | return rpcb_register_inet4(address, &msg); | 587 | return rpcb_register_inet4(sn, address, &msg); |
| 579 | case AF_INET6: | 588 | case AF_INET6: |
| 580 | return rpcb_register_inet6(address, &msg); | 589 | return rpcb_register_inet6(sn, address, &msg); |
| 581 | } | 590 | } |
| 582 | 591 | ||
| 583 | return -EAFNOSUPPORT; | 592 | return -EAFNOSUPPORT; |
| @@ -611,9 +620,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi | |||
| 611 | static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) | 620 | static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) |
| 612 | { | 621 | { |
| 613 | struct rpc_clnt *parent = clnt->cl_parent; | 622 | struct rpc_clnt *parent = clnt->cl_parent; |
| 623 | struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt); | ||
| 614 | 624 | ||
| 615 | while (parent != clnt) { | 625 | while (parent != clnt) { |
| 616 | if (parent->cl_xprt != clnt->cl_xprt) | 626 | if (rcu_dereference(parent->cl_xprt) != xprt) |
| 617 | break; | 627 | break; |
| 618 | if (clnt->cl_autobind) | 628 | if (clnt->cl_autobind) |
| 619 | break; | 629 | break; |
| @@ -644,12 +654,16 @@ void rpcb_getport_async(struct rpc_task *task) | |||
| 644 | size_t salen; | 654 | size_t salen; |
| 645 | int status; | 655 | int status; |
| 646 | 656 | ||
| 647 | clnt = rpcb_find_transport_owner(task->tk_client); | 657 | rcu_read_lock(); |
| 648 | xprt = clnt->cl_xprt; | 658 | do { |
| 659 | clnt = rpcb_find_transport_owner(task->tk_client); | ||
| 660 | xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); | ||
| 661 | } while (xprt == NULL); | ||
| 662 | rcu_read_unlock(); | ||
| 649 | 663 | ||
| 650 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", | 664 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", |
| 651 | task->tk_pid, __func__, | 665 | task->tk_pid, __func__, |
| 652 | clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); | 666 | xprt->servername, clnt->cl_prog, clnt->cl_vers, xprt->prot); |
| 653 | 667 | ||
| 654 | /* Put self on the wait queue to ensure we get notified if | 668 | /* Put self on the wait queue to ensure we get notified if |
| 655 | * some other task is already attempting to bind the port */ | 669 | * some other task is already attempting to bind the port */ |
| @@ -658,6 +672,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
| 658 | if (xprt_test_and_set_binding(xprt)) { | 672 | if (xprt_test_and_set_binding(xprt)) { |
| 659 | dprintk("RPC: %5u %s: waiting for another binder\n", | 673 | dprintk("RPC: %5u %s: waiting for another binder\n", |
| 660 | task->tk_pid, __func__); | 674 | task->tk_pid, __func__); |
| 675 | xprt_put(xprt); | ||
| 661 | return; | 676 | return; |
| 662 | } | 677 | } |
| 663 | 678 | ||
| @@ -699,8 +714,8 @@ void rpcb_getport_async(struct rpc_task *task) | |||
| 699 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", | 714 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", |
| 700 | task->tk_pid, __func__, bind_version); | 715 | task->tk_pid, __func__, bind_version); |
| 701 | 716 | ||
| 702 | rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, | 717 | rpcb_clnt = rpcb_create(xprt->xprt_net, xprt->servername, sap, salen, |
| 703 | bind_version); | 718 | xprt->prot, bind_version); |
| 704 | if (IS_ERR(rpcb_clnt)) { | 719 | if (IS_ERR(rpcb_clnt)) { |
| 705 | status = PTR_ERR(rpcb_clnt); | 720 | status = PTR_ERR(rpcb_clnt); |
| 706 | dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", | 721 | dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", |
| @@ -725,7 +740,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
| 725 | switch (bind_version) { | 740 | switch (bind_version) { |
| 726 | case RPCBVERS_4: | 741 | case RPCBVERS_4: |
| 727 | case RPCBVERS_3: | 742 | case RPCBVERS_3: |
| 728 | map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); | 743 | map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID]; |
| 729 | map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC); | 744 | map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC); |
| 730 | map->r_owner = ""; | 745 | map->r_owner = ""; |
| 731 | break; | 746 | break; |
| @@ -754,6 +769,7 @@ bailout_release_client: | |||
| 754 | bailout_nofree: | 769 | bailout_nofree: |
| 755 | rpcb_wake_rpcbind_waiters(xprt, status); | 770 | rpcb_wake_rpcbind_waiters(xprt, status); |
| 756 | task->tk_status = status; | 771 | task->tk_status = status; |
| 772 | xprt_put(xprt); | ||
| 757 | } | 773 | } |
| 758 | EXPORT_SYMBOL_GPL(rpcb_getport_async); | 774 | EXPORT_SYMBOL_GPL(rpcb_getport_async); |
| 759 | 775 | ||
| @@ -801,11 +817,11 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) | |||
| 801 | static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr, | 817 | static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr, |
| 802 | const struct rpcbind_args *rpcb) | 818 | const struct rpcbind_args *rpcb) |
| 803 | { | 819 | { |
| 804 | struct rpc_task *task = req->rq_task; | ||
| 805 | __be32 *p; | 820 | __be32 *p; |
| 806 | 821 | ||
| 807 | dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n", | 822 | dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n", |
| 808 | task->tk_pid, task->tk_msg.rpc_proc->p_name, | 823 | req->rq_task->tk_pid, |
| 824 | req->rq_task->tk_msg.rpc_proc->p_name, | ||
| 809 | rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); | 825 | rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); |
| 810 | 826 | ||
| 811 | p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2); | 827 | p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2); |
| @@ -818,7 +834,6 @@ static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
| 818 | static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, | 834 | static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, |
| 819 | struct rpcbind_args *rpcb) | 835 | struct rpcbind_args *rpcb) |
| 820 | { | 836 | { |
| 821 | struct rpc_task *task = req->rq_task; | ||
| 822 | unsigned long port; | 837 | unsigned long port; |
| 823 | __be32 *p; | 838 | __be32 *p; |
| 824 | 839 | ||
| @@ -829,8 +844,8 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
| 829 | return -EIO; | 844 | return -EIO; |
| 830 | 845 | ||
| 831 | port = be32_to_cpup(p); | 846 | port = be32_to_cpup(p); |
| 832 | dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid, | 847 | dprintk("RPC: %5u PMAP_%s result: %lu\n", req->rq_task->tk_pid, |
| 833 | task->tk_msg.rpc_proc->p_name, port); | 848 | req->rq_task->tk_msg.rpc_proc->p_name, port); |
| 834 | if (unlikely(port > USHRT_MAX)) | 849 | if (unlikely(port > USHRT_MAX)) |
| 835 | return -EIO; | 850 | return -EIO; |
| 836 | 851 | ||
| @@ -841,7 +856,6 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
| 841 | static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr, | 856 | static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr, |
| 842 | unsigned int *boolp) | 857 | unsigned int *boolp) |
| 843 | { | 858 | { |
| 844 | struct rpc_task *task = req->rq_task; | ||
| 845 | __be32 *p; | 859 | __be32 *p; |
| 846 | 860 | ||
| 847 | p = xdr_inline_decode(xdr, 4); | 861 | p = xdr_inline_decode(xdr, 4); |
| @@ -853,7 +867,8 @@ static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
| 853 | *boolp = 1; | 867 | *boolp = 1; |
| 854 | 868 | ||
| 855 | dprintk("RPC: %5u RPCB_%s call %s\n", | 869 | dprintk("RPC: %5u RPCB_%s call %s\n", |
| 856 | task->tk_pid, task->tk_msg.rpc_proc->p_name, | 870 | req->rq_task->tk_pid, |
| 871 | req->rq_task->tk_msg.rpc_proc->p_name, | ||
| 857 | (*boolp ? "succeeded" : "failed")); | 872 | (*boolp ? "succeeded" : "failed")); |
| 858 | return 0; | 873 | return 0; |
| 859 | } | 874 | } |
| @@ -873,11 +888,11 @@ static void encode_rpcb_string(struct xdr_stream *xdr, const char *string, | |||
| 873 | static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, | 888 | static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, |
| 874 | const struct rpcbind_args *rpcb) | 889 | const struct rpcbind_args *rpcb) |
| 875 | { | 890 | { |
| 876 | struct rpc_task *task = req->rq_task; | ||
| 877 | __be32 *p; | 891 | __be32 *p; |
| 878 | 892 | ||
| 879 | dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n", | 893 | dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n", |
| 880 | task->tk_pid, task->tk_msg.rpc_proc->p_name, | 894 | req->rq_task->tk_pid, |
| 895 | req->rq_task->tk_msg.rpc_proc->p_name, | ||
| 881 | rpcb->r_prog, rpcb->r_vers, | 896 | rpcb->r_prog, rpcb->r_vers, |
| 882 | rpcb->r_netid, rpcb->r_addr); | 897 | rpcb->r_netid, rpcb->r_addr); |
| 883 | 898 | ||
| @@ -895,7 +910,6 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
| 895 | { | 910 | { |
| 896 | struct sockaddr_storage address; | 911 | struct sockaddr_storage address; |
| 897 | struct sockaddr *sap = (struct sockaddr *)&address; | 912 | struct sockaddr *sap = (struct sockaddr *)&address; |
| 898 | struct rpc_task *task = req->rq_task; | ||
| 899 | __be32 *p; | 913 | __be32 *p; |
| 900 | u32 len; | 914 | u32 len; |
| 901 | 915 | ||
| @@ -912,7 +926,7 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
| 912 | */ | 926 | */ |
| 913 | if (len == 0) { | 927 | if (len == 0) { |
| 914 | dprintk("RPC: %5u RPCB reply: program not registered\n", | 928 | dprintk("RPC: %5u RPCB reply: program not registered\n", |
| 915 | task->tk_pid); | 929 | req->rq_task->tk_pid); |
| 916 | return 0; | 930 | return 0; |
| 917 | } | 931 | } |
| 918 | 932 | ||
| @@ -922,10 +936,11 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
| 922 | p = xdr_inline_decode(xdr, len); | 936 | p = xdr_inline_decode(xdr, len); |
| 923 | if (unlikely(p == NULL)) | 937 | if (unlikely(p == NULL)) |
| 924 | goto out_fail; | 938 | goto out_fail; |
| 925 | dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid, | 939 | dprintk("RPC: %5u RPCB_%s reply: %s\n", req->rq_task->tk_pid, |
| 926 | task->tk_msg.rpc_proc->p_name, (char *)p); | 940 | req->rq_task->tk_msg.rpc_proc->p_name, (char *)p); |
| 927 | 941 | ||
| 928 | if (rpc_uaddr2sockaddr((char *)p, len, sap, sizeof(address)) == 0) | 942 | if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len, |
| 943 | sap, sizeof(address)) == 0) | ||
| 929 | goto out_fail; | 944 | goto out_fail; |
| 930 | rpcb->r_port = rpc_get_port(sap); | 945 | rpcb->r_port = rpc_get_port(sap); |
| 931 | 946 | ||
| @@ -933,7 +948,8 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
| 933 | 948 | ||
| 934 | out_fail: | 949 | out_fail: |
| 935 | dprintk("RPC: %5u malformed RPCB_%s reply\n", | 950 | dprintk("RPC: %5u malformed RPCB_%s reply\n", |
| 936 | task->tk_pid, task->tk_msg.rpc_proc->p_name); | 951 | req->rq_task->tk_pid, |
| 952 | req->rq_task->tk_msg.rpc_proc->p_name); | ||
| 937 | return -EIO; | 953 | return -EIO; |
| 938 | } | 954 | } |
| 939 | 955 | ||
| @@ -1041,7 +1057,7 @@ static struct rpc_procinfo rpcb_procedures4[] = { | |||
| 1041 | }, | 1057 | }, |
| 1042 | }; | 1058 | }; |
| 1043 | 1059 | ||
| 1044 | static struct rpcb_info rpcb_next_version[] = { | 1060 | static const struct rpcb_info rpcb_next_version[] = { |
| 1045 | { | 1061 | { |
| 1046 | .rpc_vers = RPCBVERS_2, | 1062 | .rpc_vers = RPCBVERS_2, |
| 1047 | .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], | 1063 | .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], |
| @@ -1051,7 +1067,7 @@ static struct rpcb_info rpcb_next_version[] = { | |||
| 1051 | }, | 1067 | }, |
| 1052 | }; | 1068 | }; |
| 1053 | 1069 | ||
| 1054 | static struct rpcb_info rpcb_next_version6[] = { | 1070 | static const struct rpcb_info rpcb_next_version6[] = { |
| 1055 | { | 1071 | { |
| 1056 | .rpc_vers = RPCBVERS_4, | 1072 | .rpc_vers = RPCBVERS_4, |
| 1057 | .rpc_proc = &rpcb_procedures4[RPCBPROC_GETADDR], | 1073 | .rpc_proc = &rpcb_procedures4[RPCBPROC_GETADDR], |
| @@ -1065,25 +1081,25 @@ static struct rpcb_info rpcb_next_version6[] = { | |||
| 1065 | }, | 1081 | }, |
| 1066 | }; | 1082 | }; |
| 1067 | 1083 | ||
| 1068 | static struct rpc_version rpcb_version2 = { | 1084 | static const struct rpc_version rpcb_version2 = { |
| 1069 | .number = RPCBVERS_2, | 1085 | .number = RPCBVERS_2, |
| 1070 | .nrprocs = ARRAY_SIZE(rpcb_procedures2), | 1086 | .nrprocs = ARRAY_SIZE(rpcb_procedures2), |
| 1071 | .procs = rpcb_procedures2 | 1087 | .procs = rpcb_procedures2 |
| 1072 | }; | 1088 | }; |
| 1073 | 1089 | ||
| 1074 | static struct rpc_version rpcb_version3 = { | 1090 | static const struct rpc_version rpcb_version3 = { |
| 1075 | .number = RPCBVERS_3, | 1091 | .number = RPCBVERS_3, |
| 1076 | .nrprocs = ARRAY_SIZE(rpcb_procedures3), | 1092 | .nrprocs = ARRAY_SIZE(rpcb_procedures3), |
| 1077 | .procs = rpcb_procedures3 | 1093 | .procs = rpcb_procedures3 |
| 1078 | }; | 1094 | }; |
| 1079 | 1095 | ||
| 1080 | static struct rpc_version rpcb_version4 = { | 1096 | static const struct rpc_version rpcb_version4 = { |
| 1081 | .number = RPCBVERS_4, | 1097 | .number = RPCBVERS_4, |
| 1082 | .nrprocs = ARRAY_SIZE(rpcb_procedures4), | 1098 | .nrprocs = ARRAY_SIZE(rpcb_procedures4), |
| 1083 | .procs = rpcb_procedures4 | 1099 | .procs = rpcb_procedures4 |
| 1084 | }; | 1100 | }; |
| 1085 | 1101 | ||
| 1086 | static struct rpc_version *rpcb_version[] = { | 1102 | static const struct rpc_version *rpcb_version[] = { |
| 1087 | NULL, | 1103 | NULL, |
| 1088 | NULL, | 1104 | NULL, |
| 1089 | &rpcb_version2, | 1105 | &rpcb_version2, |
| @@ -1093,7 +1109,7 @@ static struct rpc_version *rpcb_version[] = { | |||
| 1093 | 1109 | ||
| 1094 | static struct rpc_stat rpcb_stats; | 1110 | static struct rpc_stat rpcb_stats; |
| 1095 | 1111 | ||
| 1096 | static struct rpc_program rpcb_program = { | 1112 | static const struct rpc_program rpcb_program = { |
| 1097 | .name = "rpcbind", | 1113 | .name = "rpcbind", |
| 1098 | .number = RPCBIND_PROGRAM, | 1114 | .number = RPCBIND_PROGRAM, |
| 1099 | .nrvers = ARRAY_SIZE(rpcb_version), | 1115 | .nrvers = ARRAY_SIZE(rpcb_version), |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 3341d8962786..994cfea2bad6 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -28,6 +28,9 @@ | |||
| 28 | #define RPCDBG_FACILITY RPCDBG_SCHED | 28 | #define RPCDBG_FACILITY RPCDBG_SCHED |
| 29 | #endif | 29 | #endif |
| 30 | 30 | ||
| 31 | #define CREATE_TRACE_POINTS | ||
| 32 | #include <trace/events/sunrpc.h> | ||
| 33 | |||
| 31 | /* | 34 | /* |
| 32 | * RPC slabs and memory pools | 35 | * RPC slabs and memory pools |
| 33 | */ | 36 | */ |
| @@ -205,9 +208,7 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c | |||
| 205 | queue->qlen = 0; | 208 | queue->qlen = 0; |
| 206 | setup_timer(&queue->timer_list.timer, __rpc_queue_timer_fn, (unsigned long)queue); | 209 | setup_timer(&queue->timer_list.timer, __rpc_queue_timer_fn, (unsigned long)queue); |
| 207 | INIT_LIST_HEAD(&queue->timer_list.list); | 210 | INIT_LIST_HEAD(&queue->timer_list.list); |
| 208 | #ifdef RPC_DEBUG | 211 | rpc_assign_waitqueue_name(queue, qname); |
| 209 | queue->name = qname; | ||
| 210 | #endif | ||
| 211 | } | 212 | } |
| 212 | 213 | ||
| 213 | void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname) | 214 | void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname) |
| @@ -251,6 +252,8 @@ static inline void rpc_task_set_debuginfo(struct rpc_task *task) | |||
| 251 | 252 | ||
| 252 | static void rpc_set_active(struct rpc_task *task) | 253 | static void rpc_set_active(struct rpc_task *task) |
| 253 | { | 254 | { |
| 255 | trace_rpc_task_begin(task->tk_client, task, NULL); | ||
| 256 | |||
| 254 | rpc_task_set_debuginfo(task); | 257 | rpc_task_set_debuginfo(task); |
| 255 | set_bit(RPC_TASK_ACTIVE, &task->tk_runstate); | 258 | set_bit(RPC_TASK_ACTIVE, &task->tk_runstate); |
| 256 | } | 259 | } |
| @@ -267,6 +270,8 @@ static int rpc_complete_task(struct rpc_task *task) | |||
| 267 | unsigned long flags; | 270 | unsigned long flags; |
| 268 | int ret; | 271 | int ret; |
| 269 | 272 | ||
| 273 | trace_rpc_task_complete(task->tk_client, task, NULL); | ||
| 274 | |||
| 270 | spin_lock_irqsave(&wq->lock, flags); | 275 | spin_lock_irqsave(&wq->lock, flags); |
| 271 | clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate); | 276 | clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate); |
| 272 | ret = atomic_dec_and_test(&task->tk_count); | 277 | ret = atomic_dec_and_test(&task->tk_count); |
| @@ -324,6 +329,8 @@ static void __rpc_sleep_on_priority(struct rpc_wait_queue *q, | |||
| 324 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", | 329 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", |
| 325 | task->tk_pid, rpc_qname(q), jiffies); | 330 | task->tk_pid, rpc_qname(q), jiffies); |
| 326 | 331 | ||
| 332 | trace_rpc_task_sleep(task->tk_client, task, q); | ||
| 333 | |||
| 327 | __rpc_add_wait_queue(q, task, queue_priority); | 334 | __rpc_add_wait_queue(q, task, queue_priority); |
| 328 | 335 | ||
| 329 | BUG_ON(task->tk_callback != NULL); | 336 | BUG_ON(task->tk_callback != NULL); |
| @@ -378,6 +385,8 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task | |||
| 378 | return; | 385 | return; |
| 379 | } | 386 | } |
| 380 | 387 | ||
| 388 | trace_rpc_task_wakeup(task->tk_client, task, queue); | ||
| 389 | |||
| 381 | __rpc_remove_wait_queue(queue, task); | 390 | __rpc_remove_wait_queue(queue, task); |
| 382 | 391 | ||
| 383 | rpc_make_runnable(task); | 392 | rpc_make_runnable(task); |
| @@ -422,7 +431,7 @@ EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); | |||
| 422 | /* | 431 | /* |
| 423 | * Wake up the next task on a priority queue. | 432 | * Wake up the next task on a priority queue. |
| 424 | */ | 433 | */ |
| 425 | static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue) | 434 | static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *queue) |
| 426 | { | 435 | { |
| 427 | struct list_head *q; | 436 | struct list_head *q; |
| 428 | struct rpc_task *task; | 437 | struct rpc_task *task; |
| @@ -467,30 +476,54 @@ new_queue: | |||
| 467 | new_owner: | 476 | new_owner: |
| 468 | rpc_set_waitqueue_owner(queue, task->tk_owner); | 477 | rpc_set_waitqueue_owner(queue, task->tk_owner); |
| 469 | out: | 478 | out: |
| 470 | rpc_wake_up_task_queue_locked(queue, task); | ||
| 471 | return task; | 479 | return task; |
| 472 | } | 480 | } |
| 473 | 481 | ||
| 482 | static struct rpc_task *__rpc_find_next_queued(struct rpc_wait_queue *queue) | ||
| 483 | { | ||
| 484 | if (RPC_IS_PRIORITY(queue)) | ||
| 485 | return __rpc_find_next_queued_priority(queue); | ||
| 486 | if (!list_empty(&queue->tasks[0])) | ||
| 487 | return list_first_entry(&queue->tasks[0], struct rpc_task, u.tk_wait.list); | ||
| 488 | return NULL; | ||
| 489 | } | ||
| 490 | |||
| 474 | /* | 491 | /* |
| 475 | * Wake up the next task on the wait queue. | 492 | * Wake up the first task on the wait queue. |
| 476 | */ | 493 | */ |
| 477 | struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue) | 494 | struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue, |
| 495 | bool (*func)(struct rpc_task *, void *), void *data) | ||
| 478 | { | 496 | { |
| 479 | struct rpc_task *task = NULL; | 497 | struct rpc_task *task = NULL; |
| 480 | 498 | ||
| 481 | dprintk("RPC: wake_up_next(%p \"%s\")\n", | 499 | dprintk("RPC: wake_up_first(%p \"%s\")\n", |
| 482 | queue, rpc_qname(queue)); | 500 | queue, rpc_qname(queue)); |
| 483 | spin_lock_bh(&queue->lock); | 501 | spin_lock_bh(&queue->lock); |
| 484 | if (RPC_IS_PRIORITY(queue)) | 502 | task = __rpc_find_next_queued(queue); |
| 485 | task = __rpc_wake_up_next_priority(queue); | 503 | if (task != NULL) { |
| 486 | else { | 504 | if (func(task, data)) |
| 487 | task_for_first(task, &queue->tasks[0]) | ||
| 488 | rpc_wake_up_task_queue_locked(queue, task); | 505 | rpc_wake_up_task_queue_locked(queue, task); |
| 506 | else | ||
| 507 | task = NULL; | ||
| 489 | } | 508 | } |
| 490 | spin_unlock_bh(&queue->lock); | 509 | spin_unlock_bh(&queue->lock); |
| 491 | 510 | ||
| 492 | return task; | 511 | return task; |
| 493 | } | 512 | } |
| 513 | EXPORT_SYMBOL_GPL(rpc_wake_up_first); | ||
| 514 | |||
| 515 | static bool rpc_wake_up_next_func(struct rpc_task *task, void *data) | ||
| 516 | { | ||
| 517 | return true; | ||
| 518 | } | ||
| 519 | |||
| 520 | /* | ||
| 521 | * Wake up the next task on the wait queue. | ||
| 522 | */ | ||
| 523 | struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *queue) | ||
| 524 | { | ||
| 525 | return rpc_wake_up_first(queue, rpc_wake_up_next_func, NULL); | ||
| 526 | } | ||
| 494 | EXPORT_SYMBOL_GPL(rpc_wake_up_next); | 527 | EXPORT_SYMBOL_GPL(rpc_wake_up_next); |
| 495 | 528 | ||
| 496 | /** | 529 | /** |
| @@ -501,14 +534,18 @@ EXPORT_SYMBOL_GPL(rpc_wake_up_next); | |||
| 501 | */ | 534 | */ |
| 502 | void rpc_wake_up(struct rpc_wait_queue *queue) | 535 | void rpc_wake_up(struct rpc_wait_queue *queue) |
| 503 | { | 536 | { |
| 504 | struct rpc_task *task, *next; | ||
| 505 | struct list_head *head; | 537 | struct list_head *head; |
| 506 | 538 | ||
| 507 | spin_lock_bh(&queue->lock); | 539 | spin_lock_bh(&queue->lock); |
| 508 | head = &queue->tasks[queue->maxpriority]; | 540 | head = &queue->tasks[queue->maxpriority]; |
| 509 | for (;;) { | 541 | for (;;) { |
| 510 | list_for_each_entry_safe(task, next, head, u.tk_wait.list) | 542 | while (!list_empty(head)) { |
| 543 | struct rpc_task *task; | ||
| 544 | task = list_first_entry(head, | ||
| 545 | struct rpc_task, | ||
| 546 | u.tk_wait.list); | ||
| 511 | rpc_wake_up_task_queue_locked(queue, task); | 547 | rpc_wake_up_task_queue_locked(queue, task); |
| 548 | } | ||
| 512 | if (head == &queue->tasks[0]) | 549 | if (head == &queue->tasks[0]) |
| 513 | break; | 550 | break; |
| 514 | head--; | 551 | head--; |
| @@ -526,13 +563,16 @@ EXPORT_SYMBOL_GPL(rpc_wake_up); | |||
| 526 | */ | 563 | */ |
| 527 | void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) | 564 | void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) |
| 528 | { | 565 | { |
| 529 | struct rpc_task *task, *next; | ||
| 530 | struct list_head *head; | 566 | struct list_head *head; |
| 531 | 567 | ||
| 532 | spin_lock_bh(&queue->lock); | 568 | spin_lock_bh(&queue->lock); |
| 533 | head = &queue->tasks[queue->maxpriority]; | 569 | head = &queue->tasks[queue->maxpriority]; |
| 534 | for (;;) { | 570 | for (;;) { |
| 535 | list_for_each_entry_safe(task, next, head, u.tk_wait.list) { | 571 | while (!list_empty(head)) { |
| 572 | struct rpc_task *task; | ||
| 573 | task = list_first_entry(head, | ||
| 574 | struct rpc_task, | ||
| 575 | u.tk_wait.list); | ||
| 536 | task->tk_status = status; | 576 | task->tk_status = status; |
| 537 | rpc_wake_up_task_queue_locked(queue, task); | 577 | rpc_wake_up_task_queue_locked(queue, task); |
| 538 | } | 578 | } |
| @@ -677,6 +717,7 @@ static void __rpc_execute(struct rpc_task *task) | |||
| 677 | if (do_action == NULL) | 717 | if (do_action == NULL) |
| 678 | break; | 718 | break; |
| 679 | } | 719 | } |
| 720 | trace_rpc_task_run_action(task->tk_client, task, task->tk_action); | ||
| 680 | do_action(task); | 721 | do_action(task); |
| 681 | 722 | ||
| 682 | /* | 723 | /* |
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 80df89d957ba..bc2068ee795b 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/sunrpc/clnt.h> | 22 | #include <linux/sunrpc/clnt.h> |
| 23 | #include <linux/sunrpc/svcsock.h> | 23 | #include <linux/sunrpc/svcsock.h> |
| 24 | #include <linux/sunrpc/metrics.h> | 24 | #include <linux/sunrpc/metrics.h> |
| 25 | #include <linux/rcupdate.h> | ||
| 25 | 26 | ||
| 26 | #include "netns.h" | 27 | #include "netns.h" |
| 27 | 28 | ||
| @@ -133,20 +134,19 @@ EXPORT_SYMBOL_GPL(rpc_free_iostats); | |||
| 133 | /** | 134 | /** |
| 134 | * rpc_count_iostats - tally up per-task stats | 135 | * rpc_count_iostats - tally up per-task stats |
| 135 | * @task: completed rpc_task | 136 | * @task: completed rpc_task |
| 137 | * @stats: array of stat structures | ||
| 136 | * | 138 | * |
| 137 | * Relies on the caller for serialization. | 139 | * Relies on the caller for serialization. |
| 138 | */ | 140 | */ |
| 139 | void rpc_count_iostats(struct rpc_task *task) | 141 | void rpc_count_iostats(const struct rpc_task *task, struct rpc_iostats *stats) |
| 140 | { | 142 | { |
| 141 | struct rpc_rqst *req = task->tk_rqstp; | 143 | struct rpc_rqst *req = task->tk_rqstp; |
| 142 | struct rpc_iostats *stats; | ||
| 143 | struct rpc_iostats *op_metrics; | 144 | struct rpc_iostats *op_metrics; |
| 144 | ktime_t delta; | 145 | ktime_t delta; |
| 145 | 146 | ||
| 146 | if (!task->tk_client || !task->tk_client->cl_metrics || !req) | 147 | if (!stats || !req) |
| 147 | return; | 148 | return; |
| 148 | 149 | ||
| 149 | stats = task->tk_client->cl_metrics; | ||
| 150 | op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; | 150 | op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; |
| 151 | 151 | ||
| 152 | op_metrics->om_ops++; | 152 | op_metrics->om_ops++; |
| @@ -164,6 +164,7 @@ void rpc_count_iostats(struct rpc_task *task) | |||
| 164 | delta = ktime_sub(ktime_get(), task->tk_start); | 164 | delta = ktime_sub(ktime_get(), task->tk_start); |
| 165 | op_metrics->om_execute = ktime_add(op_metrics->om_execute, delta); | 165 | op_metrics->om_execute = ktime_add(op_metrics->om_execute, delta); |
| 166 | } | 166 | } |
| 167 | EXPORT_SYMBOL_GPL(rpc_count_iostats); | ||
| 167 | 168 | ||
| 168 | static void _print_name(struct seq_file *seq, unsigned int op, | 169 | static void _print_name(struct seq_file *seq, unsigned int op, |
| 169 | struct rpc_procinfo *procs) | 170 | struct rpc_procinfo *procs) |
| @@ -179,7 +180,7 @@ static void _print_name(struct seq_file *seq, unsigned int op, | |||
| 179 | void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | 180 | void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) |
| 180 | { | 181 | { |
| 181 | struct rpc_iostats *stats = clnt->cl_metrics; | 182 | struct rpc_iostats *stats = clnt->cl_metrics; |
| 182 | struct rpc_xprt *xprt = clnt->cl_xprt; | 183 | struct rpc_xprt *xprt; |
| 183 | unsigned int op, maxproc = clnt->cl_maxproc; | 184 | unsigned int op, maxproc = clnt->cl_maxproc; |
| 184 | 185 | ||
| 185 | if (!stats) | 186 | if (!stats) |
| @@ -189,8 +190,11 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | |||
| 189 | seq_printf(seq, "p/v: %u/%u (%s)\n", | 190 | seq_printf(seq, "p/v: %u/%u (%s)\n", |
| 190 | clnt->cl_prog, clnt->cl_vers, clnt->cl_protname); | 191 | clnt->cl_prog, clnt->cl_vers, clnt->cl_protname); |
| 191 | 192 | ||
| 193 | rcu_read_lock(); | ||
| 194 | xprt = rcu_dereference(clnt->cl_xprt); | ||
| 192 | if (xprt) | 195 | if (xprt) |
| 193 | xprt->ops->print_stats(xprt, seq); | 196 | xprt->ops->print_stats(xprt, seq); |
| 197 | rcu_read_unlock(); | ||
| 194 | 198 | ||
| 195 | seq_printf(seq, "\tper-op statistics\n"); | 199 | seq_printf(seq, "\tper-op statistics\n"); |
| 196 | for (op = 0; op < maxproc; op++) { | 200 | for (op = 0; op < maxproc; op++) { |
| @@ -213,45 +217,46 @@ EXPORT_SYMBOL_GPL(rpc_print_iostats); | |||
| 213 | * Register/unregister RPC proc files | 217 | * Register/unregister RPC proc files |
| 214 | */ | 218 | */ |
| 215 | static inline struct proc_dir_entry * | 219 | static inline struct proc_dir_entry * |
| 216 | do_register(const char *name, void *data, const struct file_operations *fops) | 220 | do_register(struct net *net, const char *name, void *data, |
| 221 | const struct file_operations *fops) | ||
| 217 | { | 222 | { |
| 218 | struct sunrpc_net *sn; | 223 | struct sunrpc_net *sn; |
| 219 | 224 | ||
| 220 | dprintk("RPC: registering /proc/net/rpc/%s\n", name); | 225 | dprintk("RPC: registering /proc/net/rpc/%s\n", name); |
| 221 | sn = net_generic(&init_net, sunrpc_net_id); | 226 | sn = net_generic(net, sunrpc_net_id); |
| 222 | return proc_create_data(name, 0, sn->proc_net_rpc, fops, data); | 227 | return proc_create_data(name, 0, sn->proc_net_rpc, fops, data); |
| 223 | } | 228 | } |
| 224 | 229 | ||
| 225 | struct proc_dir_entry * | 230 | struct proc_dir_entry * |
| 226 | rpc_proc_register(struct rpc_stat *statp) | 231 | rpc_proc_register(struct net *net, struct rpc_stat *statp) |
| 227 | { | 232 | { |
| 228 | return do_register(statp->program->name, statp, &rpc_proc_fops); | 233 | return do_register(net, statp->program->name, statp, &rpc_proc_fops); |
| 229 | } | 234 | } |
| 230 | EXPORT_SYMBOL_GPL(rpc_proc_register); | 235 | EXPORT_SYMBOL_GPL(rpc_proc_register); |
| 231 | 236 | ||
| 232 | void | 237 | void |
| 233 | rpc_proc_unregister(const char *name) | 238 | rpc_proc_unregister(struct net *net, const char *name) |
| 234 | { | 239 | { |
| 235 | struct sunrpc_net *sn; | 240 | struct sunrpc_net *sn; |
| 236 | 241 | ||
| 237 | sn = net_generic(&init_net, sunrpc_net_id); | 242 | sn = net_generic(net, sunrpc_net_id); |
| 238 | remove_proc_entry(name, sn->proc_net_rpc); | 243 | remove_proc_entry(name, sn->proc_net_rpc); |
| 239 | } | 244 | } |
| 240 | EXPORT_SYMBOL_GPL(rpc_proc_unregister); | 245 | EXPORT_SYMBOL_GPL(rpc_proc_unregister); |
| 241 | 246 | ||
| 242 | struct proc_dir_entry * | 247 | struct proc_dir_entry * |
| 243 | svc_proc_register(struct svc_stat *statp, const struct file_operations *fops) | 248 | svc_proc_register(struct net *net, struct svc_stat *statp, const struct file_operations *fops) |
| 244 | { | 249 | { |
| 245 | return do_register(statp->program->pg_name, statp, fops); | 250 | return do_register(net, statp->program->pg_name, statp, fops); |
| 246 | } | 251 | } |
| 247 | EXPORT_SYMBOL_GPL(svc_proc_register); | 252 | EXPORT_SYMBOL_GPL(svc_proc_register); |
| 248 | 253 | ||
| 249 | void | 254 | void |
| 250 | svc_proc_unregister(const char *name) | 255 | svc_proc_unregister(struct net *net, const char *name) |
| 251 | { | 256 | { |
| 252 | struct sunrpc_net *sn; | 257 | struct sunrpc_net *sn; |
| 253 | 258 | ||
| 254 | sn = net_generic(&init_net, sunrpc_net_id); | 259 | sn = net_generic(net, sunrpc_net_id); |
| 255 | remove_proc_entry(name, sn->proc_net_rpc); | 260 | remove_proc_entry(name, sn->proc_net_rpc); |
| 256 | } | 261 | } |
| 257 | EXPORT_SYMBOL_GPL(svc_proc_unregister); | 262 | EXPORT_SYMBOL_GPL(svc_proc_unregister); |
diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index 90c292e2738b..14c9f6d1c5ff 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h | |||
| @@ -47,5 +47,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr, | |||
| 47 | struct page *headpage, unsigned long headoffset, | 47 | struct page *headpage, unsigned long headoffset, |
| 48 | struct page *tailpage, unsigned long tailoffset); | 48 | struct page *tailpage, unsigned long tailoffset); |
| 49 | 49 | ||
| 50 | int rpc_clients_notifier_register(void); | ||
| 51 | void rpc_clients_notifier_unregister(void); | ||
| 50 | #endif /* _NET_SUNRPC_SUNRPC_H */ | 52 | #endif /* _NET_SUNRPC_SUNRPC_H */ |
| 51 | 53 | ||
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 8ec9778c3f4a..8adfc88e793a 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
| @@ -25,10 +25,12 @@ | |||
| 25 | #include "netns.h" | 25 | #include "netns.h" |
| 26 | 26 | ||
| 27 | int sunrpc_net_id; | 27 | int sunrpc_net_id; |
| 28 | EXPORT_SYMBOL_GPL(sunrpc_net_id); | ||
| 28 | 29 | ||
| 29 | static __net_init int sunrpc_init_net(struct net *net) | 30 | static __net_init int sunrpc_init_net(struct net *net) |
| 30 | { | 31 | { |
| 31 | int err; | 32 | int err; |
| 33 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 32 | 34 | ||
| 33 | err = rpc_proc_init(net); | 35 | err = rpc_proc_init(net); |
| 34 | if (err) | 36 | if (err) |
| @@ -38,8 +40,18 @@ static __net_init int sunrpc_init_net(struct net *net) | |||
| 38 | if (err) | 40 | if (err) |
| 39 | goto err_ipmap; | 41 | goto err_ipmap; |
| 40 | 42 | ||
| 43 | err = unix_gid_cache_create(net); | ||
| 44 | if (err) | ||
| 45 | goto err_unixgid; | ||
| 46 | |||
| 47 | rpc_pipefs_init_net(net); | ||
| 48 | INIT_LIST_HEAD(&sn->all_clients); | ||
| 49 | spin_lock_init(&sn->rpc_client_lock); | ||
| 50 | spin_lock_init(&sn->rpcb_clnt_lock); | ||
| 41 | return 0; | 51 | return 0; |
| 42 | 52 | ||
| 53 | err_unixgid: | ||
| 54 | ip_map_cache_destroy(net); | ||
| 43 | err_ipmap: | 55 | err_ipmap: |
| 44 | rpc_proc_exit(net); | 56 | rpc_proc_exit(net); |
| 45 | err_proc: | 57 | err_proc: |
| @@ -48,6 +60,7 @@ err_proc: | |||
| 48 | 60 | ||
| 49 | static __net_exit void sunrpc_exit_net(struct net *net) | 61 | static __net_exit void sunrpc_exit_net(struct net *net) |
| 50 | { | 62 | { |
| 63 | unix_gid_cache_destroy(net); | ||
| 51 | ip_map_cache_destroy(net); | 64 | ip_map_cache_destroy(net); |
| 52 | rpc_proc_exit(net); | 65 | rpc_proc_exit(net); |
| 53 | } | 66 | } |
| @@ -59,8 +72,6 @@ static struct pernet_operations sunrpc_net_ops = { | |||
| 59 | .size = sizeof(struct sunrpc_net), | 72 | .size = sizeof(struct sunrpc_net), |
| 60 | }; | 73 | }; |
| 61 | 74 | ||
| 62 | extern struct cache_detail unix_gid_cache; | ||
| 63 | |||
| 64 | static int __init | 75 | static int __init |
| 65 | init_sunrpc(void) | 76 | init_sunrpc(void) |
| 66 | { | 77 | { |
| @@ -82,7 +93,6 @@ init_sunrpc(void) | |||
| 82 | #ifdef RPC_DEBUG | 93 | #ifdef RPC_DEBUG |
| 83 | rpc_register_sysctl(); | 94 | rpc_register_sysctl(); |
| 84 | #endif | 95 | #endif |
| 85 | cache_register(&unix_gid_cache); | ||
| 86 | svc_init_xprt_sock(); /* svc sock transport */ | 96 | svc_init_xprt_sock(); /* svc sock transport */ |
| 87 | init_socket_xprt(); /* clnt sock transport */ | 97 | init_socket_xprt(); /* clnt sock transport */ |
| 88 | return 0; | 98 | return 0; |
| @@ -105,7 +115,6 @@ cleanup_sunrpc(void) | |||
| 105 | svc_cleanup_xprt_sock(); | 115 | svc_cleanup_xprt_sock(); |
| 106 | unregister_rpc_pipefs(); | 116 | unregister_rpc_pipefs(); |
| 107 | rpc_destroy_mempool(); | 117 | rpc_destroy_mempool(); |
| 108 | cache_unregister(&unix_gid_cache); | ||
| 109 | unregister_pernet_subsys(&sunrpc_net_ops); | 118 | unregister_pernet_subsys(&sunrpc_net_ops); |
| 110 | #ifdef RPC_DEBUG | 119 | #ifdef RPC_DEBUG |
| 111 | rpc_unregister_sysctl(); | 120 | rpc_unregister_sysctl(); |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index e4aabc02368b..4153846984ac 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <linux/kthread.h> | 21 | #include <linux/kthread.h> |
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 23 | #include <linux/nsproxy.h> | ||
| 23 | 24 | ||
| 24 | #include <linux/sunrpc/types.h> | 25 | #include <linux/sunrpc/types.h> |
| 25 | #include <linux/sunrpc/xdr.h> | 26 | #include <linux/sunrpc/xdr.h> |
| @@ -30,7 +31,7 @@ | |||
| 30 | 31 | ||
| 31 | #define RPCDBG_FACILITY RPCDBG_SVCDSP | 32 | #define RPCDBG_FACILITY RPCDBG_SVCDSP |
| 32 | 33 | ||
| 33 | static void svc_unregister(const struct svc_serv *serv); | 34 | static void svc_unregister(const struct svc_serv *serv, struct net *net); |
| 34 | 35 | ||
| 35 | #define svc_serv_is_pooled(serv) ((serv)->sv_function) | 36 | #define svc_serv_is_pooled(serv) ((serv)->sv_function) |
| 36 | 37 | ||
| @@ -368,23 +369,24 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu) | |||
| 368 | return &serv->sv_pools[pidx % serv->sv_nrpools]; | 369 | return &serv->sv_pools[pidx % serv->sv_nrpools]; |
| 369 | } | 370 | } |
| 370 | 371 | ||
| 371 | static int svc_rpcb_setup(struct svc_serv *serv) | 372 | int svc_rpcb_setup(struct svc_serv *serv, struct net *net) |
| 372 | { | 373 | { |
| 373 | int err; | 374 | int err; |
| 374 | 375 | ||
| 375 | err = rpcb_create_local(); | 376 | err = rpcb_create_local(net); |
| 376 | if (err) | 377 | if (err) |
| 377 | return err; | 378 | return err; |
| 378 | 379 | ||
| 379 | /* Remove any stale portmap registrations */ | 380 | /* Remove any stale portmap registrations */ |
| 380 | svc_unregister(serv); | 381 | svc_unregister(serv, net); |
| 381 | return 0; | 382 | return 0; |
| 382 | } | 383 | } |
| 384 | EXPORT_SYMBOL_GPL(svc_rpcb_setup); | ||
| 383 | 385 | ||
| 384 | void svc_rpcb_cleanup(struct svc_serv *serv) | 386 | void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net) |
| 385 | { | 387 | { |
| 386 | svc_unregister(serv); | 388 | svc_unregister(serv, net); |
| 387 | rpcb_put_local(); | 389 | rpcb_put_local(net); |
| 388 | } | 390 | } |
| 389 | EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); | 391 | EXPORT_SYMBOL_GPL(svc_rpcb_cleanup); |
| 390 | 392 | ||
| @@ -410,7 +412,7 @@ static int svc_uses_rpcbind(struct svc_serv *serv) | |||
| 410 | */ | 412 | */ |
| 411 | static struct svc_serv * | 413 | static struct svc_serv * |
| 412 | __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, | 414 | __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, |
| 413 | void (*shutdown)(struct svc_serv *serv)) | 415 | void (*shutdown)(struct svc_serv *serv, struct net *net)) |
| 414 | { | 416 | { |
| 415 | struct svc_serv *serv; | 417 | struct svc_serv *serv; |
| 416 | unsigned int vers; | 418 | unsigned int vers; |
| @@ -470,7 +472,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, | |||
| 470 | } | 472 | } |
| 471 | 473 | ||
| 472 | if (svc_uses_rpcbind(serv)) { | 474 | if (svc_uses_rpcbind(serv)) { |
| 473 | if (svc_rpcb_setup(serv) < 0) { | 475 | if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) { |
| 474 | kfree(serv->sv_pools); | 476 | kfree(serv->sv_pools); |
| 475 | kfree(serv); | 477 | kfree(serv); |
| 476 | return NULL; | 478 | return NULL; |
| @@ -484,7 +486,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, | |||
| 484 | 486 | ||
| 485 | struct svc_serv * | 487 | struct svc_serv * |
| 486 | svc_create(struct svc_program *prog, unsigned int bufsize, | 488 | svc_create(struct svc_program *prog, unsigned int bufsize, |
| 487 | void (*shutdown)(struct svc_serv *serv)) | 489 | void (*shutdown)(struct svc_serv *serv, struct net *net)) |
| 488 | { | 490 | { |
| 489 | return __svc_create(prog, bufsize, /*npools*/1, shutdown); | 491 | return __svc_create(prog, bufsize, /*npools*/1, shutdown); |
| 490 | } | 492 | } |
| @@ -492,7 +494,7 @@ EXPORT_SYMBOL_GPL(svc_create); | |||
| 492 | 494 | ||
| 493 | struct svc_serv * | 495 | struct svc_serv * |
| 494 | svc_create_pooled(struct svc_program *prog, unsigned int bufsize, | 496 | svc_create_pooled(struct svc_program *prog, unsigned int bufsize, |
| 495 | void (*shutdown)(struct svc_serv *serv), | 497 | void (*shutdown)(struct svc_serv *serv, struct net *net), |
| 496 | svc_thread_fn func, struct module *mod) | 498 | svc_thread_fn func, struct module *mod) |
| 497 | { | 499 | { |
| 498 | struct svc_serv *serv; | 500 | struct svc_serv *serv; |
| @@ -509,6 +511,24 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, | |||
| 509 | } | 511 | } |
| 510 | EXPORT_SYMBOL_GPL(svc_create_pooled); | 512 | EXPORT_SYMBOL_GPL(svc_create_pooled); |
| 511 | 513 | ||
| 514 | void svc_shutdown_net(struct svc_serv *serv, struct net *net) | ||
| 515 | { | ||
| 516 | /* | ||
| 517 | * The set of xprts (contained in the sv_tempsocks and | ||
| 518 | * sv_permsocks lists) is now constant, since it is modified | ||
| 519 | * only by accepting new sockets (done by service threads in | ||
| 520 | * svc_recv) or aging old ones (done by sv_temptimer), or | ||
| 521 | * configuration changes (excluded by whatever locking the | ||
| 522 | * caller is using--nfsd_mutex in the case of nfsd). So it's | ||
| 523 | * safe to traverse those lists and shut everything down: | ||
| 524 | */ | ||
| 525 | svc_close_net(serv, net); | ||
| 526 | |||
| 527 | if (serv->sv_shutdown) | ||
| 528 | serv->sv_shutdown(serv, net); | ||
| 529 | } | ||
| 530 | EXPORT_SYMBOL_GPL(svc_shutdown_net); | ||
| 531 | |||
| 512 | /* | 532 | /* |
| 513 | * Destroy an RPC service. Should be called with appropriate locking to | 533 | * Destroy an RPC service. Should be called with appropriate locking to |
| 514 | * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. | 534 | * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. |
| @@ -516,6 +536,8 @@ EXPORT_SYMBOL_GPL(svc_create_pooled); | |||
| 516 | void | 536 | void |
| 517 | svc_destroy(struct svc_serv *serv) | 537 | svc_destroy(struct svc_serv *serv) |
| 518 | { | 538 | { |
| 539 | struct net *net = current->nsproxy->net_ns; | ||
| 540 | |||
| 519 | dprintk("svc: svc_destroy(%s, %d)\n", | 541 | dprintk("svc: svc_destroy(%s, %d)\n", |
| 520 | serv->sv_program->pg_name, | 542 | serv->sv_program->pg_name, |
| 521 | serv->sv_nrthreads); | 543 | serv->sv_nrthreads); |
| @@ -529,19 +551,15 @@ svc_destroy(struct svc_serv *serv) | |||
| 529 | printk("svc_destroy: no threads for serv=%p!\n", serv); | 551 | printk("svc_destroy: no threads for serv=%p!\n", serv); |
| 530 | 552 | ||
| 531 | del_timer_sync(&serv->sv_temptimer); | 553 | del_timer_sync(&serv->sv_temptimer); |
| 554 | |||
| 555 | svc_shutdown_net(serv, net); | ||
| 556 | |||
| 532 | /* | 557 | /* |
| 533 | * The set of xprts (contained in the sv_tempsocks and | 558 | * The last user is gone and thus all sockets have to be destroyed to |
| 534 | * sv_permsocks lists) is now constant, since it is modified | 559 | * the point. Check this. |
| 535 | * only by accepting new sockets (done by service threads in | ||
| 536 | * svc_recv) or aging old ones (done by sv_temptimer), or | ||
| 537 | * configuration changes (excluded by whatever locking the | ||
| 538 | * caller is using--nfsd_mutex in the case of nfsd). So it's | ||
| 539 | * safe to traverse those lists and shut everything down: | ||
| 540 | */ | 560 | */ |
| 541 | svc_close_all(serv); | 561 | BUG_ON(!list_empty(&serv->sv_permsocks)); |
| 542 | 562 | BUG_ON(!list_empty(&serv->sv_tempsocks)); | |
| 543 | if (serv->sv_shutdown) | ||
| 544 | serv->sv_shutdown(serv); | ||
| 545 | 563 | ||
| 546 | cache_clean_deferred(serv); | 564 | cache_clean_deferred(serv); |
| 547 | 565 | ||
| @@ -795,7 +813,8 @@ EXPORT_SYMBOL_GPL(svc_exit_thread); | |||
| 795 | * Returns zero on success; a negative errno value is returned | 813 | * Returns zero on success; a negative errno value is returned |
| 796 | * if any error occurs. | 814 | * if any error occurs. |
| 797 | */ | 815 | */ |
| 798 | static int __svc_rpcb_register4(const u32 program, const u32 version, | 816 | static int __svc_rpcb_register4(struct net *net, const u32 program, |
| 817 | const u32 version, | ||
| 799 | const unsigned short protocol, | 818 | const unsigned short protocol, |
| 800 | const unsigned short port) | 819 | const unsigned short port) |
| 801 | { | 820 | { |
| @@ -818,7 +837,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, | |||
| 818 | return -ENOPROTOOPT; | 837 | return -ENOPROTOOPT; |
| 819 | } | 838 | } |
| 820 | 839 | ||
| 821 | error = rpcb_v4_register(program, version, | 840 | error = rpcb_v4_register(net, program, version, |
| 822 | (const struct sockaddr *)&sin, netid); | 841 | (const struct sockaddr *)&sin, netid); |
| 823 | 842 | ||
| 824 | /* | 843 | /* |
| @@ -826,7 +845,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, | |||
| 826 | * registration request with the legacy rpcbind v2 protocol. | 845 | * registration request with the legacy rpcbind v2 protocol. |
| 827 | */ | 846 | */ |
| 828 | if (error == -EPROTONOSUPPORT) | 847 | if (error == -EPROTONOSUPPORT) |
| 829 | error = rpcb_register(program, version, protocol, port); | 848 | error = rpcb_register(net, program, version, protocol, port); |
| 830 | 849 | ||
| 831 | return error; | 850 | return error; |
| 832 | } | 851 | } |
| @@ -842,7 +861,8 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, | |||
| 842 | * Returns zero on success; a negative errno value is returned | 861 | * Returns zero on success; a negative errno value is returned |
| 843 | * if any error occurs. | 862 | * if any error occurs. |
| 844 | */ | 863 | */ |
| 845 | static int __svc_rpcb_register6(const u32 program, const u32 version, | 864 | static int __svc_rpcb_register6(struct net *net, const u32 program, |
| 865 | const u32 version, | ||
| 846 | const unsigned short protocol, | 866 | const unsigned short protocol, |
| 847 | const unsigned short port) | 867 | const unsigned short port) |
| 848 | { | 868 | { |
| @@ -865,7 +885,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version, | |||
| 865 | return -ENOPROTOOPT; | 885 | return -ENOPROTOOPT; |
| 866 | } | 886 | } |
| 867 | 887 | ||
| 868 | error = rpcb_v4_register(program, version, | 888 | error = rpcb_v4_register(net, program, version, |
| 869 | (const struct sockaddr *)&sin6, netid); | 889 | (const struct sockaddr *)&sin6, netid); |
| 870 | 890 | ||
| 871 | /* | 891 | /* |
| @@ -885,7 +905,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version, | |||
| 885 | * Returns zero on success; a negative errno value is returned | 905 | * Returns zero on success; a negative errno value is returned |
| 886 | * if any error occurs. | 906 | * if any error occurs. |
| 887 | */ | 907 | */ |
| 888 | static int __svc_register(const char *progname, | 908 | static int __svc_register(struct net *net, const char *progname, |
| 889 | const u32 program, const u32 version, | 909 | const u32 program, const u32 version, |
| 890 | const int family, | 910 | const int family, |
| 891 | const unsigned short protocol, | 911 | const unsigned short protocol, |
| @@ -895,12 +915,12 @@ static int __svc_register(const char *progname, | |||
| 895 | 915 | ||
| 896 | switch (family) { | 916 | switch (family) { |
| 897 | case PF_INET: | 917 | case PF_INET: |
| 898 | error = __svc_rpcb_register4(program, version, | 918 | error = __svc_rpcb_register4(net, program, version, |
| 899 | protocol, port); | 919 | protocol, port); |
| 900 | break; | 920 | break; |
| 901 | #if IS_ENABLED(CONFIG_IPV6) | 921 | #if IS_ENABLED(CONFIG_IPV6) |
| 902 | case PF_INET6: | 922 | case PF_INET6: |
| 903 | error = __svc_rpcb_register6(program, version, | 923 | error = __svc_rpcb_register6(net, program, version, |
| 904 | protocol, port); | 924 | protocol, port); |
| 905 | #endif | 925 | #endif |
| 906 | } | 926 | } |
| @@ -914,14 +934,16 @@ static int __svc_register(const char *progname, | |||
| 914 | /** | 934 | /** |
| 915 | * svc_register - register an RPC service with the local portmapper | 935 | * svc_register - register an RPC service with the local portmapper |
| 916 | * @serv: svc_serv struct for the service to register | 936 | * @serv: svc_serv struct for the service to register |
| 937 | * @net: net namespace for the service to register | ||
| 917 | * @family: protocol family of service's listener socket | 938 | * @family: protocol family of service's listener socket |
| 918 | * @proto: transport protocol number to advertise | 939 | * @proto: transport protocol number to advertise |
| 919 | * @port: port to advertise | 940 | * @port: port to advertise |
| 920 | * | 941 | * |
| 921 | * Service is registered for any address in the passed-in protocol family | 942 | * Service is registered for any address in the passed-in protocol family |
| 922 | */ | 943 | */ |
| 923 | int svc_register(const struct svc_serv *serv, const int family, | 944 | int svc_register(const struct svc_serv *serv, struct net *net, |
| 924 | const unsigned short proto, const unsigned short port) | 945 | const int family, const unsigned short proto, |
| 946 | const unsigned short port) | ||
| 925 | { | 947 | { |
| 926 | struct svc_program *progp; | 948 | struct svc_program *progp; |
| 927 | unsigned int i; | 949 | unsigned int i; |
| @@ -946,7 +968,7 @@ int svc_register(const struct svc_serv *serv, const int family, | |||
| 946 | if (progp->pg_vers[i]->vs_hidden) | 968 | if (progp->pg_vers[i]->vs_hidden) |
| 947 | continue; | 969 | continue; |
| 948 | 970 | ||
| 949 | error = __svc_register(progp->pg_name, progp->pg_prog, | 971 | error = __svc_register(net, progp->pg_name, progp->pg_prog, |
| 950 | i, family, proto, port); | 972 | i, family, proto, port); |
| 951 | if (error < 0) | 973 | if (error < 0) |
| 952 | break; | 974 | break; |
| @@ -963,19 +985,19 @@ int svc_register(const struct svc_serv *serv, const int family, | |||
| 963 | * any "inet6" entries anyway. So a PMAP_UNSET should be sufficient | 985 | * any "inet6" entries anyway. So a PMAP_UNSET should be sufficient |
| 964 | * in this case to clear all existing entries for [program, version]. | 986 | * in this case to clear all existing entries for [program, version]. |
| 965 | */ | 987 | */ |
| 966 | static void __svc_unregister(const u32 program, const u32 version, | 988 | static void __svc_unregister(struct net *net, const u32 program, const u32 version, |
| 967 | const char *progname) | 989 | const char *progname) |
| 968 | { | 990 | { |
| 969 | int error; | 991 | int error; |
| 970 | 992 | ||
| 971 | error = rpcb_v4_register(program, version, NULL, ""); | 993 | error = rpcb_v4_register(net, program, version, NULL, ""); |
| 972 | 994 | ||
| 973 | /* | 995 | /* |
| 974 | * User space didn't support rpcbind v4, so retry this | 996 | * User space didn't support rpcbind v4, so retry this |
| 975 | * request with the legacy rpcbind v2 protocol. | 997 | * request with the legacy rpcbind v2 protocol. |
| 976 | */ | 998 | */ |
| 977 | if (error == -EPROTONOSUPPORT) | 999 | if (error == -EPROTONOSUPPORT) |
| 978 | error = rpcb_register(program, version, 0, 0); | 1000 | error = rpcb_register(net, program, version, 0, 0); |
| 979 | 1001 | ||
| 980 | dprintk("svc: %s(%sv%u), error %d\n", | 1002 | dprintk("svc: %s(%sv%u), error %d\n", |
| 981 | __func__, progname, version, error); | 1003 | __func__, progname, version, error); |
| @@ -989,7 +1011,7 @@ static void __svc_unregister(const u32 program, const u32 version, | |||
| 989 | * The result of unregistration is reported via dprintk for those who want | 1011 | * The result of unregistration is reported via dprintk for those who want |
| 990 | * verification of the result, but is otherwise not important. | 1012 | * verification of the result, but is otherwise not important. |
| 991 | */ | 1013 | */ |
| 992 | static void svc_unregister(const struct svc_serv *serv) | 1014 | static void svc_unregister(const struct svc_serv *serv, struct net *net) |
| 993 | { | 1015 | { |
| 994 | struct svc_program *progp; | 1016 | struct svc_program *progp; |
| 995 | unsigned long flags; | 1017 | unsigned long flags; |
| @@ -1006,7 +1028,7 @@ static void svc_unregister(const struct svc_serv *serv) | |||
| 1006 | 1028 | ||
| 1007 | dprintk("svc: attempting to unregister %sv%u\n", | 1029 | dprintk("svc: attempting to unregister %sv%u\n", |
| 1008 | progp->pg_name, i); | 1030 | progp->pg_name, i); |
| 1009 | __svc_unregister(progp->pg_prog, i, progp->pg_name); | 1031 | __svc_unregister(net, progp->pg_prog, i, progp->pg_name); |
| 1010 | } | 1032 | } |
| 1011 | } | 1033 | } |
| 1012 | 1034 | ||
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 74cb0d8e9ca1..4bda09d7e1a4 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
| @@ -922,48 +922,65 @@ void svc_close_xprt(struct svc_xprt *xprt) | |||
| 922 | } | 922 | } |
| 923 | EXPORT_SYMBOL_GPL(svc_close_xprt); | 923 | EXPORT_SYMBOL_GPL(svc_close_xprt); |
| 924 | 924 | ||
| 925 | static void svc_close_list(struct list_head *xprt_list) | 925 | static void svc_close_list(struct list_head *xprt_list, struct net *net) |
| 926 | { | 926 | { |
| 927 | struct svc_xprt *xprt; | 927 | struct svc_xprt *xprt; |
| 928 | 928 | ||
| 929 | list_for_each_entry(xprt, xprt_list, xpt_list) { | 929 | list_for_each_entry(xprt, xprt_list, xpt_list) { |
| 930 | if (xprt->xpt_net != net) | ||
| 931 | continue; | ||
| 930 | set_bit(XPT_CLOSE, &xprt->xpt_flags); | 932 | set_bit(XPT_CLOSE, &xprt->xpt_flags); |
| 931 | set_bit(XPT_BUSY, &xprt->xpt_flags); | 933 | set_bit(XPT_BUSY, &xprt->xpt_flags); |
| 932 | } | 934 | } |
| 933 | } | 935 | } |
| 934 | 936 | ||
| 935 | void svc_close_all(struct svc_serv *serv) | 937 | static void svc_clear_pools(struct svc_serv *serv, struct net *net) |
| 936 | { | 938 | { |
| 937 | struct svc_pool *pool; | 939 | struct svc_pool *pool; |
| 938 | struct svc_xprt *xprt; | 940 | struct svc_xprt *xprt; |
| 939 | struct svc_xprt *tmp; | 941 | struct svc_xprt *tmp; |
| 940 | int i; | 942 | int i; |
| 941 | 943 | ||
| 942 | svc_close_list(&serv->sv_tempsocks); | ||
| 943 | svc_close_list(&serv->sv_permsocks); | ||
| 944 | |||
| 945 | for (i = 0; i < serv->sv_nrpools; i++) { | 944 | for (i = 0; i < serv->sv_nrpools; i++) { |
| 946 | pool = &serv->sv_pools[i]; | 945 | pool = &serv->sv_pools[i]; |
| 947 | 946 | ||
| 948 | spin_lock_bh(&pool->sp_lock); | 947 | spin_lock_bh(&pool->sp_lock); |
| 949 | while (!list_empty(&pool->sp_sockets)) { | 948 | list_for_each_entry_safe(xprt, tmp, &pool->sp_sockets, xpt_ready) { |
| 950 | xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready); | 949 | if (xprt->xpt_net != net) |
| 950 | continue; | ||
| 951 | list_del_init(&xprt->xpt_ready); | 951 | list_del_init(&xprt->xpt_ready); |
| 952 | } | 952 | } |
| 953 | spin_unlock_bh(&pool->sp_lock); | 953 | spin_unlock_bh(&pool->sp_lock); |
| 954 | } | 954 | } |
| 955 | } | ||
| 956 | |||
| 957 | static void svc_clear_list(struct list_head *xprt_list, struct net *net) | ||
| 958 | { | ||
| 959 | struct svc_xprt *xprt; | ||
| 960 | struct svc_xprt *tmp; | ||
| 961 | |||
| 962 | list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { | ||
| 963 | if (xprt->xpt_net != net) | ||
| 964 | continue; | ||
| 965 | svc_delete_xprt(xprt); | ||
| 966 | } | ||
| 967 | list_for_each_entry(xprt, xprt_list, xpt_list) | ||
| 968 | BUG_ON(xprt->xpt_net == net); | ||
| 969 | } | ||
| 970 | |||
| 971 | void svc_close_net(struct svc_serv *serv, struct net *net) | ||
| 972 | { | ||
| 973 | svc_close_list(&serv->sv_tempsocks, net); | ||
| 974 | svc_close_list(&serv->sv_permsocks, net); | ||
| 975 | |||
| 976 | svc_clear_pools(serv, net); | ||
| 955 | /* | 977 | /* |
| 956 | * At this point the sp_sockets lists will stay empty, since | 978 | * At this point the sp_sockets lists will stay empty, since |
| 957 | * svc_enqueue will not add new entries without taking the | 979 | * svc_enqueue will not add new entries without taking the |
| 958 | * sp_lock and checking XPT_BUSY. | 980 | * sp_lock and checking XPT_BUSY. |
| 959 | */ | 981 | */ |
| 960 | list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list) | 982 | svc_clear_list(&serv->sv_tempsocks, net); |
| 961 | svc_delete_xprt(xprt); | 983 | svc_clear_list(&serv->sv_permsocks, net); |
| 962 | list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list) | ||
| 963 | svc_delete_xprt(xprt); | ||
| 964 | |||
| 965 | BUG_ON(!list_empty(&serv->sv_permsocks)); | ||
| 966 | BUG_ON(!list_empty(&serv->sv_tempsocks)); | ||
| 967 | } | 984 | } |
| 968 | 985 | ||
| 969 | /* | 986 | /* |
| @@ -1089,6 +1106,7 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) | |||
| 1089 | * svc_find_xprt - find an RPC transport instance | 1106 | * svc_find_xprt - find an RPC transport instance |
| 1090 | * @serv: pointer to svc_serv to search | 1107 | * @serv: pointer to svc_serv to search |
| 1091 | * @xcl_name: C string containing transport's class name | 1108 | * @xcl_name: C string containing transport's class name |
| 1109 | * @net: owner net pointer | ||
| 1092 | * @af: Address family of transport's local address | 1110 | * @af: Address family of transport's local address |
| 1093 | * @port: transport's IP port number | 1111 | * @port: transport's IP port number |
| 1094 | * | 1112 | * |
| @@ -1101,7 +1119,8 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) | |||
| 1101 | * service's list that has a matching class name. | 1119 | * service's list that has a matching class name. |
| 1102 | */ | 1120 | */ |
| 1103 | struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, | 1121 | struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, |
| 1104 | const sa_family_t af, const unsigned short port) | 1122 | struct net *net, const sa_family_t af, |
| 1123 | const unsigned short port) | ||
| 1105 | { | 1124 | { |
| 1106 | struct svc_xprt *xprt; | 1125 | struct svc_xprt *xprt; |
| 1107 | struct svc_xprt *found = NULL; | 1126 | struct svc_xprt *found = NULL; |
| @@ -1112,6 +1131,8 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, | |||
| 1112 | 1131 | ||
| 1113 | spin_lock_bh(&serv->sv_lock); | 1132 | spin_lock_bh(&serv->sv_lock); |
| 1114 | list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { | 1133 | list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { |
| 1134 | if (xprt->xpt_net != net) | ||
| 1135 | continue; | ||
| 1115 | if (strcmp(xprt->xpt_class->xcl_name, xcl_name)) | 1136 | if (strcmp(xprt->xpt_class->xcl_name, xcl_name)) |
| 1116 | continue; | 1137 | continue; |
| 1117 | if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family) | 1138 | if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family) |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 01153ead1dba..bcd574f2ac56 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
| @@ -211,7 +211,7 @@ static int ip_map_parse(struct cache_detail *cd, | |||
| 211 | len = qword_get(&mesg, buf, mlen); | 211 | len = qword_get(&mesg, buf, mlen); |
| 212 | if (len <= 0) return -EINVAL; | 212 | if (len <= 0) return -EINVAL; |
| 213 | 213 | ||
| 214 | if (rpc_pton(buf, len, &address.sa, sizeof(address)) == 0) | 214 | if (rpc_pton(cd->net, buf, len, &address.sa, sizeof(address)) == 0) |
| 215 | return -EINVAL; | 215 | return -EINVAL; |
| 216 | switch (address.sa.sa_family) { | 216 | switch (address.sa.sa_family) { |
| 217 | case AF_INET: | 217 | case AF_INET: |
| @@ -436,7 +436,6 @@ struct unix_gid { | |||
| 436 | uid_t uid; | 436 | uid_t uid; |
| 437 | struct group_info *gi; | 437 | struct group_info *gi; |
| 438 | }; | 438 | }; |
| 439 | static struct cache_head *gid_table[GID_HASHMAX]; | ||
| 440 | 439 | ||
| 441 | static void unix_gid_put(struct kref *kref) | 440 | static void unix_gid_put(struct kref *kref) |
| 442 | { | 441 | { |
| @@ -494,8 +493,7 @@ static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h) | |||
| 494 | return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request); | 493 | return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request); |
| 495 | } | 494 | } |
| 496 | 495 | ||
| 497 | static struct unix_gid *unix_gid_lookup(uid_t uid); | 496 | static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid); |
| 498 | extern struct cache_detail unix_gid_cache; | ||
| 499 | 497 | ||
| 500 | static int unix_gid_parse(struct cache_detail *cd, | 498 | static int unix_gid_parse(struct cache_detail *cd, |
| 501 | char *mesg, int mlen) | 499 | char *mesg, int mlen) |
| @@ -539,19 +537,19 @@ static int unix_gid_parse(struct cache_detail *cd, | |||
| 539 | GROUP_AT(ug.gi, i) = gid; | 537 | GROUP_AT(ug.gi, i) = gid; |
| 540 | } | 538 | } |
| 541 | 539 | ||
| 542 | ugp = unix_gid_lookup(uid); | 540 | ugp = unix_gid_lookup(cd, uid); |
| 543 | if (ugp) { | 541 | if (ugp) { |
| 544 | struct cache_head *ch; | 542 | struct cache_head *ch; |
| 545 | ug.h.flags = 0; | 543 | ug.h.flags = 0; |
| 546 | ug.h.expiry_time = expiry; | 544 | ug.h.expiry_time = expiry; |
| 547 | ch = sunrpc_cache_update(&unix_gid_cache, | 545 | ch = sunrpc_cache_update(cd, |
| 548 | &ug.h, &ugp->h, | 546 | &ug.h, &ugp->h, |
| 549 | hash_long(uid, GID_HASHBITS)); | 547 | hash_long(uid, GID_HASHBITS)); |
| 550 | if (!ch) | 548 | if (!ch) |
| 551 | err = -ENOMEM; | 549 | err = -ENOMEM; |
| 552 | else { | 550 | else { |
| 553 | err = 0; | 551 | err = 0; |
| 554 | cache_put(ch, &unix_gid_cache); | 552 | cache_put(ch, cd); |
| 555 | } | 553 | } |
| 556 | } else | 554 | } else |
| 557 | err = -ENOMEM; | 555 | err = -ENOMEM; |
| @@ -587,10 +585,9 @@ static int unix_gid_show(struct seq_file *m, | |||
| 587 | return 0; | 585 | return 0; |
| 588 | } | 586 | } |
| 589 | 587 | ||
| 590 | struct cache_detail unix_gid_cache = { | 588 | static struct cache_detail unix_gid_cache_template = { |
| 591 | .owner = THIS_MODULE, | 589 | .owner = THIS_MODULE, |
| 592 | .hash_size = GID_HASHMAX, | 590 | .hash_size = GID_HASHMAX, |
| 593 | .hash_table = gid_table, | ||
| 594 | .name = "auth.unix.gid", | 591 | .name = "auth.unix.gid", |
| 595 | .cache_put = unix_gid_put, | 592 | .cache_put = unix_gid_put, |
| 596 | .cache_upcall = unix_gid_upcall, | 593 | .cache_upcall = unix_gid_upcall, |
| @@ -602,14 +599,42 @@ struct cache_detail unix_gid_cache = { | |||
| 602 | .alloc = unix_gid_alloc, | 599 | .alloc = unix_gid_alloc, |
| 603 | }; | 600 | }; |
| 604 | 601 | ||
| 605 | static struct unix_gid *unix_gid_lookup(uid_t uid) | 602 | int unix_gid_cache_create(struct net *net) |
| 603 | { | ||
| 604 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 605 | struct cache_detail *cd; | ||
| 606 | int err; | ||
| 607 | |||
| 608 | cd = cache_create_net(&unix_gid_cache_template, net); | ||
| 609 | if (IS_ERR(cd)) | ||
| 610 | return PTR_ERR(cd); | ||
| 611 | err = cache_register_net(cd, net); | ||
| 612 | if (err) { | ||
| 613 | cache_destroy_net(cd, net); | ||
| 614 | return err; | ||
| 615 | } | ||
| 616 | sn->unix_gid_cache = cd; | ||
| 617 | return 0; | ||
| 618 | } | ||
| 619 | |||
| 620 | void unix_gid_cache_destroy(struct net *net) | ||
| 621 | { | ||
| 622 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
| 623 | struct cache_detail *cd = sn->unix_gid_cache; | ||
| 624 | |||
| 625 | sn->unix_gid_cache = NULL; | ||
| 626 | cache_purge(cd); | ||
| 627 | cache_unregister_net(cd, net); | ||
| 628 | cache_destroy_net(cd, net); | ||
| 629 | } | ||
| 630 | |||
| 631 | static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid) | ||
| 606 | { | 632 | { |
| 607 | struct unix_gid ug; | 633 | struct unix_gid ug; |
| 608 | struct cache_head *ch; | 634 | struct cache_head *ch; |
| 609 | 635 | ||
| 610 | ug.uid = uid; | 636 | ug.uid = uid; |
| 611 | ch = sunrpc_cache_lookup(&unix_gid_cache, &ug.h, | 637 | ch = sunrpc_cache_lookup(cd, &ug.h, hash_long(uid, GID_HASHBITS)); |
| 612 | hash_long(uid, GID_HASHBITS)); | ||
| 613 | if (ch) | 638 | if (ch) |
| 614 | return container_of(ch, struct unix_gid, h); | 639 | return container_of(ch, struct unix_gid, h); |
| 615 | else | 640 | else |
| @@ -621,11 +646,13 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp) | |||
| 621 | struct unix_gid *ug; | 646 | struct unix_gid *ug; |
| 622 | struct group_info *gi; | 647 | struct group_info *gi; |
| 623 | int ret; | 648 | int ret; |
| 649 | struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, | ||
| 650 | sunrpc_net_id); | ||
| 624 | 651 | ||
| 625 | ug = unix_gid_lookup(uid); | 652 | ug = unix_gid_lookup(sn->unix_gid_cache, uid); |
| 626 | if (!ug) | 653 | if (!ug) |
| 627 | return ERR_PTR(-EAGAIN); | 654 | return ERR_PTR(-EAGAIN); |
| 628 | ret = cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle); | 655 | ret = cache_check(sn->unix_gid_cache, &ug->h, &rqstp->rq_chandle); |
| 629 | switch (ret) { | 656 | switch (ret) { |
| 630 | case -ENOENT: | 657 | case -ENOENT: |
| 631 | return ERR_PTR(-ENOENT); | 658 | return ERR_PTR(-ENOENT); |
| @@ -633,7 +660,7 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp) | |||
| 633 | return ERR_PTR(-ESHUTDOWN); | 660 | return ERR_PTR(-ESHUTDOWN); |
| 634 | case 0: | 661 | case 0: |
| 635 | gi = get_group_info(ug->gi); | 662 | gi = get_group_info(ug->gi); |
| 636 | cache_put(&ug->h, &unix_gid_cache); | 663 | cache_put(&ug->h, sn->unix_gid_cache); |
| 637 | return gi; | 664 | return gi; |
| 638 | default: | 665 | default: |
| 639 | return ERR_PTR(-EAGAIN); | 666 | return ERR_PTR(-EAGAIN); |
| @@ -849,56 +876,45 @@ struct auth_ops svcauth_unix = { | |||
| 849 | .set_client = svcauth_unix_set_client, | 876 | .set_client = svcauth_unix_set_client, |
| 850 | }; | 877 | }; |
| 851 | 878 | ||
| 879 | static struct cache_detail ip_map_cache_template = { | ||
| 880 | .owner = THIS_MODULE, | ||
| 881 | .hash_size = IP_HASHMAX, | ||
| 882 | .name = "auth.unix.ip", | ||
| 883 | .cache_put = ip_map_put, | ||
| 884 | .cache_upcall = ip_map_upcall, | ||
| 885 | .cache_parse = ip_map_parse, | ||
| 886 | .cache_show = ip_map_show, | ||
| 887 | .match = ip_map_match, | ||
| 888 | .init = ip_map_init, | ||
| 889 | .update = update, | ||
| 890 | .alloc = ip_map_alloc, | ||
| 891 | }; | ||
| 892 | |||
| 852 | int ip_map_cache_create(struct net *net) | 893 | int ip_map_cache_create(struct net *net) |
| 853 | { | 894 | { |
| 854 | int err = -ENOMEM; | ||
| 855 | struct cache_detail *cd; | ||
| 856 | struct cache_head **tbl; | ||
| 857 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 895 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
| 896 | struct cache_detail *cd; | ||
| 897 | int err; | ||
| 858 | 898 | ||
| 859 | cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL); | 899 | cd = cache_create_net(&ip_map_cache_template, net); |
| 860 | if (cd == NULL) | 900 | if (IS_ERR(cd)) |
| 861 | goto err_cd; | 901 | return PTR_ERR(cd); |
| 862 | |||
| 863 | tbl = kzalloc(IP_HASHMAX * sizeof(struct cache_head *), GFP_KERNEL); | ||
| 864 | if (tbl == NULL) | ||
| 865 | goto err_tbl; | ||
| 866 | |||
| 867 | cd->owner = THIS_MODULE, | ||
| 868 | cd->hash_size = IP_HASHMAX, | ||
| 869 | cd->hash_table = tbl, | ||
| 870 | cd->name = "auth.unix.ip", | ||
| 871 | cd->cache_put = ip_map_put, | ||
| 872 | cd->cache_upcall = ip_map_upcall, | ||
| 873 | cd->cache_parse = ip_map_parse, | ||
| 874 | cd->cache_show = ip_map_show, | ||
| 875 | cd->match = ip_map_match, | ||
| 876 | cd->init = ip_map_init, | ||
| 877 | cd->update = update, | ||
| 878 | cd->alloc = ip_map_alloc, | ||
| 879 | |||
| 880 | err = cache_register_net(cd, net); | 902 | err = cache_register_net(cd, net); |
| 881 | if (err) | 903 | if (err) { |
| 882 | goto err_reg; | 904 | cache_destroy_net(cd, net); |
| 883 | 905 | return err; | |
| 906 | } | ||
| 884 | sn->ip_map_cache = cd; | 907 | sn->ip_map_cache = cd; |
| 885 | return 0; | 908 | return 0; |
| 886 | |||
| 887 | err_reg: | ||
| 888 | kfree(tbl); | ||
| 889 | err_tbl: | ||
| 890 | kfree(cd); | ||
| 891 | err_cd: | ||
| 892 | return err; | ||
| 893 | } | 909 | } |
| 894 | 910 | ||
| 895 | void ip_map_cache_destroy(struct net *net) | 911 | void ip_map_cache_destroy(struct net *net) |
| 896 | { | 912 | { |
| 897 | struct sunrpc_net *sn; | 913 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
| 914 | struct cache_detail *cd = sn->ip_map_cache; | ||
| 898 | 915 | ||
| 899 | sn = net_generic(net, sunrpc_net_id); | 916 | sn->ip_map_cache = NULL; |
| 900 | cache_purge(sn->ip_map_cache); | 917 | cache_purge(cd); |
| 901 | cache_unregister_net(sn->ip_map_cache, net); | 918 | cache_unregister_net(cd, net); |
| 902 | kfree(sn->ip_map_cache->hash_table); | 919 | cache_destroy_net(cd, net); |
| 903 | kfree(sn->ip_map_cache); | ||
| 904 | } | 920 | } |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 464570906f80..40ae884db865 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -396,7 +396,7 @@ static int svc_partial_recvfrom(struct svc_rqst *rqstp, | |||
| 396 | int buflen, unsigned int base) | 396 | int buflen, unsigned int base) |
| 397 | { | 397 | { |
| 398 | size_t save_iovlen; | 398 | size_t save_iovlen; |
| 399 | void __user *save_iovbase; | 399 | void *save_iovbase; |
| 400 | unsigned int i; | 400 | unsigned int i; |
| 401 | int ret; | 401 | int ret; |
| 402 | 402 | ||
| @@ -1409,7 +1409,8 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, | |||
| 1409 | 1409 | ||
| 1410 | /* Register socket with portmapper */ | 1410 | /* Register socket with portmapper */ |
| 1411 | if (*errp >= 0 && pmap_register) | 1411 | if (*errp >= 0 && pmap_register) |
| 1412 | *errp = svc_register(serv, inet->sk_family, inet->sk_protocol, | 1412 | *errp = svc_register(serv, sock_net(sock->sk), inet->sk_family, |
| 1413 | inet->sk_protocol, | ||
| 1413 | ntohs(inet_sk(inet)->inet_sport)); | 1414 | ntohs(inet_sk(inet)->inet_sport)); |
| 1414 | 1415 | ||
| 1415 | if (*errp < 0) { | 1416 | if (*errp < 0) { |
diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c index e65dcc613339..af7d339add9d 100644 --- a/net/sunrpc/sysctl.c +++ b/net/sunrpc/sysctl.c | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | #include <linux/sunrpc/stats.h> | 20 | #include <linux/sunrpc/stats.h> |
| 21 | #include <linux/sunrpc/svc_xprt.h> | 21 | #include <linux/sunrpc/svc_xprt.h> |
| 22 | 22 | ||
| 23 | #include "netns.h" | ||
| 24 | |||
| 23 | /* | 25 | /* |
| 24 | * Declare the debug flags here | 26 | * Declare the debug flags here |
| 25 | */ | 27 | */ |
| @@ -110,7 +112,7 @@ proc_dodebug(ctl_table *table, int write, | |||
| 110 | *(unsigned int *) table->data = value; | 112 | *(unsigned int *) table->data = value; |
| 111 | /* Display the RPC tasks on writing to rpc_debug */ | 113 | /* Display the RPC tasks on writing to rpc_debug */ |
| 112 | if (strcmp(table->procname, "rpc_debug") == 0) | 114 | if (strcmp(table->procname, "rpc_debug") == 0) |
| 113 | rpc_show_tasks(); | 115 | rpc_show_tasks(&init_net); |
| 114 | } else { | 116 | } else { |
| 115 | if (!access_ok(VERIFY_WRITE, buffer, left)) | 117 | if (!access_ok(VERIFY_WRITE, buffer, left)) |
| 116 | return -EFAULT; | 118 | return -EFAULT; |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c64c0ef519b5..0cbcd1ab49ab 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -66,6 +66,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net); | |||
| 66 | static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); | 66 | static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); |
| 67 | static void xprt_connect_status(struct rpc_task *task); | 67 | static void xprt_connect_status(struct rpc_task *task); |
| 68 | static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); | 68 | static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); |
| 69 | static void xprt_destroy(struct rpc_xprt *xprt); | ||
| 69 | 70 | ||
| 70 | static DEFINE_SPINLOCK(xprt_list_lock); | 71 | static DEFINE_SPINLOCK(xprt_list_lock); |
| 71 | static LIST_HEAD(xprt_list); | 72 | static LIST_HEAD(xprt_list); |
| @@ -292,54 +293,57 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) | |||
| 292 | return retval; | 293 | return retval; |
| 293 | } | 294 | } |
| 294 | 295 | ||
| 295 | static void __xprt_lock_write_next(struct rpc_xprt *xprt) | 296 | static bool __xprt_lock_write_func(struct rpc_task *task, void *data) |
| 296 | { | 297 | { |
| 297 | struct rpc_task *task; | 298 | struct rpc_xprt *xprt = data; |
| 298 | struct rpc_rqst *req; | 299 | struct rpc_rqst *req; |
| 299 | 300 | ||
| 300 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) | ||
| 301 | return; | ||
| 302 | |||
| 303 | task = rpc_wake_up_next(&xprt->sending); | ||
| 304 | if (task == NULL) | ||
| 305 | goto out_unlock; | ||
| 306 | |||
| 307 | req = task->tk_rqstp; | 301 | req = task->tk_rqstp; |
| 308 | xprt->snd_task = task; | 302 | xprt->snd_task = task; |
| 309 | if (req) { | 303 | if (req) { |
| 310 | req->rq_bytes_sent = 0; | 304 | req->rq_bytes_sent = 0; |
| 311 | req->rq_ntrans++; | 305 | req->rq_ntrans++; |
| 312 | } | 306 | } |
| 313 | return; | 307 | return true; |
| 308 | } | ||
| 314 | 309 | ||
| 315 | out_unlock: | 310 | static void __xprt_lock_write_next(struct rpc_xprt *xprt) |
| 311 | { | ||
| 312 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) | ||
| 313 | return; | ||
| 314 | |||
| 315 | if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_func, xprt)) | ||
| 316 | return; | ||
| 316 | xprt_clear_locked(xprt); | 317 | xprt_clear_locked(xprt); |
| 317 | } | 318 | } |
| 318 | 319 | ||
| 319 | static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) | 320 | static bool __xprt_lock_write_cong_func(struct rpc_task *task, void *data) |
| 320 | { | 321 | { |
| 321 | struct rpc_task *task; | 322 | struct rpc_xprt *xprt = data; |
| 322 | struct rpc_rqst *req; | 323 | struct rpc_rqst *req; |
| 323 | 324 | ||
| 324 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) | ||
| 325 | return; | ||
| 326 | if (RPCXPRT_CONGESTED(xprt)) | ||
| 327 | goto out_unlock; | ||
| 328 | task = rpc_wake_up_next(&xprt->sending); | ||
| 329 | if (task == NULL) | ||
| 330 | goto out_unlock; | ||
| 331 | |||
| 332 | req = task->tk_rqstp; | 325 | req = task->tk_rqstp; |
| 333 | if (req == NULL) { | 326 | if (req == NULL) { |
| 334 | xprt->snd_task = task; | 327 | xprt->snd_task = task; |
| 335 | return; | 328 | return true; |
| 336 | } | 329 | } |
| 337 | if (__xprt_get_cong(xprt, task)) { | 330 | if (__xprt_get_cong(xprt, task)) { |
| 338 | xprt->snd_task = task; | 331 | xprt->snd_task = task; |
| 339 | req->rq_bytes_sent = 0; | 332 | req->rq_bytes_sent = 0; |
| 340 | req->rq_ntrans++; | 333 | req->rq_ntrans++; |
| 341 | return; | 334 | return true; |
| 342 | } | 335 | } |
| 336 | return false; | ||
| 337 | } | ||
| 338 | |||
| 339 | static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) | ||
| 340 | { | ||
| 341 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) | ||
| 342 | return; | ||
| 343 | if (RPCXPRT_CONGESTED(xprt)) | ||
| 344 | goto out_unlock; | ||
| 345 | if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_cong_func, xprt)) | ||
| 346 | return; | ||
| 343 | out_unlock: | 347 | out_unlock: |
| 344 | xprt_clear_locked(xprt); | 348 | xprt_clear_locked(xprt); |
| 345 | } | 349 | } |
| @@ -712,9 +716,7 @@ void xprt_connect(struct rpc_task *task) | |||
| 712 | if (xprt_connected(xprt)) | 716 | if (xprt_connected(xprt)) |
| 713 | xprt_release_write(xprt, task); | 717 | xprt_release_write(xprt, task); |
| 714 | else { | 718 | else { |
| 715 | if (task->tk_rqstp) | 719 | task->tk_rqstp->rq_bytes_sent = 0; |
| 716 | task->tk_rqstp->rq_bytes_sent = 0; | ||
| 717 | |||
| 718 | task->tk_timeout = task->tk_rqstp->rq_timeout; | 720 | task->tk_timeout = task->tk_rqstp->rq_timeout; |
| 719 | rpc_sleep_on(&xprt->pending, task, xprt_connect_status); | 721 | rpc_sleep_on(&xprt->pending, task, xprt_connect_status); |
| 720 | 722 | ||
| @@ -750,7 +752,7 @@ static void xprt_connect_status(struct rpc_task *task) | |||
| 750 | default: | 752 | default: |
| 751 | dprintk("RPC: %5u xprt_connect_status: error %d connecting to " | 753 | dprintk("RPC: %5u xprt_connect_status: error %d connecting to " |
| 752 | "server %s\n", task->tk_pid, -task->tk_status, | 754 | "server %s\n", task->tk_pid, -task->tk_status, |
| 753 | task->tk_client->cl_server); | 755 | xprt->servername); |
| 754 | xprt_release_write(xprt, task); | 756 | xprt_release_write(xprt, task); |
| 755 | task->tk_status = -EIO; | 757 | task->tk_status = -EIO; |
| 756 | } | 758 | } |
| @@ -884,7 +886,7 @@ void xprt_transmit(struct rpc_task *task) | |||
| 884 | { | 886 | { |
| 885 | struct rpc_rqst *req = task->tk_rqstp; | 887 | struct rpc_rqst *req = task->tk_rqstp; |
| 886 | struct rpc_xprt *xprt = req->rq_xprt; | 888 | struct rpc_xprt *xprt = req->rq_xprt; |
| 887 | int status; | 889 | int status, numreqs; |
| 888 | 890 | ||
| 889 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); | 891 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); |
| 890 | 892 | ||
| @@ -921,9 +923,14 @@ void xprt_transmit(struct rpc_task *task) | |||
| 921 | 923 | ||
| 922 | xprt->ops->set_retrans_timeout(task); | 924 | xprt->ops->set_retrans_timeout(task); |
| 923 | 925 | ||
| 926 | numreqs = atomic_read(&xprt->num_reqs); | ||
| 927 | if (numreqs > xprt->stat.max_slots) | ||
| 928 | xprt->stat.max_slots = numreqs; | ||
| 924 | xprt->stat.sends++; | 929 | xprt->stat.sends++; |
| 925 | xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs; | 930 | xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs; |
| 926 | xprt->stat.bklog_u += xprt->backlog.qlen; | 931 | xprt->stat.bklog_u += xprt->backlog.qlen; |
| 932 | xprt->stat.sending_u += xprt->sending.qlen; | ||
| 933 | xprt->stat.pending_u += xprt->pending.qlen; | ||
| 927 | 934 | ||
| 928 | /* Don't race with disconnect */ | 935 | /* Don't race with disconnect */ |
| 929 | if (!xprt_connected(xprt)) | 936 | if (!xprt_connected(xprt)) |
| @@ -1131,7 +1138,10 @@ void xprt_release(struct rpc_task *task) | |||
| 1131 | return; | 1138 | return; |
| 1132 | 1139 | ||
| 1133 | xprt = req->rq_xprt; | 1140 | xprt = req->rq_xprt; |
| 1134 | rpc_count_iostats(task); | 1141 | if (task->tk_ops->rpc_count_stats != NULL) |
| 1142 | task->tk_ops->rpc_count_stats(task, task->tk_calldata); | ||
| 1143 | else if (task->tk_client) | ||
| 1144 | rpc_count_iostats(task, task->tk_client->cl_metrics); | ||
| 1135 | spin_lock_bh(&xprt->transport_lock); | 1145 | spin_lock_bh(&xprt->transport_lock); |
| 1136 | xprt->ops->release_xprt(xprt, task); | 1146 | xprt->ops->release_xprt(xprt, task); |
| 1137 | if (xprt->ops->release_request) | 1147 | if (xprt->ops->release_request) |
| @@ -1220,6 +1230,17 @@ found: | |||
| 1220 | (unsigned long)xprt); | 1230 | (unsigned long)xprt); |
| 1221 | else | 1231 | else |
| 1222 | init_timer(&xprt->timer); | 1232 | init_timer(&xprt->timer); |
| 1233 | |||
| 1234 | if (strlen(args->servername) > RPC_MAXNETNAMELEN) { | ||
| 1235 | xprt_destroy(xprt); | ||
| 1236 | return ERR_PTR(-EINVAL); | ||
| 1237 | } | ||
| 1238 | xprt->servername = kstrdup(args->servername, GFP_KERNEL); | ||
| 1239 | if (xprt->servername == NULL) { | ||
| 1240 | xprt_destroy(xprt); | ||
| 1241 | return ERR_PTR(-ENOMEM); | ||
| 1242 | } | ||
| 1243 | |||
| 1223 | dprintk("RPC: created transport %p with %u slots\n", xprt, | 1244 | dprintk("RPC: created transport %p with %u slots\n", xprt, |
| 1224 | xprt->max_reqs); | 1245 | xprt->max_reqs); |
| 1225 | out: | 1246 | out: |
| @@ -1242,6 +1263,7 @@ static void xprt_destroy(struct rpc_xprt *xprt) | |||
| 1242 | rpc_destroy_wait_queue(&xprt->sending); | 1263 | rpc_destroy_wait_queue(&xprt->sending); |
| 1243 | rpc_destroy_wait_queue(&xprt->backlog); | 1264 | rpc_destroy_wait_queue(&xprt->backlog); |
| 1244 | cancel_work_sync(&xprt->task_cleanup); | 1265 | cancel_work_sync(&xprt->task_cleanup); |
| 1266 | kfree(xprt->servername); | ||
| 1245 | /* | 1267 | /* |
| 1246 | * Tear down transport state and free the rpc_xprt | 1268 | * Tear down transport state and free the rpc_xprt |
| 1247 | */ | 1269 | */ |
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 1776e5731dcf..558fbab574f0 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
| @@ -771,13 +771,18 @@ repost: | |||
| 771 | 771 | ||
| 772 | /* get request object */ | 772 | /* get request object */ |
| 773 | req = rpcr_to_rdmar(rqst); | 773 | req = rpcr_to_rdmar(rqst); |
| 774 | if (req->rl_reply) { | ||
| 775 | spin_unlock(&xprt->transport_lock); | ||
| 776 | dprintk("RPC: %s: duplicate reply 0x%p to RPC " | ||
| 777 | "request 0x%p: xid 0x%08x\n", __func__, rep, req, | ||
| 778 | headerp->rm_xid); | ||
| 779 | goto repost; | ||
| 780 | } | ||
| 774 | 781 | ||
| 775 | dprintk("RPC: %s: reply 0x%p completes request 0x%p\n" | 782 | dprintk("RPC: %s: reply 0x%p completes request 0x%p\n" |
| 776 | " RPC request 0x%p xid 0x%08x\n", | 783 | " RPC request 0x%p xid 0x%08x\n", |
| 777 | __func__, rep, req, rqst, headerp->rm_xid); | 784 | __func__, rep, req, rqst, headerp->rm_xid); |
| 778 | 785 | ||
| 779 | BUG_ON(!req || req->rl_reply); | ||
| 780 | |||
| 781 | /* from here on, the reply is no longer an orphan */ | 786 | /* from here on, the reply is no longer an orphan */ |
| 782 | req->rl_reply = rep; | 787 | req->rl_reply = rep; |
| 783 | 788 | ||
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 28236bab57f9..745973b729af 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
| @@ -1490,6 +1490,9 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1490 | u8 key; | 1490 | u8 key; |
| 1491 | int len, pageoff; | 1491 | int len, pageoff; |
| 1492 | int i, rc; | 1492 | int i, rc; |
| 1493 | int seg_len; | ||
| 1494 | u64 pa; | ||
| 1495 | int page_no; | ||
| 1493 | 1496 | ||
| 1494 | pageoff = offset_in_page(seg1->mr_offset); | 1497 | pageoff = offset_in_page(seg1->mr_offset); |
| 1495 | seg1->mr_offset -= pageoff; /* start of page */ | 1498 | seg1->mr_offset -= pageoff; /* start of page */ |
| @@ -1497,11 +1500,15 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1497 | len = -pageoff; | 1500 | len = -pageoff; |
| 1498 | if (*nsegs > RPCRDMA_MAX_DATA_SEGS) | 1501 | if (*nsegs > RPCRDMA_MAX_DATA_SEGS) |
| 1499 | *nsegs = RPCRDMA_MAX_DATA_SEGS; | 1502 | *nsegs = RPCRDMA_MAX_DATA_SEGS; |
| 1500 | for (i = 0; i < *nsegs;) { | 1503 | for (page_no = i = 0; i < *nsegs;) { |
| 1501 | rpcrdma_map_one(ia, seg, writing); | 1504 | rpcrdma_map_one(ia, seg, writing); |
| 1502 | seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma; | 1505 | pa = seg->mr_dma; |
| 1506 | for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) { | ||
| 1507 | seg1->mr_chunk.rl_mw->r.frmr.fr_pgl-> | ||
| 1508 | page_list[page_no++] = pa; | ||
| 1509 | pa += PAGE_SIZE; | ||
| 1510 | } | ||
| 1503 | len += seg->mr_len; | 1511 | len += seg->mr_len; |
| 1504 | BUG_ON(seg->mr_len > PAGE_SIZE); | ||
| 1505 | ++seg; | 1512 | ++seg; |
| 1506 | ++i; | 1513 | ++i; |
| 1507 | /* Check for holes */ | 1514 | /* Check for holes */ |
| @@ -1540,9 +1547,9 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1540 | frmr_wr.send_flags = IB_SEND_SIGNALED; | 1547 | frmr_wr.send_flags = IB_SEND_SIGNALED; |
| 1541 | frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; | 1548 | frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; |
| 1542 | frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; | 1549 | frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; |
| 1543 | frmr_wr.wr.fast_reg.page_list_len = i; | 1550 | frmr_wr.wr.fast_reg.page_list_len = page_no; |
| 1544 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; | 1551 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; |
| 1545 | frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT; | 1552 | frmr_wr.wr.fast_reg.length = page_no << PAGE_SHIFT; |
| 1546 | BUG_ON(frmr_wr.wr.fast_reg.length < len); | 1553 | BUG_ON(frmr_wr.wr.fast_reg.length < len); |
| 1547 | frmr_wr.wr.fast_reg.access_flags = (writing ? | 1554 | frmr_wr.wr.fast_reg.access_flags = (writing ? |
| 1548 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : | 1555 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 55472c48825e..92bc5181dbeb 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -53,12 +53,12 @@ static void xs_close(struct rpc_xprt *xprt); | |||
| 53 | /* | 53 | /* |
| 54 | * xprtsock tunables | 54 | * xprtsock tunables |
| 55 | */ | 55 | */ |
| 56 | unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; | 56 | static unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; |
| 57 | unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE; | 57 | static unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE; |
| 58 | unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE; | 58 | static unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE; |
| 59 | 59 | ||
| 60 | unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT; | 60 | static unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT; |
| 61 | unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT; | 61 | static unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT; |
| 62 | 62 | ||
| 63 | #define XS_TCP_LINGER_TO (15U * HZ) | 63 | #define XS_TCP_LINGER_TO (15U * HZ) |
| 64 | static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO; | 64 | static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO; |
| @@ -2227,7 +2227,7 @@ static void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) | |||
| 2227 | idle_time = (long)(jiffies - xprt->last_used) / HZ; | 2227 | idle_time = (long)(jiffies - xprt->last_used) / HZ; |
| 2228 | 2228 | ||
| 2229 | seq_printf(seq, "\txprt:\tlocal %lu %lu %lu %ld %lu %lu %lu " | 2229 | seq_printf(seq, "\txprt:\tlocal %lu %lu %lu %ld %lu %lu %lu " |
| 2230 | "%llu %llu\n", | 2230 | "%llu %llu %lu %llu %llu\n", |
| 2231 | xprt->stat.bind_count, | 2231 | xprt->stat.bind_count, |
| 2232 | xprt->stat.connect_count, | 2232 | xprt->stat.connect_count, |
| 2233 | xprt->stat.connect_time, | 2233 | xprt->stat.connect_time, |
| @@ -2236,7 +2236,10 @@ static void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) | |||
| 2236 | xprt->stat.recvs, | 2236 | xprt->stat.recvs, |
| 2237 | xprt->stat.bad_xids, | 2237 | xprt->stat.bad_xids, |
| 2238 | xprt->stat.req_u, | 2238 | xprt->stat.req_u, |
| 2239 | xprt->stat.bklog_u); | 2239 | xprt->stat.bklog_u, |
| 2240 | xprt->stat.max_slots, | ||
| 2241 | xprt->stat.sending_u, | ||
| 2242 | xprt->stat.pending_u); | ||
| 2240 | } | 2243 | } |
| 2241 | 2244 | ||
| 2242 | /** | 2245 | /** |
| @@ -2249,14 +2252,18 @@ static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) | |||
| 2249 | { | 2252 | { |
| 2250 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 2253 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
| 2251 | 2254 | ||
| 2252 | seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n", | 2255 | seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %llu %llu " |
| 2256 | "%lu %llu %llu\n", | ||
| 2253 | transport->srcport, | 2257 | transport->srcport, |
| 2254 | xprt->stat.bind_count, | 2258 | xprt->stat.bind_count, |
| 2255 | xprt->stat.sends, | 2259 | xprt->stat.sends, |
| 2256 | xprt->stat.recvs, | 2260 | xprt->stat.recvs, |
| 2257 | xprt->stat.bad_xids, | 2261 | xprt->stat.bad_xids, |
| 2258 | xprt->stat.req_u, | 2262 | xprt->stat.req_u, |
| 2259 | xprt->stat.bklog_u); | 2263 | xprt->stat.bklog_u, |
| 2264 | xprt->stat.max_slots, | ||
| 2265 | xprt->stat.sending_u, | ||
| 2266 | xprt->stat.pending_u); | ||
| 2260 | } | 2267 | } |
| 2261 | 2268 | ||
| 2262 | /** | 2269 | /** |
| @@ -2273,7 +2280,8 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) | |||
| 2273 | if (xprt_connected(xprt)) | 2280 | if (xprt_connected(xprt)) |
| 2274 | idle_time = (long)(jiffies - xprt->last_used) / HZ; | 2281 | idle_time = (long)(jiffies - xprt->last_used) / HZ; |
| 2275 | 2282 | ||
| 2276 | seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n", | 2283 | seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu " |
| 2284 | "%llu %llu %lu %llu %llu\n", | ||
| 2277 | transport->srcport, | 2285 | transport->srcport, |
| 2278 | xprt->stat.bind_count, | 2286 | xprt->stat.bind_count, |
| 2279 | xprt->stat.connect_count, | 2287 | xprt->stat.connect_count, |
| @@ -2283,7 +2291,10 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) | |||
| 2283 | xprt->stat.recvs, | 2291 | xprt->stat.recvs, |
| 2284 | xprt->stat.bad_xids, | 2292 | xprt->stat.bad_xids, |
| 2285 | xprt->stat.req_u, | 2293 | xprt->stat.req_u, |
| 2286 | xprt->stat.bklog_u); | 2294 | xprt->stat.bklog_u, |
| 2295 | xprt->stat.max_slots, | ||
| 2296 | xprt->stat.sending_u, | ||
| 2297 | xprt->stat.pending_u); | ||
| 2287 | } | 2298 | } |
| 2288 | 2299 | ||
| 2289 | /* | 2300 | /* |
diff --git a/security/keys/key.c b/security/keys/key.c index 7ada8019be1f..06783cffb3af 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -671,6 +671,26 @@ found_kernel_type: | |||
| 671 | return ktype; | 671 | return ktype; |
| 672 | } | 672 | } |
| 673 | 673 | ||
| 674 | void key_set_timeout(struct key *key, unsigned timeout) | ||
| 675 | { | ||
| 676 | struct timespec now; | ||
| 677 | time_t expiry = 0; | ||
| 678 | |||
| 679 | /* make the changes with the locks held to prevent races */ | ||
| 680 | down_write(&key->sem); | ||
| 681 | |||
| 682 | if (timeout > 0) { | ||
| 683 | now = current_kernel_time(); | ||
| 684 | expiry = now.tv_sec + timeout; | ||
| 685 | } | ||
| 686 | |||
| 687 | key->expiry = expiry; | ||
| 688 | key_schedule_gc(key->expiry + key_gc_delay); | ||
| 689 | |||
| 690 | up_write(&key->sem); | ||
| 691 | } | ||
| 692 | EXPORT_SYMBOL_GPL(key_set_timeout); | ||
| 693 | |||
| 674 | /* | 694 | /* |
| 675 | * Unlock a key type locked by key_type_lookup(). | 695 | * Unlock a key type locked by key_type_lookup(). |
| 676 | */ | 696 | */ |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 6523599e9ac0..fb767c6cd99f 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/syscalls.h> | 16 | #include <linux/syscalls.h> |
| 17 | #include <linux/key.h> | ||
| 17 | #include <linux/keyctl.h> | 18 | #include <linux/keyctl.h> |
| 18 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
| 19 | #include <linux/capability.h> | 20 | #include <linux/capability.h> |
| @@ -1257,10 +1258,8 @@ error: | |||
| 1257 | */ | 1258 | */ |
| 1258 | long keyctl_set_timeout(key_serial_t id, unsigned timeout) | 1259 | long keyctl_set_timeout(key_serial_t id, unsigned timeout) |
| 1259 | { | 1260 | { |
| 1260 | struct timespec now; | ||
| 1261 | struct key *key, *instkey; | 1261 | struct key *key, *instkey; |
| 1262 | key_ref_t key_ref; | 1262 | key_ref_t key_ref; |
| 1263 | time_t expiry; | ||
| 1264 | long ret; | 1263 | long ret; |
| 1265 | 1264 | ||
| 1266 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, | 1265 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| @@ -1286,20 +1285,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |||
| 1286 | 1285 | ||
| 1287 | okay: | 1286 | okay: |
| 1288 | key = key_ref_to_ptr(key_ref); | 1287 | key = key_ref_to_ptr(key_ref); |
| 1289 | 1288 | key_set_timeout(key, timeout); | |
| 1290 | /* make the changes with the locks held to prevent races */ | ||
| 1291 | down_write(&key->sem); | ||
| 1292 | |||
| 1293 | expiry = 0; | ||
| 1294 | if (timeout > 0) { | ||
| 1295 | now = current_kernel_time(); | ||
| 1296 | expiry = now.tv_sec + timeout; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | key->expiry = expiry; | ||
| 1300 | key_schedule_gc(key->expiry + key_gc_delay); | ||
| 1301 | |||
| 1302 | up_write(&key->sem); | ||
| 1303 | key_put(key); | 1289 | key_put(key); |
| 1304 | 1290 | ||
| 1305 | ret = 0; | 1291 | ret = 0; |
