diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:45:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:45:00 -0400 |
commit | 10c993a6b5418cb1026775765ba4c70ffb70853d (patch) | |
tree | 717deba79b938c2f3f786ff6fe908d30582f06f8 | |
parent | c328d54cd4ad120d76284e46dcca6c6cf996154a (diff) | |
parent | ca456252db0521e5e88024fa2b67535e9739e030 (diff) |
Merge branch 'for-linus' of git://linux-nfs.org/~bfields/linux
* 'for-linus' of git://linux-nfs.org/~bfields/linux: (52 commits)
knfsd: clear both setuid and setgid whenever a chown is done
knfsd: get rid of imode variable in nfsd_setattr
SUNRPC: Use unsigned loop and array index in svc_init_buffer()
SUNRPC: Use unsigned index when looping over arrays
SUNRPC: Update RPC server's TCP record marker decoder
SUNRPC: RPC server still uses 2.4 method for disabling TCP Nagle
NLM: don't let lockd exit on unexpected svc_recv errors (try #2)
NFS: don't let nfs_callback_svc exit on unexpected svc_recv errors (try #2)
Use a zero sized array for raw field in struct fid
nfsd: use static memory for callback program and stats
SUNRPC: remove svc_create_thread()
nfsd: fix comment
lockd: Fix stale nlmsvc_unlink_block comment
NFSD: Strip __KERNEL__ testing from unexported header files.
sunrpc: make token header values less confusing
gss_krb5: consistently use unsigned for seqnum
NFSD: Remove NFSv4 dependency on NFSv3
SUNRPC: Remove PROC_FS dependency
NFSD: Use "depends on" for PROC_FS dependency
nfsd: move most of fh_verify to separate function
...
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 | |||
10 | Table of Contents | ||
11 | ~~~~~~~~~~~~~~~~~ | ||
12 | - Overview | ||
13 | - Getting Help | ||
14 | - Installation | ||
15 | - Check RDMA and NFS Setup | ||
16 | - NFS/RDMA Setup | ||
17 | |||
18 | Overview | ||
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 | |||
32 | Getting 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 | |||
41 | Installation | ||
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 | |||
144 | Check 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 | |||
189 | NFS/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 | ||
413 | config FS_POSIX_ACL | 413 | config 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 | ||
1728 | config NFSD_V2_ACL | 1720 | config NFSD_V2_ACL |
1729 | bool | 1721 | bool |
1730 | depends on NFSD | 1722 | depends on NFSD |
1731 | 1723 | ||
1732 | config NFSD_V3 | 1724 | config 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 | ||
1739 | config NFSD_V3_ACL | 1733 | config 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 | ||
1748 | config NFSD_V4 | 1756 | config 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 | ||
1758 | config 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 | ||
1767 | config ROOT_NFS | 1772 | config 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 | ||
29 | static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; | 28 | static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; |
30 | static unsigned long next_gc; | 29 | static 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 | |||
148 | out: | 145 | out: |
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 | */ |
462 | static LIST_HEAD(nsm_handles); | 459 | static LIST_HEAD(nsm_handles); |
463 | static DEFINE_MUTEX(nsm_mutex); | 460 | static DEFINE_SPINLOCK(nsm_lock); |
464 | 461 | ||
465 | static struct nsm_handle * | 462 | static 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); | 482 | retry: |
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 | ||
515 | out: | 517 | found: |
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 | ||
49 | static DEFINE_MUTEX(nlmsvc_mutex); | 50 | static DEFINE_MUTEX(nlmsvc_mutex); |
50 | static unsigned int nlmsvc_users; | 51 | static unsigned int nlmsvc_users; |
51 | static pid_t nlmsvc_pid; | 52 | static struct task_struct *nlmsvc_task; |
52 | static struct svc_serv *nlmsvc_serv; | 53 | static struct svc_serv *nlmsvc_serv; |
53 | int nlmsvc_grace_period; | 54 | int nlmsvc_grace_period; |
54 | unsigned long nlmsvc_timeout; | 55 | unsigned long nlmsvc_timeout; |
55 | 56 | ||
56 | static DECLARE_COMPLETION(lockd_start_done); | ||
57 | static 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 | */ |
114 | static void | 112 | static int |
115 | lockd(struct svc_rqst *rqstp) | 113 | lockd(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) | |||
261 | int | 251 | int |
262 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | 252 | lockd_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); | |||
323 | void | 329 | void |
324 | lockd_down(void) | 330 | lockd_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(¤t->sighand->siglock); | 346 | kthread_stop(nlmsvc_task); |
355 | recalc_sigpending(); | ||
356 | spin_unlock_irq(¤t->sighand->siglock); | ||
357 | out: | 347 | out: |
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 @@ | |||
27 | struct nfs_callback_data { | 28 | struct 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 | ||
35 | static struct nfs_callback_data nfs_callback_info; | 34 | static 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 | */ |
60 | static void nfs_callback_svc(struct svc_rqst *rqstp) | 59 | static int |
60 | nfs_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) | |||
107 | int nfs_callback_up(void) | 102 | int 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 | } | ||
135 | out: | 142 | out: |
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 | */ |
157 | void nfs_callback_down(void) | 164 | void 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 | ||
14 | int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | 15 | int 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 | ||
347 | static struct rpc_program cb_program; | ||
348 | |||
349 | static struct rpc_stat cb_stats = { | ||
350 | .program = &cb_program | ||
351 | }; | ||
352 | |||
353 | #define NFS4_CALLBACK 0x40000000 | ||
354 | static 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 | ||
205 | int | 205 | static int |
206 | idtoname_parse(struct cache_detail *cd, char *buf, int buflen) | 206 | idtoname_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 | ||
1766 | static struct workqueue_struct *laundry_wq; | ||
1767 | static void laundromat_main(struct work_struct *); | ||
1768 | static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); | ||
1769 | |||
1770 | __be32 | 1766 | __be32 |
1771 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1767 | nfsd4_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 | ||
1877 | void | 1873 | static struct workqueue_struct *laundry_wq; |
1874 | static void laundromat_main(struct work_struct *); | ||
1875 | static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); | ||
1876 | |||
1877 | static void | ||
1878 | laundromat_main(struct work_struct *not_used) | 1878 | laundromat_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 | ||
1978 | static 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 | ||
1870 | static 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 | |||
1870 | static __be32 | 1879 | static __be32 |
1871 | nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, | 1880 | nfsd4_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 | ||
152 | extern struct seq_operations nfs_exports_op; | ||
153 | static int exports_open(struct inode *inode, struct file *file) | 153 | static 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 | ||
350 | extern int nfsd_nrthreads(void); | ||
351 | |||
352 | static ssize_t write_threads(struct file *file, char *buf, size_t size) | 360 | static 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 | ||
374 | extern int nfsd_nrpools(void); | ||
375 | extern int nfsd_get_nrthreads(int n, int *); | ||
376 | extern int nfsd_set_nrthreads(int n, int *); | ||
377 | |||
378 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) | 382 | static 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 | */ | ||
120 | static __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; | ||
228 | out: | ||
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 |
125 | fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | 243 | fh_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 | } |
283 | out: | 303 | out: |
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 | 1154 | static __be32 |
1156 | nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, | 1155 | nfsd_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 @@ | |||
1 | unifdef-y += const.h | 1 | unifdef-y += const.h |
2 | unifdef-y += debug.h | ||
2 | unifdef-y += export.h | 3 | unifdef-y += export.h |
4 | unifdef-y += nfsfh.h | ||
3 | unifdef-y += stats.h | 5 | unifdef-y += stats.h |
4 | unifdef-y += syscall.h | 6 | unifdef-y += syscall.h |
5 | unifdef-y += nfsfh.h | ||
6 | unifdef-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); | |||
77 | int nfsd_cache_lookup(struct svc_rqst *, int); | 76 | int nfsd_cache_lookup(struct svc_rqst *, int); |
78 | void nfsd_cache_update(struct svc_rqst *, int, __be32 *); | 77 | void 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; | |||
56 | extern struct svc_version nfsd_version2, nfsd_version3, | 55 | extern struct svc_version nfsd_version2, nfsd_version3, |
57 | nfsd_version4; | 56 | nfsd_version4; |
58 | extern struct svc_serv *nfsd_serv; | 57 | extern struct svc_serv *nfsd_serv; |
58 | |||
59 | extern struct seq_operations nfs_exports_op; | ||
60 | |||
59 | /* | 61 | /* |
60 | * Function prototypes. | 62 | * Function prototypes. |
61 | */ | 63 | */ |
62 | int nfsd_svc(unsigned short port, int nrservs); | 64 | int nfsd_svc(unsigned short port, int nrservs); |
63 | int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); | 65 | int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); |
64 | 66 | ||
67 | int nfsd_nrthreads(void); | ||
68 | int nfsd_nrpools(void); | ||
69 | int nfsd_get_nrthreads(int n, int *); | ||
70 | int nfsd_set_nrthreads(int n, int *); | ||
71 | |||
65 | /* nfsd/vfs.c */ | 72 | /* nfsd/vfs.c */ |
66 | int fh_lock_parent(struct svc_fh *, struct dentry *); | 73 | int fh_lock_parent(struct svc_fh *, struct dentry *); |
67 | int nfsd_racache_init(int); | 74 | int 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, | |||
150 | s32 | 148 | s32 |
151 | krb5_make_seq_num(struct crypto_blkcipher *key, | 149 | krb5_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 | ||
155 | s32 | 153 | s32 |
156 | krb5_get_seq_num(struct crypto_blkcipher *key, | 154 | krb5_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*)); |
387 | struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, | 387 | struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, |
388 | struct svc_pool *pool); | 388 | struct svc_pool *pool); |
389 | int svc_create_thread(svc_thread_fn, struct svc_serv *); | ||
390 | void svc_exit_thread(struct svc_rqst *); | 389 | void svc_exit_thread(struct svc_rqst *); |
391 | struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, | 390 | struct 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 | ||
26 | struct svc_rqst; /* forward decl */ | 26 | struct svc_rqst; /* forward decl */ |
27 | struct 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 | ||
121 | extern struct auth_domain *unix_domain_find(char *name); | 122 | extern struct auth_domain *unix_domain_find(char *name); |
122 | extern void auth_domain_put(struct auth_domain *item); | 123 | extern void auth_domain_put(struct auth_domain *item); |
123 | extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom); | 124 | extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom); |
124 | extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new); | 125 | extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new); |
125 | extern struct auth_domain *auth_domain_find(char *name); | 126 | extern struct auth_domain *auth_domain_find(char *name); |
126 | extern struct auth_domain *auth_unix_lookup(struct in_addr addr); | 127 | extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr); |
127 | extern int auth_unix_forget_old(struct auth_domain *dom); | 128 | extern int auth_unix_forget_old(struct auth_domain *dom); |
128 | extern void svcauth_unix_purge(void); | 129 | extern void svcauth_unix_purge(void); |
129 | extern void svcauth_unix_info_release(void *); | 130 | extern 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 | ||
386 | static 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 | |||
148 | g_token_size(struct xdr_netobj *mech, unsigned int body_size) | 148 | g_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 | |||
161 | g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf) | 161 | g_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 @@ | |||
43 | s32 | 43 | s32 |
44 | krb5_make_seq_num(struct crypto_blkcipher *key, | 44 | krb5_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 | |||
65 | krb5_get_seq_num(struct crypto_blkcipher *key, | 65 | krb5_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 | } |
1172 | garbage_args: | ||
1173 | /* Restore write pointer to its original value: */ | ||
1174 | xdr_ressize_check(rqstp, reject_stat); | ||
1175 | ret = SVC_GARBAGE; | ||
1176 | goto out; | ||
1172 | auth_err: | 1177 | auth_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); | |||
510 | static int | 510 | static int |
511 | svc_init_buffer(struct svc_rqst *rqstp, unsigned int size) | 511 | svc_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) | |||
534 | static void | 533 | static void |
535 | svc_release_buffer(struct svc_rqst *rqstp) | 534 | svc_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 | */ | ||
624 | int | ||
625 | svc_create_thread(svc_thread_fn func, struct svc_serv *serv) | ||
626 | { | ||
627 | return __svc_create_thread(func, serv, &serv->sv_pools[0]); | ||
628 | } | ||
629 | EXPORT_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 | */ |
634 | static inline struct svc_pool * | 624 | static 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) | |||
85 | struct ip_map { | 86 | struct 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 |
117 | static 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 | } | ||
116 | static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) | 124 | static 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 | } |
123 | static void ip_map_init(struct cache_head *cnew, struct cache_head *citem) | 131 | static 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 | } |
131 | static void update(struct cache_head *cnew, struct cache_head *citem) | 139 | static 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 | ||
168 | static struct ip_map *ip_map_lookup(char *class, struct in_addr addr); | 178 | static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr); |
169 | static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry); | 179 | static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry); |
170 | 180 | ||
171 | static int ip_map_parse(struct cache_detail *cd, | 181 | static 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 | ||
284 | static struct ip_map *ip_map_lookup(char *class, struct in_addr addr) | 311 | static 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 | ||
329 | int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom) | 356 | int 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 | } |
356 | EXPORT_SYMBOL(auth_unix_forget_old); | 383 | EXPORT_SYMBOL(auth_unix_forget_old); |
357 | 384 | ||
358 | struct auth_domain *auth_unix_lookup(struct in_addr addr) | 385 | struct 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, | |||
650 | int | 677 | int |
651 | svcauth_unix_set_client(struct svc_rqst *rqstp) | 678 | svcauth_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) | |||
1045 | static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | 1046 | static 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 | } |
1104 | EXPORT_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 */ |