aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/nfs-rdma.txt252
-rw-r--r--fs/Kconfig109
-rw-r--r--fs/lockd/host.c73
-rw-r--r--fs/lockd/svc.c150
-rw-r--r--fs/lockd/svclock.c6
-rw-r--r--fs/lockd/svcshare.c3
-rw-r--r--fs/nfs/callback.c93
-rw-r--r--fs/nfs/symlink.c1
-rw-r--r--fs/nfsd/auth.c1
-rw-r--r--fs/nfsd/export.c9
-rw-r--r--fs/nfsd/nfs4callback.c28
-rw-r--r--fs/nfsd/nfs4idmap.c2
-rw-r--r--fs/nfsd/nfs4state.c71
-rw-r--r--fs/nfsd/nfs4xdr.c13
-rw-r--r--fs/nfsd/nfsctl.c22
-rw-r--r--fs/nfsd/nfsfh.c228
-rw-r--r--fs/nfsd/nfssvc.c2
-rw-r--r--fs/nfsd/vfs.c35
-rw-r--r--include/linux/exportfs.h2
-rw-r--r--include/linux/nfs3.h2
-rw-r--r--include/linux/nfsd/Kbuild4
-rw-r--r--include/linux/nfsd/cache.h2
-rw-r--r--include/linux/nfsd/nfsd.h11
-rw-r--r--include/linux/sunrpc/cache.h1
-rw-r--r--include/linux/sunrpc/gss_krb5.h6
-rw-r--r--include/linux/sunrpc/svc.h1
-rw-r--r--include/linux/sunrpc/svcauth.h5
-rw-r--r--include/linux/sunrpc/svcsock.h4
-rw-r--r--include/net/ipv6.h9
-rw-r--r--net/sunrpc/auth_gss/gss_generic_token.c4
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c6
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seal.c9
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seqnum.c4
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_unseal.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c8
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_seal.c4
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c9
-rw-r--r--net/sunrpc/cache.c1
-rw-r--r--net/sunrpc/svc.c25
-rw-r--r--net/sunrpc/svc_xprt.c30
-rw-r--r--net/sunrpc/svcauth_unix.c118
-rw-r--r--net/sunrpc/svcsock.c29
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c2
43 files changed, 879 insertions, 517 deletions
diff --git a/Documentation/filesystems/nfs-rdma.txt b/Documentation/filesystems/nfs-rdma.txt
new file mode 100644
index 000000000000..1ae34879574b
--- /dev/null
+++ b/Documentation/filesystems/nfs-rdma.txt
@@ -0,0 +1,252 @@
1################################################################################
2# #
3# NFS/RDMA README #
4# #
5################################################################################
6
7 Author: NetApp and Open Grid Computing
8 Date: February 25, 2008
9
10Table of Contents
11~~~~~~~~~~~~~~~~~
12 - Overview
13 - Getting Help
14 - Installation
15 - Check RDMA and NFS Setup
16 - NFS/RDMA Setup
17
18Overview
19~~~~~~~~
20
21 This document describes how to install and setup the Linux NFS/RDMA client
22 and server software.
23
24 The NFS/RDMA client was first included in Linux 2.6.24. The NFS/RDMA server
25 was first included in the following release, Linux 2.6.25.
26
27 In our testing, we have obtained excellent performance results (full 10Gbit
28 wire bandwidth at minimal client CPU) under many workloads. The code passes
29 the full Connectathon test suite and operates over both Infiniband and iWARP
30 RDMA adapters.
31
32Getting Help
33~~~~~~~~~~~~
34
35 If you get stuck, you can ask questions on the
36
37 nfs-rdma-devel@lists.sourceforge.net
38
39 mailing list.
40
41Installation
42~~~~~~~~~~~~
43
44 These instructions are a step by step guide to building a machine for
45 use with NFS/RDMA.
46
47 - Install an RDMA device
48
49 Any device supported by the drivers in drivers/infiniband/hw is acceptable.
50
51 Testing has been performed using several Mellanox-based IB cards, the
52 Ammasso AMS1100 iWARP adapter, and the Chelsio cxgb3 iWARP adapter.
53
54 - Install a Linux distribution and tools
55
56 The first kernel release to contain both the NFS/RDMA client and server was
57 Linux 2.6.25 Therefore, a distribution compatible with this and subsequent
58 Linux kernel release should be installed.
59
60 The procedures described in this document have been tested with
61 distributions from Red Hat's Fedora Project (http://fedora.redhat.com/).
62
63 - Install nfs-utils-1.1.1 or greater on the client
64
65 An NFS/RDMA mount point can only be obtained by using the mount.nfs
66 command in nfs-utils-1.1.1 or greater. To see which version of mount.nfs
67 you are using, type:
68
69 > /sbin/mount.nfs -V
70
71 If the version is less than 1.1.1 or the command does not exist,
72 then you will need to install the latest version of nfs-utils.
73
74 Download the latest package from:
75
76 http://www.kernel.org/pub/linux/utils/nfs
77
78 Uncompress the package and follow the installation instructions.
79
80 If you will not be using GSS and NFSv4, the installation process
81 can be simplified by disabling these features when running configure:
82
83 > ./configure --disable-gss --disable-nfsv4
84
85 For more information on this see the package's README and INSTALL files.
86
87 After building the nfs-utils package, there will be a mount.nfs binary in
88 the utils/mount directory. This binary can be used to initiate NFS v2, v3,
89 or v4 mounts. To initiate a v4 mount, the binary must be called mount.nfs4.
90 The standard technique is to create a symlink called mount.nfs4 to mount.nfs.
91
92 NOTE: mount.nfs and therefore nfs-utils-1.1.1 or greater is only needed
93 on the NFS client machine. You do not need this specific version of
94 nfs-utils on the server. Furthermore, only the mount.nfs command from
95 nfs-utils-1.1.1 is needed on the client.
96
97 - Install a Linux kernel with NFS/RDMA
98
99 The NFS/RDMA client and server are both included in the mainline Linux
100 kernel version 2.6.25 and later. This and other versions of the 2.6 Linux
101 kernel can be found at:
102
103 ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
104
105 Download the sources and place them in an appropriate location.
106
107 - Configure the RDMA stack
108
109 Make sure your kernel configuration has RDMA support enabled. Under
110 Device Drivers -> InfiniBand support, update the kernel configuration
111 to enable InfiniBand support [NOTE: the option name is misleading. Enabling
112 InfiniBand support is required for all RDMA devices (IB, iWARP, etc.)].
113
114 Enable the appropriate IB HCA support (mlx4, mthca, ehca, ipath, etc.) or
115 iWARP adapter support (amso, cxgb3, etc.).
116
117 If you are using InfiniBand, be sure to enable IP-over-InfiniBand support.
118
119 - Configure the NFS client and server
120
121 Your kernel configuration must also have NFS file system support and/or
122 NFS server support enabled. These and other NFS related configuration
123 options can be found under File Systems -> Network File Systems.
124
125 - Build, install, reboot
126
127 The NFS/RDMA code will be enabled automatically if NFS and RDMA
128 are turned on. The NFS/RDMA client and server are configured via the hidden
129 SUNRPC_XPRT_RDMA config option that depends on SUNRPC and INFINIBAND. The
130 value of SUNRPC_XPRT_RDMA will be:
131
132 - N if either SUNRPC or INFINIBAND are N, in this case the NFS/RDMA client
133 and server will not be built
134 - M if both SUNRPC and INFINIBAND are on (M or Y) and at least one is M,
135 in this case the NFS/RDMA client and server will be built as modules
136 - Y if both SUNRPC and INFINIBAND are Y, in this case the NFS/RDMA client
137 and server will be built into the kernel
138
139 Therefore, if you have followed the steps above and turned no NFS and RDMA,
140 the NFS/RDMA client and server will be built.
141
142 Build a new kernel, install it, boot it.
143
144Check RDMA and NFS Setup
145~~~~~~~~~~~~~~~~~~~~~~~~
146
147 Before configuring the NFS/RDMA software, it is a good idea to test
148 your new kernel to ensure that the kernel is working correctly.
149 In particular, it is a good idea to verify that the RDMA stack
150 is functioning as expected and standard NFS over TCP/IP and/or UDP/IP
151 is working properly.
152
153 - Check RDMA Setup
154
155 If you built the RDMA components as modules, load them at
156 this time. For example, if you are using a Mellanox Tavor/Sinai/Arbel
157 card:
158
159 > modprobe ib_mthca
160 > modprobe ib_ipoib
161
162 If you are using InfiniBand, make sure there is a Subnet Manager (SM)
163 running on the network. If your IB switch has an embedded SM, you can
164 use it. Otherwise, you will need to run an SM, such as OpenSM, on one
165 of your end nodes.
166
167 If an SM is running on your network, you should see the following:
168
169 > cat /sys/class/infiniband/driverX/ports/1/state
170 4: ACTIVE
171
172 where driverX is mthca0, ipath5, ehca3, etc.
173
174 To further test the InfiniBand software stack, use IPoIB (this
175 assumes you have two IB hosts named host1 and host2):
176
177 host1> ifconfig ib0 a.b.c.x
178 host2> ifconfig ib0 a.b.c.y
179 host1> ping a.b.c.y
180 host2> ping a.b.c.x
181
182 For other device types, follow the appropriate procedures.
183
184 - Check NFS Setup
185
186 For the NFS components enabled above (client and/or server),
187 test their functionality over standard Ethernet using TCP/IP or UDP/IP.
188
189NFS/RDMA Setup
190~~~~~~~~~~~~~~
191
192 We recommend that you use two machines, one to act as the client and
193 one to act as the server.
194
195 One time configuration:
196
197 - On the server system, configure the /etc/exports file and
198 start the NFS/RDMA server.
199
200 Exports entries with the following format have been tested:
201
202 /vol0 10.97.103.47(rw,async) 192.168.0.47(rw,async,insecure,no_root_squash)
203
204 Here the first IP address is the client's Ethernet address and the second
205 IP address is the clients IPoIB address.
206
207 Each time a machine boots:
208
209 - Load and configure the RDMA drivers
210
211 For InfiniBand using a Mellanox adapter:
212
213 > modprobe ib_mthca
214 > modprobe ib_ipoib
215 > ifconfig ib0 a.b.c.d
216
217 NOTE: use unique addresses for the client and server
218
219 - Start the NFS server
220
221 If the NFS/RDMA server was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in kernel config),
222 load the RDMA transport module:
223
224 > modprobe svcrdma
225
226 Regardless of how the server was built (module or built-in), start the server:
227
228 > /etc/init.d/nfs start
229
230 or
231
232 > service nfs start
233
234 Instruct the server to listen on the RDMA transport:
235
236 > echo rdma 2050 > /proc/fs/nfsd/portlist
237
238 - On the client system
239
240 If the NFS/RDMA client was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in kernel config),
241 load the RDMA client module:
242
243 > modprobe xprtrdma.ko
244
245 Regardless of how the client was built (module or built-in), issue the mount.nfs command:
246
247 > /path/to/your/mount.nfs <IPoIB-server-name-or-address>:/<export> /mnt -i -o rdma,port=2050
248
249 To verify that the mount is using RDMA, run "cat /proc/mounts" and check the
250 "proto" field for the given mount.
251
252 Congratulations! You're using NFS/RDMA!
diff --git a/fs/Kconfig b/fs/Kconfig
index 8b18a8758677..56c83f40cdbe 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -411,7 +411,7 @@ config JFS_STATISTICS
411 to be made available to the user in the /proc/fs/jfs/ directory. 411 to be made available to the user in the /proc/fs/jfs/ directory.
412 412
413config FS_POSIX_ACL 413config FS_POSIX_ACL
414# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs) 414# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4)
415# 415#
416# NOTE: you can implement Posix ACLs without these helpers (XFS does). 416# NOTE: you can implement Posix ACLs without these helpers (XFS does).
417# Never use this symbol for ifdefs. 417# Never use this symbol for ifdefs.
@@ -1694,75 +1694,80 @@ config NFSD
1694 select LOCKD 1694 select LOCKD
1695 select SUNRPC 1695 select SUNRPC
1696 select EXPORTFS 1696 select EXPORTFS
1697 select NFSD_V2_ACL if NFSD_V3_ACL
1698 select NFS_ACL_SUPPORT if NFSD_V2_ACL 1697 select NFS_ACL_SUPPORT if NFSD_V2_ACL
1699 select NFSD_TCP if NFSD_V4 1698 help
1700 select CRYPTO_MD5 if NFSD_V4 1699 Choose Y here if you want to allow other computers to access
1701 select CRYPTO if NFSD_V4 1700 files residing on this system using Sun's Network File System
1702 select FS_POSIX_ACL if NFSD_V4 1701 protocol. To compile the NFS server support as a module,
1703 select PROC_FS if NFSD_V4 1702 choose M here: the module will be called nfsd.
1704 select PROC_FS if SUNRPC_GSS 1703
1705 help 1704 You may choose to use a user-space NFS server instead, in which
1706 If you want your Linux box to act as an NFS *server*, so that other 1705 case you can choose N here.
1707 computers on your local network which support NFS can access certain 1706
1708 directories on your box transparently, you have two options: you can 1707 To export local file systems using NFS, you also need to install
1709 use the self-contained user space program nfsd, in which case you 1708 user space programs which can be found in the Linux nfs-utils
1710 should say N here, or you can say Y and use the kernel based NFS 1709 package, available from http://linux-nfs.org/. More detail about
1711 server. The advantage of the kernel based solution is that it is 1710 the Linux NFS server implementation is available via the
1712 faster. 1711 exports(5) man page.
1713 1712
1714 In either case, you will need support software; the respective 1713 Below you can choose which versions of the NFS protocol are
1715 locations are given in the file <file:Documentation/Changes> in the 1714 available to clients mounting the NFS server on this system.
1716 NFS section. 1715 Support for NFS version 2 (RFC 1094) is always available when
1717 1716 CONFIG_NFSD is selected.
1718 If you say Y here, you will get support for version 2 of the NFS 1717
1719 protocol (NFSv2). If you also want NFSv3, say Y to the next question 1718 If unsure, say N.
1720 as well.
1721
1722 Please read the NFS-HOWTO, available from
1723 <http://www.tldp.org/docs.html#howto>.
1724
1725 To compile the NFS server support as a module, choose M here: the
1726 module will be called nfsd. If unsure, say N.
1727 1719
1728config NFSD_V2_ACL 1720config NFSD_V2_ACL
1729 bool 1721 bool
1730 depends on NFSD 1722 depends on NFSD
1731 1723
1732config NFSD_V3 1724config NFSD_V3
1733 bool "Provide NFSv3 server support" 1725 bool "NFS server support for NFS version 3"
1734 depends on NFSD 1726 depends on NFSD
1735 help 1727 help
1736 If you would like to include the NFSv3 server as well as the NFSv2 1728 This option enables support in your system's NFS server for
1737 server, say Y here. If unsure, say Y. 1729 version 3 of the NFS protocol (RFC 1813).
1730
1731 If unsure, say Y.
1738 1732
1739config NFSD_V3_ACL 1733config NFSD_V3_ACL
1740 bool "Provide server support for the NFSv3 ACL protocol extension" 1734 bool "NFS server support for the NFSv3 ACL protocol extension"
1741 depends on NFSD_V3 1735 depends on NFSD_V3
1736 select NFSD_V2_ACL
1742 help 1737 help
1743 Implement the NFSv3 ACL protocol extension for manipulating POSIX 1738 Solaris NFS servers support an auxiliary NFSv3 ACL protocol that
1744 Access Control Lists on exported file systems. NFS clients should 1739 never became an official part of the NFS version 3 protocol.
1745 be compiled with the NFSv3 ACL protocol extension; see the 1740 This protocol extension allows applications on NFS clients to
1746 CONFIG_NFS_V3_ACL option. If unsure, say N. 1741 manipulate POSIX Access Control Lists on files residing on NFS
1742 servers. NFS servers enforce POSIX ACLs on local files whether
1743 this protocol is available or not.
1744
1745 This option enables support in your system's NFS server for the
1746 NFSv3 ACL protocol extension allowing NFS clients to manipulate
1747 POSIX ACLs on files exported by your system's NFS server. NFS
1748 clients which support the Solaris NFSv3 ACL protocol can then
1749 access and modify ACLs on your NFS server.
1750
1751 To store ACLs on your NFS server, you also need to enable ACL-
1752 related CONFIG options for your local file systems of choice.
1753
1754 If unsure, say N.
1747 1755
1748config NFSD_V4 1756config NFSD_V4
1749 bool "Provide NFSv4 server support (EXPERIMENTAL)" 1757 bool "NFS server support for NFS version 4 (EXPERIMENTAL)"
1750 depends on NFSD && NFSD_V3 && EXPERIMENTAL 1758 depends on NFSD && PROC_FS && EXPERIMENTAL
1759 select NFSD_V3
1760 select FS_POSIX_ACL
1751 select RPCSEC_GSS_KRB5 1761 select RPCSEC_GSS_KRB5
1752 help 1762 help
1753 If you would like to include the NFSv4 server as well as the NFSv2 1763 This option enables support in your system's NFS server for
1754 and NFSv3 servers, say Y here. This feature is experimental, and 1764 version 4 of the NFS protocol (RFC 3530).
1755 should only be used if you are interested in helping to test NFSv4.
1756 If unsure, say N.
1757 1765
1758config NFSD_TCP 1766 To export files using NFSv4, you need to install additional user
1759 bool "Provide NFS server over TCP support" 1767 space programs which can be found in the Linux nfs-utils package,
1760 depends on NFSD 1768 available from http://linux-nfs.org/.
1761 default y 1769
1762 help 1770 If unsure, say N.
1763 If you want your NFS server to support TCP connections, say Y here.
1764 TCP connections usually perform better than the default UDP when
1765 the network is lossy or congested. If unsure, say Y.
1766 1771
1767config ROOT_NFS 1772config ROOT_NFS
1768 bool "Root file system on NFS" 1773 bool "Root file system on NFS"
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index f1ef49fff118..c7854791898f 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -19,12 +19,11 @@
19 19
20 20
21#define NLMDBG_FACILITY NLMDBG_HOSTCACHE 21#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
22#define NLM_HOST_MAX 64
23#define NLM_HOST_NRHASH 32 22#define NLM_HOST_NRHASH 32
24#define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1)) 23#define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1))
25#define NLM_HOST_REBIND (60 * HZ) 24#define NLM_HOST_REBIND (60 * HZ)
26#define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) 25#define NLM_HOST_EXPIRE (300 * HZ)
27#define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) 26#define NLM_HOST_COLLECT (120 * HZ)
28 27
29static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; 28static struct hlist_head nlm_hosts[NLM_HOST_NRHASH];
30static unsigned long next_gc; 29static unsigned long next_gc;
@@ -142,9 +141,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin,
142 INIT_LIST_HEAD(&host->h_granted); 141 INIT_LIST_HEAD(&host->h_granted);
143 INIT_LIST_HEAD(&host->h_reclaim); 142 INIT_LIST_HEAD(&host->h_reclaim);
144 143
145 if (++nrhosts > NLM_HOST_MAX) 144 nrhosts++;
146 next_gc = 0;
147
148out: 145out:
149 mutex_unlock(&nlm_host_mutex); 146 mutex_unlock(&nlm_host_mutex);
150 return host; 147 return host;
@@ -460,7 +457,7 @@ nlm_gc_hosts(void)
460 * Manage NSM handles 457 * Manage NSM handles
461 */ 458 */
462static LIST_HEAD(nsm_handles); 459static LIST_HEAD(nsm_handles);
463static DEFINE_MUTEX(nsm_mutex); 460static DEFINE_SPINLOCK(nsm_lock);
464 461
465static struct nsm_handle * 462static struct nsm_handle *
466__nsm_find(const struct sockaddr_in *sin, 463__nsm_find(const struct sockaddr_in *sin,
@@ -468,7 +465,7 @@ __nsm_find(const struct sockaddr_in *sin,
468 int create) 465 int create)
469{ 466{
470 struct nsm_handle *nsm = NULL; 467 struct nsm_handle *nsm = NULL;
471 struct list_head *pos; 468 struct nsm_handle *pos;
472 469
473 if (!sin) 470 if (!sin)
474 return NULL; 471 return NULL;
@@ -482,38 +479,43 @@ __nsm_find(const struct sockaddr_in *sin,
482 return NULL; 479 return NULL;
483 } 480 }
484 481
485 mutex_lock(&nsm_mutex); 482retry:
486 list_for_each(pos, &nsm_handles) { 483 spin_lock(&nsm_lock);
487 nsm = list_entry(pos, struct nsm_handle, sm_link); 484 list_for_each_entry(pos, &nsm_handles, sm_link) {
488 485
489 if (hostname && nsm_use_hostnames) { 486 if (hostname && nsm_use_hostnames) {
490 if (strlen(nsm->sm_name) != hostname_len 487 if (strlen(pos->sm_name) != hostname_len
491 || memcmp(nsm->sm_name, hostname, hostname_len)) 488 || memcmp(pos->sm_name, hostname, hostname_len))
492 continue; 489 continue;
493 } else if (!nlm_cmp_addr(&nsm->sm_addr, sin)) 490 } else if (!nlm_cmp_addr(&pos->sm_addr, sin))
494 continue; 491 continue;
495 atomic_inc(&nsm->sm_count); 492 atomic_inc(&pos->sm_count);
496 goto out; 493 kfree(nsm);
494 nsm = pos;
495 goto found;
497 } 496 }
498 497 if (nsm) {
499 if (!create) { 498 list_add(&nsm->sm_link, &nsm_handles);
500 nsm = NULL; 499 goto found;
501 goto out;
502 } 500 }
501 spin_unlock(&nsm_lock);
502
503 if (!create)
504 return NULL;
503 505
504 nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); 506 nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
505 if (nsm != NULL) { 507 if (nsm == NULL)
506 nsm->sm_addr = *sin; 508 return NULL;
507 nsm->sm_name = (char *) (nsm + 1);
508 memcpy(nsm->sm_name, hostname, hostname_len);
509 nsm->sm_name[hostname_len] = '\0';
510 atomic_set(&nsm->sm_count, 1);
511 509
512 list_add(&nsm->sm_link, &nsm_handles); 510 nsm->sm_addr = *sin;
513 } 511 nsm->sm_name = (char *) (nsm + 1);
512 memcpy(nsm->sm_name, hostname, hostname_len);
513 nsm->sm_name[hostname_len] = '\0';
514 atomic_set(&nsm->sm_count, 1);
515 goto retry;
514 516
515out: 517found:
516 mutex_unlock(&nsm_mutex); 518 spin_unlock(&nsm_lock);
517 return nsm; 519 return nsm;
518} 520}
519 521
@@ -532,12 +534,9 @@ nsm_release(struct nsm_handle *nsm)
532{ 534{
533 if (!nsm) 535 if (!nsm)
534 return; 536 return;
535 if (atomic_dec_and_test(&nsm->sm_count)) { 537 if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
536 mutex_lock(&nsm_mutex); 538 list_del(&nsm->sm_link);
537 if (atomic_read(&nsm->sm_count) == 0) { 539 spin_unlock(&nsm_lock);
538 list_del(&nsm->sm_link); 540 kfree(nsm);
539 kfree(nsm);
540 }
541 mutex_unlock(&nsm_mutex);
542 } 541 }
543} 542}
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 1ed8bd4de941..cf977bbcf303 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -25,6 +25,7 @@
25#include <linux/smp.h> 25#include <linux/smp.h>
26#include <linux/smp_lock.h> 26#include <linux/smp_lock.h>
27#include <linux/mutex.h> 27#include <linux/mutex.h>
28#include <linux/kthread.h>
28#include <linux/freezer.h> 29#include <linux/freezer.h>
29 30
30#include <linux/sunrpc/types.h> 31#include <linux/sunrpc/types.h>
@@ -48,14 +49,11 @@ EXPORT_SYMBOL(nlmsvc_ops);
48 49
49static DEFINE_MUTEX(nlmsvc_mutex); 50static DEFINE_MUTEX(nlmsvc_mutex);
50static unsigned int nlmsvc_users; 51static unsigned int nlmsvc_users;
51static pid_t nlmsvc_pid; 52static struct task_struct *nlmsvc_task;
52static struct svc_serv *nlmsvc_serv; 53static struct svc_serv *nlmsvc_serv;
53int nlmsvc_grace_period; 54int nlmsvc_grace_period;
54unsigned long nlmsvc_timeout; 55unsigned long nlmsvc_timeout;
55 56
56static DECLARE_COMPLETION(lockd_start_done);
57static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
58
59/* 57/*
60 * 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),
61 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 59 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
@@ -111,35 +109,30 @@ static inline void clear_grace_period(void)
111/* 109/*
112 * This is the lockd kernel thread 110 * This is the lockd kernel thread
113 */ 111 */
114static void 112static int
115lockd(struct svc_rqst *rqstp) 113lockd(void *vrqstp)
116{ 114{
117 int err = 0; 115 int err = 0, preverr = 0;
116 struct svc_rqst *rqstp = vrqstp;
118 unsigned long grace_period_expire; 117 unsigned long grace_period_expire;
119 118
120 /* Lock module and set up kernel thread */ 119 /* try_to_freeze() is called from svc_recv() */
121 /* lockd_up is waiting for us to startup, so will
122 * be holding a reference to this module, so it
123 * is safe to just claim another reference
124 */
125 __module_get(THIS_MODULE);
126 lock_kernel();
127
128 /*
129 * Let our maker know we're running.
130 */
131 nlmsvc_pid = current->pid;
132 nlmsvc_serv = rqstp->rq_server;
133 complete(&lockd_start_done);
134
135 daemonize("lockd");
136 set_freezable(); 120 set_freezable();
137 121
138 /* Process request with signals blocked, but allow SIGKILL. */ 122 /* Allow SIGKILL to tell lockd to drop all of its locks */
139 allow_signal(SIGKILL); 123 allow_signal(SIGKILL);
140 124
141 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); 125 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
142 126
127 /*
128 * FIXME: it would be nice if lockd didn't spend its entire life
129 * running under the BKL. At the very least, it would be good to
130 * have someone clarify what it's intended to protect here. I've
131 * seen some handwavy posts about posix locking needing to be
132 * done under the BKL, but it's far from clear.
133 */
134 lock_kernel();
135
143 if (!nlm_timeout) 136 if (!nlm_timeout)
144 nlm_timeout = LOCKD_DFLT_TIMEO; 137 nlm_timeout = LOCKD_DFLT_TIMEO;
145 nlmsvc_timeout = nlm_timeout * HZ; 138 nlmsvc_timeout = nlm_timeout * HZ;
@@ -148,10 +141,9 @@ lockd(struct svc_rqst *rqstp)
148 141
149 /* 142 /*
150 * The main request loop. We don't terminate until the last 143 * The main request loop. We don't terminate until the last
151 * NFS mount or NFS daemon has gone away, and we've been sent a 144 * NFS mount or NFS daemon has gone away.
152 * signal, or else another process has taken over our job.
153 */ 145 */
154 while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { 146 while (!kthread_should_stop()) {
155 long timeout = MAX_SCHEDULE_TIMEOUT; 147 long timeout = MAX_SCHEDULE_TIMEOUT;
156 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); 148 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
157 149
@@ -161,6 +153,7 @@ lockd(struct svc_rqst *rqstp)
161 nlmsvc_invalidate_all(); 153 nlmsvc_invalidate_all();
162 grace_period_expire = set_grace_period(); 154 grace_period_expire = set_grace_period();
163 } 155 }
156 continue;
164 } 157 }
165 158
166 /* 159 /*
@@ -179,14 +172,20 @@ lockd(struct svc_rqst *rqstp)
179 * recvfrom routine. 172 * recvfrom routine.
180 */ 173 */
181 err = svc_recv(rqstp, timeout); 174 err = svc_recv(rqstp, timeout);
182 if (err == -EAGAIN || err == -EINTR) 175 if (err == -EAGAIN || err == -EINTR) {
176 preverr = err;
183 continue; 177 continue;
178 }
184 if (err < 0) { 179 if (err < 0) {
185 printk(KERN_WARNING 180 if (err != preverr) {
186 "lockd: terminating on error %d\n", 181 printk(KERN_WARNING "%s: unexpected error "
187 -err); 182 "from svc_recv (%d)\n", __func__, err);
188 break; 183 preverr = err;
184 }
185 schedule_timeout_interruptible(HZ);
186 continue;
189 } 187 }
188 preverr = err;
190 189
191 dprintk("lockd: request from %s\n", 190 dprintk("lockd: request from %s\n",
192 svc_print_addr(rqstp, buf, sizeof(buf))); 191 svc_print_addr(rqstp, buf, sizeof(buf)));
@@ -195,28 +194,19 @@ lockd(struct svc_rqst *rqstp)
195 } 194 }
196 195
197 flush_signals(current); 196 flush_signals(current);
197 if (nlmsvc_ops)
198 nlmsvc_invalidate_all();
199 nlm_shutdown_hosts();
198 200
199 /* 201 unlock_kernel();
200 * Check whether there's a new lockd process before 202
201 * shutting down the hosts and clearing the slot. 203 nlmsvc_task = NULL;
202 */ 204 nlmsvc_serv = NULL;
203 if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
204 if (nlmsvc_ops)
205 nlmsvc_invalidate_all();
206 nlm_shutdown_hosts();
207 nlmsvc_pid = 0;
208 nlmsvc_serv = NULL;
209 } else
210 printk(KERN_DEBUG
211 "lockd: new process, skipping host shutdown\n");
212 wake_up(&lockd_exit);
213 205
214 /* Exit the RPC thread */ 206 /* Exit the RPC thread */
215 svc_exit_thread(rqstp); 207 svc_exit_thread(rqstp);
216 208
217 /* Release module */ 209 return 0;
218 unlock_kernel();
219 module_put_and_exit(0);
220} 210}
221 211
222/* 212/*
@@ -261,14 +251,15 @@ static int make_socks(struct svc_serv *serv, int proto)
261int 251int
262lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ 252lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
263{ 253{
264 struct svc_serv * serv; 254 struct svc_serv *serv;
265 int error = 0; 255 struct svc_rqst *rqstp;
256 int error = 0;
266 257
267 mutex_lock(&nlmsvc_mutex); 258 mutex_lock(&nlmsvc_mutex);
268 /* 259 /*
269 * Check whether we're already up and running. 260 * Check whether we're already up and running.
270 */ 261 */
271 if (nlmsvc_pid) { 262 if (nlmsvc_serv) {
272 if (proto) 263 if (proto)
273 error = make_socks(nlmsvc_serv, proto); 264 error = make_socks(nlmsvc_serv, proto);
274 goto out; 265 goto out;
@@ -295,13 +286,28 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
295 /* 286 /*
296 * Create the kernel thread and wait for it to start. 287 * Create the kernel thread and wait for it to start.
297 */ 288 */
298 error = svc_create_thread(lockd, serv); 289 rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
299 if (error) { 290 if (IS_ERR(rqstp)) {
291 error = PTR_ERR(rqstp);
292 printk(KERN_WARNING
293 "lockd_up: svc_rqst allocation failed, error=%d\n",
294 error);
295 goto destroy_and_out;
296 }
297
298 svc_sock_update_bufs(serv);
299 nlmsvc_serv = rqstp->rq_server;
300
301 nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name);
302 if (IS_ERR(nlmsvc_task)) {
303 error = PTR_ERR(nlmsvc_task);
304 nlmsvc_task = NULL;
305 nlmsvc_serv = NULL;
300 printk(KERN_WARNING 306 printk(KERN_WARNING
301 "lockd_up: create thread failed, error=%d\n", error); 307 "lockd_up: kthread_run failed, error=%d\n", error);
308 svc_exit_thread(rqstp);
302 goto destroy_and_out; 309 goto destroy_and_out;
303 } 310 }
304 wait_for_completion(&lockd_start_done);
305 311
306 /* 312 /*
307 * Note: svc_serv structures have an initial use count of 1, 313 * Note: svc_serv structures have an initial use count of 1,
@@ -323,37 +329,21 @@ EXPORT_SYMBOL(lockd_up);
323void 329void
324lockd_down(void) 330lockd_down(void)
325{ 331{
326 static int warned;
327
328 mutex_lock(&nlmsvc_mutex); 332 mutex_lock(&nlmsvc_mutex);
329 if (nlmsvc_users) { 333 if (nlmsvc_users) {
330 if (--nlmsvc_users) 334 if (--nlmsvc_users)
331 goto out; 335 goto out;
332 } else 336 } else {
333 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid); 337 printk(KERN_ERR "lockd_down: no users! task=%p\n",
334 338 nlmsvc_task);
335 if (!nlmsvc_pid) { 339 BUG();
336 if (warned++ == 0)
337 printk(KERN_WARNING "lockd_down: no lockd running.\n");
338 goto out;
339 } 340 }
340 warned = 0;
341 341
342 kill_proc(nlmsvc_pid, SIGKILL, 1); 342 if (!nlmsvc_task) {
343 /* 343 printk(KERN_ERR "lockd_down: no lockd running.\n");
344 * Wait for the lockd process to exit, but since we're holding 344 BUG();
345 * the lockd semaphore, we can't wait around forever ...
346 */
347 clear_thread_flag(TIF_SIGPENDING);
348 interruptible_sleep_on_timeout(&lockd_exit, HZ);
349 if (nlmsvc_pid) {
350 printk(KERN_WARNING
351 "lockd_down: lockd failed to exit, clearing pid\n");
352 nlmsvc_pid = 0;
353 } 345 }
354 spin_lock_irq(&current->sighand->siglock); 346 kthread_stop(nlmsvc_task);
355 recalc_sigpending();
356 spin_unlock_irq(&current->sighand->siglock);
357out: 347out:
358 mutex_unlock(&nlmsvc_mutex); 348 mutex_unlock(&nlmsvc_mutex);
359} 349}
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index fe9bdb4a220c..1f122c1940af 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -29,6 +29,7 @@
29#include <linux/sunrpc/svc.h> 29#include <linux/sunrpc/svc.h>
30#include <linux/lockd/nlm.h> 30#include <linux/lockd/nlm.h>
31#include <linux/lockd/lockd.h> 31#include <linux/lockd/lockd.h>
32#include <linux/kthread.h>
32 33
33#define NLMDBG_FACILITY NLMDBG_SVCLOCK 34#define NLMDBG_FACILITY NLMDBG_SVCLOCK
34 35
@@ -226,8 +227,7 @@ failed:
226} 227}
227 228
228/* 229/*
229 * Delete a block. If the lock was cancelled or the grant callback 230 * Delete a block.
230 * failed, unlock is set to 1.
231 * It is the caller's responsibility to check whether the file 231 * It is the caller's responsibility to check whether the file
232 * can be closed hereafter. 232 * can be closed hereafter.
233 */ 233 */
@@ -887,7 +887,7 @@ nlmsvc_retry_blocked(void)
887 unsigned long timeout = MAX_SCHEDULE_TIMEOUT; 887 unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
888 struct nlm_block *block; 888 struct nlm_block *block;
889 889
890 while (!list_empty(&nlm_blocked)) { 890 while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
891 block = list_entry(nlm_blocked.next, struct nlm_block, b_list); 891 block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
892 892
893 if (block->b_when == NLM_NEVER) 893 if (block->b_when == NLM_NEVER)
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 068886de4dda..b0ae07008700 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -71,7 +71,8 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
71 struct nlm_share *share, **shpp; 71 struct nlm_share *share, **shpp;
72 struct xdr_netobj *oh = &argp->lock.oh; 72 struct xdr_netobj *oh = &argp->lock.oh;
73 73
74 for (shpp = &file->f_shares; (share = *shpp) != 0; shpp = &share->s_next) { 74 for (shpp = &file->f_shares; (share = *shpp) != NULL;
75 shpp = &share->s_next) {
75 if (share->s_host == host && nlm_cmp_owner(share, oh)) { 76 if (share->s_host == host && nlm_cmp_owner(share, oh)) {
76 *shpp = share->s_next; 77 *shpp = share->s_next;
77 kfree(share); 78 kfree(share);
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 66648dd92d97..5606ae3d72d3 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -15,6 +15,7 @@
15#include <linux/nfs_fs.h> 15#include <linux/nfs_fs.h>
16#include <linux/mutex.h> 16#include <linux/mutex.h>
17#include <linux/freezer.h> 17#include <linux/freezer.h>
18#include <linux/kthread.h>
18 19
19#include <net/inet_sock.h> 20#include <net/inet_sock.h>
20 21
@@ -27,9 +28,7 @@
27struct nfs_callback_data { 28struct nfs_callback_data {
28 unsigned int users; 29 unsigned int users;
29 struct svc_serv *serv; 30 struct svc_serv *serv;
30 pid_t pid; 31 struct task_struct *task;
31 struct completion started;
32 struct completion stopped;
33}; 32};
34 33
35static struct nfs_callback_data nfs_callback_info; 34static struct nfs_callback_data nfs_callback_info;
@@ -57,48 +56,44 @@ module_param_call(callback_tcpport, param_set_port, param_get_int,
57/* 56/*
58 * This is the callback kernel thread. 57 * This is the callback kernel thread.
59 */ 58 */
60static void nfs_callback_svc(struct svc_rqst *rqstp) 59static int
60nfs_callback_svc(void *vrqstp)
61{ 61{
62 int err; 62 int err, preverr = 0;
63 struct svc_rqst *rqstp = vrqstp;
63 64
64 __module_get(THIS_MODULE);
65 lock_kernel();
66
67 nfs_callback_info.pid = current->pid;
68 daemonize("nfsv4-svc");
69 /* Process request with signals blocked, but allow SIGKILL. */
70 allow_signal(SIGKILL);
71 set_freezable(); 65 set_freezable();
72 66
73 complete(&nfs_callback_info.started); 67 /*
74 68 * FIXME: do we really need to run this under the BKL? If so, please
75 for(;;) { 69 * add a comment about what it's intended to protect.
76 if (signalled()) { 70 */
77 if (nfs_callback_info.users == 0) 71 lock_kernel();
78 break; 72 while (!kthread_should_stop()) {
79 flush_signals(current);
80 }
81 /* 73 /*
82 * Listen for a request on the socket 74 * Listen for a request on the socket
83 */ 75 */
84 err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); 76 err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
85 if (err == -EAGAIN || err == -EINTR) 77 if (err == -EAGAIN || err == -EINTR) {
78 preverr = err;
86 continue; 79 continue;
80 }
87 if (err < 0) { 81 if (err < 0) {
88 printk(KERN_WARNING 82 if (err != preverr) {
89 "%s: terminating on error %d\n", 83 printk(KERN_WARNING "%s: unexpected error "
90 __FUNCTION__, -err); 84 "from svc_recv (%d)\n", __func__, err);
91 break; 85 preverr = err;
86 }
87 schedule_timeout_uninterruptible(HZ);
88 continue;
92 } 89 }
90 preverr = err;
93 svc_process(rqstp); 91 svc_process(rqstp);
94 } 92 }
95
96 flush_signals(current);
97 svc_exit_thread(rqstp);
98 nfs_callback_info.pid = 0;
99 complete(&nfs_callback_info.stopped);
100 unlock_kernel(); 93 unlock_kernel();
101 module_put_and_exit(0); 94 nfs_callback_info.task = NULL;
95 svc_exit_thread(rqstp);
96 return 0;
102} 97}
103 98
104/* 99/*
@@ -107,14 +102,13 @@ static void nfs_callback_svc(struct svc_rqst *rqstp)
107int nfs_callback_up(void) 102int nfs_callback_up(void)
108{ 103{
109 struct svc_serv *serv = NULL; 104 struct svc_serv *serv = NULL;
105 struct svc_rqst *rqstp;
110 int ret = 0; 106 int ret = 0;
111 107
112 lock_kernel(); 108 lock_kernel();
113 mutex_lock(&nfs_callback_mutex); 109 mutex_lock(&nfs_callback_mutex);
114 if (nfs_callback_info.users++ || nfs_callback_info.pid != 0) 110 if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
115 goto out; 111 goto out;
116 init_completion(&nfs_callback_info.started);
117 init_completion(&nfs_callback_info.stopped);
118 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); 112 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
119 ret = -ENOMEM; 113 ret = -ENOMEM;
120 if (!serv) 114 if (!serv)
@@ -127,15 +121,28 @@ int nfs_callback_up(void)
127 nfs_callback_tcpport = ret; 121 nfs_callback_tcpport = ret;
128 dprintk("Callback port = 0x%x\n", nfs_callback_tcpport); 122 dprintk("Callback port = 0x%x\n", nfs_callback_tcpport);
129 123
130 ret = svc_create_thread(nfs_callback_svc, serv); 124 rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
131 if (ret < 0) 125 if (IS_ERR(rqstp)) {
126 ret = PTR_ERR(rqstp);
132 goto out_err; 127 goto out_err;
128 }
129
130 svc_sock_update_bufs(serv);
133 nfs_callback_info.serv = serv; 131 nfs_callback_info.serv = serv;
134 wait_for_completion(&nfs_callback_info.started); 132
133 nfs_callback_info.task = kthread_run(nfs_callback_svc, rqstp,
134 "nfsv4-svc");
135 if (IS_ERR(nfs_callback_info.task)) {
136 ret = PTR_ERR(nfs_callback_info.task);
137 nfs_callback_info.serv = NULL;
138 nfs_callback_info.task = NULL;
139 svc_exit_thread(rqstp);
140 goto out_err;
141 }
135out: 142out:
136 /* 143 /*
137 * svc_create creates the svc_serv with sv_nrthreads == 1, and then 144 * svc_create creates the svc_serv with sv_nrthreads == 1, and then
138 * svc_create_thread increments that. So we need to call svc_destroy 145 * svc_prepare_thread increments that. So we need to call svc_destroy
139 * on both success and failure so that the refcount is 1 when the 146 * on both success and failure so that the refcount is 1 when the
140 * thread exits. 147 * thread exits.
141 */ 148 */
@@ -152,19 +159,15 @@ out_err:
152} 159}
153 160
154/* 161/*
155 * Kill the server process if it is not already up. 162 * Kill the server process if it is not already down.
156 */ 163 */
157void nfs_callback_down(void) 164void nfs_callback_down(void)
158{ 165{
159 lock_kernel(); 166 lock_kernel();
160 mutex_lock(&nfs_callback_mutex); 167 mutex_lock(&nfs_callback_mutex);
161 nfs_callback_info.users--; 168 nfs_callback_info.users--;
162 do { 169 if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL)
163 if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0) 170 kthread_stop(nfs_callback_info.task);
164 break;
165 if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0)
166 break;
167 } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0);
168 mutex_unlock(&nfs_callback_mutex); 171 mutex_unlock(&nfs_callback_mutex);
169 unlock_kernel(); 172 unlock_kernel();
170} 173}
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 83e865a16ad1..412738dbfbc7 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -10,7 +10,6 @@
10 * nfs symlink handling code 10 * nfs symlink handling code
11 */ 11 */
12 12
13#define NFS_NEED_XDR_TYPES
14#include <linux/time.h> 13#include <linux/time.h>
15#include <linux/errno.h> 14#include <linux/errno.h>
16#include <linux/sunrpc/clnt.h> 15#include <linux/sunrpc/clnt.h>
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index d13403e33622..294992e9bf69 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -10,6 +10,7 @@
10#include <linux/sunrpc/svcauth.h> 10#include <linux/sunrpc/svcauth.h>
11#include <linux/nfsd/nfsd.h> 11#include <linux/nfsd/nfsd.h>
12#include <linux/nfsd/export.h> 12#include <linux/nfsd/export.h>
13#include "auth.h"
13 14
14int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) 15int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
15{ 16{
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 8a6f7c924c75..33bfcf09db46 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -35,6 +35,7 @@
35#include <linux/lockd/bind.h> 35#include <linux/lockd/bind.h>
36#include <linux/sunrpc/msg_prot.h> 36#include <linux/sunrpc/msg_prot.h>
37#include <linux/sunrpc/gss_api.h> 37#include <linux/sunrpc/gss_api.h>
38#include <net/ipv6.h>
38 39
39#define NFSDDBG_FACILITY NFSDDBG_EXPORT 40#define NFSDDBG_FACILITY NFSDDBG_EXPORT
40 41
@@ -1548,6 +1549,7 @@ exp_addclient(struct nfsctl_client *ncp)
1548{ 1549{
1549 struct auth_domain *dom; 1550 struct auth_domain *dom;
1550 int i, err; 1551 int i, err;
1552 struct in6_addr addr6;
1551 1553
1552 /* First, consistency check. */ 1554 /* First, consistency check. */
1553 err = -EINVAL; 1555 err = -EINVAL;
@@ -1566,9 +1568,10 @@ exp_addclient(struct nfsctl_client *ncp)
1566 goto out_unlock; 1568 goto out_unlock;
1567 1569
1568 /* Insert client into hashtable. */ 1570 /* Insert client into hashtable. */
1569 for (i = 0; i < ncp->cl_naddr; i++) 1571 for (i = 0; i < ncp->cl_naddr; i++) {
1570 auth_unix_add_addr(ncp->cl_addrlist[i], dom); 1572 ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
1571 1573 auth_unix_add_addr(&addr6, dom);
1574 }
1572 auth_unix_forget_old(dom); 1575 auth_unix_forget_old(dom);
1573 auth_domain_put(dom); 1576 auth_domain_put(dom);
1574 1577
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index aae2b29ae2c9..562abf3380d0 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -344,6 +344,21 @@ static struct rpc_version * nfs_cb_version[] = {
344 &nfs_cb_version4, 344 &nfs_cb_version4,
345}; 345};
346 346
347static struct rpc_program cb_program;
348
349static struct rpc_stat cb_stats = {
350 .program = &cb_program
351};
352
353#define NFS4_CALLBACK 0x40000000
354static struct rpc_program cb_program = {
355 .name = "nfs4_cb",
356 .number = NFS4_CALLBACK,
357 .nrvers = ARRAY_SIZE(nfs_cb_version),
358 .version = nfs_cb_version,
359 .stats = &cb_stats,
360};
361
347/* Reference counting, callback cleanup, etc., all look racy as heck. 362/* Reference counting, callback cleanup, etc., all look racy as heck.
348 * And why is cb_set an atomic? */ 363 * And why is cb_set an atomic? */
349 364
@@ -358,13 +373,12 @@ static int do_probe_callback(void *data)
358 .to_maxval = (NFSD_LEASE_TIME/2) * HZ, 373 .to_maxval = (NFSD_LEASE_TIME/2) * HZ,
359 .to_exponential = 1, 374 .to_exponential = 1,
360 }; 375 };
361 struct rpc_program * program = &cb->cb_program;
362 struct rpc_create_args args = { 376 struct rpc_create_args args = {
363 .protocol = IPPROTO_TCP, 377 .protocol = IPPROTO_TCP,
364 .address = (struct sockaddr *)&addr, 378 .address = (struct sockaddr *)&addr,
365 .addrsize = sizeof(addr), 379 .addrsize = sizeof(addr),
366 .timeout = &timeparms, 380 .timeout = &timeparms,
367 .program = program, 381 .program = &cb_program,
368 .version = nfs_cb_version[1]->number, 382 .version = nfs_cb_version[1]->number,
369 .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ 383 .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
370 .flags = (RPC_CLNT_CREATE_NOPING), 384 .flags = (RPC_CLNT_CREATE_NOPING),
@@ -382,16 +396,8 @@ static int do_probe_callback(void *data)
382 addr.sin_port = htons(cb->cb_port); 396 addr.sin_port = htons(cb->cb_port);
383 addr.sin_addr.s_addr = htonl(cb->cb_addr); 397 addr.sin_addr.s_addr = htonl(cb->cb_addr);
384 398
385 /* Initialize rpc_program */
386 program->name = "nfs4_cb";
387 program->number = cb->cb_prog;
388 program->nrvers = ARRAY_SIZE(nfs_cb_version);
389 program->version = nfs_cb_version;
390 program->stats = &cb->cb_stat;
391
392 /* Initialize rpc_stat */ 399 /* Initialize rpc_stat */
393 memset(program->stats, 0, sizeof(cb->cb_stat)); 400 memset(args.program->stats, 0, sizeof(struct rpc_stat));
394 program->stats->program = program;
395 401
396 /* Create RPC client */ 402 /* Create RPC client */
397 client = rpc_create(&args); 403 client = rpc_create(&args);
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 996bd88b75ba..5b398421b051 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -202,7 +202,7 @@ static struct cache_detail idtoname_cache = {
202 .alloc = ent_alloc, 202 .alloc = ent_alloc,
203}; 203};
204 204
205int 205static int
206idtoname_parse(struct cache_detail *cd, char *buf, int buflen) 206idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
207{ 207{
208 struct ent ent, *res; 208 struct ent ent, *res;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 81a75f3081f4..55dfdd71f1b0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1639,6 +1639,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
1639 locks_init_lock(&fl); 1639 locks_init_lock(&fl);
1640 fl.fl_lmops = &nfsd_lease_mng_ops; 1640 fl.fl_lmops = &nfsd_lease_mng_ops;
1641 fl.fl_flags = FL_LEASE; 1641 fl.fl_flags = FL_LEASE;
1642 fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
1642 fl.fl_end = OFFSET_MAX; 1643 fl.fl_end = OFFSET_MAX;
1643 fl.fl_owner = (fl_owner_t)dp; 1644 fl.fl_owner = (fl_owner_t)dp;
1644 fl.fl_file = stp->st_vfs_file; 1645 fl.fl_file = stp->st_vfs_file;
@@ -1647,8 +1648,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
1647 /* vfs_setlease checks to see if delegation should be handed out. 1648 /* vfs_setlease checks to see if delegation should be handed out.
1648 * the lock_manager callbacks fl_mylease and fl_change are used 1649 * the lock_manager callbacks fl_mylease and fl_change are used
1649 */ 1650 */
1650 if ((status = vfs_setlease(stp->st_vfs_file, 1651 if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) {
1651 flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
1652 dprintk("NFSD: setlease failed [%d], no delegation\n", status); 1652 dprintk("NFSD: setlease failed [%d], no delegation\n", status);
1653 unhash_delegation(dp); 1653 unhash_delegation(dp);
1654 flag = NFS4_OPEN_DELEGATE_NONE; 1654 flag = NFS4_OPEN_DELEGATE_NONE;
@@ -1763,10 +1763,6 @@ out:
1763 return status; 1763 return status;
1764} 1764}
1765 1765
1766static struct workqueue_struct *laundry_wq;
1767static void laundromat_main(struct work_struct *);
1768static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
1769
1770__be32 1766__be32
1771nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 1767nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1772 clientid_t *clid) 1768 clientid_t *clid)
@@ -1874,7 +1870,11 @@ nfs4_laundromat(void)
1874 return clientid_val; 1870 return clientid_val;
1875} 1871}
1876 1872
1877void 1873static struct workqueue_struct *laundry_wq;
1874static void laundromat_main(struct work_struct *);
1875static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
1876
1877static void
1878laundromat_main(struct work_struct *not_used) 1878laundromat_main(struct work_struct *not_used)
1879{ 1879{
1880 time_t t; 1880 time_t t;
@@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags)
1975 && mandatory_lock(inode); 1975 && mandatory_lock(inode);
1976} 1976}
1977 1977
1978static int check_stateid_generation(stateid_t *in, stateid_t *ref)
1979{
1980 /* If the client sends us a stateid from the future, it's buggy: */
1981 if (in->si_generation > ref->si_generation)
1982 return nfserr_bad_stateid;
1983 /*
1984 * The following, however, can happen. For example, if the
1985 * client sends an open and some IO at the same time, the open
1986 * may bump si_generation while the IO is still in flight.
1987 * Thanks to hard links and renames, the client never knows what
1988 * file an open will affect. So it could avoid that situation
1989 * only by serializing all opens and IO from the same open
1990 * owner. To recover from the old_stateid error, the client
1991 * will just have to retry the IO:
1992 */
1993 if (in->si_generation < ref->si_generation)
1994 return nfserr_old_stateid;
1995 return nfs_ok;
1996}
1997
1978/* 1998/*
1979* Checks for stateid operations 1999* Checks for stateid operations
1980*/ 2000*/
@@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
2023 goto out; 2043 goto out;
2024 stidp = &stp->st_stateid; 2044 stidp = &stp->st_stateid;
2025 } 2045 }
2026 if (stateid->si_generation > stidp->si_generation) 2046 status = check_stateid_generation(stateid, stidp);
2027 goto out; 2047 if (status)
2028
2029 /* OLD STATEID */
2030 status = nfserr_old_stateid;
2031 if (stateid->si_generation < stidp->si_generation)
2032 goto out; 2048 goto out;
2033 if (stp) { 2049 if (stp) {
2034 if ((status = nfs4_check_openmode(stp,flags))) 2050 if ((status = nfs4_check_openmode(stp,flags)))
@@ -2036,7 +2052,7 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
2036 renew_client(stp->st_stateowner->so_client); 2052 renew_client(stp->st_stateowner->so_client);
2037 if (filpp) 2053 if (filpp)
2038 *filpp = stp->st_vfs_file; 2054 *filpp = stp->st_vfs_file;
2039 } else if (dp) { 2055 } else {
2040 if ((status = nfs4_check_delegmode(dp, flags))) 2056 if ((status = nfs4_check_delegmode(dp, flags)))
2041 goto out; 2057 goto out;
2042 renew_client(dp->dl_client); 2058 renew_client(dp->dl_client);
@@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
2065{ 2081{
2066 struct nfs4_stateid *stp; 2082 struct nfs4_stateid *stp;
2067 struct nfs4_stateowner *sop; 2083 struct nfs4_stateowner *sop;
2084 __be32 status;
2068 2085
2069 dprintk("NFSD: preprocess_seqid_op: seqid=%d " 2086 dprintk("NFSD: preprocess_seqid_op: seqid=%d "
2070 "stateid = (%08x/%08x/%08x/%08x)\n", seqid, 2087 "stateid = (%08x/%08x/%08x/%08x)\n", seqid,
@@ -2127,7 +2144,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
2127 } 2144 }
2128 } 2145 }
2129 2146
2130 if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { 2147 if (nfs4_check_fh(current_fh, stp)) {
2131 dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); 2148 dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
2132 return nfserr_bad_stateid; 2149 return nfserr_bad_stateid;
2133 } 2150 }
@@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
2150 " confirmed yet!\n"); 2167 " confirmed yet!\n");
2151 return nfserr_bad_stateid; 2168 return nfserr_bad_stateid;
2152 } 2169 }
2153 if (stateid->si_generation > stp->st_stateid.si_generation) { 2170 status = check_stateid_generation(stateid, &stp->st_stateid);
2154 dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); 2171 if (status)
2155 return nfserr_bad_stateid; 2172 return status;
2156 }
2157
2158 if (stateid->si_generation < stp->st_stateid.si_generation) {
2159 dprintk("NFSD: preprocess_seqid_op: old stateid!\n");
2160 return nfserr_old_stateid;
2161 }
2162 renew_client(sop->so_client); 2173 renew_client(sop->so_client);
2163 return nfs_ok; 2174 return nfs_ok;
2164 2175
@@ -2194,7 +2205,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2194 2205
2195 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2206 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2196 oc->oc_seqid, &oc->oc_req_stateid, 2207 oc->oc_seqid, &oc->oc_req_stateid,
2197 CHECK_FH | CONFIRM | OPEN_STATE, 2208 CONFIRM | OPEN_STATE,
2198 &oc->oc_stateowner, &stp, NULL))) 2209 &oc->oc_stateowner, &stp, NULL)))
2199 goto out; 2210 goto out;
2200 2211
@@ -2265,7 +2276,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
2265 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2276 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2266 od->od_seqid, 2277 od->od_seqid,
2267 &od->od_stateid, 2278 &od->od_stateid,
2268 CHECK_FH | OPEN_STATE, 2279 OPEN_STATE,
2269 &od->od_stateowner, &stp, NULL))) 2280 &od->od_stateowner, &stp, NULL)))
2270 goto out; 2281 goto out;
2271 2282
@@ -2318,7 +2329,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2318 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2329 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2319 close->cl_seqid, 2330 close->cl_seqid,
2320 &close->cl_stateid, 2331 &close->cl_stateid,
2321 CHECK_FH | OPEN_STATE | CLOSE_STATE, 2332 OPEN_STATE | CLOSE_STATE,
2322 &close->cl_stateowner, &stp, NULL))) 2333 &close->cl_stateowner, &stp, NULL)))
2323 goto out; 2334 goto out;
2324 status = nfs_ok; 2335 status = nfs_ok;
@@ -2623,7 +2634,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2623 status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2634 status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2624 lock->lk_new_open_seqid, 2635 lock->lk_new_open_seqid,
2625 &lock->lk_new_open_stateid, 2636 &lock->lk_new_open_stateid,
2626 CHECK_FH | OPEN_STATE, 2637 OPEN_STATE,
2627 &lock->lk_replay_owner, &open_stp, 2638 &lock->lk_replay_owner, &open_stp,
2628 lock); 2639 lock);
2629 if (status) 2640 if (status)
@@ -2650,7 +2661,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2650 status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2661 status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2651 lock->lk_old_lock_seqid, 2662 lock->lk_old_lock_seqid,
2652 &lock->lk_old_lock_stateid, 2663 &lock->lk_old_lock_stateid,
2653 CHECK_FH | LOCK_STATE, 2664 LOCK_STATE,
2654 &lock->lk_replay_owner, &lock_stp, lock); 2665 &lock->lk_replay_owner, &lock_stp, lock);
2655 if (status) 2666 if (status)
2656 goto out; 2667 goto out;
@@ -2847,7 +2858,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2847 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2858 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2848 locku->lu_seqid, 2859 locku->lu_seqid,
2849 &locku->lu_stateid, 2860 &locku->lu_stateid,
2850 CHECK_FH | LOCK_STATE, 2861 LOCK_STATE,
2851 &locku->lu_stateowner, &stp, NULL))) 2862 &locku->lu_stateowner, &stp, NULL)))
2852 goto out; 2863 goto out;
2853 2864
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 0e6a179eccaf..1ba7ad981935 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1867,6 +1867,15 @@ out_serverfault:
1867 goto out; 1867 goto out;
1868} 1868}
1869 1869
1870static inline int attributes_need_mount(u32 *bmval)
1871{
1872 if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME))
1873 return 1;
1874 if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID)
1875 return 1;
1876 return 0;
1877}
1878
1870static __be32 1879static __be32
1871nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, 1880nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1872 const char *name, int namlen, __be32 *p, int *buflen) 1881 const char *name, int namlen, __be32 *p, int *buflen)
@@ -1888,9 +1897,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1888 * we will not follow the cross mount and will fill the attribtutes 1897 * we will not follow the cross mount and will fill the attribtutes
1889 * directly from the mountpoint dentry. 1898 * directly from the mountpoint dentry.
1890 */ 1899 */
1891 if (d_mountpoint(dentry) && 1900 if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval))
1892 (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
1893 (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
1894 ignore_crossmnt = 1; 1901 ignore_crossmnt = 1;
1895 else if (d_mountpoint(dentry)) { 1902 else if (d_mountpoint(dentry)) {
1896 int err; 1903 int err;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 8516137cdbb0..613bcb8171a5 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -37,6 +37,7 @@
37#include <linux/nfsd/syscall.h> 37#include <linux/nfsd/syscall.h>
38 38
39#include <asm/uaccess.h> 39#include <asm/uaccess.h>
40#include <net/ipv6.h>
40 41
41/* 42/*
42 * We have a single directory with 9 nodes in it. 43 * We have a single directory with 9 nodes in it.
@@ -149,7 +150,6 @@ static const struct file_operations transaction_ops = {
149 .release = simple_transaction_release, 150 .release = simple_transaction_release,
150}; 151};
151 152
152extern struct seq_operations nfs_exports_op;
153static int exports_open(struct inode *inode, struct file *file) 153static int exports_open(struct inode *inode, struct file *file)
154{ 154{
155 return seq_open(file, &nfs_exports_op); 155 return seq_open(file, &nfs_exports_op);
@@ -222,6 +222,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
222 struct auth_domain *clp; 222 struct auth_domain *clp;
223 int err = 0; 223 int err = 0;
224 struct knfsd_fh *res; 224 struct knfsd_fh *res;
225 struct in6_addr in6;
225 226
226 if (size < sizeof(*data)) 227 if (size < sizeof(*data))
227 return -EINVAL; 228 return -EINVAL;
@@ -236,7 +237,11 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
236 res = (struct knfsd_fh*)buf; 237 res = (struct knfsd_fh*)buf;
237 238
238 exp_readlock(); 239 exp_readlock();
239 if (!(clp = auth_unix_lookup(sin->sin_addr))) 240
241 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
242
243 clp = auth_unix_lookup(&in6);
244 if (!clp)
240 err = -EPERM; 245 err = -EPERM;
241 else { 246 else {
242 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); 247 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -257,6 +262,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
257 int err = 0; 262 int err = 0;
258 struct knfsd_fh fh; 263 struct knfsd_fh fh;
259 char *res; 264 char *res;
265 struct in6_addr in6;
260 266
261 if (size < sizeof(*data)) 267 if (size < sizeof(*data))
262 return -EINVAL; 268 return -EINVAL;
@@ -271,7 +277,11 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
271 res = buf; 277 res = buf;
272 sin = (struct sockaddr_in *)&data->gd_addr; 278 sin = (struct sockaddr_in *)&data->gd_addr;
273 exp_readlock(); 279 exp_readlock();
274 if (!(clp = auth_unix_lookup(sin->sin_addr))) 280
281 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
282
283 clp = auth_unix_lookup(&in6);
284 if (!clp)
275 err = -EPERM; 285 err = -EPERM;
276 else { 286 else {
277 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); 287 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
@@ -347,8 +357,6 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
347 return mesg - buf; 357 return mesg - buf;
348} 358}
349 359
350extern int nfsd_nrthreads(void);
351
352static ssize_t write_threads(struct file *file, char *buf, size_t size) 360static ssize_t write_threads(struct file *file, char *buf, size_t size)
353{ 361{
354 /* if size > 0, look for a number of threads and call nfsd_svc 362 /* if size > 0, look for a number of threads and call nfsd_svc
@@ -371,10 +379,6 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
371 return strlen(buf); 379 return strlen(buf);
372} 380}
373 381
374extern int nfsd_nrpools(void);
375extern int nfsd_get_nrthreads(int n, int *);
376extern int nfsd_set_nrthreads(int n, int *);
377
378static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) 382static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
379{ 383{
380 /* if size > 0, look for an array of number of threads per node 384 /* if size > 0, look for an array of number of threads per node
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 3e6b3f41ee1f..100ae5641162 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -113,6 +113,124 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
113} 113}
114 114
115/* 115/*
116 * Use the given filehandle to look up the corresponding export and
117 * dentry. On success, the results are used to set fh_export and
118 * fh_dentry.
119 */
120static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
121{
122 struct knfsd_fh *fh = &fhp->fh_handle;
123 struct fid *fid = NULL, sfid;
124 struct svc_export *exp;
125 struct dentry *dentry;
126 int fileid_type;
127 int data_left = fh->fh_size/4;
128 __be32 error;
129
130 error = nfserr_stale;
131 if (rqstp->rq_vers > 2)
132 error = nfserr_badhandle;
133 if (rqstp->rq_vers == 4 && fh->fh_size == 0)
134 return nfserr_nofilehandle;
135
136 if (fh->fh_version == 1) {
137 int len;
138
139 if (--data_left < 0)
140 return error;
141 if (fh->fh_auth_type != 0)
142 return error;
143 len = key_len(fh->fh_fsid_type) / 4;
144 if (len == 0)
145 return error;
146 if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
147 /* deprecated, convert to type 3 */
148 len = key_len(FSID_ENCODE_DEV)/4;
149 fh->fh_fsid_type = FSID_ENCODE_DEV;
150 fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
151 fh->fh_fsid[1] = fh->fh_fsid[2];
152 }
153 data_left -= len;
154 if (data_left < 0)
155 return error;
156 exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth);
157 fid = (struct fid *)(fh->fh_auth + len);
158 } else {
159 __u32 tfh[2];
160 dev_t xdev;
161 ino_t xino;
162
163 if (fh->fh_size != NFS_FHSIZE)
164 return error;
165 /* assume old filehandle format */
166 xdev = old_decode_dev(fh->ofh_xdev);
167 xino = u32_to_ino_t(fh->ofh_xino);
168 mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
169 exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
170 }
171
172 error = nfserr_stale;
173 if (PTR_ERR(exp) == -ENOENT)
174 return error;
175
176 if (IS_ERR(exp))
177 return nfserrno(PTR_ERR(exp));
178
179 error = nfsd_setuser_and_check_port(rqstp, exp);
180 if (error)
181 goto out;
182
183 /*
184 * Look up the dentry using the NFS file handle.
185 */
186 error = nfserr_stale;
187 if (rqstp->rq_vers > 2)
188 error = nfserr_badhandle;
189
190 if (fh->fh_version != 1) {
191 sfid.i32.ino = fh->ofh_ino;
192 sfid.i32.gen = fh->ofh_generation;
193 sfid.i32.parent_ino = fh->ofh_dirino;
194 fid = &sfid;
195 data_left = 3;
196 if (fh->ofh_dirino == 0)
197 fileid_type = FILEID_INO32_GEN;
198 else
199 fileid_type = FILEID_INO32_GEN_PARENT;
200 } else
201 fileid_type = fh->fh_fileid_type;
202
203 if (fileid_type == FILEID_ROOT)
204 dentry = dget(exp->ex_path.dentry);
205 else {
206 dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
207 data_left, fileid_type,
208 nfsd_acceptable, exp);
209 }
210 if (dentry == NULL)
211 goto out;
212 if (IS_ERR(dentry)) {
213 if (PTR_ERR(dentry) != -EINVAL)
214 error = nfserrno(PTR_ERR(dentry));
215 goto out;
216 }
217
218 if (S_ISDIR(dentry->d_inode->i_mode) &&
219 (dentry->d_flags & DCACHE_DISCONNECTED)) {
220 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
221 dentry->d_parent->d_name.name, dentry->d_name.name);
222 }
223
224 fhp->fh_dentry = dentry;
225 fhp->fh_export = exp;
226 nfsd_nr_verified++;
227 return 0;
228out:
229 exp_put(exp);
230 return error;
231}
232
233/*
116 * Perform sanity checks on the dentry in a client's file handle. 234 * Perform sanity checks on the dentry in a client's file handle.
117 * 235 *
118 * Note that the file handle dentry may need to be freed even after 236 * Note that the file handle dentry may need to be freed even after
@@ -124,115 +242,18 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
124__be32 242__be32
125fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) 243fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
126{ 244{
127 struct knfsd_fh *fh = &fhp->fh_handle; 245 struct svc_export *exp;
128 struct svc_export *exp = NULL;
129 struct dentry *dentry; 246 struct dentry *dentry;
130 __be32 error = 0; 247 __be32 error;
131 248
132 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); 249 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
133 250
134 if (!fhp->fh_dentry) { 251 if (!fhp->fh_dentry) {
135 struct fid *fid = NULL, sfid; 252 error = nfsd_set_fh_dentry(rqstp, fhp);
136 int fileid_type;
137 int data_left = fh->fh_size/4;
138
139 error = nfserr_stale;
140 if (rqstp->rq_vers > 2)
141 error = nfserr_badhandle;
142 if (rqstp->rq_vers == 4 && fh->fh_size == 0)
143 return nfserr_nofilehandle;
144
145 if (fh->fh_version == 1) {
146 int len;
147 if (--data_left<0) goto out;
148 switch (fh->fh_auth_type) {
149 case 0: break;
150 default: goto out;
151 }
152 len = key_len(fh->fh_fsid_type) / 4;
153 if (len == 0) goto out;
154 if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
155 /* deprecated, convert to type 3 */
156 len = key_len(FSID_ENCODE_DEV)/4;
157 fh->fh_fsid_type = FSID_ENCODE_DEV;
158 fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
159 fh->fh_fsid[1] = fh->fh_fsid[2];
160 }
161 if ((data_left -= len)<0) goto out;
162 exp = rqst_exp_find(rqstp, fh->fh_fsid_type,
163 fh->fh_auth);
164 fid = (struct fid *)(fh->fh_auth + len);
165 } else {
166 __u32 tfh[2];
167 dev_t xdev;
168 ino_t xino;
169 if (fh->fh_size != NFS_FHSIZE)
170 goto out;
171 /* assume old filehandle format */
172 xdev = old_decode_dev(fh->ofh_xdev);
173 xino = u32_to_ino_t(fh->ofh_xino);
174 mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
175 exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
176 }
177
178 error = nfserr_stale;
179 if (PTR_ERR(exp) == -ENOENT)
180 goto out;
181
182 if (IS_ERR(exp)) {
183 error = nfserrno(PTR_ERR(exp));
184 goto out;
185 }
186
187 error = nfsd_setuser_and_check_port(rqstp, exp);
188 if (error) 253 if (error)
189 goto out; 254 goto out;
190 255 dentry = fhp->fh_dentry;
191 /* 256 exp = fhp->fh_export;
192 * Look up the dentry using the NFS file handle.
193 */
194 error = nfserr_stale;
195 if (rqstp->rq_vers > 2)
196 error = nfserr_badhandle;
197
198 if (fh->fh_version != 1) {
199 sfid.i32.ino = fh->ofh_ino;
200 sfid.i32.gen = fh->ofh_generation;
201 sfid.i32.parent_ino = fh->ofh_dirino;
202 fid = &sfid;
203 data_left = 3;
204 if (fh->ofh_dirino == 0)
205 fileid_type = FILEID_INO32_GEN;
206 else
207 fileid_type = FILEID_INO32_GEN_PARENT;
208 } else
209 fileid_type = fh->fh_fileid_type;
210
211 if (fileid_type == FILEID_ROOT)
212 dentry = dget(exp->ex_path.dentry);
213 else {
214 dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
215 data_left, fileid_type,
216 nfsd_acceptable, exp);
217 }
218 if (dentry == NULL)
219 goto out;
220 if (IS_ERR(dentry)) {
221 if (PTR_ERR(dentry) != -EINVAL)
222 error = nfserrno(PTR_ERR(dentry));
223 goto out;
224 }
225
226 if (S_ISDIR(dentry->d_inode->i_mode) &&
227 (dentry->d_flags & DCACHE_DISCONNECTED)) {
228 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
229 dentry->d_parent->d_name.name, dentry->d_name.name);
230 }
231
232 fhp->fh_dentry = dentry;
233 fhp->fh_export = exp;
234 nfsd_nr_verified++;
235 cache_get(&exp->h);
236 } else { 257 } else {
237 /* 258 /*
238 * just rechecking permissions 259 * just rechecking permissions
@@ -242,7 +263,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
242 dprintk("nfsd: fh_verify - just checking\n"); 263 dprintk("nfsd: fh_verify - just checking\n");
243 dentry = fhp->fh_dentry; 264 dentry = fhp->fh_dentry;
244 exp = fhp->fh_export; 265 exp = fhp->fh_export;
245 cache_get(&exp->h);
246 /* 266 /*
247 * Set user creds for this exportpoint; necessary even 267 * Set user creds for this exportpoint; necessary even
248 * in the "just checking" case because this may be a 268 * in the "just checking" case because this may be a
@@ -281,8 +301,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
281 access, ntohl(error)); 301 access, ntohl(error));
282 } 302 }
283out: 303out:
284 if (exp && !IS_ERR(exp))
285 exp_put(exp);
286 if (error == nfserr_stale) 304 if (error == nfserr_stale)
287 nfsdstats.fh_stale++; 305 nfsdstats.fh_stale++;
288 return error; 306 return error;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 9647b0f7bc0c..941041f4b136 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -244,7 +244,6 @@ static int nfsd_init_socks(int port)
244 if (error < 0) 244 if (error < 0)
245 return error; 245 return error;
246 246
247#ifdef CONFIG_NFSD_TCP
248 error = lockd_up(IPPROTO_TCP); 247 error = lockd_up(IPPROTO_TCP);
249 if (error >= 0) { 248 if (error >= 0) {
250 error = svc_create_xprt(nfsd_serv, "tcp", port, 249 error = svc_create_xprt(nfsd_serv, "tcp", port,
@@ -254,7 +253,6 @@ static int nfsd_init_socks(int port)
254 } 253 }
255 if (error < 0) 254 if (error < 0)
256 return error; 255 return error;
257#endif
258 return 0; 256 return 0;
259} 257}
260 258
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 304bf5f643c9..a3a291f771f4 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -264,7 +264,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
264 struct inode *inode; 264 struct inode *inode;
265 int accmode = MAY_SATTR; 265 int accmode = MAY_SATTR;
266 int ftype = 0; 266 int ftype = 0;
267 int imode;
268 __be32 err; 267 __be32 err;
269 int host_err; 268 int host_err;
270 int size_change = 0; 269 int size_change = 0;
@@ -360,25 +359,25 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
360 DQUOT_INIT(inode); 359 DQUOT_INIT(inode);
361 } 360 }
362 361
363 imode = inode->i_mode; 362 /* sanitize the mode change */
364 if (iap->ia_valid & ATTR_MODE) { 363 if (iap->ia_valid & ATTR_MODE) {
365 iap->ia_mode &= S_IALLUGO; 364 iap->ia_mode &= S_IALLUGO;
366 imode = iap->ia_mode |= (imode & ~S_IALLUGO); 365 iap->ia_mode |= (inode->i_mode & ~S_IALLUGO);
367 /* if changing uid/gid revoke setuid/setgid in mode */ 366 }
368 if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) { 367
369 iap->ia_valid |= ATTR_KILL_PRIV; 368 /* Revoke setuid/setgid on chown */
369 if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) ||
370 ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) {
371 iap->ia_valid |= ATTR_KILL_PRIV;
372 if (iap->ia_valid & ATTR_MODE) {
373 /* we're setting mode too, just clear the s*id bits */
370 iap->ia_mode &= ~S_ISUID; 374 iap->ia_mode &= ~S_ISUID;
375 if (iap->ia_mode & S_IXGRP)
376 iap->ia_mode &= ~S_ISGID;
377 } else {
378 /* set ATTR_KILL_* bits and let VFS handle it */
379 iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
371 } 380 }
372 if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
373 iap->ia_mode &= ~S_ISGID;
374 } else {
375 /*
376 * Revoke setuid/setgid bit on chown/chgrp
377 */
378 if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid)
379 iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV;
380 if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
381 iap->ia_valid |= ATTR_KILL_SGID;
382 } 381 }
383 382
384 /* Change the attributes. */ 383 /* Change the attributes. */
@@ -988,7 +987,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
988 * flushing the data to disk is handled separately below. 987 * flushing the data to disk is handled separately below.
989 */ 988 */
990 989
991 if (file->f_op->fsync == 0) {/* COMMIT3 cannot work */ 990 if (!file->f_op->fsync) {/* COMMIT3 cannot work */
992 stable = 2; 991 stable = 2;
993 *stablep = 2; /* FILE_SYNC */ 992 *stablep = 2; /* FILE_SYNC */
994 } 993 }
@@ -1152,7 +1151,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
1152} 1151}
1153#endif /* CONFIG_NFSD_V3 */ 1152#endif /* CONFIG_NFSD_V3 */
1154 1153
1155__be32 1154static __be32
1156nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, 1155nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
1157 struct iattr *iap) 1156 struct iattr *iap)
1158{ 1157{
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index adcbb05b120b..de8387b7ceb6 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -43,7 +43,7 @@ struct fid {
43 u32 parent_ino; 43 u32 parent_ino;
44 u32 parent_gen; 44 u32 parent_gen;
45 } i32; 45 } i32;
46 __u32 raw[6]; 46 __u32 raw[0];
47 }; 47 };
48}; 48};
49 49
diff --git a/include/linux/nfs3.h b/include/linux/nfs3.h
index 7f11fa589207..539f3b550eab 100644
--- a/include/linux/nfs3.h
+++ b/include/linux/nfs3.h
@@ -96,7 +96,7 @@ struct nfs3_fh {
96#define MOUNTPROC3_UMNTALL 4 96#define MOUNTPROC3_UMNTALL 4
97 97
98 98
99#if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES) 99#if defined(__KERNEL__)
100 100
101/* Number of 32bit words in post_op_attr */ 101/* Number of 32bit words in post_op_attr */
102#define NFS3_POST_OP_ATTR_WORDS 22 102#define NFS3_POST_OP_ATTR_WORDS 22
diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild
index e726fc3a4375..fc972048e572 100644
--- a/include/linux/nfsd/Kbuild
+++ b/include/linux/nfsd/Kbuild
@@ -1,6 +1,6 @@
1unifdef-y += const.h 1unifdef-y += const.h
2unifdef-y += debug.h
2unifdef-y += export.h 3unifdef-y += export.h
4unifdef-y += nfsfh.h
3unifdef-y += stats.h 5unifdef-y += stats.h
4unifdef-y += syscall.h 6unifdef-y += syscall.h
5unifdef-y += nfsfh.h
6unifdef-y += debug.h
diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h
index 7b5d784cc858..04b355c801d8 100644
--- a/include/linux/nfsd/cache.h
+++ b/include/linux/nfsd/cache.h
@@ -10,7 +10,6 @@
10#ifndef NFSCACHE_H 10#ifndef NFSCACHE_H
11#define NFSCACHE_H 11#define NFSCACHE_H
12 12
13#ifdef __KERNEL__
14#include <linux/in.h> 13#include <linux/in.h>
15#include <linux/uio.h> 14#include <linux/uio.h>
16 15
@@ -77,5 +76,4 @@ void nfsd_reply_cache_shutdown(void);
77int nfsd_cache_lookup(struct svc_rqst *, int); 76int nfsd_cache_lookup(struct svc_rqst *, int);
78void nfsd_cache_update(struct svc_rqst *, int, __be32 *); 77void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
79 78
80#endif /* __KERNEL__ */
81#endif /* NFSCACHE_H */ 79#endif /* NFSCACHE_H */
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 8caf4c4f64e6..21ee440dd3e7 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -27,7 +27,6 @@
27#define NFSD_VERSION "0.5" 27#define NFSD_VERSION "0.5"
28#define NFSD_SUPPORTED_MINOR_VERSION 0 28#define NFSD_SUPPORTED_MINOR_VERSION 0
29 29
30#ifdef __KERNEL__
31/* 30/*
32 * Special flags for nfsd_permission. These must be different from MAY_READ, 31 * Special flags for nfsd_permission. These must be different from MAY_READ,
33 * MAY_WRITE, and MAY_EXEC. 32 * MAY_WRITE, and MAY_EXEC.
@@ -56,12 +55,20 @@ extern struct svc_program nfsd_program;
56extern struct svc_version nfsd_version2, nfsd_version3, 55extern struct svc_version nfsd_version2, nfsd_version3,
57 nfsd_version4; 56 nfsd_version4;
58extern struct svc_serv *nfsd_serv; 57extern struct svc_serv *nfsd_serv;
58
59extern struct seq_operations nfs_exports_op;
60
59/* 61/*
60 * Function prototypes. 62 * Function prototypes.
61 */ 63 */
62int nfsd_svc(unsigned short port, int nrservs); 64int nfsd_svc(unsigned short port, int nrservs);
63int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); 65int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
64 66
67int nfsd_nrthreads(void);
68int nfsd_nrpools(void);
69int nfsd_get_nrthreads(int n, int *);
70int nfsd_set_nrthreads(int n, int *);
71
65/* nfsd/vfs.c */ 72/* nfsd/vfs.c */
66int fh_lock_parent(struct svc_fh *, struct dentry *); 73int fh_lock_parent(struct svc_fh *, struct dentry *);
67int nfsd_racache_init(int); 74int nfsd_racache_init(int);
@@ -326,6 +333,4 @@ extern struct timeval nfssvc_boot;
326 333
327#endif /* CONFIG_NFSD_V4 */ 334#endif /* CONFIG_NFSD_V4 */
328 335
329#endif /* __KERNEL__ */
330
331#endif /* LINUX_NFSD_NFSD_H */ 336#endif /* LINUX_NFSD_NFSD_H */
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 03547d6abee5..2d8b211b9324 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -120,7 +120,6 @@ struct cache_deferred_req {
120 struct list_head hash; /* on hash chain */ 120 struct list_head hash; /* on hash chain */
121 struct list_head recent; /* on fifo */ 121 struct list_head recent; /* on fifo */
122 struct cache_head *item; /* cache item we wait on */ 122 struct cache_head *item; /* cache item we wait on */
123 time_t recv_time;
124 void *owner; /* we might need to discard all defered requests 123 void *owner; /* we might need to discard all defered requests
125 * owned by someone */ 124 * owned by someone */
126 void (*revisit)(struct cache_deferred_req *req, 125 void (*revisit)(struct cache_deferred_req *req,
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 5a4b1e0206e3..a10f1fb0bf7c 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -70,8 +70,6 @@ enum seal_alg {
70 SEAL_ALG_DES3KD = 0x0002 70 SEAL_ALG_DES3KD = 0x0002
71}; 71};
72 72
73#define KRB5_CKSUM_LENGTH 8
74
75#define CKSUMTYPE_CRC32 0x0001 73#define CKSUMTYPE_CRC32 0x0001
76#define CKSUMTYPE_RSA_MD4 0x0002 74#define CKSUMTYPE_RSA_MD4 0x0002
77#define CKSUMTYPE_RSA_MD4_DES 0x0003 75#define CKSUMTYPE_RSA_MD4_DES 0x0003
@@ -150,9 +148,9 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *inbuf,
150s32 148s32
151krb5_make_seq_num(struct crypto_blkcipher *key, 149krb5_make_seq_num(struct crypto_blkcipher *key,
152 int direction, 150 int direction,
153 s32 seqnum, unsigned char *cksum, unsigned char *buf); 151 u32 seqnum, unsigned char *cksum, unsigned char *buf);
154 152
155s32 153s32
156krb5_get_seq_num(struct crypto_blkcipher *key, 154krb5_get_seq_num(struct crypto_blkcipher *key,
157 unsigned char *cksum, 155 unsigned char *cksum,
158 unsigned char *buf, int *direction, s32 * seqnum); 156 unsigned char *buf, int *direction, u32 *seqnum);
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 64c97552964a..4b54c5fdcfd9 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -386,7 +386,6 @@ struct svc_serv * svc_create(struct svc_program *, unsigned int,
386 void (*shutdown)(struct svc_serv*)); 386 void (*shutdown)(struct svc_serv*));
387struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, 387struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
388 struct svc_pool *pool); 388 struct svc_pool *pool);
389int svc_create_thread(svc_thread_fn, struct svc_serv *);
390void svc_exit_thread(struct svc_rqst *); 389void svc_exit_thread(struct svc_rqst *);
391struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, 390struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
392 void (*shutdown)(struct svc_serv*), 391 void (*shutdown)(struct svc_serv*),
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 22e1ef8e200e..d39dbdc7b10f 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -24,6 +24,7 @@ struct svc_cred {
24}; 24};
25 25
26struct svc_rqst; /* forward decl */ 26struct svc_rqst; /* forward decl */
27struct in6_addr;
27 28
28/* Authentication is done in the context of a domain. 29/* Authentication is done in the context of a domain.
29 * 30 *
@@ -120,10 +121,10 @@ extern void svc_auth_unregister(rpc_authflavor_t flavor);
120 121
121extern struct auth_domain *unix_domain_find(char *name); 122extern struct auth_domain *unix_domain_find(char *name);
122extern void auth_domain_put(struct auth_domain *item); 123extern void auth_domain_put(struct auth_domain *item);
123extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom); 124extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom);
124extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new); 125extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
125extern struct auth_domain *auth_domain_find(char *name); 126extern struct auth_domain *auth_domain_find(char *name);
126extern struct auth_domain *auth_unix_lookup(struct in_addr addr); 127extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr);
127extern int auth_unix_forget_old(struct auth_domain *dom); 128extern int auth_unix_forget_old(struct auth_domain *dom);
128extern void svcauth_unix_purge(void); 129extern void svcauth_unix_purge(void);
129extern void svcauth_unix_info_release(void *); 130extern void svcauth_unix_info_release(void *);
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 206f092ad4c7..8cff696dedf5 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -26,8 +26,8 @@ struct svc_sock {
26 void (*sk_owspace)(struct sock *); 26 void (*sk_owspace)(struct sock *);
27 27
28 /* private TCP part */ 28 /* private TCP part */
29 int sk_reclen; /* length of record */ 29 u32 sk_reclen; /* length of record */
30 int sk_tcplen; /* current read length */ 30 u32 sk_tcplen; /* current read length */
31}; 31};
32 32
33/* 33/*
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 49c48983019f..e0a612bc9c4e 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -383,6 +383,15 @@ static inline int ipv6_addr_orchid(const struct in6_addr *a)
383 == htonl(0x20010010)); 383 == htonl(0x20010010));
384} 384}
385 385
386static inline void ipv6_addr_set_v4mapped(const __be32 addr,
387 struct in6_addr *v4mapped)
388{
389 ipv6_addr_set(v4mapped,
390 0, 0,
391 htonl(0x0000FFFF),
392 addr);
393}
394
386/* 395/*
387 * find the first different bit between two addresses 396 * find the first different bit between two addresses
388 * length of address must be a multiple of 32bits 397 * length of address must be a multiple of 32bits
diff --git a/net/sunrpc/auth_gss/gss_generic_token.c b/net/sunrpc/auth_gss/gss_generic_token.c
index ea8c92ecdae5..d83b881685fe 100644
--- a/net/sunrpc/auth_gss/gss_generic_token.c
+++ b/net/sunrpc/auth_gss/gss_generic_token.c
@@ -148,7 +148,7 @@ int
148g_token_size(struct xdr_netobj *mech, unsigned int body_size) 148g_token_size(struct xdr_netobj *mech, unsigned int body_size)
149{ 149{
150 /* set body_size to sequence contents size */ 150 /* set body_size to sequence contents size */
151 body_size += 4 + (int) mech->len; /* NEED overflow check */ 151 body_size += 2 + (int) mech->len; /* NEED overflow check */
152 return(1 + der_length_size(body_size) + body_size); 152 return(1 + der_length_size(body_size) + body_size);
153} 153}
154 154
@@ -161,7 +161,7 @@ void
161g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf) 161g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf)
162{ 162{
163 *(*buf)++ = 0x60; 163 *(*buf)++ = 0x60;
164 der_write_length(buf, 4 + mech->len + body_size); 164 der_write_length(buf, 2 + mech->len + body_size);
165 *(*buf)++ = 0x06; 165 *(*buf)++ = 0x06;
166 *(*buf)++ = (unsigned char) mech->len; 166 *(*buf)++ = (unsigned char) mech->len;
167 TWRITE_STR(*buf, mech->data, ((int) mech->len)); 167 TWRITE_STR(*buf, mech->data, ((int) mech->len));
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 0dd792338fa9..1d52308ca324 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -66,8 +66,8 @@ krb5_encrypt(
66 goto out; 66 goto out;
67 67
68 if (crypto_blkcipher_ivsize(tfm) > 16) { 68 if (crypto_blkcipher_ivsize(tfm) > 16) {
69 dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n", 69 dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n",
70 crypto_blkcipher_ivsize(tfm)); 70 crypto_blkcipher_ivsize(tfm));
71 goto out; 71 goto out;
72 } 72 }
73 73
@@ -102,7 +102,7 @@ krb5_decrypt(
102 goto out; 102 goto out;
103 103
104 if (crypto_blkcipher_ivsize(tfm) > 16) { 104 if (crypto_blkcipher_ivsize(tfm) > 16) {
105 dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n", 105 dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n",
106 crypto_blkcipher_ivsize(tfm)); 106 crypto_blkcipher_ivsize(tfm));
107 goto out; 107 goto out;
108 } 108 }
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index dedcbd6108f4..5f1d36dfbcf7 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -87,10 +87,10 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
87 87
88 now = get_seconds(); 88 now = get_seconds();
89 89
90 token->len = g_token_size(&ctx->mech_used, 22); 90 token->len = g_token_size(&ctx->mech_used, 24);
91 91
92 ptr = token->data; 92 ptr = token->data;
93 g_make_token_header(&ctx->mech_used, 22, &ptr); 93 g_make_token_header(&ctx->mech_used, 24, &ptr);
94 94
95 *ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff); 95 *ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
96 *ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff); 96 *ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);
@@ -109,15 +109,14 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
109 md5cksum.data, md5cksum.len)) 109 md5cksum.data, md5cksum.len))
110 return GSS_S_FAILURE; 110 return GSS_S_FAILURE;
111 111
112 memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, 112 memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
113 KRB5_CKSUM_LENGTH);
114 113
115 spin_lock(&krb5_seq_lock); 114 spin_lock(&krb5_seq_lock);
116 seq_send = ctx->seq_send++; 115 seq_send = ctx->seq_send++;
117 spin_unlock(&krb5_seq_lock); 116 spin_unlock(&krb5_seq_lock);
118 117
119 if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff, 118 if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
120 ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8)) 119 seq_send, krb5_hdr + 16, krb5_hdr + 8))
121 return GSS_S_FAILURE; 120 return GSS_S_FAILURE;
122 121
123 return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; 122 return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
index 43f3421f1e6a..f160be6c1a46 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
@@ -43,7 +43,7 @@
43s32 43s32
44krb5_make_seq_num(struct crypto_blkcipher *key, 44krb5_make_seq_num(struct crypto_blkcipher *key,
45 int direction, 45 int direction,
46 s32 seqnum, 46 u32 seqnum,
47 unsigned char *cksum, unsigned char *buf) 47 unsigned char *cksum, unsigned char *buf)
48{ 48{
49 unsigned char plain[8]; 49 unsigned char plain[8];
@@ -65,7 +65,7 @@ s32
65krb5_get_seq_num(struct crypto_blkcipher *key, 65krb5_get_seq_num(struct crypto_blkcipher *key,
66 unsigned char *cksum, 66 unsigned char *cksum,
67 unsigned char *buf, 67 unsigned char *buf,
68 int *direction, s32 * seqnum) 68 int *direction, u32 *seqnum)
69{ 69{
70 s32 code; 70 s32 code;
71 unsigned char plain[8]; 71 unsigned char plain[8];
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index e30a993466bc..d91a5d004803 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -82,7 +82,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
82 struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; 82 struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
83 s32 now; 83 s32 now;
84 int direction; 84 int direction;
85 s32 seqnum; 85 u32 seqnum;
86 unsigned char *ptr = (unsigned char *)read_token->data; 86 unsigned char *ptr = (unsigned char *)read_token->data;
87 int bodysize; 87 int bodysize;
88 88
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 3bdc527ee64a..b00b1b426301 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -137,7 +137,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
137 BUG_ON((buf->len - offset) % blocksize); 137 BUG_ON((buf->len - offset) % blocksize);
138 plainlen = blocksize + buf->len - offset; 138 plainlen = blocksize + buf->len - offset;
139 139
140 headlen = g_token_size(&kctx->mech_used, 22 + plainlen) - 140 headlen = g_token_size(&kctx->mech_used, 24 + plainlen) -
141 (buf->len - offset); 141 (buf->len - offset);
142 142
143 ptr = buf->head[0].iov_base + offset; 143 ptr = buf->head[0].iov_base + offset;
@@ -149,7 +149,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
149 buf->len += headlen; 149 buf->len += headlen;
150 BUG_ON((buf->len - offset - headlen) % blocksize); 150 BUG_ON((buf->len - offset - headlen) % blocksize);
151 151
152 g_make_token_header(&kctx->mech_used, 22 + plainlen, &ptr); 152 g_make_token_header(&kctx->mech_used, 24 + plainlen, &ptr);
153 153
154 154
155 *ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff); 155 *ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
@@ -176,9 +176,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
176 if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, 176 if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
177 md5cksum.data, md5cksum.len)) 177 md5cksum.data, md5cksum.len))
178 return GSS_S_FAILURE; 178 return GSS_S_FAILURE;
179 memcpy(krb5_hdr + 16, 179 memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
180 md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
181 KRB5_CKSUM_LENGTH);
182 180
183 spin_lock(&krb5_seq_lock); 181 spin_lock(&krb5_seq_lock);
184 seq_send = kctx->seq_send++; 182 seq_send = kctx->seq_send++;
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
index abf17ce2e3b1..c832712f8d55 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_seal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c
@@ -107,10 +107,10 @@ spkm3_make_token(struct spkm3_ctx *ctx,
107 tokenlen = 10 + ctxelen + 1 + md5elen + 1; 107 tokenlen = 10 + ctxelen + 1 + md5elen + 1;
108 108
109 /* Create token header using generic routines */ 109 /* Create token header using generic routines */
110 token->len = g_token_size(&ctx->mech_used, tokenlen); 110 token->len = g_token_size(&ctx->mech_used, tokenlen + 2);
111 111
112 ptr = token->data; 112 ptr = token->data;
113 g_make_token_header(&ctx->mech_used, tokenlen, &ptr); 113 g_make_token_header(&ctx->mech_used, tokenlen + 2, &ptr);
114 114
115 spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit); 115 spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
116 } else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */ 116 } else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 481f984e9a22..5905d56737d6 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1146,7 +1146,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1146 case RPC_GSS_SVC_INTEGRITY: 1146 case RPC_GSS_SVC_INTEGRITY:
1147 if (unwrap_integ_data(&rqstp->rq_arg, 1147 if (unwrap_integ_data(&rqstp->rq_arg,
1148 gc->gc_seq, rsci->mechctx)) 1148 gc->gc_seq, rsci->mechctx))
1149 goto auth_err; 1149 goto garbage_args;
1150 /* placeholders for length and seq. number: */ 1150 /* placeholders for length and seq. number: */
1151 svc_putnl(resv, 0); 1151 svc_putnl(resv, 0);
1152 svc_putnl(resv, 0); 1152 svc_putnl(resv, 0);
@@ -1154,7 +1154,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1154 case RPC_GSS_SVC_PRIVACY: 1154 case RPC_GSS_SVC_PRIVACY:
1155 if (unwrap_priv_data(rqstp, &rqstp->rq_arg, 1155 if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
1156 gc->gc_seq, rsci->mechctx)) 1156 gc->gc_seq, rsci->mechctx))
1157 goto auth_err; 1157 goto garbage_args;
1158 /* placeholders for length and seq. number: */ 1158 /* placeholders for length and seq. number: */
1159 svc_putnl(resv, 0); 1159 svc_putnl(resv, 0);
1160 svc_putnl(resv, 0); 1160 svc_putnl(resv, 0);
@@ -1169,6 +1169,11 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1169 ret = SVC_OK; 1169 ret = SVC_OK;
1170 goto out; 1170 goto out;
1171 } 1171 }
1172garbage_args:
1173 /* Restore write pointer to its original value: */
1174 xdr_ressize_check(rqstp, reject_stat);
1175 ret = SVC_GARBAGE;
1176 goto out;
1172auth_err: 1177auth_err:
1173 /* Restore write pointer to its original value: */ 1178 /* Restore write pointer to its original value: */
1174 xdr_ressize_check(rqstp, reject_stat); 1179 xdr_ressize_check(rqstp, reject_stat);
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index b5f2786251b9..d75530ff2a6d 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -571,7 +571,6 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
571 return -ETIMEDOUT; 571 return -ETIMEDOUT;
572 572
573 dreq->item = item; 573 dreq->item = item;
574 dreq->recv_time = get_seconds();
575 574
576 spin_lock(&cache_defer_lock); 575 spin_lock(&cache_defer_lock);
577 576
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 090af78d68b5..d74c2d269539 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -510,8 +510,7 @@ EXPORT_SYMBOL(svc_destroy);
510static int 510static int
511svc_init_buffer(struct svc_rqst *rqstp, unsigned int size) 511svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
512{ 512{
513 int pages; 513 unsigned int pages, arghi;
514 int arghi;
515 514
516 pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply. 515 pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
517 * We assume one is at most one page 516 * We assume one is at most one page
@@ -525,7 +524,7 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
525 rqstp->rq_pages[arghi++] = p; 524 rqstp->rq_pages[arghi++] = p;
526 pages--; 525 pages--;
527 } 526 }
528 return ! pages; 527 return pages == 0;
529} 528}
530 529
531/* 530/*
@@ -534,8 +533,9 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
534static void 533static void
535svc_release_buffer(struct svc_rqst *rqstp) 534svc_release_buffer(struct svc_rqst *rqstp)
536{ 535{
537 int i; 536 unsigned int i;
538 for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++) 537
538 for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
539 if (rqstp->rq_pages[i]) 539 if (rqstp->rq_pages[i])
540 put_page(rqstp->rq_pages[i]); 540 put_page(rqstp->rq_pages[i]);
541} 541}
@@ -590,7 +590,7 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
590 struct svc_rqst *rqstp; 590 struct svc_rqst *rqstp;
591 int error = -ENOMEM; 591 int error = -ENOMEM;
592 int have_oldmask = 0; 592 int have_oldmask = 0;
593 cpumask_t oldmask; 593 cpumask_t uninitialized_var(oldmask);
594 594
595 rqstp = svc_prepare_thread(serv, pool); 595 rqstp = svc_prepare_thread(serv, pool);
596 if (IS_ERR(rqstp)) { 596 if (IS_ERR(rqstp)) {
@@ -619,16 +619,6 @@ out_thread:
619} 619}
620 620
621/* 621/*
622 * Create a thread in the default pool. Caller must hold BKL.
623 */
624int
625svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
626{
627 return __svc_create_thread(func, serv, &serv->sv_pools[0]);
628}
629EXPORT_SYMBOL(svc_create_thread);
630
631/*
632 * Choose a pool in which to create a new thread, for svc_set_num_threads 622 * Choose a pool in which to create a new thread, for svc_set_num_threads
633 */ 623 */
634static inline struct svc_pool * 624static inline struct svc_pool *
@@ -921,8 +911,7 @@ svc_process(struct svc_rqst *rqstp)
921 case SVC_OK: 911 case SVC_OK:
922 break; 912 break;
923 case SVC_GARBAGE: 913 case SVC_GARBAGE:
924 rpc_stat = rpc_garbage_args; 914 goto err_garbage;
925 goto err_bad;
926 case SVC_SYSERR: 915 case SVC_SYSERR:
927 rpc_stat = rpc_system_err; 916 rpc_stat = rpc_system_err;
928 goto err_bad; 917 goto err_bad;
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 332eb47539e1..d8e8d79a8451 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -18,6 +18,7 @@
18#include <linux/skbuff.h> 18#include <linux/skbuff.h>
19#include <linux/file.h> 19#include <linux/file.h>
20#include <linux/freezer.h> 20#include <linux/freezer.h>
21#include <linux/kthread.h>
21#include <net/sock.h> 22#include <net/sock.h>
22#include <net/checksum.h> 23#include <net/checksum.h>
23#include <net/ip.h> 24#include <net/ip.h>
@@ -586,8 +587,12 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
586 while (rqstp->rq_pages[i] == NULL) { 587 while (rqstp->rq_pages[i] == NULL) {
587 struct page *p = alloc_page(GFP_KERNEL); 588 struct page *p = alloc_page(GFP_KERNEL);
588 if (!p) { 589 if (!p) {
589 int j = msecs_to_jiffies(500); 590 set_current_state(TASK_INTERRUPTIBLE);
590 schedule_timeout_uninterruptible(j); 591 if (signalled() || kthread_should_stop()) {
592 set_current_state(TASK_RUNNING);
593 return -EINTR;
594 }
595 schedule_timeout(msecs_to_jiffies(500));
591 } 596 }
592 rqstp->rq_pages[i] = p; 597 rqstp->rq_pages[i] = p;
593 } 598 }
@@ -607,7 +612,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
607 612
608 try_to_freeze(); 613 try_to_freeze();
609 cond_resched(); 614 cond_resched();
610 if (signalled()) 615 if (signalled() || kthread_should_stop())
611 return -EINTR; 616 return -EINTR;
612 617
613 spin_lock_bh(&pool->sp_lock); 618 spin_lock_bh(&pool->sp_lock);
@@ -626,6 +631,20 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
626 * to bring down the daemons ... 631 * to bring down the daemons ...
627 */ 632 */
628 set_current_state(TASK_INTERRUPTIBLE); 633 set_current_state(TASK_INTERRUPTIBLE);
634
635 /*
636 * checking kthread_should_stop() here allows us to avoid
637 * locking and signalling when stopping kthreads that call
638 * svc_recv. If the thread has already been woken up, then
639 * we can exit here without sleeping. If not, then it
640 * it'll be woken up quickly during the schedule_timeout
641 */
642 if (kthread_should_stop()) {
643 set_current_state(TASK_RUNNING);
644 spin_unlock_bh(&pool->sp_lock);
645 return -EINTR;
646 }
647
629 add_wait_queue(&rqstp->rq_wait, &wait); 648 add_wait_queue(&rqstp->rq_wait, &wait);
630 spin_unlock_bh(&pool->sp_lock); 649 spin_unlock_bh(&pool->sp_lock);
631 650
@@ -641,7 +660,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
641 svc_thread_dequeue(pool, rqstp); 660 svc_thread_dequeue(pool, rqstp);
642 spin_unlock_bh(&pool->sp_lock); 661 spin_unlock_bh(&pool->sp_lock);
643 dprintk("svc: server %p, no data yet\n", rqstp); 662 dprintk("svc: server %p, no data yet\n", rqstp);
644 return signalled()? -EINTR : -EAGAIN; 663 if (signalled() || kthread_should_stop())
664 return -EINTR;
665 else
666 return -EAGAIN;
645 } 667 }
646 } 668 }
647 spin_unlock_bh(&pool->sp_lock); 669 spin_unlock_bh(&pool->sp_lock);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 3c64051e4555..3f30ee6006ae 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -11,7 +11,8 @@
11#include <linux/hash.h> 11#include <linux/hash.h>
12#include <linux/string.h> 12#include <linux/string.h>
13#include <net/sock.h> 13#include <net/sock.h>
14 14#include <net/ipv6.h>
15#include <linux/kernel.h>
15#define RPCDBG_FACILITY RPCDBG_AUTH 16#define RPCDBG_FACILITY RPCDBG_AUTH
16 17
17 18
@@ -85,7 +86,7 @@ static void svcauth_unix_domain_release(struct auth_domain *dom)
85struct ip_map { 86struct ip_map {
86 struct cache_head h; 87 struct cache_head h;
87 char m_class[8]; /* e.g. "nfsd" */ 88 char m_class[8]; /* e.g. "nfsd" */
88 struct in_addr m_addr; 89 struct in6_addr m_addr;
89 struct unix_domain *m_client; 90 struct unix_domain *m_client;
90 int m_add_change; 91 int m_add_change;
91}; 92};
@@ -113,12 +114,19 @@ static inline int hash_ip(__be32 ip)
113 return (hash ^ (hash>>8)) & 0xff; 114 return (hash ^ (hash>>8)) & 0xff;
114} 115}
115#endif 116#endif
117static inline int hash_ip6(struct in6_addr ip)
118{
119 return (hash_ip(ip.s6_addr32[0]) ^
120 hash_ip(ip.s6_addr32[1]) ^
121 hash_ip(ip.s6_addr32[2]) ^
122 hash_ip(ip.s6_addr32[3]));
123}
116static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) 124static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
117{ 125{
118 struct ip_map *orig = container_of(corig, struct ip_map, h); 126 struct ip_map *orig = container_of(corig, struct ip_map, h);
119 struct ip_map *new = container_of(cnew, struct ip_map, h); 127 struct ip_map *new = container_of(cnew, struct ip_map, h);
120 return strcmp(orig->m_class, new->m_class) == 0 128 return strcmp(orig->m_class, new->m_class) == 0
121 && orig->m_addr.s_addr == new->m_addr.s_addr; 129 && ipv6_addr_equal(&orig->m_addr, &new->m_addr);
122} 130}
123static void ip_map_init(struct cache_head *cnew, struct cache_head *citem) 131static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
124{ 132{
@@ -126,7 +134,7 @@ static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
126 struct ip_map *item = container_of(citem, struct ip_map, h); 134 struct ip_map *item = container_of(citem, struct ip_map, h);
127 135
128 strcpy(new->m_class, item->m_class); 136 strcpy(new->m_class, item->m_class);
129 new->m_addr.s_addr = item->m_addr.s_addr; 137 ipv6_addr_copy(&new->m_addr, &item->m_addr);
130} 138}
131static void update(struct cache_head *cnew, struct cache_head *citem) 139static void update(struct cache_head *cnew, struct cache_head *citem)
132{ 140{
@@ -150,22 +158,24 @@ static void ip_map_request(struct cache_detail *cd,
150 struct cache_head *h, 158 struct cache_head *h,
151 char **bpp, int *blen) 159 char **bpp, int *blen)
152{ 160{
153 char text_addr[20]; 161 char text_addr[40];
154 struct ip_map *im = container_of(h, struct ip_map, h); 162 struct ip_map *im = container_of(h, struct ip_map, h);
155 __be32 addr = im->m_addr.s_addr;
156
157 snprintf(text_addr, 20, "%u.%u.%u.%u",
158 ntohl(addr) >> 24 & 0xff,
159 ntohl(addr) >> 16 & 0xff,
160 ntohl(addr) >> 8 & 0xff,
161 ntohl(addr) >> 0 & 0xff);
162 163
164 if (ipv6_addr_v4mapped(&(im->m_addr))) {
165 snprintf(text_addr, 20, NIPQUAD_FMT,
166 ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
167 ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
168 ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
169 ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
170 } else {
171 snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
172 }
163 qword_add(bpp, blen, im->m_class); 173 qword_add(bpp, blen, im->m_class);
164 qword_add(bpp, blen, text_addr); 174 qword_add(bpp, blen, text_addr);
165 (*bpp)[-1] = '\n'; 175 (*bpp)[-1] = '\n';
166} 176}
167 177
168static struct ip_map *ip_map_lookup(char *class, struct in_addr addr); 178static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
169static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry); 179static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
170 180
171static int ip_map_parse(struct cache_detail *cd, 181static int ip_map_parse(struct cache_detail *cd,
@@ -176,10 +186,10 @@ static int ip_map_parse(struct cache_detail *cd,
176 * for scratch: */ 186 * for scratch: */
177 char *buf = mesg; 187 char *buf = mesg;
178 int len; 188 int len;
179 int b1,b2,b3,b4; 189 int b1, b2, b3, b4, b5, b6, b7, b8;
180 char c; 190 char c;
181 char class[8]; 191 char class[8];
182 struct in_addr addr; 192 struct in6_addr addr;
183 int err; 193 int err;
184 194
185 struct ip_map *ipmp; 195 struct ip_map *ipmp;
@@ -198,7 +208,23 @@ static int ip_map_parse(struct cache_detail *cd,
198 len = qword_get(&mesg, buf, mlen); 208 len = qword_get(&mesg, buf, mlen);
199 if (len <= 0) return -EINVAL; 209 if (len <= 0) return -EINVAL;
200 210
201 if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) 211 if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
212 addr.s6_addr32[0] = 0;
213 addr.s6_addr32[1] = 0;
214 addr.s6_addr32[2] = htonl(0xffff);
215 addr.s6_addr32[3] =
216 htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
217 } else if (sscanf(buf, NIP6_FMT "%c",
218 &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
219 addr.s6_addr16[0] = htons(b1);
220 addr.s6_addr16[1] = htons(b2);
221 addr.s6_addr16[2] = htons(b3);
222 addr.s6_addr16[3] = htons(b4);
223 addr.s6_addr16[4] = htons(b5);
224 addr.s6_addr16[5] = htons(b6);
225 addr.s6_addr16[6] = htons(b7);
226 addr.s6_addr16[7] = htons(b8);
227 } else
202 return -EINVAL; 228 return -EINVAL;
203 229
204 expiry = get_expiry(&mesg); 230 expiry = get_expiry(&mesg);
@@ -216,10 +242,7 @@ static int ip_map_parse(struct cache_detail *cd,
216 } else 242 } else
217 dom = NULL; 243 dom = NULL;
218 244
219 addr.s_addr = 245 ipmp = ip_map_lookup(class, &addr);
220 htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
221
222 ipmp = ip_map_lookup(class,addr);
223 if (ipmp) { 246 if (ipmp) {
224 err = ip_map_update(ipmp, 247 err = ip_map_update(ipmp,
225 container_of(dom, struct unix_domain, h), 248 container_of(dom, struct unix_domain, h),
@@ -239,7 +262,7 @@ static int ip_map_show(struct seq_file *m,
239 struct cache_head *h) 262 struct cache_head *h)
240{ 263{
241 struct ip_map *im; 264 struct ip_map *im;
242 struct in_addr addr; 265 struct in6_addr addr;
243 char *dom = "-no-domain-"; 266 char *dom = "-no-domain-";
244 267
245 if (h == NULL) { 268 if (h == NULL) {
@@ -248,20 +271,24 @@ static int ip_map_show(struct seq_file *m,
248 } 271 }
249 im = container_of(h, struct ip_map, h); 272 im = container_of(h, struct ip_map, h);
250 /* class addr domain */ 273 /* class addr domain */
251 addr = im->m_addr; 274 ipv6_addr_copy(&addr, &im->m_addr);
252 275
253 if (test_bit(CACHE_VALID, &h->flags) && 276 if (test_bit(CACHE_VALID, &h->flags) &&
254 !test_bit(CACHE_NEGATIVE, &h->flags)) 277 !test_bit(CACHE_NEGATIVE, &h->flags))
255 dom = im->m_client->h.name; 278 dom = im->m_client->h.name;
256 279
257 seq_printf(m, "%s %d.%d.%d.%d %s\n", 280 if (ipv6_addr_v4mapped(&addr)) {
258 im->m_class, 281 seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
259 ntohl(addr.s_addr) >> 24 & 0xff, 282 im->m_class,
260 ntohl(addr.s_addr) >> 16 & 0xff, 283 ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
261 ntohl(addr.s_addr) >> 8 & 0xff, 284 ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
262 ntohl(addr.s_addr) >> 0 & 0xff, 285 ntohl(addr.s6_addr32[3]) >> 8 & 0xff,
263 dom 286 ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
264 ); 287 dom);
288 } else {
289 seq_printf(m, "%s" NIP6_FMT "%s\n",
290 im->m_class, NIP6(addr), dom);
291 }
265 return 0; 292 return 0;
266} 293}
267 294
@@ -281,16 +308,16 @@ struct cache_detail ip_map_cache = {
281 .alloc = ip_map_alloc, 308 .alloc = ip_map_alloc,
282}; 309};
283 310
284static struct ip_map *ip_map_lookup(char *class, struct in_addr addr) 311static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
285{ 312{
286 struct ip_map ip; 313 struct ip_map ip;
287 struct cache_head *ch; 314 struct cache_head *ch;
288 315
289 strcpy(ip.m_class, class); 316 strcpy(ip.m_class, class);
290 ip.m_addr = addr; 317 ipv6_addr_copy(&ip.m_addr, addr);
291 ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h, 318 ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
292 hash_str(class, IP_HASHBITS) ^ 319 hash_str(class, IP_HASHBITS) ^
293 hash_ip(addr.s_addr)); 320 hash_ip6(*addr));
294 321
295 if (ch) 322 if (ch)
296 return container_of(ch, struct ip_map, h); 323 return container_of(ch, struct ip_map, h);
@@ -319,14 +346,14 @@ static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t ex
319 ch = sunrpc_cache_update(&ip_map_cache, 346 ch = sunrpc_cache_update(&ip_map_cache,
320 &ip.h, &ipm->h, 347 &ip.h, &ipm->h,
321 hash_str(ipm->m_class, IP_HASHBITS) ^ 348 hash_str(ipm->m_class, IP_HASHBITS) ^
322 hash_ip(ipm->m_addr.s_addr)); 349 hash_ip6(ipm->m_addr));
323 if (!ch) 350 if (!ch)
324 return -ENOMEM; 351 return -ENOMEM;
325 cache_put(ch, &ip_map_cache); 352 cache_put(ch, &ip_map_cache);
326 return 0; 353 return 0;
327} 354}
328 355
329int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom) 356int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
330{ 357{
331 struct unix_domain *udom; 358 struct unix_domain *udom;
332 struct ip_map *ipmp; 359 struct ip_map *ipmp;
@@ -355,7 +382,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
355} 382}
356EXPORT_SYMBOL(auth_unix_forget_old); 383EXPORT_SYMBOL(auth_unix_forget_old);
357 384
358struct auth_domain *auth_unix_lookup(struct in_addr addr) 385struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
359{ 386{
360 struct ip_map *ipm; 387 struct ip_map *ipm;
361 struct auth_domain *rv; 388 struct auth_domain *rv;
@@ -650,9 +677,24 @@ static int unix_gid_find(uid_t uid, struct group_info **gip,
650int 677int
651svcauth_unix_set_client(struct svc_rqst *rqstp) 678svcauth_unix_set_client(struct svc_rqst *rqstp)
652{ 679{
653 struct sockaddr_in *sin = svc_addr_in(rqstp); 680 struct sockaddr_in *sin;
681 struct sockaddr_in6 *sin6, sin6_storage;
654 struct ip_map *ipm; 682 struct ip_map *ipm;
655 683
684 switch (rqstp->rq_addr.ss_family) {
685 case AF_INET:
686 sin = svc_addr_in(rqstp);
687 sin6 = &sin6_storage;
688 ipv6_addr_set(&sin6->sin6_addr, 0, 0,
689 htonl(0x0000FFFF), sin->sin_addr.s_addr);
690 break;
691 case AF_INET6:
692 sin6 = svc_addr_in6(rqstp);
693 break;
694 default:
695 BUG();
696 }
697
656 rqstp->rq_client = NULL; 698 rqstp->rq_client = NULL;
657 if (rqstp->rq_proc == 0) 699 if (rqstp->rq_proc == 0)
658 return SVC_OK; 700 return SVC_OK;
@@ -660,7 +702,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
660 ipm = ip_map_cached_get(rqstp); 702 ipm = ip_map_cached_get(rqstp);
661 if (ipm == NULL) 703 if (ipm == NULL)
662 ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, 704 ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
663 sin->sin_addr); 705 &sin6->sin6_addr);
664 706
665 if (ipm == NULL) 707 if (ipm == NULL)
666 return SVC_DENIED; 708 return SVC_DENIED;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index c475977de05a..3e65719f1ef6 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -38,6 +38,7 @@
38#include <net/checksum.h> 38#include <net/checksum.h>
39#include <net/ip.h> 39#include <net/ip.h>
40#include <net/ipv6.h> 40#include <net/ipv6.h>
41#include <net/tcp.h>
41#include <net/tcp_states.h> 42#include <net/tcp_states.h>
42#include <asm/uaccess.h> 43#include <asm/uaccess.h>
43#include <asm/ioctls.h> 44#include <asm/ioctls.h>
@@ -45,6 +46,7 @@
45#include <linux/sunrpc/types.h> 46#include <linux/sunrpc/types.h>
46#include <linux/sunrpc/clnt.h> 47#include <linux/sunrpc/clnt.h>
47#include <linux/sunrpc/xdr.h> 48#include <linux/sunrpc/xdr.h>
49#include <linux/sunrpc/msg_prot.h>
48#include <linux/sunrpc/svcsock.h> 50#include <linux/sunrpc/svcsock.h>
49#include <linux/sunrpc/stats.h> 51#include <linux/sunrpc/stats.h>
50 52
@@ -822,8 +824,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
822 * the next four bytes. Otherwise try to gobble up as much as 824 * the next four bytes. Otherwise try to gobble up as much as
823 * possible up to the complete record length. 825 * possible up to the complete record length.
824 */ 826 */
825 if (svsk->sk_tcplen < 4) { 827 if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
826 unsigned long want = 4 - svsk->sk_tcplen; 828 int want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
827 struct kvec iov; 829 struct kvec iov;
828 830
829 iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen; 831 iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen;
@@ -833,32 +835,31 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
833 svsk->sk_tcplen += len; 835 svsk->sk_tcplen += len;
834 836
835 if (len < want) { 837 if (len < want) {
836 dprintk("svc: short recvfrom while reading record length (%d of %lu)\n", 838 dprintk("svc: short recvfrom while reading record "
837 len, want); 839 "length (%d of %d)\n", len, want);
838 svc_xprt_received(&svsk->sk_xprt); 840 svc_xprt_received(&svsk->sk_xprt);
839 return -EAGAIN; /* record header not complete */ 841 return -EAGAIN; /* record header not complete */
840 } 842 }
841 843
842 svsk->sk_reclen = ntohl(svsk->sk_reclen); 844 svsk->sk_reclen = ntohl(svsk->sk_reclen);
843 if (!(svsk->sk_reclen & 0x80000000)) { 845 if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) {
844 /* FIXME: technically, a record can be fragmented, 846 /* FIXME: technically, a record can be fragmented,
845 * and non-terminal fragments will not have the top 847 * and non-terminal fragments will not have the top
846 * bit set in the fragment length header. 848 * bit set in the fragment length header.
847 * But apparently no known nfs clients send fragmented 849 * But apparently no known nfs clients send fragmented
848 * records. */ 850 * records. */
849 if (net_ratelimit()) 851 if (net_ratelimit())
850 printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx" 852 printk(KERN_NOTICE "RPC: multiple fragments "
851 " (non-terminal)\n", 853 "per record not supported\n");
852 (unsigned long) svsk->sk_reclen);
853 goto err_delete; 854 goto err_delete;
854 } 855 }
855 svsk->sk_reclen &= 0x7fffffff; 856 svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK;
856 dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen); 857 dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
857 if (svsk->sk_reclen > serv->sv_max_mesg) { 858 if (svsk->sk_reclen > serv->sv_max_mesg) {
858 if (net_ratelimit()) 859 if (net_ratelimit())
859 printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx" 860 printk(KERN_NOTICE "RPC: "
860 " (large)\n", 861 "fragment too large: 0x%08lx\n",
861 (unsigned long) svsk->sk_reclen); 862 (unsigned long)svsk->sk_reclen);
862 goto err_delete; 863 goto err_delete;
863 } 864 }
864 } 865 }
@@ -1045,7 +1046,6 @@ void svc_cleanup_xprt_sock(void)
1045static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) 1046static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
1046{ 1047{
1047 struct sock *sk = svsk->sk_sk; 1048 struct sock *sk = svsk->sk_sk;
1048 struct tcp_sock *tp = tcp_sk(sk);
1049 1049
1050 svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv); 1050 svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
1051 set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); 1051 set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
@@ -1063,7 +1063,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
1063 svsk->sk_reclen = 0; 1063 svsk->sk_reclen = 0;
1064 svsk->sk_tcplen = 0; 1064 svsk->sk_tcplen = 0;
1065 1065
1066 tp->nonagle = 1; /* disable Nagle's algorithm */ 1066 tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
1067 1067
1068 /* initialise setting must have enough space to 1068 /* initialise setting must have enough space to
1069 * receive and respond to one request. 1069 * receive and respond to one request.
@@ -1101,6 +1101,7 @@ void svc_sock_update_bufs(struct svc_serv *serv)
1101 } 1101 }
1102 spin_unlock_bh(&serv->sv_lock); 1102 spin_unlock_bh(&serv->sv_lock);
1103} 1103}
1104EXPORT_SYMBOL(svc_sock_update_bufs);
1104 1105
1105/* 1106/*
1106 * Initialize socket for RPC use and create svc_sock struct 1107 * Initialize socket for RPC use and create svc_sock struct
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 16fd3f6718ff..af408fc12634 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -1036,6 +1036,8 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
1036 wait_event(xprt->sc_send_wait, 1036 wait_event(xprt->sc_send_wait,
1037 atomic_read(&xprt->sc_sq_count) < 1037 atomic_read(&xprt->sc_sq_count) <
1038 xprt->sc_sq_depth); 1038 xprt->sc_sq_depth);
1039 if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
1040 return 0;
1039 continue; 1041 continue;
1040 } 1042 }
1041 /* Bumped used SQ WR count and post */ 1043 /* Bumped used SQ WR count and post */