Merge branch 'for-linus' of git://linux-nfs.org/~bfields/linux
* 'for-linus' of git://linux-nfs.org/~bfields/linux: (52 commits) knfsd: clear both setuid and setgid whenever a chown is done knfsd: get rid of imode variable in nfsd_setattr SUNRPC: Use unsigned loop and array index in svc_init_buffer() SUNRPC: Use unsigned index when looping over arrays SUNRPC: Update RPC server's TCP record marker decoder SUNRPC: RPC server still uses 2.4 method for disabling TCP Nagle NLM: don't let lockd exit on unexpected svc_recv errors (try #2) NFS: don't let nfs_callback_svc exit on unexpected svc_recv errors (try #2) Use a zero sized array for raw field in struct fid nfsd: use static memory for callback program and stats SUNRPC: remove svc_create_thread() nfsd: fix comment lockd: Fix stale nlmsvc_unlink_block comment NFSD: Strip __KERNEL__ testing from unexported header files. sunrpc: make token header values less confusing gss_krb5: consistently use unsigned for seqnum NFSD: Remove NFSv4 dependency on NFSv3 SUNRPC: Remove PROC_FS dependency NFSD: Use "depends on" for PROC_FS dependency nfsd: move most of fh_verify to separate function ...
This commit is contained in:
252
Documentation/filesystems/nfs-rdma.txt
Normal file
252
Documentation/filesystems/nfs-rdma.txt
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
################################################################################
|
||||||
|
# #
|
||||||
|
# NFS/RDMA README #
|
||||||
|
# #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
Author: NetApp and Open Grid Computing
|
||||||
|
Date: February 25, 2008
|
||||||
|
|
||||||
|
Table of Contents
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
- Overview
|
||||||
|
- Getting Help
|
||||||
|
- Installation
|
||||||
|
- Check RDMA and NFS Setup
|
||||||
|
- NFS/RDMA Setup
|
||||||
|
|
||||||
|
Overview
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
This document describes how to install and setup the Linux NFS/RDMA client
|
||||||
|
and server software.
|
||||||
|
|
||||||
|
The NFS/RDMA client was first included in Linux 2.6.24. The NFS/RDMA server
|
||||||
|
was first included in the following release, Linux 2.6.25.
|
||||||
|
|
||||||
|
In our testing, we have obtained excellent performance results (full 10Gbit
|
||||||
|
wire bandwidth at minimal client CPU) under many workloads. The code passes
|
||||||
|
the full Connectathon test suite and operates over both Infiniband and iWARP
|
||||||
|
RDMA adapters.
|
||||||
|
|
||||||
|
Getting Help
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If you get stuck, you can ask questions on the
|
||||||
|
|
||||||
|
nfs-rdma-devel@lists.sourceforge.net
|
||||||
|
|
||||||
|
mailing list.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
These instructions are a step by step guide to building a machine for
|
||||||
|
use with NFS/RDMA.
|
||||||
|
|
||||||
|
- Install an RDMA device
|
||||||
|
|
||||||
|
Any device supported by the drivers in drivers/infiniband/hw is acceptable.
|
||||||
|
|
||||||
|
Testing has been performed using several Mellanox-based IB cards, the
|
||||||
|
Ammasso AMS1100 iWARP adapter, and the Chelsio cxgb3 iWARP adapter.
|
||||||
|
|
||||||
|
- Install a Linux distribution and tools
|
||||||
|
|
||||||
|
The first kernel release to contain both the NFS/RDMA client and server was
|
||||||
|
Linux 2.6.25 Therefore, a distribution compatible with this and subsequent
|
||||||
|
Linux kernel release should be installed.
|
||||||
|
|
||||||
|
The procedures described in this document have been tested with
|
||||||
|
distributions from Red Hat's Fedora Project (http://fedora.redhat.com/).
|
||||||
|
|
||||||
|
- Install nfs-utils-1.1.1 or greater on the client
|
||||||
|
|
||||||
|
An NFS/RDMA mount point can only be obtained by using the mount.nfs
|
||||||
|
command in nfs-utils-1.1.1 or greater. To see which version of mount.nfs
|
||||||
|
you are using, type:
|
||||||
|
|
||||||
|
> /sbin/mount.nfs -V
|
||||||
|
|
||||||
|
If the version is less than 1.1.1 or the command does not exist,
|
||||||
|
then you will need to install the latest version of nfs-utils.
|
||||||
|
|
||||||
|
Download the latest package from:
|
||||||
|
|
||||||
|
http://www.kernel.org/pub/linux/utils/nfs
|
||||||
|
|
||||||
|
Uncompress the package and follow the installation instructions.
|
||||||
|
|
||||||
|
If you will not be using GSS and NFSv4, the installation process
|
||||||
|
can be simplified by disabling these features when running configure:
|
||||||
|
|
||||||
|
> ./configure --disable-gss --disable-nfsv4
|
||||||
|
|
||||||
|
For more information on this see the package's README and INSTALL files.
|
||||||
|
|
||||||
|
After building the nfs-utils package, there will be a mount.nfs binary in
|
||||||
|
the utils/mount directory. This binary can be used to initiate NFS v2, v3,
|
||||||
|
or v4 mounts. To initiate a v4 mount, the binary must be called mount.nfs4.
|
||||||
|
The standard technique is to create a symlink called mount.nfs4 to mount.nfs.
|
||||||
|
|
||||||
|
NOTE: mount.nfs and therefore nfs-utils-1.1.1 or greater is only needed
|
||||||
|
on the NFS client machine. You do not need this specific version of
|
||||||
|
nfs-utils on the server. Furthermore, only the mount.nfs command from
|
||||||
|
nfs-utils-1.1.1 is needed on the client.
|
||||||
|
|
||||||
|
- Install a Linux kernel with NFS/RDMA
|
||||||
|
|
||||||
|
The NFS/RDMA client and server are both included in the mainline Linux
|
||||||
|
kernel version 2.6.25 and later. This and other versions of the 2.6 Linux
|
||||||
|
kernel can be found at:
|
||||||
|
|
||||||
|
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
|
||||||
|
|
||||||
|
Download the sources and place them in an appropriate location.
|
||||||
|
|
||||||
|
- Configure the RDMA stack
|
||||||
|
|
||||||
|
Make sure your kernel configuration has RDMA support enabled. Under
|
||||||
|
Device Drivers -> InfiniBand support, update the kernel configuration
|
||||||
|
to enable InfiniBand support [NOTE: the option name is misleading. Enabling
|
||||||
|
InfiniBand support is required for all RDMA devices (IB, iWARP, etc.)].
|
||||||
|
|
||||||
|
Enable the appropriate IB HCA support (mlx4, mthca, ehca, ipath, etc.) or
|
||||||
|
iWARP adapter support (amso, cxgb3, etc.).
|
||||||
|
|
||||||
|
If you are using InfiniBand, be sure to enable IP-over-InfiniBand support.
|
||||||
|
|
||||||
|
- Configure the NFS client and server
|
||||||
|
|
||||||
|
Your kernel configuration must also have NFS file system support and/or
|
||||||
|
NFS server support enabled. These and other NFS related configuration
|
||||||
|
options can be found under File Systems -> Network File Systems.
|
||||||
|
|
||||||
|
- Build, install, reboot
|
||||||
|
|
||||||
|
The NFS/RDMA code will be enabled automatically if NFS and RDMA
|
||||||
|
are turned on. The NFS/RDMA client and server are configured via the hidden
|
||||||
|
SUNRPC_XPRT_RDMA config option that depends on SUNRPC and INFINIBAND. The
|
||||||
|
value of SUNRPC_XPRT_RDMA will be:
|
||||||
|
|
||||||
|
- N if either SUNRPC or INFINIBAND are N, in this case the NFS/RDMA client
|
||||||
|
and server will not be built
|
||||||
|
- M if both SUNRPC and INFINIBAND are on (M or Y) and at least one is M,
|
||||||
|
in this case the NFS/RDMA client and server will be built as modules
|
||||||
|
- Y if both SUNRPC and INFINIBAND are Y, in this case the NFS/RDMA client
|
||||||
|
and server will be built into the kernel
|
||||||
|
|
||||||
|
Therefore, if you have followed the steps above and turned no NFS and RDMA,
|
||||||
|
the NFS/RDMA client and server will be built.
|
||||||
|
|
||||||
|
Build a new kernel, install it, boot it.
|
||||||
|
|
||||||
|
Check RDMA and NFS Setup
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Before configuring the NFS/RDMA software, it is a good idea to test
|
||||||
|
your new kernel to ensure that the kernel is working correctly.
|
||||||
|
In particular, it is a good idea to verify that the RDMA stack
|
||||||
|
is functioning as expected and standard NFS over TCP/IP and/or UDP/IP
|
||||||
|
is working properly.
|
||||||
|
|
||||||
|
- Check RDMA Setup
|
||||||
|
|
||||||
|
If you built the RDMA components as modules, load them at
|
||||||
|
this time. For example, if you are using a Mellanox Tavor/Sinai/Arbel
|
||||||
|
card:
|
||||||
|
|
||||||
|
> modprobe ib_mthca
|
||||||
|
> modprobe ib_ipoib
|
||||||
|
|
||||||
|
If you are using InfiniBand, make sure there is a Subnet Manager (SM)
|
||||||
|
running on the network. If your IB switch has an embedded SM, you can
|
||||||
|
use it. Otherwise, you will need to run an SM, such as OpenSM, on one
|
||||||
|
of your end nodes.
|
||||||
|
|
||||||
|
If an SM is running on your network, you should see the following:
|
||||||
|
|
||||||
|
> cat /sys/class/infiniband/driverX/ports/1/state
|
||||||
|
4: ACTIVE
|
||||||
|
|
||||||
|
where driverX is mthca0, ipath5, ehca3, etc.
|
||||||
|
|
||||||
|
To further test the InfiniBand software stack, use IPoIB (this
|
||||||
|
assumes you have two IB hosts named host1 and host2):
|
||||||
|
|
||||||
|
host1> ifconfig ib0 a.b.c.x
|
||||||
|
host2> ifconfig ib0 a.b.c.y
|
||||||
|
host1> ping a.b.c.y
|
||||||
|
host2> ping a.b.c.x
|
||||||
|
|
||||||
|
For other device types, follow the appropriate procedures.
|
||||||
|
|
||||||
|
- Check NFS Setup
|
||||||
|
|
||||||
|
For the NFS components enabled above (client and/or server),
|
||||||
|
test their functionality over standard Ethernet using TCP/IP or UDP/IP.
|
||||||
|
|
||||||
|
NFS/RDMA Setup
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
We recommend that you use two machines, one to act as the client and
|
||||||
|
one to act as the server.
|
||||||
|
|
||||||
|
One time configuration:
|
||||||
|
|
||||||
|
- On the server system, configure the /etc/exports file and
|
||||||
|
start the NFS/RDMA server.
|
||||||
|
|
||||||
|
Exports entries with the following format have been tested:
|
||||||
|
|
||||||
|
/vol0 10.97.103.47(rw,async) 192.168.0.47(rw,async,insecure,no_root_squash)
|
||||||
|
|
||||||
|
Here the first IP address is the client's Ethernet address and the second
|
||||||
|
IP address is the clients IPoIB address.
|
||||||
|
|
||||||
|
Each time a machine boots:
|
||||||
|
|
||||||
|
- Load and configure the RDMA drivers
|
||||||
|
|
||||||
|
For InfiniBand using a Mellanox adapter:
|
||||||
|
|
||||||
|
> modprobe ib_mthca
|
||||||
|
> modprobe ib_ipoib
|
||||||
|
> ifconfig ib0 a.b.c.d
|
||||||
|
|
||||||
|
NOTE: use unique addresses for the client and server
|
||||||
|
|
||||||
|
- Start the NFS server
|
||||||
|
|
||||||
|
If the NFS/RDMA server was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in kernel config),
|
||||||
|
load the RDMA transport module:
|
||||||
|
|
||||||
|
> modprobe svcrdma
|
||||||
|
|
||||||
|
Regardless of how the server was built (module or built-in), start the server:
|
||||||
|
|
||||||
|
> /etc/init.d/nfs start
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
> service nfs start
|
||||||
|
|
||||||
|
Instruct the server to listen on the RDMA transport:
|
||||||
|
|
||||||
|
> echo rdma 2050 > /proc/fs/nfsd/portlist
|
||||||
|
|
||||||
|
- On the client system
|
||||||
|
|
||||||
|
If the NFS/RDMA client was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in kernel config),
|
||||||
|
load the RDMA client module:
|
||||||
|
|
||||||
|
> modprobe xprtrdma.ko
|
||||||
|
|
||||||
|
Regardless of how the client was built (module or built-in), issue the mount.nfs command:
|
||||||
|
|
||||||
|
> /path/to/your/mount.nfs <IPoIB-server-name-or-address>:/<export> /mnt -i -o rdma,port=2050
|
||||||
|
|
||||||
|
To verify that the mount is using RDMA, run "cat /proc/mounts" and check the
|
||||||
|
"proto" field for the given mount.
|
||||||
|
|
||||||
|
Congratulations! You're using NFS/RDMA!
|
||||||
101
fs/Kconfig
101
fs/Kconfig
@@ -411,7 +411,7 @@ config JFS_STATISTICS
|
|||||||
to be made available to the user in the /proc/fs/jfs/ directory.
|
to be made available to the user in the /proc/fs/jfs/ directory.
|
||||||
|
|
||||||
config FS_POSIX_ACL
|
config FS_POSIX_ACL
|
||||||
# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs)
|
# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4)
|
||||||
#
|
#
|
||||||
# NOTE: you can implement Posix ACLs without these helpers (XFS does).
|
# NOTE: you can implement Posix ACLs without these helpers (XFS does).
|
||||||
# Never use this symbol for ifdefs.
|
# Never use this symbol for ifdefs.
|
||||||
@@ -1694,75 +1694,80 @@ config NFSD
|
|||||||
select LOCKD
|
select LOCKD
|
||||||
select SUNRPC
|
select SUNRPC
|
||||||
select EXPORTFS
|
select EXPORTFS
|
||||||
select NFSD_V2_ACL if NFSD_V3_ACL
|
|
||||||
select NFS_ACL_SUPPORT if NFSD_V2_ACL
|
select NFS_ACL_SUPPORT if NFSD_V2_ACL
|
||||||
select NFSD_TCP if NFSD_V4
|
|
||||||
select CRYPTO_MD5 if NFSD_V4
|
|
||||||
select CRYPTO if NFSD_V4
|
|
||||||
select FS_POSIX_ACL if NFSD_V4
|
|
||||||
select PROC_FS if NFSD_V4
|
|
||||||
select PROC_FS if SUNRPC_GSS
|
|
||||||
help
|
help
|
||||||
If you want your Linux box to act as an NFS *server*, so that other
|
Choose Y here if you want to allow other computers to access
|
||||||
computers on your local network which support NFS can access certain
|
files residing on this system using Sun's Network File System
|
||||||
directories on your box transparently, you have two options: you can
|
protocol. To compile the NFS server support as a module,
|
||||||
use the self-contained user space program nfsd, in which case you
|
choose M here: the module will be called nfsd.
|
||||||
should say N here, or you can say Y and use the kernel based NFS
|
|
||||||
server. The advantage of the kernel based solution is that it is
|
|
||||||
faster.
|
|
||||||
|
|
||||||
In either case, you will need support software; the respective
|
You may choose to use a user-space NFS server instead, in which
|
||||||
locations are given in the file <file:Documentation/Changes> in the
|
case you can choose N here.
|
||||||
NFS section.
|
|
||||||
|
|
||||||
If you say Y here, you will get support for version 2 of the NFS
|
To export local file systems using NFS, you also need to install
|
||||||
protocol (NFSv2). If you also want NFSv3, say Y to the next question
|
user space programs which can be found in the Linux nfs-utils
|
||||||
as well.
|
package, available from http://linux-nfs.org/. More detail about
|
||||||
|
the Linux NFS server implementation is available via the
|
||||||
|
exports(5) man page.
|
||||||
|
|
||||||
Please read the NFS-HOWTO, available from
|
Below you can choose which versions of the NFS protocol are
|
||||||
<http://www.tldp.org/docs.html#howto>.
|
available to clients mounting the NFS server on this system.
|
||||||
|
Support for NFS version 2 (RFC 1094) is always available when
|
||||||
|
CONFIG_NFSD is selected.
|
||||||
|
|
||||||
To compile the NFS server support as a module, choose M here: the
|
If unsure, say N.
|
||||||
module will be called nfsd. If unsure, say N.
|
|
||||||
|
|
||||||
config NFSD_V2_ACL
|
config NFSD_V2_ACL
|
||||||
bool
|
bool
|
||||||
depends on NFSD
|
depends on NFSD
|
||||||
|
|
||||||
config NFSD_V3
|
config NFSD_V3
|
||||||
bool "Provide NFSv3 server support"
|
bool "NFS server support for NFS version 3"
|
||||||
depends on NFSD
|
depends on NFSD
|
||||||
help
|
help
|
||||||
If you would like to include the NFSv3 server as well as the NFSv2
|
This option enables support in your system's NFS server for
|
||||||
server, say Y here. If unsure, say Y.
|
version 3 of the NFS protocol (RFC 1813).
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
config NFSD_V3_ACL
|
config NFSD_V3_ACL
|
||||||
bool "Provide server support for the NFSv3 ACL protocol extension"
|
bool "NFS server support for the NFSv3 ACL protocol extension"
|
||||||
depends on NFSD_V3
|
depends on NFSD_V3
|
||||||
|
select NFSD_V2_ACL
|
||||||
help
|
help
|
||||||
Implement the NFSv3 ACL protocol extension for manipulating POSIX
|
Solaris NFS servers support an auxiliary NFSv3 ACL protocol that
|
||||||
Access Control Lists on exported file systems. NFS clients should
|
never became an official part of the NFS version 3 protocol.
|
||||||
be compiled with the NFSv3 ACL protocol extension; see the
|
This protocol extension allows applications on NFS clients to
|
||||||
CONFIG_NFS_V3_ACL option. If unsure, say N.
|
manipulate POSIX Access Control Lists on files residing on NFS
|
||||||
|
servers. NFS servers enforce POSIX ACLs on local files whether
|
||||||
|
this protocol is available or not.
|
||||||
|
|
||||||
|
This option enables support in your system's NFS server for the
|
||||||
|
NFSv3 ACL protocol extension allowing NFS clients to manipulate
|
||||||
|
POSIX ACLs on files exported by your system's NFS server. NFS
|
||||||
|
clients which support the Solaris NFSv3 ACL protocol can then
|
||||||
|
access and modify ACLs on your NFS server.
|
||||||
|
|
||||||
|
To store ACLs on your NFS server, you also need to enable ACL-
|
||||||
|
related CONFIG options for your local file systems of choice.
|
||||||
|
|
||||||
config NFSD_V4
|
|
||||||
bool "Provide NFSv4 server support (EXPERIMENTAL)"
|
|
||||||
depends on NFSD && NFSD_V3 && EXPERIMENTAL
|
|
||||||
select RPCSEC_GSS_KRB5
|
|
||||||
help
|
|
||||||
If you would like to include the NFSv4 server as well as the NFSv2
|
|
||||||
and NFSv3 servers, say Y here. This feature is experimental, and
|
|
||||||
should only be used if you are interested in helping to test NFSv4.
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
config NFSD_TCP
|
config NFSD_V4
|
||||||
bool "Provide NFS server over TCP support"
|
bool "NFS server support for NFS version 4 (EXPERIMENTAL)"
|
||||||
depends on NFSD
|
depends on NFSD && PROC_FS && EXPERIMENTAL
|
||||||
default y
|
select NFSD_V3
|
||||||
|
select FS_POSIX_ACL
|
||||||
|
select RPCSEC_GSS_KRB5
|
||||||
help
|
help
|
||||||
If you want your NFS server to support TCP connections, say Y here.
|
This option enables support in your system's NFS server for
|
||||||
TCP connections usually perform better than the default UDP when
|
version 4 of the NFS protocol (RFC 3530).
|
||||||
the network is lossy or congested. If unsure, say Y.
|
|
||||||
|
To export files using NFSv4, you need to install additional user
|
||||||
|
space programs which can be found in the Linux nfs-utils package,
|
||||||
|
available from http://linux-nfs.org/.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
config ROOT_NFS
|
config ROOT_NFS
|
||||||
bool "Root file system on NFS"
|
bool "Root file system on NFS"
|
||||||
|
|||||||
@@ -19,12 +19,11 @@
|
|||||||
|
|
||||||
|
|
||||||
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
|
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
|
||||||
#define NLM_HOST_MAX 64
|
|
||||||
#define NLM_HOST_NRHASH 32
|
#define NLM_HOST_NRHASH 32
|
||||||
#define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1))
|
#define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1))
|
||||||
#define NLM_HOST_REBIND (60 * HZ)
|
#define NLM_HOST_REBIND (60 * HZ)
|
||||||
#define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
|
#define NLM_HOST_EXPIRE (300 * HZ)
|
||||||
#define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ)
|
#define NLM_HOST_COLLECT (120 * HZ)
|
||||||
|
|
||||||
static struct hlist_head nlm_hosts[NLM_HOST_NRHASH];
|
static struct hlist_head nlm_hosts[NLM_HOST_NRHASH];
|
||||||
static unsigned long next_gc;
|
static unsigned long next_gc;
|
||||||
@@ -142,9 +141,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin,
|
|||||||
INIT_LIST_HEAD(&host->h_granted);
|
INIT_LIST_HEAD(&host->h_granted);
|
||||||
INIT_LIST_HEAD(&host->h_reclaim);
|
INIT_LIST_HEAD(&host->h_reclaim);
|
||||||
|
|
||||||
if (++nrhosts > NLM_HOST_MAX)
|
nrhosts++;
|
||||||
next_gc = 0;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&nlm_host_mutex);
|
mutex_unlock(&nlm_host_mutex);
|
||||||
return host;
|
return host;
|
||||||
@@ -460,7 +457,7 @@ nlm_gc_hosts(void)
|
|||||||
* Manage NSM handles
|
* Manage NSM handles
|
||||||
*/
|
*/
|
||||||
static LIST_HEAD(nsm_handles);
|
static LIST_HEAD(nsm_handles);
|
||||||
static DEFINE_MUTEX(nsm_mutex);
|
static DEFINE_SPINLOCK(nsm_lock);
|
||||||
|
|
||||||
static struct nsm_handle *
|
static struct nsm_handle *
|
||||||
__nsm_find(const struct sockaddr_in *sin,
|
__nsm_find(const struct sockaddr_in *sin,
|
||||||
@@ -468,7 +465,7 @@ __nsm_find(const struct sockaddr_in *sin,
|
|||||||
int create)
|
int create)
|
||||||
{
|
{
|
||||||
struct nsm_handle *nsm = NULL;
|
struct nsm_handle *nsm = NULL;
|
||||||
struct list_head *pos;
|
struct nsm_handle *pos;
|
||||||
|
|
||||||
if (!sin)
|
if (!sin)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -482,38 +479,43 @@ __nsm_find(const struct sockaddr_in *sin,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&nsm_mutex);
|
retry:
|
||||||
list_for_each(pos, &nsm_handles) {
|
spin_lock(&nsm_lock);
|
||||||
nsm = list_entry(pos, struct nsm_handle, sm_link);
|
list_for_each_entry(pos, &nsm_handles, sm_link) {
|
||||||
|
|
||||||
if (hostname && nsm_use_hostnames) {
|
if (hostname && nsm_use_hostnames) {
|
||||||
if (strlen(nsm->sm_name) != hostname_len
|
if (strlen(pos->sm_name) != hostname_len
|
||||||
|| memcmp(nsm->sm_name, hostname, hostname_len))
|
|| memcmp(pos->sm_name, hostname, hostname_len))
|
||||||
continue;
|
continue;
|
||||||
} else if (!nlm_cmp_addr(&nsm->sm_addr, sin))
|
} else if (!nlm_cmp_addr(&pos->sm_addr, sin))
|
||||||
continue;
|
continue;
|
||||||
atomic_inc(&nsm->sm_count);
|
atomic_inc(&pos->sm_count);
|
||||||
goto out;
|
kfree(nsm);
|
||||||
|
nsm = pos;
|
||||||
|
goto found;
|
||||||
}
|
}
|
||||||
|
if (nsm) {
|
||||||
|
list_add(&nsm->sm_link, &nsm_handles);
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
spin_unlock(&nsm_lock);
|
||||||
|
|
||||||
if (!create) {
|
if (!create)
|
||||||
nsm = NULL;
|
return NULL;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
|
nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
|
||||||
if (nsm != NULL) {
|
if (nsm == NULL)
|
||||||
nsm->sm_addr = *sin;
|
return NULL;
|
||||||
nsm->sm_name = (char *) (nsm + 1);
|
|
||||||
memcpy(nsm->sm_name, hostname, hostname_len);
|
|
||||||
nsm->sm_name[hostname_len] = '\0';
|
|
||||||
atomic_set(&nsm->sm_count, 1);
|
|
||||||
|
|
||||||
list_add(&nsm->sm_link, &nsm_handles);
|
nsm->sm_addr = *sin;
|
||||||
}
|
nsm->sm_name = (char *) (nsm + 1);
|
||||||
|
memcpy(nsm->sm_name, hostname, hostname_len);
|
||||||
|
nsm->sm_name[hostname_len] = '\0';
|
||||||
|
atomic_set(&nsm->sm_count, 1);
|
||||||
|
goto retry;
|
||||||
|
|
||||||
out:
|
found:
|
||||||
mutex_unlock(&nsm_mutex);
|
spin_unlock(&nsm_lock);
|
||||||
return nsm;
|
return nsm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,12 +534,9 @@ nsm_release(struct nsm_handle *nsm)
|
|||||||
{
|
{
|
||||||
if (!nsm)
|
if (!nsm)
|
||||||
return;
|
return;
|
||||||
if (atomic_dec_and_test(&nsm->sm_count)) {
|
if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
|
||||||
mutex_lock(&nsm_mutex);
|
list_del(&nsm->sm_link);
|
||||||
if (atomic_read(&nsm->sm_count) == 0) {
|
spin_unlock(&nsm_lock);
|
||||||
list_del(&nsm->sm_link);
|
kfree(nsm);
|
||||||
kfree(nsm);
|
|
||||||
}
|
|
||||||
mutex_unlock(&nsm_mutex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
152
fs/lockd/svc.c
152
fs/lockd/svc.c
@@ -25,6 +25,7 @@
|
|||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
#include <linux/smp_lock.h>
|
#include <linux/smp_lock.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
|
|
||||||
#include <linux/sunrpc/types.h>
|
#include <linux/sunrpc/types.h>
|
||||||
@@ -48,14 +49,11 @@ EXPORT_SYMBOL(nlmsvc_ops);
|
|||||||
|
|
||||||
static DEFINE_MUTEX(nlmsvc_mutex);
|
static DEFINE_MUTEX(nlmsvc_mutex);
|
||||||
static unsigned int nlmsvc_users;
|
static unsigned int nlmsvc_users;
|
||||||
static pid_t nlmsvc_pid;
|
static struct task_struct *nlmsvc_task;
|
||||||
static struct svc_serv *nlmsvc_serv;
|
static struct svc_serv *nlmsvc_serv;
|
||||||
int nlmsvc_grace_period;
|
int nlmsvc_grace_period;
|
||||||
unsigned long nlmsvc_timeout;
|
unsigned long nlmsvc_timeout;
|
||||||
|
|
||||||
static DECLARE_COMPLETION(lockd_start_done);
|
|
||||||
static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These can be set at insmod time (useful for NFS as root filesystem),
|
* These can be set at insmod time (useful for NFS as root filesystem),
|
||||||
* and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
|
* and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
|
||||||
@@ -111,35 +109,30 @@ static inline void clear_grace_period(void)
|
|||||||
/*
|
/*
|
||||||
* This is the lockd kernel thread
|
* This is the lockd kernel thread
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
lockd(struct svc_rqst *rqstp)
|
lockd(void *vrqstp)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0, preverr = 0;
|
||||||
|
struct svc_rqst *rqstp = vrqstp;
|
||||||
unsigned long grace_period_expire;
|
unsigned long grace_period_expire;
|
||||||
|
|
||||||
/* Lock module and set up kernel thread */
|
/* try_to_freeze() is called from svc_recv() */
|
||||||
/* lockd_up is waiting for us to startup, so will
|
|
||||||
* be holding a reference to this module, so it
|
|
||||||
* is safe to just claim another reference
|
|
||||||
*/
|
|
||||||
__module_get(THIS_MODULE);
|
|
||||||
lock_kernel();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Let our maker know we're running.
|
|
||||||
*/
|
|
||||||
nlmsvc_pid = current->pid;
|
|
||||||
nlmsvc_serv = rqstp->rq_server;
|
|
||||||
complete(&lockd_start_done);
|
|
||||||
|
|
||||||
daemonize("lockd");
|
|
||||||
set_freezable();
|
set_freezable();
|
||||||
|
|
||||||
/* Process request with signals blocked, but allow SIGKILL. */
|
/* Allow SIGKILL to tell lockd to drop all of its locks */
|
||||||
allow_signal(SIGKILL);
|
allow_signal(SIGKILL);
|
||||||
|
|
||||||
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
|
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: it would be nice if lockd didn't spend its entire life
|
||||||
|
* running under the BKL. At the very least, it would be good to
|
||||||
|
* have someone clarify what it's intended to protect here. I've
|
||||||
|
* seen some handwavy posts about posix locking needing to be
|
||||||
|
* done under the BKL, but it's far from clear.
|
||||||
|
*/
|
||||||
|
lock_kernel();
|
||||||
|
|
||||||
if (!nlm_timeout)
|
if (!nlm_timeout)
|
||||||
nlm_timeout = LOCKD_DFLT_TIMEO;
|
nlm_timeout = LOCKD_DFLT_TIMEO;
|
||||||
nlmsvc_timeout = nlm_timeout * HZ;
|
nlmsvc_timeout = nlm_timeout * HZ;
|
||||||
@@ -148,10 +141,9 @@ lockd(struct svc_rqst *rqstp)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The main request loop. We don't terminate until the last
|
* The main request loop. We don't terminate until the last
|
||||||
* NFS mount or NFS daemon has gone away, and we've been sent a
|
* NFS mount or NFS daemon has gone away.
|
||||||
* signal, or else another process has taken over our job.
|
|
||||||
*/
|
*/
|
||||||
while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) {
|
while (!kthread_should_stop()) {
|
||||||
long timeout = MAX_SCHEDULE_TIMEOUT;
|
long timeout = MAX_SCHEDULE_TIMEOUT;
|
||||||
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
|
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
|
||||||
|
|
||||||
@@ -161,6 +153,7 @@ lockd(struct svc_rqst *rqstp)
|
|||||||
nlmsvc_invalidate_all();
|
nlmsvc_invalidate_all();
|
||||||
grace_period_expire = set_grace_period();
|
grace_period_expire = set_grace_period();
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -179,14 +172,20 @@ lockd(struct svc_rqst *rqstp)
|
|||||||
* recvfrom routine.
|
* recvfrom routine.
|
||||||
*/
|
*/
|
||||||
err = svc_recv(rqstp, timeout);
|
err = svc_recv(rqstp, timeout);
|
||||||
if (err == -EAGAIN || err == -EINTR)
|
if (err == -EAGAIN || err == -EINTR) {
|
||||||
|
preverr = err;
|
||||||
continue;
|
continue;
|
||||||
if (err < 0) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"lockd: terminating on error %d\n",
|
|
||||||
-err);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if (err < 0) {
|
||||||
|
if (err != preverr) {
|
||||||
|
printk(KERN_WARNING "%s: unexpected error "
|
||||||
|
"from svc_recv (%d)\n", __func__, err);
|
||||||
|
preverr = err;
|
||||||
|
}
|
||||||
|
schedule_timeout_interruptible(HZ);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
preverr = err;
|
||||||
|
|
||||||
dprintk("lockd: request from %s\n",
|
dprintk("lockd: request from %s\n",
|
||||||
svc_print_addr(rqstp, buf, sizeof(buf)));
|
svc_print_addr(rqstp, buf, sizeof(buf)));
|
||||||
@@ -195,28 +194,19 @@ lockd(struct svc_rqst *rqstp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
flush_signals(current);
|
flush_signals(current);
|
||||||
|
if (nlmsvc_ops)
|
||||||
|
nlmsvc_invalidate_all();
|
||||||
|
nlm_shutdown_hosts();
|
||||||
|
|
||||||
/*
|
unlock_kernel();
|
||||||
* Check whether there's a new lockd process before
|
|
||||||
* shutting down the hosts and clearing the slot.
|
nlmsvc_task = NULL;
|
||||||
*/
|
nlmsvc_serv = NULL;
|
||||||
if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
|
|
||||||
if (nlmsvc_ops)
|
|
||||||
nlmsvc_invalidate_all();
|
|
||||||
nlm_shutdown_hosts();
|
|
||||||
nlmsvc_pid = 0;
|
|
||||||
nlmsvc_serv = NULL;
|
|
||||||
} else
|
|
||||||
printk(KERN_DEBUG
|
|
||||||
"lockd: new process, skipping host shutdown\n");
|
|
||||||
wake_up(&lockd_exit);
|
|
||||||
|
|
||||||
/* Exit the RPC thread */
|
/* Exit the RPC thread */
|
||||||
svc_exit_thread(rqstp);
|
svc_exit_thread(rqstp);
|
||||||
|
|
||||||
/* Release module */
|
return 0;
|
||||||
unlock_kernel();
|
|
||||||
module_put_and_exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -261,14 +251,15 @@ static int make_socks(struct svc_serv *serv, int proto)
|
|||||||
int
|
int
|
||||||
lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
|
lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
|
||||||
{
|
{
|
||||||
struct svc_serv * serv;
|
struct svc_serv *serv;
|
||||||
int error = 0;
|
struct svc_rqst *rqstp;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
mutex_lock(&nlmsvc_mutex);
|
mutex_lock(&nlmsvc_mutex);
|
||||||
/*
|
/*
|
||||||
* Check whether we're already up and running.
|
* Check whether we're already up and running.
|
||||||
*/
|
*/
|
||||||
if (nlmsvc_pid) {
|
if (nlmsvc_serv) {
|
||||||
if (proto)
|
if (proto)
|
||||||
error = make_socks(nlmsvc_serv, proto);
|
error = make_socks(nlmsvc_serv, proto);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -295,13 +286,28 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
|
|||||||
/*
|
/*
|
||||||
* Create the kernel thread and wait for it to start.
|
* Create the kernel thread and wait for it to start.
|
||||||
*/
|
*/
|
||||||
error = svc_create_thread(lockd, serv);
|
rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
|
||||||
if (error) {
|
if (IS_ERR(rqstp)) {
|
||||||
|
error = PTR_ERR(rqstp);
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
"lockd_up: create thread failed, error=%d\n", error);
|
"lockd_up: svc_rqst allocation failed, error=%d\n",
|
||||||
|
error);
|
||||||
|
goto destroy_and_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_sock_update_bufs(serv);
|
||||||
|
nlmsvc_serv = rqstp->rq_server;
|
||||||
|
|
||||||
|
nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name);
|
||||||
|
if (IS_ERR(nlmsvc_task)) {
|
||||||
|
error = PTR_ERR(nlmsvc_task);
|
||||||
|
nlmsvc_task = NULL;
|
||||||
|
nlmsvc_serv = NULL;
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"lockd_up: kthread_run failed, error=%d\n", error);
|
||||||
|
svc_exit_thread(rqstp);
|
||||||
goto destroy_and_out;
|
goto destroy_and_out;
|
||||||
}
|
}
|
||||||
wait_for_completion(&lockd_start_done);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: svc_serv structures have an initial use count of 1,
|
* Note: svc_serv structures have an initial use count of 1,
|
||||||
@@ -323,37 +329,21 @@ EXPORT_SYMBOL(lockd_up);
|
|||||||
void
|
void
|
||||||
lockd_down(void)
|
lockd_down(void)
|
||||||
{
|
{
|
||||||
static int warned;
|
|
||||||
|
|
||||||
mutex_lock(&nlmsvc_mutex);
|
mutex_lock(&nlmsvc_mutex);
|
||||||
if (nlmsvc_users) {
|
if (nlmsvc_users) {
|
||||||
if (--nlmsvc_users)
|
if (--nlmsvc_users)
|
||||||
goto out;
|
goto out;
|
||||||
} else
|
} else {
|
||||||
printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid);
|
printk(KERN_ERR "lockd_down: no users! task=%p\n",
|
||||||
|
nlmsvc_task);
|
||||||
if (!nlmsvc_pid) {
|
BUG();
|
||||||
if (warned++ == 0)
|
|
||||||
printk(KERN_WARNING "lockd_down: no lockd running.\n");
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
warned = 0;
|
|
||||||
|
|
||||||
kill_proc(nlmsvc_pid, SIGKILL, 1);
|
if (!nlmsvc_task) {
|
||||||
/*
|
printk(KERN_ERR "lockd_down: no lockd running.\n");
|
||||||
* Wait for the lockd process to exit, but since we're holding
|
BUG();
|
||||||
* the lockd semaphore, we can't wait around forever ...
|
|
||||||
*/
|
|
||||||
clear_thread_flag(TIF_SIGPENDING);
|
|
||||||
interruptible_sleep_on_timeout(&lockd_exit, HZ);
|
|
||||||
if (nlmsvc_pid) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"lockd_down: lockd failed to exit, clearing pid\n");
|
|
||||||
nlmsvc_pid = 0;
|
|
||||||
}
|
}
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
kthread_stop(nlmsvc_task);
|
||||||
recalc_sigpending();
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&nlmsvc_mutex);
|
mutex_unlock(&nlmsvc_mutex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include <linux/sunrpc/svc.h>
|
#include <linux/sunrpc/svc.h>
|
||||||
#include <linux/lockd/nlm.h>
|
#include <linux/lockd/nlm.h>
|
||||||
#include <linux/lockd/lockd.h>
|
#include <linux/lockd/lockd.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
|
||||||
#define NLMDBG_FACILITY NLMDBG_SVCLOCK
|
#define NLMDBG_FACILITY NLMDBG_SVCLOCK
|
||||||
|
|
||||||
@@ -226,8 +227,7 @@ failed:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete a block. If the lock was cancelled or the grant callback
|
* Delete a block.
|
||||||
* failed, unlock is set to 1.
|
|
||||||
* It is the caller's responsibility to check whether the file
|
* It is the caller's responsibility to check whether the file
|
||||||
* can be closed hereafter.
|
* can be closed hereafter.
|
||||||
*/
|
*/
|
||||||
@@ -887,7 +887,7 @@ nlmsvc_retry_blocked(void)
|
|||||||
unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
|
unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
|
||||||
struct nlm_block *block;
|
struct nlm_block *block;
|
||||||
|
|
||||||
while (!list_empty(&nlm_blocked)) {
|
while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
|
||||||
block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
|
block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
|
||||||
|
|
||||||
if (block->b_when == NLM_NEVER)
|
if (block->b_when == NLM_NEVER)
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
|
|||||||
struct nlm_share *share, **shpp;
|
struct nlm_share *share, **shpp;
|
||||||
struct xdr_netobj *oh = &argp->lock.oh;
|
struct xdr_netobj *oh = &argp->lock.oh;
|
||||||
|
|
||||||
for (shpp = &file->f_shares; (share = *shpp) != 0; shpp = &share->s_next) {
|
for (shpp = &file->f_shares; (share = *shpp) != NULL;
|
||||||
|
shpp = &share->s_next) {
|
||||||
if (share->s_host == host && nlm_cmp_owner(share, oh)) {
|
if (share->s_host == host && nlm_cmp_owner(share, oh)) {
|
||||||
*shpp = share->s_next;
|
*shpp = share->s_next;
|
||||||
kfree(share);
|
kfree(share);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <linux/nfs_fs.h>
|
#include <linux/nfs_fs.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
|
||||||
#include <net/inet_sock.h>
|
#include <net/inet_sock.h>
|
||||||
|
|
||||||
@@ -27,9 +28,7 @@
|
|||||||
struct nfs_callback_data {
|
struct nfs_callback_data {
|
||||||
unsigned int users;
|
unsigned int users;
|
||||||
struct svc_serv *serv;
|
struct svc_serv *serv;
|
||||||
pid_t pid;
|
struct task_struct *task;
|
||||||
struct completion started;
|
|
||||||
struct completion stopped;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nfs_callback_data nfs_callback_info;
|
static struct nfs_callback_data nfs_callback_info;
|
||||||
@@ -57,48 +56,44 @@ module_param_call(callback_tcpport, param_set_port, param_get_int,
|
|||||||
/*
|
/*
|
||||||
* This is the callback kernel thread.
|
* This is the callback kernel thread.
|
||||||
*/
|
*/
|
||||||
static void nfs_callback_svc(struct svc_rqst *rqstp)
|
static int
|
||||||
|
nfs_callback_svc(void *vrqstp)
|
||||||
{
|
{
|
||||||
int err;
|
int err, preverr = 0;
|
||||||
|
struct svc_rqst *rqstp = vrqstp;
|
||||||
|
|
||||||
__module_get(THIS_MODULE);
|
|
||||||
lock_kernel();
|
|
||||||
|
|
||||||
nfs_callback_info.pid = current->pid;
|
|
||||||
daemonize("nfsv4-svc");
|
|
||||||
/* Process request with signals blocked, but allow SIGKILL. */
|
|
||||||
allow_signal(SIGKILL);
|
|
||||||
set_freezable();
|
set_freezable();
|
||||||
|
|
||||||
complete(&nfs_callback_info.started);
|
/*
|
||||||
|
* FIXME: do we really need to run this under the BKL? If so, please
|
||||||
for(;;) {
|
* add a comment about what it's intended to protect.
|
||||||
if (signalled()) {
|
*/
|
||||||
if (nfs_callback_info.users == 0)
|
lock_kernel();
|
||||||
break;
|
while (!kthread_should_stop()) {
|
||||||
flush_signals(current);
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* Listen for a request on the socket
|
* Listen for a request on the socket
|
||||||
*/
|
*/
|
||||||
err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
|
err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
|
||||||
if (err == -EAGAIN || err == -EINTR)
|
if (err == -EAGAIN || err == -EINTR) {
|
||||||
|
preverr = err;
|
||||||
continue;
|
continue;
|
||||||
if (err < 0) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"%s: terminating on error %d\n",
|
|
||||||
__FUNCTION__, -err);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if (err < 0) {
|
||||||
|
if (err != preverr) {
|
||||||
|
printk(KERN_WARNING "%s: unexpected error "
|
||||||
|
"from svc_recv (%d)\n", __func__, err);
|
||||||
|
preverr = err;
|
||||||
|
}
|
||||||
|
schedule_timeout_uninterruptible(HZ);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
preverr = err;
|
||||||
svc_process(rqstp);
|
svc_process(rqstp);
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_signals(current);
|
|
||||||
svc_exit_thread(rqstp);
|
|
||||||
nfs_callback_info.pid = 0;
|
|
||||||
complete(&nfs_callback_info.stopped);
|
|
||||||
unlock_kernel();
|
unlock_kernel();
|
||||||
module_put_and_exit(0);
|
nfs_callback_info.task = NULL;
|
||||||
|
svc_exit_thread(rqstp);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -107,14 +102,13 @@ static void nfs_callback_svc(struct svc_rqst *rqstp)
|
|||||||
int nfs_callback_up(void)
|
int nfs_callback_up(void)
|
||||||
{
|
{
|
||||||
struct svc_serv *serv = NULL;
|
struct svc_serv *serv = NULL;
|
||||||
|
struct svc_rqst *rqstp;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
mutex_lock(&nfs_callback_mutex);
|
mutex_lock(&nfs_callback_mutex);
|
||||||
if (nfs_callback_info.users++ || nfs_callback_info.pid != 0)
|
if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
|
||||||
goto out;
|
goto out;
|
||||||
init_completion(&nfs_callback_info.started);
|
|
||||||
init_completion(&nfs_callback_info.stopped);
|
|
||||||
serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
|
serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
if (!serv)
|
if (!serv)
|
||||||
@@ -127,15 +121,28 @@ int nfs_callback_up(void)
|
|||||||
nfs_callback_tcpport = ret;
|
nfs_callback_tcpport = ret;
|
||||||
dprintk("Callback port = 0x%x\n", nfs_callback_tcpport);
|
dprintk("Callback port = 0x%x\n", nfs_callback_tcpport);
|
||||||
|
|
||||||
ret = svc_create_thread(nfs_callback_svc, serv);
|
rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
|
||||||
if (ret < 0)
|
if (IS_ERR(rqstp)) {
|
||||||
|
ret = PTR_ERR(rqstp);
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_sock_update_bufs(serv);
|
||||||
nfs_callback_info.serv = serv;
|
nfs_callback_info.serv = serv;
|
||||||
wait_for_completion(&nfs_callback_info.started);
|
|
||||||
|
nfs_callback_info.task = kthread_run(nfs_callback_svc, rqstp,
|
||||||
|
"nfsv4-svc");
|
||||||
|
if (IS_ERR(nfs_callback_info.task)) {
|
||||||
|
ret = PTR_ERR(nfs_callback_info.task);
|
||||||
|
nfs_callback_info.serv = NULL;
|
||||||
|
nfs_callback_info.task = NULL;
|
||||||
|
svc_exit_thread(rqstp);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
/*
|
/*
|
||||||
* svc_create creates the svc_serv with sv_nrthreads == 1, and then
|
* svc_create creates the svc_serv with sv_nrthreads == 1, and then
|
||||||
* svc_create_thread increments that. So we need to call svc_destroy
|
* svc_prepare_thread increments that. So we need to call svc_destroy
|
||||||
* on both success and failure so that the refcount is 1 when the
|
* on both success and failure so that the refcount is 1 when the
|
||||||
* thread exits.
|
* thread exits.
|
||||||
*/
|
*/
|
||||||
@@ -152,19 +159,15 @@ out_err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kill the server process if it is not already up.
|
* Kill the server process if it is not already down.
|
||||||
*/
|
*/
|
||||||
void nfs_callback_down(void)
|
void nfs_callback_down(void)
|
||||||
{
|
{
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
mutex_lock(&nfs_callback_mutex);
|
mutex_lock(&nfs_callback_mutex);
|
||||||
nfs_callback_info.users--;
|
nfs_callback_info.users--;
|
||||||
do {
|
if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL)
|
||||||
if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0)
|
kthread_stop(nfs_callback_info.task);
|
||||||
break;
|
|
||||||
if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0)
|
|
||||||
break;
|
|
||||||
} while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0);
|
|
||||||
mutex_unlock(&nfs_callback_mutex);
|
mutex_unlock(&nfs_callback_mutex);
|
||||||
unlock_kernel();
|
unlock_kernel();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
* nfs symlink handling code
|
* nfs symlink handling code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define NFS_NEED_XDR_TYPES
|
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <linux/sunrpc/svcauth.h>
|
#include <linux/sunrpc/svcauth.h>
|
||||||
#include <linux/nfsd/nfsd.h>
|
#include <linux/nfsd/nfsd.h>
|
||||||
#include <linux/nfsd/export.h>
|
#include <linux/nfsd/export.h>
|
||||||
|
#include "auth.h"
|
||||||
|
|
||||||
int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
|
int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <linux/lockd/bind.h>
|
#include <linux/lockd/bind.h>
|
||||||
#include <linux/sunrpc/msg_prot.h>
|
#include <linux/sunrpc/msg_prot.h>
|
||||||
#include <linux/sunrpc/gss_api.h>
|
#include <linux/sunrpc/gss_api.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
|
|
||||||
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
|
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
|
||||||
|
|
||||||
@@ -1548,6 +1549,7 @@ exp_addclient(struct nfsctl_client *ncp)
|
|||||||
{
|
{
|
||||||
struct auth_domain *dom;
|
struct auth_domain *dom;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
struct in6_addr addr6;
|
||||||
|
|
||||||
/* First, consistency check. */
|
/* First, consistency check. */
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
@@ -1566,9 +1568,10 @@ exp_addclient(struct nfsctl_client *ncp)
|
|||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
/* Insert client into hashtable. */
|
/* Insert client into hashtable. */
|
||||||
for (i = 0; i < ncp->cl_naddr; i++)
|
for (i = 0; i < ncp->cl_naddr; i++) {
|
||||||
auth_unix_add_addr(ncp->cl_addrlist[i], dom);
|
ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
|
||||||
|
auth_unix_add_addr(&addr6, dom);
|
||||||
|
}
|
||||||
auth_unix_forget_old(dom);
|
auth_unix_forget_old(dom);
|
||||||
auth_domain_put(dom);
|
auth_domain_put(dom);
|
||||||
|
|
||||||
|
|||||||
@@ -344,6 +344,21 @@ static struct rpc_version * nfs_cb_version[] = {
|
|||||||
&nfs_cb_version4,
|
&nfs_cb_version4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct rpc_program cb_program;
|
||||||
|
|
||||||
|
static struct rpc_stat cb_stats = {
|
||||||
|
.program = &cb_program
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NFS4_CALLBACK 0x40000000
|
||||||
|
static struct rpc_program cb_program = {
|
||||||
|
.name = "nfs4_cb",
|
||||||
|
.number = NFS4_CALLBACK,
|
||||||
|
.nrvers = ARRAY_SIZE(nfs_cb_version),
|
||||||
|
.version = nfs_cb_version,
|
||||||
|
.stats = &cb_stats,
|
||||||
|
};
|
||||||
|
|
||||||
/* Reference counting, callback cleanup, etc., all look racy as heck.
|
/* Reference counting, callback cleanup, etc., all look racy as heck.
|
||||||
* And why is cb_set an atomic? */
|
* And why is cb_set an atomic? */
|
||||||
|
|
||||||
@@ -358,13 +373,12 @@ static int do_probe_callback(void *data)
|
|||||||
.to_maxval = (NFSD_LEASE_TIME/2) * HZ,
|
.to_maxval = (NFSD_LEASE_TIME/2) * HZ,
|
||||||
.to_exponential = 1,
|
.to_exponential = 1,
|
||||||
};
|
};
|
||||||
struct rpc_program * program = &cb->cb_program;
|
|
||||||
struct rpc_create_args args = {
|
struct rpc_create_args args = {
|
||||||
.protocol = IPPROTO_TCP,
|
.protocol = IPPROTO_TCP,
|
||||||
.address = (struct sockaddr *)&addr,
|
.address = (struct sockaddr *)&addr,
|
||||||
.addrsize = sizeof(addr),
|
.addrsize = sizeof(addr),
|
||||||
.timeout = &timeparms,
|
.timeout = &timeparms,
|
||||||
.program = program,
|
.program = &cb_program,
|
||||||
.version = nfs_cb_version[1]->number,
|
.version = nfs_cb_version[1]->number,
|
||||||
.authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
|
.authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
|
||||||
.flags = (RPC_CLNT_CREATE_NOPING),
|
.flags = (RPC_CLNT_CREATE_NOPING),
|
||||||
@@ -382,16 +396,8 @@ static int do_probe_callback(void *data)
|
|||||||
addr.sin_port = htons(cb->cb_port);
|
addr.sin_port = htons(cb->cb_port);
|
||||||
addr.sin_addr.s_addr = htonl(cb->cb_addr);
|
addr.sin_addr.s_addr = htonl(cb->cb_addr);
|
||||||
|
|
||||||
/* Initialize rpc_program */
|
|
||||||
program->name = "nfs4_cb";
|
|
||||||
program->number = cb->cb_prog;
|
|
||||||
program->nrvers = ARRAY_SIZE(nfs_cb_version);
|
|
||||||
program->version = nfs_cb_version;
|
|
||||||
program->stats = &cb->cb_stat;
|
|
||||||
|
|
||||||
/* Initialize rpc_stat */
|
/* Initialize rpc_stat */
|
||||||
memset(program->stats, 0, sizeof(cb->cb_stat));
|
memset(args.program->stats, 0, sizeof(struct rpc_stat));
|
||||||
program->stats->program = program;
|
|
||||||
|
|
||||||
/* Create RPC client */
|
/* Create RPC client */
|
||||||
client = rpc_create(&args);
|
client = rpc_create(&args);
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ static struct cache_detail idtoname_cache = {
|
|||||||
.alloc = ent_alloc,
|
.alloc = ent_alloc,
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
static int
|
||||||
idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
|
idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
|
||||||
{
|
{
|
||||||
struct ent ent, *res;
|
struct ent ent, *res;
|
||||||
|
|||||||
@@ -1639,6 +1639,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
|
|||||||
locks_init_lock(&fl);
|
locks_init_lock(&fl);
|
||||||
fl.fl_lmops = &nfsd_lease_mng_ops;
|
fl.fl_lmops = &nfsd_lease_mng_ops;
|
||||||
fl.fl_flags = FL_LEASE;
|
fl.fl_flags = FL_LEASE;
|
||||||
|
fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
|
||||||
fl.fl_end = OFFSET_MAX;
|
fl.fl_end = OFFSET_MAX;
|
||||||
fl.fl_owner = (fl_owner_t)dp;
|
fl.fl_owner = (fl_owner_t)dp;
|
||||||
fl.fl_file = stp->st_vfs_file;
|
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
|
|||||||
/* vfs_setlease checks to see if delegation should be handed out.
|
/* vfs_setlease checks to see if delegation should be handed out.
|
||||||
* the lock_manager callbacks fl_mylease and fl_change are used
|
* the lock_manager callbacks fl_mylease and fl_change are used
|
||||||
*/
|
*/
|
||||||
if ((status = vfs_setlease(stp->st_vfs_file,
|
if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) {
|
||||||
flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
|
|
||||||
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
|
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
|
||||||
unhash_delegation(dp);
|
unhash_delegation(dp);
|
||||||
flag = NFS4_OPEN_DELEGATE_NONE;
|
flag = NFS4_OPEN_DELEGATE_NONE;
|
||||||
@@ -1763,10 +1763,6 @@ out:
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct workqueue_struct *laundry_wq;
|
|
||||||
static void laundromat_main(struct work_struct *);
|
|
||||||
static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
|
|
||||||
|
|
||||||
__be32
|
__be32
|
||||||
nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
clientid_t *clid)
|
clientid_t *clid)
|
||||||
@@ -1874,7 +1870,11 @@ nfs4_laundromat(void)
|
|||||||
return clientid_val;
|
return clientid_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static struct workqueue_struct *laundry_wq;
|
||||||
|
static void laundromat_main(struct work_struct *);
|
||||||
|
static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
|
||||||
|
|
||||||
|
static void
|
||||||
laundromat_main(struct work_struct *not_used)
|
laundromat_main(struct work_struct *not_used)
|
||||||
{
|
{
|
||||||
time_t t;
|
time_t t;
|
||||||
@@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags)
|
|||||||
&& mandatory_lock(inode);
|
&& mandatory_lock(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_stateid_generation(stateid_t *in, stateid_t *ref)
|
||||||
|
{
|
||||||
|
/* If the client sends us a stateid from the future, it's buggy: */
|
||||||
|
if (in->si_generation > ref->si_generation)
|
||||||
|
return nfserr_bad_stateid;
|
||||||
|
/*
|
||||||
|
* The following, however, can happen. For example, if the
|
||||||
|
* client sends an open and some IO at the same time, the open
|
||||||
|
* may bump si_generation while the IO is still in flight.
|
||||||
|
* Thanks to hard links and renames, the client never knows what
|
||||||
|
* file an open will affect. So it could avoid that situation
|
||||||
|
* only by serializing all opens and IO from the same open
|
||||||
|
* owner. To recover from the old_stateid error, the client
|
||||||
|
* will just have to retry the IO:
|
||||||
|
*/
|
||||||
|
if (in->si_generation < ref->si_generation)
|
||||||
|
return nfserr_old_stateid;
|
||||||
|
return nfs_ok;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks for stateid operations
|
* Checks for stateid operations
|
||||||
*/
|
*/
|
||||||
@@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
|
|||||||
goto out;
|
goto out;
|
||||||
stidp = &stp->st_stateid;
|
stidp = &stp->st_stateid;
|
||||||
}
|
}
|
||||||
if (stateid->si_generation > stidp->si_generation)
|
status = check_stateid_generation(stateid, stidp);
|
||||||
goto out;
|
if (status)
|
||||||
|
|
||||||
/* OLD STATEID */
|
|
||||||
status = nfserr_old_stateid;
|
|
||||||
if (stateid->si_generation < stidp->si_generation)
|
|
||||||
goto out;
|
goto out;
|
||||||
if (stp) {
|
if (stp) {
|
||||||
if ((status = nfs4_check_openmode(stp,flags)))
|
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
|
|||||||
renew_client(stp->st_stateowner->so_client);
|
renew_client(stp->st_stateowner->so_client);
|
||||||
if (filpp)
|
if (filpp)
|
||||||
*filpp = stp->st_vfs_file;
|
*filpp = stp->st_vfs_file;
|
||||||
} else if (dp) {
|
} else {
|
||||||
if ((status = nfs4_check_delegmode(dp, flags)))
|
if ((status = nfs4_check_delegmode(dp, flags)))
|
||||||
goto out;
|
goto out;
|
||||||
renew_client(dp->dl_client);
|
renew_client(dp->dl_client);
|
||||||
@@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
|
|||||||
{
|
{
|
||||||
struct nfs4_stateid *stp;
|
struct nfs4_stateid *stp;
|
||||||
struct nfs4_stateowner *sop;
|
struct nfs4_stateowner *sop;
|
||||||
|
__be32 status;
|
||||||
|
|
||||||
dprintk("NFSD: preprocess_seqid_op: seqid=%d "
|
dprintk("NFSD: preprocess_seqid_op: seqid=%d "
|
||||||
"stateid = (%08x/%08x/%08x/%08x)\n", seqid,
|
"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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
|
if (nfs4_check_fh(current_fh, stp)) {
|
||||||
dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
|
dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
|
||||||
return nfserr_bad_stateid;
|
return nfserr_bad_stateid;
|
||||||
}
|
}
|
||||||
@@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
|
|||||||
" confirmed yet!\n");
|
" confirmed yet!\n");
|
||||||
return nfserr_bad_stateid;
|
return nfserr_bad_stateid;
|
||||||
}
|
}
|
||||||
if (stateid->si_generation > stp->st_stateid.si_generation) {
|
status = check_stateid_generation(stateid, &stp->st_stateid);
|
||||||
dprintk("NFSD: preprocess_seqid_op: future stateid?!\n");
|
if (status)
|
||||||
return nfserr_bad_stateid;
|
return status;
|
||||||
}
|
|
||||||
|
|
||||||
if (stateid->si_generation < stp->st_stateid.si_generation) {
|
|
||||||
dprintk("NFSD: preprocess_seqid_op: old stateid!\n");
|
|
||||||
return nfserr_old_stateid;
|
|
||||||
}
|
|
||||||
renew_client(sop->so_client);
|
renew_client(sop->so_client);
|
||||||
return nfs_ok;
|
return nfs_ok;
|
||||||
|
|
||||||
@@ -2194,7 +2205,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
|
|
||||||
if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
||||||
oc->oc_seqid, &oc->oc_req_stateid,
|
oc->oc_seqid, &oc->oc_req_stateid,
|
||||||
CHECK_FH | CONFIRM | OPEN_STATE,
|
CONFIRM | OPEN_STATE,
|
||||||
&oc->oc_stateowner, &stp, NULL)))
|
&oc->oc_stateowner, &stp, NULL)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -2265,7 +2276,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
|
|||||||
if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
||||||
od->od_seqid,
|
od->od_seqid,
|
||||||
&od->od_stateid,
|
&od->od_stateid,
|
||||||
CHECK_FH | OPEN_STATE,
|
OPEN_STATE,
|
||||||
&od->od_stateowner, &stp, NULL)))
|
&od->od_stateowner, &stp, NULL)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -2318,7 +2329,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
||||||
close->cl_seqid,
|
close->cl_seqid,
|
||||||
&close->cl_stateid,
|
&close->cl_stateid,
|
||||||
CHECK_FH | OPEN_STATE | CLOSE_STATE,
|
OPEN_STATE | CLOSE_STATE,
|
||||||
&close->cl_stateowner, &stp, NULL)))
|
&close->cl_stateowner, &stp, NULL)))
|
||||||
goto out;
|
goto out;
|
||||||
status = nfs_ok;
|
status = nfs_ok;
|
||||||
@@ -2623,7 +2634,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
||||||
lock->lk_new_open_seqid,
|
lock->lk_new_open_seqid,
|
||||||
&lock->lk_new_open_stateid,
|
&lock->lk_new_open_stateid,
|
||||||
CHECK_FH | OPEN_STATE,
|
OPEN_STATE,
|
||||||
&lock->lk_replay_owner, &open_stp,
|
&lock->lk_replay_owner, &open_stp,
|
||||||
lock);
|
lock);
|
||||||
if (status)
|
if (status)
|
||||||
@@ -2650,7 +2661,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
||||||
lock->lk_old_lock_seqid,
|
lock->lk_old_lock_seqid,
|
||||||
&lock->lk_old_lock_stateid,
|
&lock->lk_old_lock_stateid,
|
||||||
CHECK_FH | LOCK_STATE,
|
LOCK_STATE,
|
||||||
&lock->lk_replay_owner, &lock_stp, lock);
|
&lock->lk_replay_owner, &lock_stp, lock);
|
||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -2847,7 +2858,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
|
||||||
locku->lu_seqid,
|
locku->lu_seqid,
|
||||||
&locku->lu_stateid,
|
&locku->lu_stateid,
|
||||||
CHECK_FH | LOCK_STATE,
|
LOCK_STATE,
|
||||||
&locku->lu_stateowner, &stp, NULL)))
|
&locku->lu_stateowner, &stp, NULL)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|||||||
@@ -1867,6 +1867,15 @@ out_serverfault:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int attributes_need_mount(u32 *bmval)
|
||||||
|
{
|
||||||
|
if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME))
|
||||||
|
return 1;
|
||||||
|
if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
|
nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
|
||||||
const char *name, int namlen, __be32 *p, int *buflen)
|
const char *name, int namlen, __be32 *p, int *buflen)
|
||||||
@@ -1888,9 +1897,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
|
|||||||
* we will not follow the cross mount and will fill the attribtutes
|
* we will not follow the cross mount and will fill the attribtutes
|
||||||
* directly from the mountpoint dentry.
|
* directly from the mountpoint dentry.
|
||||||
*/
|
*/
|
||||||
if (d_mountpoint(dentry) &&
|
if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval))
|
||||||
(cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
|
|
||||||
(cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
|
|
||||||
ignore_crossmnt = 1;
|
ignore_crossmnt = 1;
|
||||||
else if (d_mountpoint(dentry)) {
|
else if (d_mountpoint(dentry)) {
|
||||||
int err;
|
int err;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <linux/nfsd/syscall.h>
|
#include <linux/nfsd/syscall.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have a single directory with 9 nodes in it.
|
* We have a single directory with 9 nodes in it.
|
||||||
@@ -149,7 +150,6 @@ static const struct file_operations transaction_ops = {
|
|||||||
.release = simple_transaction_release,
|
.release = simple_transaction_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct seq_operations nfs_exports_op;
|
|
||||||
static int exports_open(struct inode *inode, struct file *file)
|
static int exports_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
return seq_open(file, &nfs_exports_op);
|
return seq_open(file, &nfs_exports_op);
|
||||||
@@ -222,6 +222,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
|
|||||||
struct auth_domain *clp;
|
struct auth_domain *clp;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct knfsd_fh *res;
|
struct knfsd_fh *res;
|
||||||
|
struct in6_addr in6;
|
||||||
|
|
||||||
if (size < sizeof(*data))
|
if (size < sizeof(*data))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -236,7 +237,11 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
|
|||||||
res = (struct knfsd_fh*)buf;
|
res = (struct knfsd_fh*)buf;
|
||||||
|
|
||||||
exp_readlock();
|
exp_readlock();
|
||||||
if (!(clp = auth_unix_lookup(sin->sin_addr)))
|
|
||||||
|
ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
|
||||||
|
|
||||||
|
clp = auth_unix_lookup(&in6);
|
||||||
|
if (!clp)
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
else {
|
else {
|
||||||
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
|
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)
|
|||||||
int err = 0;
|
int err = 0;
|
||||||
struct knfsd_fh fh;
|
struct knfsd_fh fh;
|
||||||
char *res;
|
char *res;
|
||||||
|
struct in6_addr in6;
|
||||||
|
|
||||||
if (size < sizeof(*data))
|
if (size < sizeof(*data))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -271,7 +277,11 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
|
|||||||
res = buf;
|
res = buf;
|
||||||
sin = (struct sockaddr_in *)&data->gd_addr;
|
sin = (struct sockaddr_in *)&data->gd_addr;
|
||||||
exp_readlock();
|
exp_readlock();
|
||||||
if (!(clp = auth_unix_lookup(sin->sin_addr)))
|
|
||||||
|
ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
|
||||||
|
|
||||||
|
clp = auth_unix_lookup(&in6);
|
||||||
|
if (!clp)
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
else {
|
else {
|
||||||
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
|
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)
|
|||||||
return mesg - buf;
|
return mesg - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int nfsd_nrthreads(void);
|
|
||||||
|
|
||||||
static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||||||
{
|
{
|
||||||
/* if size > 0, look for a number of threads and call nfsd_svc
|
/* 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)
|
|||||||
return strlen(buf);
|
return strlen(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int nfsd_nrpools(void);
|
|
||||||
extern int nfsd_get_nrthreads(int n, int *);
|
|
||||||
extern int nfsd_set_nrthreads(int n, int *);
|
|
||||||
|
|
||||||
static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
|
static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
|
||||||
{
|
{
|
||||||
/* if size > 0, look for an array of number of threads per node
|
/* if size > 0, look for an array of number of threads per node
|
||||||
|
|||||||
228
fs/nfsd/nfsfh.c
228
fs/nfsd/nfsfh.c
@@ -112,6 +112,124 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
|
|||||||
return nfserrno(nfsd_setuser(rqstp, exp));
|
return nfserrno(nfsd_setuser(rqstp, exp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use the given filehandle to look up the corresponding export and
|
||||||
|
* dentry. On success, the results are used to set fh_export and
|
||||||
|
* fh_dentry.
|
||||||
|
*/
|
||||||
|
static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
|
||||||
|
{
|
||||||
|
struct knfsd_fh *fh = &fhp->fh_handle;
|
||||||
|
struct fid *fid = NULL, sfid;
|
||||||
|
struct svc_export *exp;
|
||||||
|
struct dentry *dentry;
|
||||||
|
int fileid_type;
|
||||||
|
int data_left = fh->fh_size/4;
|
||||||
|
__be32 error;
|
||||||
|
|
||||||
|
error = nfserr_stale;
|
||||||
|
if (rqstp->rq_vers > 2)
|
||||||
|
error = nfserr_badhandle;
|
||||||
|
if (rqstp->rq_vers == 4 && fh->fh_size == 0)
|
||||||
|
return nfserr_nofilehandle;
|
||||||
|
|
||||||
|
if (fh->fh_version == 1) {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (--data_left < 0)
|
||||||
|
return error;
|
||||||
|
if (fh->fh_auth_type != 0)
|
||||||
|
return error;
|
||||||
|
len = key_len(fh->fh_fsid_type) / 4;
|
||||||
|
if (len == 0)
|
||||||
|
return error;
|
||||||
|
if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
|
||||||
|
/* deprecated, convert to type 3 */
|
||||||
|
len = key_len(FSID_ENCODE_DEV)/4;
|
||||||
|
fh->fh_fsid_type = FSID_ENCODE_DEV;
|
||||||
|
fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
|
||||||
|
fh->fh_fsid[1] = fh->fh_fsid[2];
|
||||||
|
}
|
||||||
|
data_left -= len;
|
||||||
|
if (data_left < 0)
|
||||||
|
return error;
|
||||||
|
exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth);
|
||||||
|
fid = (struct fid *)(fh->fh_auth + len);
|
||||||
|
} else {
|
||||||
|
__u32 tfh[2];
|
||||||
|
dev_t xdev;
|
||||||
|
ino_t xino;
|
||||||
|
|
||||||
|
if (fh->fh_size != NFS_FHSIZE)
|
||||||
|
return error;
|
||||||
|
/* assume old filehandle format */
|
||||||
|
xdev = old_decode_dev(fh->ofh_xdev);
|
||||||
|
xino = u32_to_ino_t(fh->ofh_xino);
|
||||||
|
mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
|
||||||
|
exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = nfserr_stale;
|
||||||
|
if (PTR_ERR(exp) == -ENOENT)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (IS_ERR(exp))
|
||||||
|
return nfserrno(PTR_ERR(exp));
|
||||||
|
|
||||||
|
error = nfsd_setuser_and_check_port(rqstp, exp);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up the dentry using the NFS file handle.
|
||||||
|
*/
|
||||||
|
error = nfserr_stale;
|
||||||
|
if (rqstp->rq_vers > 2)
|
||||||
|
error = nfserr_badhandle;
|
||||||
|
|
||||||
|
if (fh->fh_version != 1) {
|
||||||
|
sfid.i32.ino = fh->ofh_ino;
|
||||||
|
sfid.i32.gen = fh->ofh_generation;
|
||||||
|
sfid.i32.parent_ino = fh->ofh_dirino;
|
||||||
|
fid = &sfid;
|
||||||
|
data_left = 3;
|
||||||
|
if (fh->ofh_dirino == 0)
|
||||||
|
fileid_type = FILEID_INO32_GEN;
|
||||||
|
else
|
||||||
|
fileid_type = FILEID_INO32_GEN_PARENT;
|
||||||
|
} else
|
||||||
|
fileid_type = fh->fh_fileid_type;
|
||||||
|
|
||||||
|
if (fileid_type == FILEID_ROOT)
|
||||||
|
dentry = dget(exp->ex_path.dentry);
|
||||||
|
else {
|
||||||
|
dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
|
||||||
|
data_left, fileid_type,
|
||||||
|
nfsd_acceptable, exp);
|
||||||
|
}
|
||||||
|
if (dentry == NULL)
|
||||||
|
goto out;
|
||||||
|
if (IS_ERR(dentry)) {
|
||||||
|
if (PTR_ERR(dentry) != -EINVAL)
|
||||||
|
error = nfserrno(PTR_ERR(dentry));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(dentry->d_inode->i_mode) &&
|
||||||
|
(dentry->d_flags & DCACHE_DISCONNECTED)) {
|
||||||
|
printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
|
||||||
|
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fhp->fh_dentry = dentry;
|
||||||
|
fhp->fh_export = exp;
|
||||||
|
nfsd_nr_verified++;
|
||||||
|
return 0;
|
||||||
|
out:
|
||||||
|
exp_put(exp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform sanity checks on the dentry in a client's file handle.
|
* Perform sanity checks on the dentry in a client's file handle.
|
||||||
*
|
*
|
||||||
@@ -124,115 +242,18 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
|
|||||||
__be32
|
__be32
|
||||||
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
|
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
|
||||||
{
|
{
|
||||||
struct knfsd_fh *fh = &fhp->fh_handle;
|
struct svc_export *exp;
|
||||||
struct svc_export *exp = NULL;
|
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
__be32 error = 0;
|
__be32 error;
|
||||||
|
|
||||||
dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
|
dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
|
||||||
|
|
||||||
if (!fhp->fh_dentry) {
|
if (!fhp->fh_dentry) {
|
||||||
struct fid *fid = NULL, sfid;
|
error = nfsd_set_fh_dentry(rqstp, fhp);
|
||||||
int fileid_type;
|
|
||||||
int data_left = fh->fh_size/4;
|
|
||||||
|
|
||||||
error = nfserr_stale;
|
|
||||||
if (rqstp->rq_vers > 2)
|
|
||||||
error = nfserr_badhandle;
|
|
||||||
if (rqstp->rq_vers == 4 && fh->fh_size == 0)
|
|
||||||
return nfserr_nofilehandle;
|
|
||||||
|
|
||||||
if (fh->fh_version == 1) {
|
|
||||||
int len;
|
|
||||||
if (--data_left<0) goto out;
|
|
||||||
switch (fh->fh_auth_type) {
|
|
||||||
case 0: break;
|
|
||||||
default: goto out;
|
|
||||||
}
|
|
||||||
len = key_len(fh->fh_fsid_type) / 4;
|
|
||||||
if (len == 0) goto out;
|
|
||||||
if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
|
|
||||||
/* deprecated, convert to type 3 */
|
|
||||||
len = key_len(FSID_ENCODE_DEV)/4;
|
|
||||||
fh->fh_fsid_type = FSID_ENCODE_DEV;
|
|
||||||
fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
|
|
||||||
fh->fh_fsid[1] = fh->fh_fsid[2];
|
|
||||||
}
|
|
||||||
if ((data_left -= len)<0) goto out;
|
|
||||||
exp = rqst_exp_find(rqstp, fh->fh_fsid_type,
|
|
||||||
fh->fh_auth);
|
|
||||||
fid = (struct fid *)(fh->fh_auth + len);
|
|
||||||
} else {
|
|
||||||
__u32 tfh[2];
|
|
||||||
dev_t xdev;
|
|
||||||
ino_t xino;
|
|
||||||
if (fh->fh_size != NFS_FHSIZE)
|
|
||||||
goto out;
|
|
||||||
/* assume old filehandle format */
|
|
||||||
xdev = old_decode_dev(fh->ofh_xdev);
|
|
||||||
xino = u32_to_ino_t(fh->ofh_xino);
|
|
||||||
mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
|
|
||||||
exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
|
|
||||||
}
|
|
||||||
|
|
||||||
error = nfserr_stale;
|
|
||||||
if (PTR_ERR(exp) == -ENOENT)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (IS_ERR(exp)) {
|
|
||||||
error = nfserrno(PTR_ERR(exp));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = nfsd_setuser_and_check_port(rqstp, exp);
|
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
dentry = fhp->fh_dentry;
|
||||||
/*
|
exp = fhp->fh_export;
|
||||||
* Look up the dentry using the NFS file handle.
|
|
||||||
*/
|
|
||||||
error = nfserr_stale;
|
|
||||||
if (rqstp->rq_vers > 2)
|
|
||||||
error = nfserr_badhandle;
|
|
||||||
|
|
||||||
if (fh->fh_version != 1) {
|
|
||||||
sfid.i32.ino = fh->ofh_ino;
|
|
||||||
sfid.i32.gen = fh->ofh_generation;
|
|
||||||
sfid.i32.parent_ino = fh->ofh_dirino;
|
|
||||||
fid = &sfid;
|
|
||||||
data_left = 3;
|
|
||||||
if (fh->ofh_dirino == 0)
|
|
||||||
fileid_type = FILEID_INO32_GEN;
|
|
||||||
else
|
|
||||||
fileid_type = FILEID_INO32_GEN_PARENT;
|
|
||||||
} else
|
|
||||||
fileid_type = fh->fh_fileid_type;
|
|
||||||
|
|
||||||
if (fileid_type == FILEID_ROOT)
|
|
||||||
dentry = dget(exp->ex_path.dentry);
|
|
||||||
else {
|
|
||||||
dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
|
|
||||||
data_left, fileid_type,
|
|
||||||
nfsd_acceptable, exp);
|
|
||||||
}
|
|
||||||
if (dentry == NULL)
|
|
||||||
goto out;
|
|
||||||
if (IS_ERR(dentry)) {
|
|
||||||
if (PTR_ERR(dentry) != -EINVAL)
|
|
||||||
error = nfserrno(PTR_ERR(dentry));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISDIR(dentry->d_inode->i_mode) &&
|
|
||||||
(dentry->d_flags & DCACHE_DISCONNECTED)) {
|
|
||||||
printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
|
|
||||||
dentry->d_parent->d_name.name, dentry->d_name.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
fhp->fh_dentry = dentry;
|
|
||||||
fhp->fh_export = exp;
|
|
||||||
nfsd_nr_verified++;
|
|
||||||
cache_get(&exp->h);
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* just rechecking permissions
|
* just rechecking permissions
|
||||||
@@ -242,7 +263,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
|
|||||||
dprintk("nfsd: fh_verify - just checking\n");
|
dprintk("nfsd: fh_verify - just checking\n");
|
||||||
dentry = fhp->fh_dentry;
|
dentry = fhp->fh_dentry;
|
||||||
exp = fhp->fh_export;
|
exp = fhp->fh_export;
|
||||||
cache_get(&exp->h);
|
|
||||||
/*
|
/*
|
||||||
* Set user creds for this exportpoint; necessary even
|
* Set user creds for this exportpoint; necessary even
|
||||||
* in the "just checking" case because this may be a
|
* 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)
|
|||||||
access, ntohl(error));
|
access, ntohl(error));
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
if (exp && !IS_ERR(exp))
|
|
||||||
exp_put(exp);
|
|
||||||
if (error == nfserr_stale)
|
if (error == nfserr_stale)
|
||||||
nfsdstats.fh_stale++;
|
nfsdstats.fh_stale++;
|
||||||
return error;
|
return error;
|
||||||
|
|||||||
@@ -244,7 +244,6 @@ static int nfsd_init_socks(int port)
|
|||||||
if (error < 0)
|
if (error < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
#ifdef CONFIG_NFSD_TCP
|
|
||||||
error = lockd_up(IPPROTO_TCP);
|
error = lockd_up(IPPROTO_TCP);
|
||||||
if (error >= 0) {
|
if (error >= 0) {
|
||||||
error = svc_create_xprt(nfsd_serv, "tcp", port,
|
error = svc_create_xprt(nfsd_serv, "tcp", port,
|
||||||
@@ -254,7 +253,6 @@ static int nfsd_init_socks(int port)
|
|||||||
}
|
}
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
return error;
|
return error;
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -264,7 +264,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
|||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
int accmode = MAY_SATTR;
|
int accmode = MAY_SATTR;
|
||||||
int ftype = 0;
|
int ftype = 0;
|
||||||
int imode;
|
|
||||||
__be32 err;
|
__be32 err;
|
||||||
int host_err;
|
int host_err;
|
||||||
int size_change = 0;
|
int size_change = 0;
|
||||||
@@ -360,25 +359,25 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
|||||||
DQUOT_INIT(inode);
|
DQUOT_INIT(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
imode = inode->i_mode;
|
/* sanitize the mode change */
|
||||||
if (iap->ia_valid & ATTR_MODE) {
|
if (iap->ia_valid & ATTR_MODE) {
|
||||||
iap->ia_mode &= S_IALLUGO;
|
iap->ia_mode &= S_IALLUGO;
|
||||||
imode = iap->ia_mode |= (imode & ~S_IALLUGO);
|
iap->ia_mode |= (inode->i_mode & ~S_IALLUGO);
|
||||||
/* if changing uid/gid revoke setuid/setgid in mode */
|
}
|
||||||
if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) {
|
|
||||||
iap->ia_valid |= ATTR_KILL_PRIV;
|
/* Revoke setuid/setgid on chown */
|
||||||
|
if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) ||
|
||||||
|
((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) {
|
||||||
|
iap->ia_valid |= ATTR_KILL_PRIV;
|
||||||
|
if (iap->ia_valid & ATTR_MODE) {
|
||||||
|
/* we're setting mode too, just clear the s*id bits */
|
||||||
iap->ia_mode &= ~S_ISUID;
|
iap->ia_mode &= ~S_ISUID;
|
||||||
|
if (iap->ia_mode & S_IXGRP)
|
||||||
|
iap->ia_mode &= ~S_ISGID;
|
||||||
|
} else {
|
||||||
|
/* set ATTR_KILL_* bits and let VFS handle it */
|
||||||
|
iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
|
||||||
}
|
}
|
||||||
if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
|
|
||||||
iap->ia_mode &= ~S_ISGID;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Revoke setuid/setgid bit on chown/chgrp
|
|
||||||
*/
|
|
||||||
if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid)
|
|
||||||
iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV;
|
|
||||||
if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
|
|
||||||
iap->ia_valid |= ATTR_KILL_SGID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change the attributes. */
|
/* Change the attributes. */
|
||||||
@@ -988,7 +987,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
|||||||
* flushing the data to disk is handled separately below.
|
* flushing the data to disk is handled separately below.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (file->f_op->fsync == 0) {/* COMMIT3 cannot work */
|
if (!file->f_op->fsync) {/* COMMIT3 cannot work */
|
||||||
stable = 2;
|
stable = 2;
|
||||||
*stablep = 2; /* FILE_SYNC */
|
*stablep = 2; /* FILE_SYNC */
|
||||||
}
|
}
|
||||||
@@ -1152,7 +1151,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_NFSD_V3 */
|
#endif /* CONFIG_NFSD_V3 */
|
||||||
|
|
||||||
__be32
|
static __be32
|
||||||
nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
|
nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
|
||||||
struct iattr *iap)
|
struct iattr *iap)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ struct fid {
|
|||||||
u32 parent_ino;
|
u32 parent_ino;
|
||||||
u32 parent_gen;
|
u32 parent_gen;
|
||||||
} i32;
|
} i32;
|
||||||
__u32 raw[6];
|
__u32 raw[0];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ struct nfs3_fh {
|
|||||||
#define MOUNTPROC3_UMNTALL 4
|
#define MOUNTPROC3_UMNTALL 4
|
||||||
|
|
||||||
|
|
||||||
#if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
|
#if defined(__KERNEL__)
|
||||||
|
|
||||||
/* Number of 32bit words in post_op_attr */
|
/* Number of 32bit words in post_op_attr */
|
||||||
#define NFS3_POST_OP_ATTR_WORDS 22
|
#define NFS3_POST_OP_ATTR_WORDS 22
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
unifdef-y += const.h
|
unifdef-y += const.h
|
||||||
|
unifdef-y += debug.h
|
||||||
unifdef-y += export.h
|
unifdef-y += export.h
|
||||||
|
unifdef-y += nfsfh.h
|
||||||
unifdef-y += stats.h
|
unifdef-y += stats.h
|
||||||
unifdef-y += syscall.h
|
unifdef-y += syscall.h
|
||||||
unifdef-y += nfsfh.h
|
|
||||||
unifdef-y += debug.h
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#ifndef NFSCACHE_H
|
#ifndef NFSCACHE_H
|
||||||
#define NFSCACHE_H
|
#define NFSCACHE_H
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
|
||||||
#include <linux/in.h>
|
#include <linux/in.h>
|
||||||
#include <linux/uio.h>
|
#include <linux/uio.h>
|
||||||
|
|
||||||
@@ -77,5 +76,4 @@ void nfsd_reply_cache_shutdown(void);
|
|||||||
int nfsd_cache_lookup(struct svc_rqst *, int);
|
int nfsd_cache_lookup(struct svc_rqst *, int);
|
||||||
void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
|
void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
|
||||||
#endif /* NFSCACHE_H */
|
#endif /* NFSCACHE_H */
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
#define NFSD_VERSION "0.5"
|
#define NFSD_VERSION "0.5"
|
||||||
#define NFSD_SUPPORTED_MINOR_VERSION 0
|
#define NFSD_SUPPORTED_MINOR_VERSION 0
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
|
||||||
/*
|
/*
|
||||||
* Special flags for nfsd_permission. These must be different from MAY_READ,
|
* Special flags for nfsd_permission. These must be different from MAY_READ,
|
||||||
* MAY_WRITE, and MAY_EXEC.
|
* MAY_WRITE, and MAY_EXEC.
|
||||||
@@ -56,12 +55,20 @@ extern struct svc_program nfsd_program;
|
|||||||
extern struct svc_version nfsd_version2, nfsd_version3,
|
extern struct svc_version nfsd_version2, nfsd_version3,
|
||||||
nfsd_version4;
|
nfsd_version4;
|
||||||
extern struct svc_serv *nfsd_serv;
|
extern struct svc_serv *nfsd_serv;
|
||||||
|
|
||||||
|
extern struct seq_operations nfs_exports_op;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function prototypes.
|
* Function prototypes.
|
||||||
*/
|
*/
|
||||||
int nfsd_svc(unsigned short port, int nrservs);
|
int nfsd_svc(unsigned short port, int nrservs);
|
||||||
int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
|
int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
|
||||||
|
|
||||||
|
int nfsd_nrthreads(void);
|
||||||
|
int nfsd_nrpools(void);
|
||||||
|
int nfsd_get_nrthreads(int n, int *);
|
||||||
|
int nfsd_set_nrthreads(int n, int *);
|
||||||
|
|
||||||
/* nfsd/vfs.c */
|
/* nfsd/vfs.c */
|
||||||
int fh_lock_parent(struct svc_fh *, struct dentry *);
|
int fh_lock_parent(struct svc_fh *, struct dentry *);
|
||||||
int nfsd_racache_init(int);
|
int nfsd_racache_init(int);
|
||||||
@@ -326,6 +333,4 @@ extern struct timeval nfssvc_boot;
|
|||||||
|
|
||||||
#endif /* CONFIG_NFSD_V4 */
|
#endif /* CONFIG_NFSD_V4 */
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
|
||||||
|
|
||||||
#endif /* LINUX_NFSD_NFSD_H */
|
#endif /* LINUX_NFSD_NFSD_H */
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ struct cache_deferred_req {
|
|||||||
struct list_head hash; /* on hash chain */
|
struct list_head hash; /* on hash chain */
|
||||||
struct list_head recent; /* on fifo */
|
struct list_head recent; /* on fifo */
|
||||||
struct cache_head *item; /* cache item we wait on */
|
struct cache_head *item; /* cache item we wait on */
|
||||||
time_t recv_time;
|
|
||||||
void *owner; /* we might need to discard all defered requests
|
void *owner; /* we might need to discard all defered requests
|
||||||
* owned by someone */
|
* owned by someone */
|
||||||
void (*revisit)(struct cache_deferred_req *req,
|
void (*revisit)(struct cache_deferred_req *req,
|
||||||
|
|||||||
@@ -70,8 +70,6 @@ enum seal_alg {
|
|||||||
SEAL_ALG_DES3KD = 0x0002
|
SEAL_ALG_DES3KD = 0x0002
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KRB5_CKSUM_LENGTH 8
|
|
||||||
|
|
||||||
#define CKSUMTYPE_CRC32 0x0001
|
#define CKSUMTYPE_CRC32 0x0001
|
||||||
#define CKSUMTYPE_RSA_MD4 0x0002
|
#define CKSUMTYPE_RSA_MD4 0x0002
|
||||||
#define CKSUMTYPE_RSA_MD4_DES 0x0003
|
#define CKSUMTYPE_RSA_MD4_DES 0x0003
|
||||||
@@ -150,9 +148,9 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *inbuf,
|
|||||||
s32
|
s32
|
||||||
krb5_make_seq_num(struct crypto_blkcipher *key,
|
krb5_make_seq_num(struct crypto_blkcipher *key,
|
||||||
int direction,
|
int direction,
|
||||||
s32 seqnum, unsigned char *cksum, unsigned char *buf);
|
u32 seqnum, unsigned char *cksum, unsigned char *buf);
|
||||||
|
|
||||||
s32
|
s32
|
||||||
krb5_get_seq_num(struct crypto_blkcipher *key,
|
krb5_get_seq_num(struct crypto_blkcipher *key,
|
||||||
unsigned char *cksum,
|
unsigned char *cksum,
|
||||||
unsigned char *buf, int *direction, s32 * seqnum);
|
unsigned char *buf, int *direction, u32 *seqnum);
|
||||||
|
|||||||
@@ -386,7 +386,6 @@ struct svc_serv * svc_create(struct svc_program *, unsigned int,
|
|||||||
void (*shutdown)(struct svc_serv*));
|
void (*shutdown)(struct svc_serv*));
|
||||||
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
|
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
|
||||||
struct svc_pool *pool);
|
struct svc_pool *pool);
|
||||||
int svc_create_thread(svc_thread_fn, struct svc_serv *);
|
|
||||||
void svc_exit_thread(struct svc_rqst *);
|
void svc_exit_thread(struct svc_rqst *);
|
||||||
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
|
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
|
||||||
void (*shutdown)(struct svc_serv*),
|
void (*shutdown)(struct svc_serv*),
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ struct svc_cred {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct svc_rqst; /* forward decl */
|
struct svc_rqst; /* forward decl */
|
||||||
|
struct in6_addr;
|
||||||
|
|
||||||
/* Authentication is done in the context of a domain.
|
/* Authentication is done in the context of a domain.
|
||||||
*
|
*
|
||||||
@@ -120,10 +121,10 @@ extern void svc_auth_unregister(rpc_authflavor_t flavor);
|
|||||||
|
|
||||||
extern struct auth_domain *unix_domain_find(char *name);
|
extern struct auth_domain *unix_domain_find(char *name);
|
||||||
extern void auth_domain_put(struct auth_domain *item);
|
extern void auth_domain_put(struct auth_domain *item);
|
||||||
extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
|
extern int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom);
|
||||||
extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
|
extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
|
||||||
extern struct auth_domain *auth_domain_find(char *name);
|
extern struct auth_domain *auth_domain_find(char *name);
|
||||||
extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
|
extern struct auth_domain *auth_unix_lookup(struct in6_addr *addr);
|
||||||
extern int auth_unix_forget_old(struct auth_domain *dom);
|
extern int auth_unix_forget_old(struct auth_domain *dom);
|
||||||
extern void svcauth_unix_purge(void);
|
extern void svcauth_unix_purge(void);
|
||||||
extern void svcauth_unix_info_release(void *);
|
extern void svcauth_unix_info_release(void *);
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ struct svc_sock {
|
|||||||
void (*sk_owspace)(struct sock *);
|
void (*sk_owspace)(struct sock *);
|
||||||
|
|
||||||
/* private TCP part */
|
/* private TCP part */
|
||||||
int sk_reclen; /* length of record */
|
u32 sk_reclen; /* length of record */
|
||||||
int sk_tcplen; /* current read length */
|
u32 sk_tcplen; /* current read length */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -383,6 +383,15 @@ static inline int ipv6_addr_orchid(const struct in6_addr *a)
|
|||||||
== htonl(0x20010010));
|
== htonl(0x20010010));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void ipv6_addr_set_v4mapped(const __be32 addr,
|
||||||
|
struct in6_addr *v4mapped)
|
||||||
|
{
|
||||||
|
ipv6_addr_set(v4mapped,
|
||||||
|
0, 0,
|
||||||
|
htonl(0x0000FFFF),
|
||||||
|
addr);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find the first different bit between two addresses
|
* find the first different bit between two addresses
|
||||||
* length of address must be a multiple of 32bits
|
* length of address must be a multiple of 32bits
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ int
|
|||||||
g_token_size(struct xdr_netobj *mech, unsigned int body_size)
|
g_token_size(struct xdr_netobj *mech, unsigned int body_size)
|
||||||
{
|
{
|
||||||
/* set body_size to sequence contents size */
|
/* set body_size to sequence contents size */
|
||||||
body_size += 4 + (int) mech->len; /* NEED overflow check */
|
body_size += 2 + (int) mech->len; /* NEED overflow check */
|
||||||
return(1 + der_length_size(body_size) + body_size);
|
return(1 + der_length_size(body_size) + body_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ void
|
|||||||
g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf)
|
g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf)
|
||||||
{
|
{
|
||||||
*(*buf)++ = 0x60;
|
*(*buf)++ = 0x60;
|
||||||
der_write_length(buf, 4 + mech->len + body_size);
|
der_write_length(buf, 2 + mech->len + body_size);
|
||||||
*(*buf)++ = 0x06;
|
*(*buf)++ = 0x06;
|
||||||
*(*buf)++ = (unsigned char) mech->len;
|
*(*buf)++ = (unsigned char) mech->len;
|
||||||
TWRITE_STR(*buf, mech->data, ((int) mech->len));
|
TWRITE_STR(*buf, mech->data, ((int) mech->len));
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ krb5_encrypt(
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (crypto_blkcipher_ivsize(tfm) > 16) {
|
if (crypto_blkcipher_ivsize(tfm) > 16) {
|
||||||
dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n",
|
dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n",
|
||||||
crypto_blkcipher_ivsize(tfm));
|
crypto_blkcipher_ivsize(tfm));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ krb5_decrypt(
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (crypto_blkcipher_ivsize(tfm) > 16) {
|
if (crypto_blkcipher_ivsize(tfm) > 16) {
|
||||||
dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n",
|
dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n",
|
||||||
crypto_blkcipher_ivsize(tfm));
|
crypto_blkcipher_ivsize(tfm));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,10 +87,10 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
|
|||||||
|
|
||||||
now = get_seconds();
|
now = get_seconds();
|
||||||
|
|
||||||
token->len = g_token_size(&ctx->mech_used, 22);
|
token->len = g_token_size(&ctx->mech_used, 24);
|
||||||
|
|
||||||
ptr = token->data;
|
ptr = token->data;
|
||||||
g_make_token_header(&ctx->mech_used, 22, &ptr);
|
g_make_token_header(&ctx->mech_used, 24, &ptr);
|
||||||
|
|
||||||
*ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
|
*ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
|
||||||
*ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);
|
*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,
|
|||||||
md5cksum.data, md5cksum.len))
|
md5cksum.data, md5cksum.len))
|
||||||
return GSS_S_FAILURE;
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
|
memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
|
||||||
KRB5_CKSUM_LENGTH);
|
|
||||||
|
|
||||||
spin_lock(&krb5_seq_lock);
|
spin_lock(&krb5_seq_lock);
|
||||||
seq_send = ctx->seq_send++;
|
seq_send = ctx->seq_send++;
|
||||||
spin_unlock(&krb5_seq_lock);
|
spin_unlock(&krb5_seq_lock);
|
||||||
|
|
||||||
if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
|
if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
|
||||||
ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))
|
seq_send, krb5_hdr + 16, krb5_hdr + 8))
|
||||||
return GSS_S_FAILURE;
|
return GSS_S_FAILURE;
|
||||||
|
|
||||||
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
|
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
s32
|
s32
|
||||||
krb5_make_seq_num(struct crypto_blkcipher *key,
|
krb5_make_seq_num(struct crypto_blkcipher *key,
|
||||||
int direction,
|
int direction,
|
||||||
s32 seqnum,
|
u32 seqnum,
|
||||||
unsigned char *cksum, unsigned char *buf)
|
unsigned char *cksum, unsigned char *buf)
|
||||||
{
|
{
|
||||||
unsigned char plain[8];
|
unsigned char plain[8];
|
||||||
@@ -65,7 +65,7 @@ s32
|
|||||||
krb5_get_seq_num(struct crypto_blkcipher *key,
|
krb5_get_seq_num(struct crypto_blkcipher *key,
|
||||||
unsigned char *cksum,
|
unsigned char *cksum,
|
||||||
unsigned char *buf,
|
unsigned char *buf,
|
||||||
int *direction, s32 * seqnum)
|
int *direction, u32 *seqnum)
|
||||||
{
|
{
|
||||||
s32 code;
|
s32 code;
|
||||||
unsigned char plain[8];
|
unsigned char plain[8];
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
|
|||||||
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
|
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
|
||||||
s32 now;
|
s32 now;
|
||||||
int direction;
|
int direction;
|
||||||
s32 seqnum;
|
u32 seqnum;
|
||||||
unsigned char *ptr = (unsigned char *)read_token->data;
|
unsigned char *ptr = (unsigned char *)read_token->data;
|
||||||
int bodysize;
|
int bodysize;
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
|
|||||||
BUG_ON((buf->len - offset) % blocksize);
|
BUG_ON((buf->len - offset) % blocksize);
|
||||||
plainlen = blocksize + buf->len - offset;
|
plainlen = blocksize + buf->len - offset;
|
||||||
|
|
||||||
headlen = g_token_size(&kctx->mech_used, 22 + plainlen) -
|
headlen = g_token_size(&kctx->mech_used, 24 + plainlen) -
|
||||||
(buf->len - offset);
|
(buf->len - offset);
|
||||||
|
|
||||||
ptr = buf->head[0].iov_base + offset;
|
ptr = buf->head[0].iov_base + offset;
|
||||||
@@ -149,7 +149,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
|
|||||||
buf->len += headlen;
|
buf->len += headlen;
|
||||||
BUG_ON((buf->len - offset - headlen) % blocksize);
|
BUG_ON((buf->len - offset - headlen) % blocksize);
|
||||||
|
|
||||||
g_make_token_header(&kctx->mech_used, 22 + plainlen, &ptr);
|
g_make_token_header(&kctx->mech_used, 24 + plainlen, &ptr);
|
||||||
|
|
||||||
|
|
||||||
*ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
|
*ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
|
||||||
@@ -176,9 +176,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
|
|||||||
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
|
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
|
||||||
md5cksum.data, md5cksum.len))
|
md5cksum.data, md5cksum.len))
|
||||||
return GSS_S_FAILURE;
|
return GSS_S_FAILURE;
|
||||||
memcpy(krb5_hdr + 16,
|
memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
|
||||||
md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
|
|
||||||
KRB5_CKSUM_LENGTH);
|
|
||||||
|
|
||||||
spin_lock(&krb5_seq_lock);
|
spin_lock(&krb5_seq_lock);
|
||||||
seq_send = kctx->seq_send++;
|
seq_send = kctx->seq_send++;
|
||||||
|
|||||||
@@ -107,10 +107,10 @@ spkm3_make_token(struct spkm3_ctx *ctx,
|
|||||||
tokenlen = 10 + ctxelen + 1 + md5elen + 1;
|
tokenlen = 10 + ctxelen + 1 + md5elen + 1;
|
||||||
|
|
||||||
/* Create token header using generic routines */
|
/* Create token header using generic routines */
|
||||||
token->len = g_token_size(&ctx->mech_used, tokenlen);
|
token->len = g_token_size(&ctx->mech_used, tokenlen + 2);
|
||||||
|
|
||||||
ptr = token->data;
|
ptr = token->data;
|
||||||
g_make_token_header(&ctx->mech_used, tokenlen, &ptr);
|
g_make_token_header(&ctx->mech_used, tokenlen + 2, &ptr);
|
||||||
|
|
||||||
spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
|
spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
|
||||||
} else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
|
} else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
|
||||||
|
|||||||
@@ -1146,7 +1146,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
|
|||||||
case RPC_GSS_SVC_INTEGRITY:
|
case RPC_GSS_SVC_INTEGRITY:
|
||||||
if (unwrap_integ_data(&rqstp->rq_arg,
|
if (unwrap_integ_data(&rqstp->rq_arg,
|
||||||
gc->gc_seq, rsci->mechctx))
|
gc->gc_seq, rsci->mechctx))
|
||||||
goto auth_err;
|
goto garbage_args;
|
||||||
/* placeholders for length and seq. number: */
|
/* placeholders for length and seq. number: */
|
||||||
svc_putnl(resv, 0);
|
svc_putnl(resv, 0);
|
||||||
svc_putnl(resv, 0);
|
svc_putnl(resv, 0);
|
||||||
@@ -1154,7 +1154,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
|
|||||||
case RPC_GSS_SVC_PRIVACY:
|
case RPC_GSS_SVC_PRIVACY:
|
||||||
if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
|
if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
|
||||||
gc->gc_seq, rsci->mechctx))
|
gc->gc_seq, rsci->mechctx))
|
||||||
goto auth_err;
|
goto garbage_args;
|
||||||
/* placeholders for length and seq. number: */
|
/* placeholders for length and seq. number: */
|
||||||
svc_putnl(resv, 0);
|
svc_putnl(resv, 0);
|
||||||
svc_putnl(resv, 0);
|
svc_putnl(resv, 0);
|
||||||
@@ -1169,6 +1169,11 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
|
|||||||
ret = SVC_OK;
|
ret = SVC_OK;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
garbage_args:
|
||||||
|
/* Restore write pointer to its original value: */
|
||||||
|
xdr_ressize_check(rqstp, reject_stat);
|
||||||
|
ret = SVC_GARBAGE;
|
||||||
|
goto out;
|
||||||
auth_err:
|
auth_err:
|
||||||
/* Restore write pointer to its original value: */
|
/* Restore write pointer to its original value: */
|
||||||
xdr_ressize_check(rqstp, reject_stat);
|
xdr_ressize_check(rqstp, reject_stat);
|
||||||
|
|||||||
@@ -571,7 +571,6 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
|
|||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
dreq->item = item;
|
dreq->item = item;
|
||||||
dreq->recv_time = get_seconds();
|
|
||||||
|
|
||||||
spin_lock(&cache_defer_lock);
|
spin_lock(&cache_defer_lock);
|
||||||
|
|
||||||
|
|||||||
@@ -510,8 +510,7 @@ EXPORT_SYMBOL(svc_destroy);
|
|||||||
static int
|
static int
|
||||||
svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
|
svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
|
||||||
{
|
{
|
||||||
int pages;
|
unsigned int pages, arghi;
|
||||||
int arghi;
|
|
||||||
|
|
||||||
pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
|
pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
|
||||||
* We assume one is at most one page
|
* We assume one is at most one page
|
||||||
@@ -525,7 +524,7 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
|
|||||||
rqstp->rq_pages[arghi++] = p;
|
rqstp->rq_pages[arghi++] = p;
|
||||||
pages--;
|
pages--;
|
||||||
}
|
}
|
||||||
return ! pages;
|
return pages == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -534,8 +533,9 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
|
|||||||
static void
|
static void
|
||||||
svc_release_buffer(struct svc_rqst *rqstp)
|
svc_release_buffer(struct svc_rqst *rqstp)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++)
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
|
||||||
if (rqstp->rq_pages[i])
|
if (rqstp->rq_pages[i])
|
||||||
put_page(rqstp->rq_pages[i]);
|
put_page(rqstp->rq_pages[i]);
|
||||||
}
|
}
|
||||||
@@ -590,7 +590,7 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
|
|||||||
struct svc_rqst *rqstp;
|
struct svc_rqst *rqstp;
|
||||||
int error = -ENOMEM;
|
int error = -ENOMEM;
|
||||||
int have_oldmask = 0;
|
int have_oldmask = 0;
|
||||||
cpumask_t oldmask;
|
cpumask_t uninitialized_var(oldmask);
|
||||||
|
|
||||||
rqstp = svc_prepare_thread(serv, pool);
|
rqstp = svc_prepare_thread(serv, pool);
|
||||||
if (IS_ERR(rqstp)) {
|
if (IS_ERR(rqstp)) {
|
||||||
@@ -618,16 +618,6 @@ out_thread:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a thread in the default pool. Caller must hold BKL.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
|
|
||||||
{
|
|
||||||
return __svc_create_thread(func, serv, &serv->sv_pools[0]);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(svc_create_thread);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Choose a pool in which to create a new thread, for svc_set_num_threads
|
* Choose a pool in which to create a new thread, for svc_set_num_threads
|
||||||
*/
|
*/
|
||||||
@@ -921,8 +911,7 @@ svc_process(struct svc_rqst *rqstp)
|
|||||||
case SVC_OK:
|
case SVC_OK:
|
||||||
break;
|
break;
|
||||||
case SVC_GARBAGE:
|
case SVC_GARBAGE:
|
||||||
rpc_stat = rpc_garbage_args;
|
goto err_garbage;
|
||||||
goto err_bad;
|
|
||||||
case SVC_SYSERR:
|
case SVC_SYSERR:
|
||||||
rpc_stat = rpc_system_err;
|
rpc_stat = rpc_system_err;
|
||||||
goto err_bad;
|
goto err_bad;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
#include <net/checksum.h>
|
#include <net/checksum.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
@@ -586,8 +587,12 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
|||||||
while (rqstp->rq_pages[i] == NULL) {
|
while (rqstp->rq_pages[i] == NULL) {
|
||||||
struct page *p = alloc_page(GFP_KERNEL);
|
struct page *p = alloc_page(GFP_KERNEL);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
int j = msecs_to_jiffies(500);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
schedule_timeout_uninterruptible(j);
|
if (signalled() || kthread_should_stop()) {
|
||||||
|
set_current_state(TASK_RUNNING);
|
||||||
|
return -EINTR;
|
||||||
|
}
|
||||||
|
schedule_timeout(msecs_to_jiffies(500));
|
||||||
}
|
}
|
||||||
rqstp->rq_pages[i] = p;
|
rqstp->rq_pages[i] = p;
|
||||||
}
|
}
|
||||||
@@ -607,7 +612,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
|||||||
|
|
||||||
try_to_freeze();
|
try_to_freeze();
|
||||||
cond_resched();
|
cond_resched();
|
||||||
if (signalled())
|
if (signalled() || kthread_should_stop())
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
|
|
||||||
spin_lock_bh(&pool->sp_lock);
|
spin_lock_bh(&pool->sp_lock);
|
||||||
@@ -626,6 +631,20 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
|||||||
* to bring down the daemons ...
|
* to bring down the daemons ...
|
||||||
*/
|
*/
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* checking kthread_should_stop() here allows us to avoid
|
||||||
|
* locking and signalling when stopping kthreads that call
|
||||||
|
* svc_recv. If the thread has already been woken up, then
|
||||||
|
* we can exit here without sleeping. If not, then it
|
||||||
|
* it'll be woken up quickly during the schedule_timeout
|
||||||
|
*/
|
||||||
|
if (kthread_should_stop()) {
|
||||||
|
set_current_state(TASK_RUNNING);
|
||||||
|
spin_unlock_bh(&pool->sp_lock);
|
||||||
|
return -EINTR;
|
||||||
|
}
|
||||||
|
|
||||||
add_wait_queue(&rqstp->rq_wait, &wait);
|
add_wait_queue(&rqstp->rq_wait, &wait);
|
||||||
spin_unlock_bh(&pool->sp_lock);
|
spin_unlock_bh(&pool->sp_lock);
|
||||||
|
|
||||||
@@ -641,7 +660,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
|||||||
svc_thread_dequeue(pool, rqstp);
|
svc_thread_dequeue(pool, rqstp);
|
||||||
spin_unlock_bh(&pool->sp_lock);
|
spin_unlock_bh(&pool->sp_lock);
|
||||||
dprintk("svc: server %p, no data yet\n", rqstp);
|
dprintk("svc: server %p, no data yet\n", rqstp);
|
||||||
return signalled()? -EINTR : -EAGAIN;
|
if (signalled() || kthread_should_stop())
|
||||||
|
return -EINTR;
|
||||||
|
else
|
||||||
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&pool->sp_lock);
|
spin_unlock_bh(&pool->sp_lock);
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
#include <linux/hash.h>
|
#include <linux/hash.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#define RPCDBG_FACILITY RPCDBG_AUTH
|
#define RPCDBG_FACILITY RPCDBG_AUTH
|
||||||
|
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ static void svcauth_unix_domain_release(struct auth_domain *dom)
|
|||||||
struct ip_map {
|
struct ip_map {
|
||||||
struct cache_head h;
|
struct cache_head h;
|
||||||
char m_class[8]; /* e.g. "nfsd" */
|
char m_class[8]; /* e.g. "nfsd" */
|
||||||
struct in_addr m_addr;
|
struct in6_addr m_addr;
|
||||||
struct unix_domain *m_client;
|
struct unix_domain *m_client;
|
||||||
int m_add_change;
|
int m_add_change;
|
||||||
};
|
};
|
||||||
@@ -113,12 +114,19 @@ static inline int hash_ip(__be32 ip)
|
|||||||
return (hash ^ (hash>>8)) & 0xff;
|
return (hash ^ (hash>>8)) & 0xff;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
static inline int hash_ip6(struct in6_addr ip)
|
||||||
|
{
|
||||||
|
return (hash_ip(ip.s6_addr32[0]) ^
|
||||||
|
hash_ip(ip.s6_addr32[1]) ^
|
||||||
|
hash_ip(ip.s6_addr32[2]) ^
|
||||||
|
hash_ip(ip.s6_addr32[3]));
|
||||||
|
}
|
||||||
static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
|
static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
|
||||||
{
|
{
|
||||||
struct ip_map *orig = container_of(corig, struct ip_map, h);
|
struct ip_map *orig = container_of(corig, struct ip_map, h);
|
||||||
struct ip_map *new = container_of(cnew, struct ip_map, h);
|
struct ip_map *new = container_of(cnew, struct ip_map, h);
|
||||||
return strcmp(orig->m_class, new->m_class) == 0
|
return strcmp(orig->m_class, new->m_class) == 0
|
||||||
&& orig->m_addr.s_addr == new->m_addr.s_addr;
|
&& ipv6_addr_equal(&orig->m_addr, &new->m_addr);
|
||||||
}
|
}
|
||||||
static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
|
static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
|
||||||
{
|
{
|
||||||
@@ -126,7 +134,7 @@ static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
|
|||||||
struct ip_map *item = container_of(citem, struct ip_map, h);
|
struct ip_map *item = container_of(citem, struct ip_map, h);
|
||||||
|
|
||||||
strcpy(new->m_class, item->m_class);
|
strcpy(new->m_class, item->m_class);
|
||||||
new->m_addr.s_addr = item->m_addr.s_addr;
|
ipv6_addr_copy(&new->m_addr, &item->m_addr);
|
||||||
}
|
}
|
||||||
static void update(struct cache_head *cnew, struct cache_head *citem)
|
static void update(struct cache_head *cnew, struct cache_head *citem)
|
||||||
{
|
{
|
||||||
@@ -150,22 +158,24 @@ static void ip_map_request(struct cache_detail *cd,
|
|||||||
struct cache_head *h,
|
struct cache_head *h,
|
||||||
char **bpp, int *blen)
|
char **bpp, int *blen)
|
||||||
{
|
{
|
||||||
char text_addr[20];
|
char text_addr[40];
|
||||||
struct ip_map *im = container_of(h, struct ip_map, h);
|
struct ip_map *im = container_of(h, struct ip_map, h);
|
||||||
__be32 addr = im->m_addr.s_addr;
|
|
||||||
|
|
||||||
snprintf(text_addr, 20, "%u.%u.%u.%u",
|
|
||||||
ntohl(addr) >> 24 & 0xff,
|
|
||||||
ntohl(addr) >> 16 & 0xff,
|
|
||||||
ntohl(addr) >> 8 & 0xff,
|
|
||||||
ntohl(addr) >> 0 & 0xff);
|
|
||||||
|
|
||||||
|
if (ipv6_addr_v4mapped(&(im->m_addr))) {
|
||||||
|
snprintf(text_addr, 20, NIPQUAD_FMT,
|
||||||
|
ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff,
|
||||||
|
ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff,
|
||||||
|
ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff,
|
||||||
|
ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff);
|
||||||
|
} else {
|
||||||
|
snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr));
|
||||||
|
}
|
||||||
qword_add(bpp, blen, im->m_class);
|
qword_add(bpp, blen, im->m_class);
|
||||||
qword_add(bpp, blen, text_addr);
|
qword_add(bpp, blen, text_addr);
|
||||||
(*bpp)[-1] = '\n';
|
(*bpp)[-1] = '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);
|
static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr);
|
||||||
static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
|
static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
|
||||||
|
|
||||||
static int ip_map_parse(struct cache_detail *cd,
|
static int ip_map_parse(struct cache_detail *cd,
|
||||||
@@ -176,10 +186,10 @@ static int ip_map_parse(struct cache_detail *cd,
|
|||||||
* for scratch: */
|
* for scratch: */
|
||||||
char *buf = mesg;
|
char *buf = mesg;
|
||||||
int len;
|
int len;
|
||||||
int b1,b2,b3,b4;
|
int b1, b2, b3, b4, b5, b6, b7, b8;
|
||||||
char c;
|
char c;
|
||||||
char class[8];
|
char class[8];
|
||||||
struct in_addr addr;
|
struct in6_addr addr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
struct ip_map *ipmp;
|
struct ip_map *ipmp;
|
||||||
@@ -198,7 +208,23 @@ static int ip_map_parse(struct cache_detail *cd,
|
|||||||
len = qword_get(&mesg, buf, mlen);
|
len = qword_get(&mesg, buf, mlen);
|
||||||
if (len <= 0) return -EINVAL;
|
if (len <= 0) return -EINVAL;
|
||||||
|
|
||||||
if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
|
if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) {
|
||||||
|
addr.s6_addr32[0] = 0;
|
||||||
|
addr.s6_addr32[1] = 0;
|
||||||
|
addr.s6_addr32[2] = htonl(0xffff);
|
||||||
|
addr.s6_addr32[3] =
|
||||||
|
htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
|
||||||
|
} else if (sscanf(buf, NIP6_FMT "%c",
|
||||||
|
&b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
|
||||||
|
addr.s6_addr16[0] = htons(b1);
|
||||||
|
addr.s6_addr16[1] = htons(b2);
|
||||||
|
addr.s6_addr16[2] = htons(b3);
|
||||||
|
addr.s6_addr16[3] = htons(b4);
|
||||||
|
addr.s6_addr16[4] = htons(b5);
|
||||||
|
addr.s6_addr16[5] = htons(b6);
|
||||||
|
addr.s6_addr16[6] = htons(b7);
|
||||||
|
addr.s6_addr16[7] = htons(b8);
|
||||||
|
} else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
expiry = get_expiry(&mesg);
|
expiry = get_expiry(&mesg);
|
||||||
@@ -216,10 +242,7 @@ static int ip_map_parse(struct cache_detail *cd,
|
|||||||
} else
|
} else
|
||||||
dom = NULL;
|
dom = NULL;
|
||||||
|
|
||||||
addr.s_addr =
|
ipmp = ip_map_lookup(class, &addr);
|
||||||
htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
|
|
||||||
|
|
||||||
ipmp = ip_map_lookup(class,addr);
|
|
||||||
if (ipmp) {
|
if (ipmp) {
|
||||||
err = ip_map_update(ipmp,
|
err = ip_map_update(ipmp,
|
||||||
container_of(dom, struct unix_domain, h),
|
container_of(dom, struct unix_domain, h),
|
||||||
@@ -239,7 +262,7 @@ static int ip_map_show(struct seq_file *m,
|
|||||||
struct cache_head *h)
|
struct cache_head *h)
|
||||||
{
|
{
|
||||||
struct ip_map *im;
|
struct ip_map *im;
|
||||||
struct in_addr addr;
|
struct in6_addr addr;
|
||||||
char *dom = "-no-domain-";
|
char *dom = "-no-domain-";
|
||||||
|
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
@@ -248,20 +271,24 @@ static int ip_map_show(struct seq_file *m,
|
|||||||
}
|
}
|
||||||
im = container_of(h, struct ip_map, h);
|
im = container_of(h, struct ip_map, h);
|
||||||
/* class addr domain */
|
/* class addr domain */
|
||||||
addr = im->m_addr;
|
ipv6_addr_copy(&addr, &im->m_addr);
|
||||||
|
|
||||||
if (test_bit(CACHE_VALID, &h->flags) &&
|
if (test_bit(CACHE_VALID, &h->flags) &&
|
||||||
!test_bit(CACHE_NEGATIVE, &h->flags))
|
!test_bit(CACHE_NEGATIVE, &h->flags))
|
||||||
dom = im->m_client->h.name;
|
dom = im->m_client->h.name;
|
||||||
|
|
||||||
seq_printf(m, "%s %d.%d.%d.%d %s\n",
|
if (ipv6_addr_v4mapped(&addr)) {
|
||||||
im->m_class,
|
seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
|
||||||
ntohl(addr.s_addr) >> 24 & 0xff,
|
im->m_class,
|
||||||
ntohl(addr.s_addr) >> 16 & 0xff,
|
ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
|
||||||
ntohl(addr.s_addr) >> 8 & 0xff,
|
ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
|
||||||
ntohl(addr.s_addr) >> 0 & 0xff,
|
ntohl(addr.s6_addr32[3]) >> 8 & 0xff,
|
||||||
dom
|
ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
|
||||||
);
|
dom);
|
||||||
|
} else {
|
||||||
|
seq_printf(m, "%s" NIP6_FMT "%s\n",
|
||||||
|
im->m_class, NIP6(addr), dom);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,16 +308,16 @@ struct cache_detail ip_map_cache = {
|
|||||||
.alloc = ip_map_alloc,
|
.alloc = ip_map_alloc,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ip_map *ip_map_lookup(char *class, struct in_addr addr)
|
static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct ip_map ip;
|
struct ip_map ip;
|
||||||
struct cache_head *ch;
|
struct cache_head *ch;
|
||||||
|
|
||||||
strcpy(ip.m_class, class);
|
strcpy(ip.m_class, class);
|
||||||
ip.m_addr = addr;
|
ipv6_addr_copy(&ip.m_addr, addr);
|
||||||
ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
|
ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,
|
||||||
hash_str(class, IP_HASHBITS) ^
|
hash_str(class, IP_HASHBITS) ^
|
||||||
hash_ip(addr.s_addr));
|
hash_ip6(*addr));
|
||||||
|
|
||||||
if (ch)
|
if (ch)
|
||||||
return container_of(ch, struct ip_map, h);
|
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
|
|||||||
ch = sunrpc_cache_update(&ip_map_cache,
|
ch = sunrpc_cache_update(&ip_map_cache,
|
||||||
&ip.h, &ipm->h,
|
&ip.h, &ipm->h,
|
||||||
hash_str(ipm->m_class, IP_HASHBITS) ^
|
hash_str(ipm->m_class, IP_HASHBITS) ^
|
||||||
hash_ip(ipm->m_addr.s_addr));
|
hash_ip6(ipm->m_addr));
|
||||||
if (!ch)
|
if (!ch)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
cache_put(ch, &ip_map_cache);
|
cache_put(ch, &ip_map_cache);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
|
int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
|
||||||
{
|
{
|
||||||
struct unix_domain *udom;
|
struct unix_domain *udom;
|
||||||
struct ip_map *ipmp;
|
struct ip_map *ipmp;
|
||||||
@@ -355,7 +382,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(auth_unix_forget_old);
|
EXPORT_SYMBOL(auth_unix_forget_old);
|
||||||
|
|
||||||
struct auth_domain *auth_unix_lookup(struct in_addr addr)
|
struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct ip_map *ipm;
|
struct ip_map *ipm;
|
||||||
struct auth_domain *rv;
|
struct auth_domain *rv;
|
||||||
@@ -650,9 +677,24 @@ static int unix_gid_find(uid_t uid, struct group_info **gip,
|
|||||||
int
|
int
|
||||||
svcauth_unix_set_client(struct svc_rqst *rqstp)
|
svcauth_unix_set_client(struct svc_rqst *rqstp)
|
||||||
{
|
{
|
||||||
struct sockaddr_in *sin = svc_addr_in(rqstp);
|
struct sockaddr_in *sin;
|
||||||
|
struct sockaddr_in6 *sin6, sin6_storage;
|
||||||
struct ip_map *ipm;
|
struct ip_map *ipm;
|
||||||
|
|
||||||
|
switch (rqstp->rq_addr.ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
sin = svc_addr_in(rqstp);
|
||||||
|
sin6 = &sin6_storage;
|
||||||
|
ipv6_addr_set(&sin6->sin6_addr, 0, 0,
|
||||||
|
htonl(0x0000FFFF), sin->sin_addr.s_addr);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
sin6 = svc_addr_in6(rqstp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
rqstp->rq_client = NULL;
|
rqstp->rq_client = NULL;
|
||||||
if (rqstp->rq_proc == 0)
|
if (rqstp->rq_proc == 0)
|
||||||
return SVC_OK;
|
return SVC_OK;
|
||||||
@@ -660,7 +702,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
|
|||||||
ipm = ip_map_cached_get(rqstp);
|
ipm = ip_map_cached_get(rqstp);
|
||||||
if (ipm == NULL)
|
if (ipm == NULL)
|
||||||
ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
|
ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
|
||||||
sin->sin_addr);
|
&sin6->sin6_addr);
|
||||||
|
|
||||||
if (ipm == NULL)
|
if (ipm == NULL)
|
||||||
return SVC_DENIED;
|
return SVC_DENIED;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include <net/checksum.h>
|
#include <net/checksum.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
|
#include <net/tcp.h>
|
||||||
#include <net/tcp_states.h>
|
#include <net/tcp_states.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/ioctls.h>
|
#include <asm/ioctls.h>
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
#include <linux/sunrpc/types.h>
|
#include <linux/sunrpc/types.h>
|
||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
#include <linux/sunrpc/xdr.h>
|
#include <linux/sunrpc/xdr.h>
|
||||||
|
#include <linux/sunrpc/msg_prot.h>
|
||||||
#include <linux/sunrpc/svcsock.h>
|
#include <linux/sunrpc/svcsock.h>
|
||||||
#include <linux/sunrpc/stats.h>
|
#include <linux/sunrpc/stats.h>
|
||||||
|
|
||||||
@@ -822,8 +824,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
|
|||||||
* the next four bytes. Otherwise try to gobble up as much as
|
* the next four bytes. Otherwise try to gobble up as much as
|
||||||
* possible up to the complete record length.
|
* possible up to the complete record length.
|
||||||
*/
|
*/
|
||||||
if (svsk->sk_tcplen < 4) {
|
if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
|
||||||
unsigned long want = 4 - svsk->sk_tcplen;
|
int want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
|
||||||
struct kvec iov;
|
struct kvec iov;
|
||||||
|
|
||||||
iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen;
|
iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen;
|
||||||
@@ -833,32 +835,31 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
|
|||||||
svsk->sk_tcplen += len;
|
svsk->sk_tcplen += len;
|
||||||
|
|
||||||
if (len < want) {
|
if (len < want) {
|
||||||
dprintk("svc: short recvfrom while reading record length (%d of %lu)\n",
|
dprintk("svc: short recvfrom while reading record "
|
||||||
len, want);
|
"length (%d of %d)\n", len, want);
|
||||||
svc_xprt_received(&svsk->sk_xprt);
|
svc_xprt_received(&svsk->sk_xprt);
|
||||||
return -EAGAIN; /* record header not complete */
|
return -EAGAIN; /* record header not complete */
|
||||||
}
|
}
|
||||||
|
|
||||||
svsk->sk_reclen = ntohl(svsk->sk_reclen);
|
svsk->sk_reclen = ntohl(svsk->sk_reclen);
|
||||||
if (!(svsk->sk_reclen & 0x80000000)) {
|
if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) {
|
||||||
/* FIXME: technically, a record can be fragmented,
|
/* FIXME: technically, a record can be fragmented,
|
||||||
* and non-terminal fragments will not have the top
|
* and non-terminal fragments will not have the top
|
||||||
* bit set in the fragment length header.
|
* bit set in the fragment length header.
|
||||||
* But apparently no known nfs clients send fragmented
|
* But apparently no known nfs clients send fragmented
|
||||||
* records. */
|
* records. */
|
||||||
if (net_ratelimit())
|
if (net_ratelimit())
|
||||||
printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
|
printk(KERN_NOTICE "RPC: multiple fragments "
|
||||||
" (non-terminal)\n",
|
"per record not supported\n");
|
||||||
(unsigned long) svsk->sk_reclen);
|
|
||||||
goto err_delete;
|
goto err_delete;
|
||||||
}
|
}
|
||||||
svsk->sk_reclen &= 0x7fffffff;
|
svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK;
|
||||||
dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
|
dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
|
||||||
if (svsk->sk_reclen > serv->sv_max_mesg) {
|
if (svsk->sk_reclen > serv->sv_max_mesg) {
|
||||||
if (net_ratelimit())
|
if (net_ratelimit())
|
||||||
printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
|
printk(KERN_NOTICE "RPC: "
|
||||||
" (large)\n",
|
"fragment too large: 0x%08lx\n",
|
||||||
(unsigned long) svsk->sk_reclen);
|
(unsigned long)svsk->sk_reclen);
|
||||||
goto err_delete;
|
goto err_delete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1045,7 +1046,6 @@ void svc_cleanup_xprt_sock(void)
|
|||||||
static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
|
static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
|
||||||
{
|
{
|
||||||
struct sock *sk = svsk->sk_sk;
|
struct sock *sk = svsk->sk_sk;
|
||||||
struct tcp_sock *tp = tcp_sk(sk);
|
|
||||||
|
|
||||||
svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
|
svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
|
||||||
set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
|
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)
|
|||||||
svsk->sk_reclen = 0;
|
svsk->sk_reclen = 0;
|
||||||
svsk->sk_tcplen = 0;
|
svsk->sk_tcplen = 0;
|
||||||
|
|
||||||
tp->nonagle = 1; /* disable Nagle's algorithm */
|
tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
|
||||||
|
|
||||||
/* initialise setting must have enough space to
|
/* initialise setting must have enough space to
|
||||||
* receive and respond to one request.
|
* receive and respond to one request.
|
||||||
@@ -1101,6 +1101,7 @@ void svc_sock_update_bufs(struct svc_serv *serv)
|
|||||||
}
|
}
|
||||||
spin_unlock_bh(&serv->sv_lock);
|
spin_unlock_bh(&serv->sv_lock);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(svc_sock_update_bufs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize socket for RPC use and create svc_sock struct
|
* Initialize socket for RPC use and create svc_sock struct
|
||||||
|
|||||||
@@ -1036,6 +1036,8 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
|
|||||||
wait_event(xprt->sc_send_wait,
|
wait_event(xprt->sc_send_wait,
|
||||||
atomic_read(&xprt->sc_sq_count) <
|
atomic_read(&xprt->sc_sq_count) <
|
||||||
xprt->sc_sq_depth);
|
xprt->sc_sq_depth);
|
||||||
|
if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
|
||||||
|
return 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Bumped used SQ WR count and post */
|
/* Bumped used SQ WR count and post */
|
||||||
|
|||||||
Reference in New Issue
Block a user