diff options
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 */ |
