Merge branch 'for-2.6.30' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.30' of git://linux-nfs.org/~bfields/linux: (81 commits) nfsd41: define nfsd4_set_statp as noop for !CONFIG_NFSD_V4 nfsd41: define NFSD_DRC_SIZE_SHIFT in set_max_drc nfsd41: Documentation/filesystems/nfs41-server.txt nfsd41: CREATE_EXCLUSIVE4_1 nfsd41: SUPPATTR_EXCLCREAT attribute nfsd41: support for 3-word long attribute bitmask nfsd: dynamically skip encoded fattr bitmap in _nfsd4_verify nfsd41: pass writable attrs mask to nfsd4_decode_fattr nfsd41: provide support for minor version 1 at rpc level nfsd41: control nfsv4.1 svc via /proc/fs/nfsd/versions nfsd41: add OPEN4_SHARE_ACCESS_WANT nfs4_stateid bmap nfsd41: access_valid nfsd41: clientid handling nfsd41: check encode size for sessions maxresponse cached nfsd41: stateid handling nfsd: pass nfsd4_compound_state* to nfs4_preprocess_{state,seq}id_op nfsd41: destroy_session operation nfsd41: non-page DRC for solo sequence responses nfsd41: Add a create session replay cache nfsd41: create_session operation ...
This commit is contained in:
Коммит
a63856252d
|
@ -0,0 +1,159 @@
|
||||||
|
|
||||||
|
Kernel NFS Server Statistics
|
||||||
|
============================
|
||||||
|
|
||||||
|
This document describes the format and semantics of the statistics
|
||||||
|
which the kernel NFS server makes available to userspace. These
|
||||||
|
statistics are available in several text form pseudo files, each of
|
||||||
|
which is described separately below.
|
||||||
|
|
||||||
|
In most cases you don't need to know these formats, as the nfsstat(8)
|
||||||
|
program from the nfs-utils distribution provides a helpful command-line
|
||||||
|
interface for extracting and printing them.
|
||||||
|
|
||||||
|
All the files described here are formatted as a sequence of text lines,
|
||||||
|
separated by newline '\n' characters. Lines beginning with a hash
|
||||||
|
'#' character are comments intended for humans and should be ignored
|
||||||
|
by parsing routines. All other lines contain a sequence of fields
|
||||||
|
separated by whitespace.
|
||||||
|
|
||||||
|
/proc/fs/nfsd/pool_stats
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
This file is available in kernels from 2.6.30 onwards, if the
|
||||||
|
/proc/fs/nfsd filesystem is mounted (it almost always should be).
|
||||||
|
|
||||||
|
The first line is a comment which describes the fields present in
|
||||||
|
all the other lines. The other lines present the following data as
|
||||||
|
a sequence of unsigned decimal numeric fields. One line is shown
|
||||||
|
for each NFS thread pool.
|
||||||
|
|
||||||
|
All counters are 64 bits wide and wrap naturally. There is no way
|
||||||
|
to zero these counters, instead applications should do their own
|
||||||
|
rate conversion.
|
||||||
|
|
||||||
|
pool
|
||||||
|
The id number of the NFS thread pool to which this line applies.
|
||||||
|
This number does not change.
|
||||||
|
|
||||||
|
Thread pool ids are a contiguous set of small integers starting
|
||||||
|
at zero. The maximum value depends on the thread pool mode, but
|
||||||
|
currently cannot be larger than the number of CPUs in the system.
|
||||||
|
Note that in the default case there will be a single thread pool
|
||||||
|
which contains all the nfsd threads and all the CPUs in the system,
|
||||||
|
and thus this file will have a single line with a pool id of "0".
|
||||||
|
|
||||||
|
packets-arrived
|
||||||
|
Counts how many NFS packets have arrived. More precisely, this
|
||||||
|
is the number of times that the network stack has notified the
|
||||||
|
sunrpc server layer that new data may be available on a transport
|
||||||
|
(e.g. an NFS or UDP socket or an NFS/RDMA endpoint).
|
||||||
|
|
||||||
|
Depending on the NFS workload patterns and various network stack
|
||||||
|
effects (such as Large Receive Offload) which can combine packets
|
||||||
|
on the wire, this may be either more or less than the number
|
||||||
|
of NFS calls received (which statistic is available elsewhere).
|
||||||
|
However this is a more accurate and less workload-dependent measure
|
||||||
|
of how much CPU load is being placed on the sunrpc server layer
|
||||||
|
due to NFS network traffic.
|
||||||
|
|
||||||
|
sockets-enqueued
|
||||||
|
Counts how many times an NFS transport is enqueued to wait for
|
||||||
|
an nfsd thread to service it, i.e. no nfsd thread was considered
|
||||||
|
available.
|
||||||
|
|
||||||
|
The circumstance this statistic tracks indicates that there was NFS
|
||||||
|
network-facing work to be done but it couldn't be done immediately,
|
||||||
|
thus introducing a small delay in servicing NFS calls. The ideal
|
||||||
|
rate of change for this counter is zero; significantly non-zero
|
||||||
|
values may indicate a performance limitation.
|
||||||
|
|
||||||
|
This can happen either because there are too few nfsd threads in the
|
||||||
|
thread pool for the NFS workload (the workload is thread-limited),
|
||||||
|
or because the NFS workload needs more CPU time than is available in
|
||||||
|
the thread pool (the workload is CPU-limited). In the former case,
|
||||||
|
configuring more nfsd threads will probably improve the performance
|
||||||
|
of the NFS workload. In the latter case, the sunrpc server layer is
|
||||||
|
already choosing not to wake idle nfsd threads because there are too
|
||||||
|
many nfsd threads which want to run but cannot, so configuring more
|
||||||
|
nfsd threads will make no difference whatsoever. The overloads-avoided
|
||||||
|
statistic (see below) can be used to distinguish these cases.
|
||||||
|
|
||||||
|
threads-woken
|
||||||
|
Counts how many times an idle nfsd thread is woken to try to
|
||||||
|
receive some data from an NFS transport.
|
||||||
|
|
||||||
|
This statistic tracks the circumstance where incoming
|
||||||
|
network-facing NFS work is being handled quickly, which is a good
|
||||||
|
thing. The ideal rate of change for this counter will be close
|
||||||
|
to but less than the rate of change of the packets-arrived counter.
|
||||||
|
|
||||||
|
overloads-avoided
|
||||||
|
Counts how many times the sunrpc server layer chose not to wake an
|
||||||
|
nfsd thread, despite the presence of idle nfsd threads, because
|
||||||
|
too many nfsd threads had been recently woken but could not get
|
||||||
|
enough CPU time to actually run.
|
||||||
|
|
||||||
|
This statistic counts a circumstance where the sunrpc layer
|
||||||
|
heuristically avoids overloading the CPU scheduler with too many
|
||||||
|
runnable nfsd threads. The ideal rate of change for this counter
|
||||||
|
is zero. Significant non-zero values indicate that the workload
|
||||||
|
is CPU limited. Usually this is associated with heavy CPU usage
|
||||||
|
on all the CPUs in the nfsd thread pool.
|
||||||
|
|
||||||
|
If a sustained large overloads-avoided rate is detected on a pool,
|
||||||
|
the top(1) utility should be used to check for the following
|
||||||
|
pattern of CPU usage on all the CPUs associated with the given
|
||||||
|
nfsd thread pool.
|
||||||
|
|
||||||
|
- %us ~= 0 (as you're *NOT* running applications on your NFS server)
|
||||||
|
|
||||||
|
- %wa ~= 0
|
||||||
|
|
||||||
|
- %id ~= 0
|
||||||
|
|
||||||
|
- %sy + %hi + %si ~= 100
|
||||||
|
|
||||||
|
If this pattern is seen, configuring more nfsd threads will *not*
|
||||||
|
improve the performance of the workload. If this patten is not
|
||||||
|
seen, then something more subtle is wrong.
|
||||||
|
|
||||||
|
threads-timedout
|
||||||
|
Counts how many times an nfsd thread triggered an idle timeout,
|
||||||
|
i.e. was not woken to handle any incoming network packets for
|
||||||
|
some time.
|
||||||
|
|
||||||
|
This statistic counts a circumstance where there are more nfsd
|
||||||
|
threads configured than can be used by the NFS workload. This is
|
||||||
|
a clue that the number of nfsd threads can be reduced without
|
||||||
|
affecting performance. Unfortunately, it's only a clue and not
|
||||||
|
a strong indication, for a couple of reasons:
|
||||||
|
|
||||||
|
- Currently the rate at which the counter is incremented is quite
|
||||||
|
slow; the idle timeout is 60 minutes. Unless the NFS workload
|
||||||
|
remains constant for hours at a time, this counter is unlikely
|
||||||
|
to be providing information that is still useful.
|
||||||
|
|
||||||
|
- It is usually a wise policy to provide some slack,
|
||||||
|
i.e. configure a few more nfsds than are currently needed,
|
||||||
|
to allow for future spikes in load.
|
||||||
|
|
||||||
|
|
||||||
|
Note that incoming packets on NFS transports will be dealt with in
|
||||||
|
one of three ways. An nfsd thread can be woken (threads-woken counts
|
||||||
|
this case), or the transport can be enqueued for later attention
|
||||||
|
(sockets-enqueued counts this case), or the packet can be temporarily
|
||||||
|
deferred because the transport is currently being used by an nfsd
|
||||||
|
thread. This last case is not very interesting and is not explicitly
|
||||||
|
counted, but can be inferred from the other counters thus:
|
||||||
|
|
||||||
|
packets-deferred = packets-arrived - ( sockets-enqueued + threads-woken )
|
||||||
|
|
||||||
|
|
||||||
|
More
|
||||||
|
----
|
||||||
|
Descriptions of the other statistics file should go here.
|
||||||
|
|
||||||
|
|
||||||
|
Greg Banks <gnb@sgi.com>
|
||||||
|
26 Mar 2009
|
|
@ -0,0 +1,161 @@
|
||||||
|
NFSv4.1 Server Implementation
|
||||||
|
|
||||||
|
Server support for minorversion 1 can be controlled using the
|
||||||
|
/proc/fs/nfsd/versions control file. The string output returned
|
||||||
|
by reading this file will contain either "+4.1" or "-4.1"
|
||||||
|
correspondingly.
|
||||||
|
|
||||||
|
Currently, server support for minorversion 1 is disabled by default.
|
||||||
|
It can be enabled at run time by writing the string "+4.1" to
|
||||||
|
the /proc/fs/nfsd/versions control file. Note that to write this
|
||||||
|
control file, the nfsd service must be taken down. Use your user-mode
|
||||||
|
nfs-utils to set this up; see rpc.nfsd(8)
|
||||||
|
|
||||||
|
The NFSv4 minorversion 1 (NFSv4.1) implementation in nfsd is based
|
||||||
|
on the latest NFSv4.1 Internet Draft:
|
||||||
|
http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-29
|
||||||
|
|
||||||
|
From the many new features in NFSv4.1 the current implementation
|
||||||
|
focuses on the mandatory-to-implement NFSv4.1 Sessions, providing
|
||||||
|
"exactly once" semantics and better control and throttling of the
|
||||||
|
resources allocated for each client.
|
||||||
|
|
||||||
|
Other NFSv4.1 features, Parallel NFS operations in particular,
|
||||||
|
are still under development out of tree.
|
||||||
|
See http://wiki.linux-nfs.org/wiki/index.php/PNFS_prototype_design
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
The table below, taken from the NFSv4.1 document, lists
|
||||||
|
the operations that are mandatory to implement (REQ), optional
|
||||||
|
(OPT), and NFSv4.0 operations that are required not to implement (MNI)
|
||||||
|
in minor version 1. The first column indicates the operations that
|
||||||
|
are not supported yet by the linux server implementation.
|
||||||
|
|
||||||
|
The OPTIONAL features identified and their abbreviations are as follows:
|
||||||
|
pNFS Parallel NFS
|
||||||
|
FDELG File Delegations
|
||||||
|
DDELG Directory Delegations
|
||||||
|
|
||||||
|
The following abbreviations indicate the linux server implementation status.
|
||||||
|
I Implemented NFSv4.1 operations.
|
||||||
|
NS Not Supported.
|
||||||
|
NS* unimplemented optional feature.
|
||||||
|
P pNFS features implemented out of tree.
|
||||||
|
PNS pNFS features that are not supported yet (out of tree).
|
||||||
|
|
||||||
|
Operations
|
||||||
|
|
||||||
|
+----------------------+------------+--------------+----------------+
|
||||||
|
| Operation | REQ, REC, | Feature | Definition |
|
||||||
|
| | OPT, or | (REQ, REC, | |
|
||||||
|
| | MNI | or OPT) | |
|
||||||
|
+----------------------+------------+--------------+----------------+
|
||||||
|
| ACCESS | REQ | | Section 18.1 |
|
||||||
|
NS | BACKCHANNEL_CTL | REQ | | Section 18.33 |
|
||||||
|
NS | BIND_CONN_TO_SESSION | REQ | | Section 18.34 |
|
||||||
|
| CLOSE | REQ | | Section 18.2 |
|
||||||
|
| COMMIT | REQ | | Section 18.3 |
|
||||||
|
| CREATE | REQ | | Section 18.4 |
|
||||||
|
I | CREATE_SESSION | REQ | | Section 18.36 |
|
||||||
|
NS*| DELEGPURGE | OPT | FDELG (REQ) | Section 18.5 |
|
||||||
|
| DELEGRETURN | OPT | FDELG, | Section 18.6 |
|
||||||
|
| | | DDELG, pNFS | |
|
||||||
|
| | | (REQ) | |
|
||||||
|
NS | DESTROY_CLIENTID | REQ | | Section 18.50 |
|
||||||
|
I | DESTROY_SESSION | REQ | | Section 18.37 |
|
||||||
|
I | EXCHANGE_ID | REQ | | Section 18.35 |
|
||||||
|
NS | FREE_STATEID | REQ | | Section 18.38 |
|
||||||
|
| GETATTR | REQ | | Section 18.7 |
|
||||||
|
P | GETDEVICEINFO | OPT | pNFS (REQ) | Section 18.40 |
|
||||||
|
P | GETDEVICELIST | OPT | pNFS (OPT) | Section 18.41 |
|
||||||
|
| GETFH | REQ | | Section 18.8 |
|
||||||
|
NS*| GET_DIR_DELEGATION | OPT | DDELG (REQ) | Section 18.39 |
|
||||||
|
P | LAYOUTCOMMIT | OPT | pNFS (REQ) | Section 18.42 |
|
||||||
|
P | LAYOUTGET | OPT | pNFS (REQ) | Section 18.43 |
|
||||||
|
P | LAYOUTRETURN | OPT | pNFS (REQ) | Section 18.44 |
|
||||||
|
| LINK | OPT | | Section 18.9 |
|
||||||
|
| LOCK | REQ | | Section 18.10 |
|
||||||
|
| LOCKT | REQ | | Section 18.11 |
|
||||||
|
| LOCKU | REQ | | Section 18.12 |
|
||||||
|
| LOOKUP | REQ | | Section 18.13 |
|
||||||
|
| LOOKUPP | REQ | | Section 18.14 |
|
||||||
|
| NVERIFY | REQ | | Section 18.15 |
|
||||||
|
| OPEN | REQ | | Section 18.16 |
|
||||||
|
NS*| OPENATTR | OPT | | Section 18.17 |
|
||||||
|
| OPEN_CONFIRM | MNI | | N/A |
|
||||||
|
| OPEN_DOWNGRADE | REQ | | Section 18.18 |
|
||||||
|
| PUTFH | REQ | | Section 18.19 |
|
||||||
|
| PUTPUBFH | REQ | | Section 18.20 |
|
||||||
|
| PUTROOTFH | REQ | | Section 18.21 |
|
||||||
|
| READ | REQ | | Section 18.22 |
|
||||||
|
| READDIR | REQ | | Section 18.23 |
|
||||||
|
| READLINK | OPT | | Section 18.24 |
|
||||||
|
NS | RECLAIM_COMPLETE | REQ | | Section 18.51 |
|
||||||
|
| RELEASE_LOCKOWNER | MNI | | N/A |
|
||||||
|
| REMOVE | REQ | | Section 18.25 |
|
||||||
|
| RENAME | REQ | | Section 18.26 |
|
||||||
|
| RENEW | MNI | | N/A |
|
||||||
|
| RESTOREFH | REQ | | Section 18.27 |
|
||||||
|
| SAVEFH | REQ | | Section 18.28 |
|
||||||
|
| SECINFO | REQ | | Section 18.29 |
|
||||||
|
NS | SECINFO_NO_NAME | REC | pNFS files | Section 18.45, |
|
||||||
|
| | | layout (REQ) | Section 13.12 |
|
||||||
|
I | SEQUENCE | REQ | | Section 18.46 |
|
||||||
|
| SETATTR | REQ | | Section 18.30 |
|
||||||
|
| SETCLIENTID | MNI | | N/A |
|
||||||
|
| SETCLIENTID_CONFIRM | MNI | | N/A |
|
||||||
|
NS | SET_SSV | REQ | | Section 18.47 |
|
||||||
|
NS | TEST_STATEID | REQ | | Section 18.48 |
|
||||||
|
| VERIFY | REQ | | Section 18.31 |
|
||||||
|
NS*| WANT_DELEGATION | OPT | FDELG (OPT) | Section 18.49 |
|
||||||
|
| WRITE | REQ | | Section 18.32 |
|
||||||
|
|
||||||
|
Callback Operations
|
||||||
|
|
||||||
|
+-------------------------+-----------+-------------+---------------+
|
||||||
|
| Operation | REQ, REC, | Feature | Definition |
|
||||||
|
| | OPT, or | (REQ, REC, | |
|
||||||
|
| | MNI | or OPT) | |
|
||||||
|
+-------------------------+-----------+-------------+---------------+
|
||||||
|
| CB_GETATTR | OPT | FDELG (REQ) | Section 20.1 |
|
||||||
|
P | CB_LAYOUTRECALL | OPT | pNFS (REQ) | Section 20.3 |
|
||||||
|
NS*| CB_NOTIFY | OPT | DDELG (REQ) | Section 20.4 |
|
||||||
|
P | CB_NOTIFY_DEVICEID | OPT | pNFS (OPT) | Section 20.12 |
|
||||||
|
NS*| CB_NOTIFY_LOCK | OPT | | Section 20.11 |
|
||||||
|
NS*| CB_PUSH_DELEG | OPT | FDELG (OPT) | Section 20.5 |
|
||||||
|
| CB_RECALL | OPT | FDELG, | Section 20.2 |
|
||||||
|
| | | DDELG, pNFS | |
|
||||||
|
| | | (REQ) | |
|
||||||
|
NS*| CB_RECALL_ANY | OPT | FDELG, | Section 20.6 |
|
||||||
|
| | | DDELG, pNFS | |
|
||||||
|
| | | (REQ) | |
|
||||||
|
NS | CB_RECALL_SLOT | REQ | | Section 20.8 |
|
||||||
|
NS*| CB_RECALLABLE_OBJ_AVAIL | OPT | DDELG, pNFS | Section 20.7 |
|
||||||
|
| | | (REQ) | |
|
||||||
|
I | CB_SEQUENCE | OPT | FDELG, | Section 20.9 |
|
||||||
|
| | | DDELG, pNFS | |
|
||||||
|
| | | (REQ) | |
|
||||||
|
NS*| CB_WANTS_CANCELLED | OPT | FDELG, | Section 20.10 |
|
||||||
|
| | | DDELG, pNFS | |
|
||||||
|
| | | (REQ) | |
|
||||||
|
+-------------------------+-----------+-------------+---------------+
|
||||||
|
|
||||||
|
Implementation notes:
|
||||||
|
|
||||||
|
EXCHANGE_ID:
|
||||||
|
* only SP4_NONE state protection supported
|
||||||
|
* implementation ids are ignored
|
||||||
|
|
||||||
|
CREATE_SESSION:
|
||||||
|
* backchannel attributes are ignored
|
||||||
|
* backchannel security parameters are ignored
|
||||||
|
|
||||||
|
SEQUENCE:
|
||||||
|
* no support for dynamic slot table renegotiation (optional)
|
||||||
|
|
||||||
|
nfsv4.1 COMPOUND rules:
|
||||||
|
The following cases aren't supported yet:
|
||||||
|
* Enforcing of NFS4ERR_NOT_ONLY_OP for: BIND_CONN_TO_SESSION, CREATE_SESSION,
|
||||||
|
DESTROY_CLIENTID, DESTROY_SESSION, EXCHANGE_ID.
|
||||||
|
* DESTROY_SESSION MUST be the final operation in the COMPOUND request.
|
||||||
|
|
|
@ -426,8 +426,15 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||||
ret = nlm_granted;
|
ret = nlm_granted;
|
||||||
goto out;
|
goto out;
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
|
/*
|
||||||
|
* If this is a blocking request for an
|
||||||
|
* already pending lock request then we need
|
||||||
|
* to put it back on lockd's block list
|
||||||
|
*/
|
||||||
|
if (wait)
|
||||||
|
break;
|
||||||
ret = nlm_lck_denied;
|
ret = nlm_lck_denied;
|
||||||
break;
|
goto out;
|
||||||
case FILE_LOCK_DEFERRED:
|
case FILE_LOCK_DEFERRED:
|
||||||
if (wait)
|
if (wait)
|
||||||
break;
|
break;
|
||||||
|
@ -443,10 +450,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nlm_lck_denied;
|
|
||||||
if (!wait)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = nlm_lck_blocked;
|
ret = nlm_lck_blocked;
|
||||||
|
|
||||||
/* Append to list of blocked */
|
/* Append to list of blocked */
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
config NFSD
|
config NFSD
|
||||||
tristate "NFS server support"
|
tristate "NFS server support"
|
||||||
depends on INET
|
depends on INET
|
||||||
|
depends on FILE_LOCKING
|
||||||
select LOCKD
|
select LOCKD
|
||||||
select SUNRPC
|
select SUNRPC
|
||||||
select EXPORTFS
|
select EXPORTFS
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/unistd.h>
|
#include <linux/unistd.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/major.h>
|
#include <linux/major.h>
|
||||||
|
#include <linux/magic.h>
|
||||||
|
|
||||||
#include <linux/sunrpc/svc.h>
|
#include <linux/sunrpc/svc.h>
|
||||||
#include <linux/nfsd/nfsd.h>
|
#include <linux/nfsd/nfsd.h>
|
||||||
|
@ -202,6 +203,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
|
||||||
struct nfsd3_writeres *resp)
|
struct nfsd3_writeres *resp)
|
||||||
{
|
{
|
||||||
__be32 nfserr;
|
__be32 nfserr;
|
||||||
|
unsigned long cnt = argp->len;
|
||||||
|
|
||||||
dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
|
dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
|
||||||
SVCFH_fmt(&argp->fh),
|
SVCFH_fmt(&argp->fh),
|
||||||
|
@ -214,9 +216,9 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
|
||||||
nfserr = nfsd_write(rqstp, &resp->fh, NULL,
|
nfserr = nfsd_write(rqstp, &resp->fh, NULL,
|
||||||
argp->offset,
|
argp->offset,
|
||||||
rqstp->rq_vec, argp->vlen,
|
rqstp->rq_vec, argp->vlen,
|
||||||
argp->len,
|
&cnt,
|
||||||
&resp->committed);
|
&resp->committed);
|
||||||
resp->count = argp->count;
|
resp->count = cnt;
|
||||||
RETURN_STATUS(nfserr);
|
RETURN_STATUS(nfserr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,7 +571,7 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
|
||||||
struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
|
struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
|
||||||
|
|
||||||
/* Note that we don't care for remote fs's here */
|
/* Note that we don't care for remote fs's here */
|
||||||
if (sb->s_magic == 0x4d44 /* MSDOS_SUPER_MAGIC */) {
|
if (sb->s_magic == MSDOS_SUPER_MAGIC) {
|
||||||
resp->f_properties = NFS3_FSF_BILLYBOY;
|
resp->f_properties = NFS3_FSF_BILLYBOY;
|
||||||
}
|
}
|
||||||
resp->f_maxfilesize = sb->s_maxbytes;
|
resp->f_maxfilesize = sb->s_maxbytes;
|
||||||
|
@ -610,7 +612,7 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
|
||||||
resp->p_link_max = EXT2_LINK_MAX;
|
resp->p_link_max = EXT2_LINK_MAX;
|
||||||
resp->p_name_max = EXT2_NAME_LEN;
|
resp->p_name_max = EXT2_NAME_LEN;
|
||||||
break;
|
break;
|
||||||
case 0x4d44: /* MSDOS_SUPER_MAGIC */
|
case MSDOS_SUPER_MAGIC:
|
||||||
resp->p_case_insensitive = 1;
|
resp->p_case_insensitive = 1;
|
||||||
resp->p_case_preserving = 0;
|
resp->p_case_preserving = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -218,7 +218,7 @@ static int
|
||||||
encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
|
encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
|
||||||
{
|
{
|
||||||
__be32 *p;
|
__be32 *p;
|
||||||
int len = cb_rec->cbr_fhlen;
|
int len = cb_rec->cbr_fh.fh_size;
|
||||||
|
|
||||||
RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
|
RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
|
||||||
WRITE32(OP_CB_RECALL);
|
WRITE32(OP_CB_RECALL);
|
||||||
|
@ -226,7 +226,7 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
|
||||||
WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t));
|
WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t));
|
||||||
WRITE32(cb_rec->cbr_trunc);
|
WRITE32(cb_rec->cbr_trunc);
|
||||||
WRITE32(len);
|
WRITE32(len);
|
||||||
WRITEMEM(cb_rec->cbr_fhval, len);
|
WRITEMEM(&cb_rec->cbr_fh.fh_base, len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,9 +361,8 @@ static struct rpc_program cb_program = {
|
||||||
/* 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? */
|
||||||
|
|
||||||
static int do_probe_callback(void *data)
|
static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp)
|
||||||
{
|
{
|
||||||
struct nfs4_client *clp = data;
|
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
struct nfs4_callback *cb = &clp->cl_callback;
|
struct nfs4_callback *cb = &clp->cl_callback;
|
||||||
struct rpc_timeout timeparms = {
|
struct rpc_timeout timeparms = {
|
||||||
|
@ -384,17 +383,10 @@ static int do_probe_callback(void *data)
|
||||||
.flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
|
.flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
|
||||||
.client_name = clp->cl_principal,
|
.client_name = clp->cl_principal,
|
||||||
};
|
};
|
||||||
struct rpc_message msg = {
|
|
||||||
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
|
|
||||||
.rpc_argp = clp,
|
|
||||||
};
|
|
||||||
struct rpc_clnt *client;
|
struct rpc_clnt *client;
|
||||||
int status;
|
|
||||||
|
|
||||||
if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) {
|
if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
|
||||||
status = nfserr_cb_path_down;
|
return ERR_PTR(-EINVAL);
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize address */
|
/* Initialize address */
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
@ -404,9 +396,29 @@ static int do_probe_callback(void *data)
|
||||||
|
|
||||||
/* Create RPC client */
|
/* Create RPC client */
|
||||||
client = rpc_create(&args);
|
client = rpc_create(&args);
|
||||||
|
if (IS_ERR(client))
|
||||||
|
dprintk("NFSD: couldn't create callback client: %ld\n",
|
||||||
|
PTR_ERR(client));
|
||||||
|
return client;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_probe_callback(void *data)
|
||||||
|
{
|
||||||
|
struct nfs4_client *clp = data;
|
||||||
|
struct nfs4_callback *cb = &clp->cl_callback;
|
||||||
|
struct rpc_message msg = {
|
||||||
|
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
|
||||||
|
.rpc_argp = clp,
|
||||||
|
};
|
||||||
|
struct rpc_clnt *client;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
client = setup_callback_client(clp);
|
||||||
if (IS_ERR(client)) {
|
if (IS_ERR(client)) {
|
||||||
dprintk("NFSD: couldn't create callback client\n");
|
|
||||||
status = PTR_ERR(client);
|
status = PTR_ERR(client);
|
||||||
|
dprintk("NFSD: couldn't create callback client: %d\n",
|
||||||
|
status);
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,10 +434,10 @@ static int do_probe_callback(void *data)
|
||||||
out_release_client:
|
out_release_client:
|
||||||
rpc_shutdown_client(client);
|
rpc_shutdown_client(client);
|
||||||
out_err:
|
out_err:
|
||||||
dprintk("NFSD: warning: no callback path to client %.*s\n",
|
dprintk("NFSD: warning: no callback path to client %.*s: error %d\n",
|
||||||
(int)clp->cl_name.len, clp->cl_name.data);
|
(int)clp->cl_name.len, clp->cl_name.data, status);
|
||||||
put_nfs4_client(clp);
|
put_nfs4_client(clp);
|
||||||
return status;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -451,7 +463,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* called with dp->dl_count inc'ed.
|
* called with dp->dl_count inc'ed.
|
||||||
* nfs4_lock_state() may or may not have been called.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
nfsd4_cb_recall(struct nfs4_delegation *dp)
|
nfsd4_cb_recall(struct nfs4_delegation *dp)
|
||||||
|
|
|
@ -93,6 +93,21 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
|
||||||
open->op_truncate = 0;
|
open->op_truncate = 0;
|
||||||
|
|
||||||
if (open->op_create) {
|
if (open->op_create) {
|
||||||
|
/* FIXME: check session persistence and pnfs flags.
|
||||||
|
* The nfsv4.1 spec requires the following semantics:
|
||||||
|
*
|
||||||
|
* Persistent | pNFS | Server REQUIRED | Client Allowed
|
||||||
|
* Reply Cache | server | |
|
||||||
|
* -------------+--------+-----------------+--------------------
|
||||||
|
* no | no | EXCLUSIVE4_1 | EXCLUSIVE4_1
|
||||||
|
* | | | (SHOULD)
|
||||||
|
* | | and EXCLUSIVE4 | or EXCLUSIVE4
|
||||||
|
* | | | (SHOULD NOT)
|
||||||
|
* no | yes | EXCLUSIVE4_1 | EXCLUSIVE4_1
|
||||||
|
* yes | no | GUARDED4 | GUARDED4
|
||||||
|
* yes | yes | GUARDED4 | GUARDED4
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: create modes (UNCHECKED,GUARDED...) are the same
|
* Note: create modes (UNCHECKED,GUARDED...) are the same
|
||||||
* in NFSv4 as in v3.
|
* in NFSv4 as in v3.
|
||||||
|
@ -103,11 +118,13 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
|
||||||
(u32 *)open->op_verf.data,
|
(u32 *)open->op_verf.data,
|
||||||
&open->op_truncate, &created);
|
&open->op_truncate, &created);
|
||||||
|
|
||||||
/* If we ever decide to use different attrs to store the
|
/*
|
||||||
* verifier in nfsd_create_v3, then we'll need to change this
|
* Following rfc 3530 14.2.16, use the returned bitmask
|
||||||
|
* to indicate which attributes we used to store the
|
||||||
|
* verifier:
|
||||||
*/
|
*/
|
||||||
if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
|
if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
|
||||||
open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
|
open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS |
|
||||||
FATTR4_WORD1_TIME_MODIFY);
|
FATTR4_WORD1_TIME_MODIFY);
|
||||||
} else {
|
} else {
|
||||||
status = nfsd_lookup(rqstp, current_fh,
|
status = nfsd_lookup(rqstp, current_fh,
|
||||||
|
@ -118,13 +135,11 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
set_change_info(&open->op_cinfo, current_fh);
|
set_change_info(&open->op_cinfo, current_fh);
|
||||||
|
fh_dup2(current_fh, &resfh);
|
||||||
|
|
||||||
/* set reply cache */
|
/* set reply cache */
|
||||||
fh_dup2(current_fh, &resfh);
|
fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
|
||||||
open->op_stateowner->so_replay.rp_openfh_len = resfh.fh_handle.fh_size;
|
&resfh.fh_handle);
|
||||||
memcpy(open->op_stateowner->so_replay.rp_openfh,
|
|
||||||
&resfh.fh_handle.fh_base, resfh.fh_handle.fh_size);
|
|
||||||
|
|
||||||
if (!created)
|
if (!created)
|
||||||
status = do_open_permission(rqstp, current_fh, open,
|
status = do_open_permission(rqstp, current_fh, open,
|
||||||
NFSD_MAY_NOP);
|
NFSD_MAY_NOP);
|
||||||
|
@ -150,10 +165,8 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
|
||||||
memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));
|
memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));
|
||||||
|
|
||||||
/* set replay cache */
|
/* set replay cache */
|
||||||
open->op_stateowner->so_replay.rp_openfh_len = current_fh->fh_handle.fh_size;
|
fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
|
||||||
memcpy(open->op_stateowner->so_replay.rp_openfh,
|
¤t_fh->fh_handle);
|
||||||
¤t_fh->fh_handle.fh_base,
|
|
||||||
current_fh->fh_handle.fh_size);
|
|
||||||
|
|
||||||
open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
|
open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
|
||||||
(open->op_iattr.ia_size == 0);
|
(open->op_iattr.ia_size == 0);
|
||||||
|
@ -164,12 +177,23 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
copy_clientid(clientid_t *clid, struct nfsd4_session *session)
|
||||||
|
{
|
||||||
|
struct nfsd4_sessionid *sid =
|
||||||
|
(struct nfsd4_sessionid *)session->se_sessionid.data;
|
||||||
|
|
||||||
|
clid->cl_boot = sid->clientid.cl_boot;
|
||||||
|
clid->cl_id = sid->clientid.cl_id;
|
||||||
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
struct nfsd4_open *open)
|
struct nfsd4_open *open)
|
||||||
{
|
{
|
||||||
__be32 status;
|
__be32 status;
|
||||||
|
struct nfsd4_compoundres *resp;
|
||||||
|
|
||||||
dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
|
dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
|
||||||
(int)open->op_fname.len, open->op_fname.data,
|
(int)open->op_fname.len, open->op_fname.data,
|
||||||
open->op_stateowner);
|
open->op_stateowner);
|
||||||
|
@ -178,16 +202,19 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
|
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
|
||||||
return nfserr_inval;
|
return nfserr_inval;
|
||||||
|
|
||||||
|
if (nfsd4_has_session(cstate))
|
||||||
|
copy_clientid(&open->op_clientid, cstate->session);
|
||||||
|
|
||||||
nfs4_lock_state();
|
nfs4_lock_state();
|
||||||
|
|
||||||
/* check seqid for replay. set nfs4_owner */
|
/* check seqid for replay. set nfs4_owner */
|
||||||
status = nfsd4_process_open1(open);
|
resp = rqstp->rq_resp;
|
||||||
|
status = nfsd4_process_open1(&resp->cstate, open);
|
||||||
if (status == nfserr_replay_me) {
|
if (status == nfserr_replay_me) {
|
||||||
struct nfs4_replay *rp = &open->op_stateowner->so_replay;
|
struct nfs4_replay *rp = &open->op_stateowner->so_replay;
|
||||||
fh_put(&cstate->current_fh);
|
fh_put(&cstate->current_fh);
|
||||||
cstate->current_fh.fh_handle.fh_size = rp->rp_openfh_len;
|
fh_copy_shallow(&cstate->current_fh.fh_handle,
|
||||||
memcpy(&cstate->current_fh.fh_handle.fh_base, rp->rp_openfh,
|
&rp->rp_openfh);
|
||||||
rp->rp_openfh_len);
|
|
||||||
status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
|
status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
|
||||||
if (status)
|
if (status)
|
||||||
dprintk("nfsd4_open: replay failed"
|
dprintk("nfsd4_open: replay failed"
|
||||||
|
@ -209,10 +236,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
|
|
||||||
switch (open->op_claim_type) {
|
switch (open->op_claim_type) {
|
||||||
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
|
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
|
||||||
status = nfserr_inval;
|
|
||||||
if (open->op_create)
|
|
||||||
goto out;
|
|
||||||
/* fall through */
|
|
||||||
case NFS4_OPEN_CLAIM_NULL:
|
case NFS4_OPEN_CLAIM_NULL:
|
||||||
/*
|
/*
|
||||||
* (1) set CURRENT_FH to the file being opened,
|
* (1) set CURRENT_FH to the file being opened,
|
||||||
|
@ -455,8 +478,9 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
|
if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
|
||||||
return nfserr_inval;
|
return nfserr_inval;
|
||||||
|
|
||||||
getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
|
getattr->ga_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
|
||||||
getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
|
getattr->ga_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
|
||||||
|
getattr->ga_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
|
||||||
|
|
||||||
getattr->ga_fhp = &cstate->current_fh;
|
getattr->ga_fhp = &cstate->current_fh;
|
||||||
return nfs_ok;
|
return nfs_ok;
|
||||||
|
@ -520,9 +544,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
|
|
||||||
nfs4_lock_state();
|
nfs4_lock_state();
|
||||||
/* check stateid */
|
/* check stateid */
|
||||||
if ((status = nfs4_preprocess_stateid_op(&cstate->current_fh,
|
if ((status = nfs4_preprocess_stateid_op(cstate, &read->rd_stateid,
|
||||||
&read->rd_stateid,
|
RD_STATE, &read->rd_filp))) {
|
||||||
CHECK_FH | RD_STATE, &read->rd_filp))) {
|
|
||||||
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
|
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -548,8 +571,9 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
|
if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
|
||||||
return nfserr_inval;
|
return nfserr_inval;
|
||||||
|
|
||||||
readdir->rd_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
|
readdir->rd_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
|
||||||
readdir->rd_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
|
readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
|
||||||
|
readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
|
||||||
|
|
||||||
if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
|
if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
|
||||||
(cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
|
(cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
|
||||||
|
@ -653,8 +677,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
|
|
||||||
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
|
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
|
||||||
nfs4_lock_state();
|
nfs4_lock_state();
|
||||||
status = nfs4_preprocess_stateid_op(&cstate->current_fh,
|
status = nfs4_preprocess_stateid_op(cstate,
|
||||||
&setattr->sa_stateid, CHECK_FH | WR_STATE, NULL);
|
&setattr->sa_stateid, WR_STATE, NULL);
|
||||||
nfs4_unlock_state();
|
nfs4_unlock_state();
|
||||||
if (status) {
|
if (status) {
|
||||||
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
|
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
|
||||||
|
@ -685,6 +709,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
struct file *filp = NULL;
|
struct file *filp = NULL;
|
||||||
u32 *p;
|
u32 *p;
|
||||||
__be32 status = nfs_ok;
|
__be32 status = nfs_ok;
|
||||||
|
unsigned long cnt;
|
||||||
|
|
||||||
/* no need to check permission - this will be done in nfsd_write() */
|
/* no need to check permission - this will be done in nfsd_write() */
|
||||||
|
|
||||||
|
@ -692,8 +717,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
return nfserr_inval;
|
return nfserr_inval;
|
||||||
|
|
||||||
nfs4_lock_state();
|
nfs4_lock_state();
|
||||||
status = nfs4_preprocess_stateid_op(&cstate->current_fh, stateid,
|
status = nfs4_preprocess_stateid_op(cstate, stateid, WR_STATE, &filp);
|
||||||
CHECK_FH | WR_STATE, &filp);
|
|
||||||
if (filp)
|
if (filp)
|
||||||
get_file(filp);
|
get_file(filp);
|
||||||
nfs4_unlock_state();
|
nfs4_unlock_state();
|
||||||
|
@ -703,7 +727,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
write->wr_bytes_written = write->wr_buflen;
|
cnt = write->wr_buflen;
|
||||||
write->wr_how_written = write->wr_stable_how;
|
write->wr_how_written = write->wr_stable_how;
|
||||||
p = (u32 *)write->wr_verifier.data;
|
p = (u32 *)write->wr_verifier.data;
|
||||||
*p++ = nfssvc_boot.tv_sec;
|
*p++ = nfssvc_boot.tv_sec;
|
||||||
|
@ -711,10 +735,12 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
|
|
||||||
status = nfsd_write(rqstp, &cstate->current_fh, filp,
|
status = nfsd_write(rqstp, &cstate->current_fh, filp,
|
||||||
write->wr_offset, rqstp->rq_vec, write->wr_vlen,
|
write->wr_offset, rqstp->rq_vec, write->wr_vlen,
|
||||||
write->wr_buflen, &write->wr_how_written);
|
&cnt, &write->wr_how_written);
|
||||||
if (filp)
|
if (filp)
|
||||||
fput(filp);
|
fput(filp);
|
||||||
|
|
||||||
|
write->wr_bytes_written = cnt;
|
||||||
|
|
||||||
if (status == nfserr_symlink)
|
if (status == nfserr_symlink)
|
||||||
status = nfserr_inval;
|
status = nfserr_inval;
|
||||||
return status;
|
return status;
|
||||||
|
@ -737,8 +763,9 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
if ((verify->ve_bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0)
|
if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(cstate->minorversion))
|
||||||
|| (verify->ve_bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
|
|| (verify->ve_bmval[1] & ~nfsd_suppattrs1(cstate->minorversion))
|
||||||
|
|| (verify->ve_bmval[2] & ~nfsd_suppattrs2(cstate->minorversion)))
|
||||||
return nfserr_attrnotsupp;
|
return nfserr_attrnotsupp;
|
||||||
if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
|
if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
|
||||||
|| (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
|
|| (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
|
||||||
|
@ -766,7 +793,8 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
if (status)
|
if (status)
|
||||||
goto out_kfree;
|
goto out_kfree;
|
||||||
|
|
||||||
p = buf + 3;
|
/* skip bitmap */
|
||||||
|
p = buf + 1 + ntohl(buf[0]);
|
||||||
status = nfserr_not_same;
|
status = nfserr_not_same;
|
||||||
if (ntohl(*p++) != verify->ve_attrlen)
|
if (ntohl(*p++) != verify->ve_attrlen)
|
||||||
goto out_kfree;
|
goto out_kfree;
|
||||||
|
@ -813,39 +841,17 @@ static inline void nfsd4_increment_op_stats(u32 opnum)
|
||||||
nfsdstats.nfs4_opcount[opnum]++;
|
nfsdstats.nfs4_opcount[opnum]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cstate_free(struct nfsd4_compound_state *cstate)
|
|
||||||
{
|
|
||||||
if (cstate == NULL)
|
|
||||||
return;
|
|
||||||
fh_put(&cstate->current_fh);
|
|
||||||
fh_put(&cstate->save_fh);
|
|
||||||
BUG_ON(cstate->replay_owner);
|
|
||||||
kfree(cstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct nfsd4_compound_state *cstate_alloc(void)
|
|
||||||
{
|
|
||||||
struct nfsd4_compound_state *cstate;
|
|
||||||
|
|
||||||
cstate = kmalloc(sizeof(struct nfsd4_compound_state), GFP_KERNEL);
|
|
||||||
if (cstate == NULL)
|
|
||||||
return NULL;
|
|
||||||
fh_init(&cstate->current_fh, NFS4_FHSIZE);
|
|
||||||
fh_init(&cstate->save_fh, NFS4_FHSIZE);
|
|
||||||
cstate->replay_owner = NULL;
|
|
||||||
return cstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
|
typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
|
||||||
void *);
|
void *);
|
||||||
|
enum nfsd4_op_flags {
|
||||||
|
ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */
|
||||||
|
ALLOWED_ON_ABSENT_FS = 2 << 0, /* ops processed on absent fs */
|
||||||
|
ALLOWED_AS_FIRST_OP = 3 << 0, /* ops reqired first in compound */
|
||||||
|
};
|
||||||
|
|
||||||
struct nfsd4_operation {
|
struct nfsd4_operation {
|
||||||
nfsd4op_func op_func;
|
nfsd4op_func op_func;
|
||||||
u32 op_flags;
|
u32 op_flags;
|
||||||
/* Most ops require a valid current filehandle; a few don't: */
|
|
||||||
#define ALLOWED_WITHOUT_FH 1
|
|
||||||
/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
|
|
||||||
#define ALLOWED_ON_ABSENT_FS 2
|
|
||||||
char *op_name;
|
char *op_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -853,6 +859,51 @@ static struct nfsd4_operation nfsd4_ops[];
|
||||||
|
|
||||||
static const char *nfsd4_op_name(unsigned opnum);
|
static const char *nfsd4_op_name(unsigned opnum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a replay of a compound for which no cache entry pages
|
||||||
|
* were used. Encode the sequence operation, and if cachethis is FALSE
|
||||||
|
* encode the uncache rep error on the next operation.
|
||||||
|
*/
|
||||||
|
static __be32
|
||||||
|
nfsd4_enc_uncached_replay(struct nfsd4_compoundargs *args,
|
||||||
|
struct nfsd4_compoundres *resp)
|
||||||
|
{
|
||||||
|
struct nfsd4_op *op;
|
||||||
|
|
||||||
|
dprintk("--> %s resp->opcnt %d ce_cachethis %u \n", __func__,
|
||||||
|
resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis);
|
||||||
|
|
||||||
|
/* Encode the replayed sequence operation */
|
||||||
|
BUG_ON(resp->opcnt != 1);
|
||||||
|
op = &args->ops[resp->opcnt - 1];
|
||||||
|
nfsd4_encode_operation(resp, op);
|
||||||
|
|
||||||
|
/*return nfserr_retry_uncached_rep in next operation. */
|
||||||
|
if (resp->cstate.slot->sl_cache_entry.ce_cachethis == 0) {
|
||||||
|
op = &args->ops[resp->opcnt++];
|
||||||
|
op->status = nfserr_retry_uncached_rep;
|
||||||
|
nfsd4_encode_operation(resp, op);
|
||||||
|
}
|
||||||
|
return op->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enforce NFSv4.1 COMPOUND ordering rules.
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
* - enforce NFS4ERR_NOT_ONLY_OP,
|
||||||
|
* - DESTROY_SESSION MUST be the final operation in the COMPOUND request.
|
||||||
|
*/
|
||||||
|
static bool nfs41_op_ordering_ok(struct nfsd4_compoundargs *args)
|
||||||
|
{
|
||||||
|
if (args->minorversion && args->opcnt > 0) {
|
||||||
|
struct nfsd4_op *op = &args->ops[0];
|
||||||
|
return (op->status == nfserr_op_illegal) ||
|
||||||
|
(nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* COMPOUND call.
|
* COMPOUND call.
|
||||||
*/
|
*/
|
||||||
|
@ -863,12 +914,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
|
||||||
{
|
{
|
||||||
struct nfsd4_op *op;
|
struct nfsd4_op *op;
|
||||||
struct nfsd4_operation *opdesc;
|
struct nfsd4_operation *opdesc;
|
||||||
struct nfsd4_compound_state *cstate = NULL;
|
struct nfsd4_compound_state *cstate = &resp->cstate;
|
||||||
int slack_bytes;
|
int slack_bytes;
|
||||||
__be32 status;
|
__be32 status;
|
||||||
|
|
||||||
resp->xbuf = &rqstp->rq_res;
|
resp->xbuf = &rqstp->rq_res;
|
||||||
resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len;
|
resp->p = rqstp->rq_res.head[0].iov_base +
|
||||||
|
rqstp->rq_res.head[0].iov_len;
|
||||||
resp->tagp = resp->p;
|
resp->tagp = resp->p;
|
||||||
/* reserve space for: taglen, tag, and opcnt */
|
/* reserve space for: taglen, tag, and opcnt */
|
||||||
resp->p += 2 + XDR_QUADLEN(args->taglen);
|
resp->p += 2 + XDR_QUADLEN(args->taglen);
|
||||||
|
@ -877,18 +929,25 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
|
||||||
resp->tag = args->tag;
|
resp->tag = args->tag;
|
||||||
resp->opcnt = 0;
|
resp->opcnt = 0;
|
||||||
resp->rqstp = rqstp;
|
resp->rqstp = rqstp;
|
||||||
|
resp->cstate.minorversion = args->minorversion;
|
||||||
|
resp->cstate.replay_owner = NULL;
|
||||||
|
fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
|
||||||
|
fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
|
||||||
|
/* Use the deferral mechanism only for NFSv4.0 compounds */
|
||||||
|
rqstp->rq_usedeferral = (args->minorversion == 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* According to RFC3010, this takes precedence over all other errors.
|
* According to RFC3010, this takes precedence over all other errors.
|
||||||
*/
|
*/
|
||||||
status = nfserr_minor_vers_mismatch;
|
status = nfserr_minor_vers_mismatch;
|
||||||
if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
|
if (args->minorversion > nfsd_supported_minorversion)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
status = nfserr_resource;
|
if (!nfs41_op_ordering_ok(args)) {
|
||||||
cstate = cstate_alloc();
|
op = &args->ops[0];
|
||||||
if (cstate == NULL)
|
op->status = nfserr_sequence_pos;
|
||||||
goto out;
|
goto encode_op;
|
||||||
|
}
|
||||||
|
|
||||||
status = nfs_ok;
|
status = nfs_ok;
|
||||||
while (!status && resp->opcnt < args->opcnt) {
|
while (!status && resp->opcnt < args->opcnt) {
|
||||||
|
@ -897,7 +956,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
|
||||||
dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
|
dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
|
||||||
resp->opcnt, args->opcnt, op->opnum,
|
resp->opcnt, args->opcnt, op->opnum,
|
||||||
nfsd4_op_name(op->opnum));
|
nfsd4_op_name(op->opnum));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The XDR decode routines may have pre-set op->status;
|
* The XDR decode routines may have pre-set op->status;
|
||||||
* for example, if there is a miscellaneous XDR error
|
* for example, if there is a miscellaneous XDR error
|
||||||
|
@ -938,6 +996,15 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
|
||||||
BUG_ON(op->status == nfs_ok);
|
BUG_ON(op->status == nfs_ok);
|
||||||
|
|
||||||
encode_op:
|
encode_op:
|
||||||
|
/* Only from SEQUENCE or CREATE_SESSION */
|
||||||
|
if (resp->cstate.status == nfserr_replay_cache) {
|
||||||
|
dprintk("%s NFS4.1 replay from cache\n", __func__);
|
||||||
|
if (nfsd4_not_cached(resp))
|
||||||
|
status = nfsd4_enc_uncached_replay(args, resp);
|
||||||
|
else
|
||||||
|
status = op->status;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (op->status == nfserr_replay_me) {
|
if (op->status == nfserr_replay_me) {
|
||||||
op->replay = &cstate->replay_owner->so_replay;
|
op->replay = &cstate->replay_owner->so_replay;
|
||||||
nfsd4_encode_replay(resp, op);
|
nfsd4_encode_replay(resp, op);
|
||||||
|
@ -961,15 +1028,24 @@ encode_op:
|
||||||
|
|
||||||
nfsd4_increment_op_stats(op->opnum);
|
nfsd4_increment_op_stats(op->opnum);
|
||||||
}
|
}
|
||||||
|
if (!rqstp->rq_usedeferral && status == nfserr_dropit) {
|
||||||
|
dprintk("%s Dropit - send NFS4ERR_DELAY\n", __func__);
|
||||||
|
status = nfserr_jukebox;
|
||||||
|
}
|
||||||
|
|
||||||
cstate_free(cstate);
|
resp->cstate.status = status;
|
||||||
|
fh_put(&resp->cstate.current_fh);
|
||||||
|
fh_put(&resp->cstate.save_fh);
|
||||||
|
BUG_ON(resp->cstate.replay_owner);
|
||||||
out:
|
out:
|
||||||
nfsd4_release_compoundargs(args);
|
nfsd4_release_compoundargs(args);
|
||||||
|
/* Reset deferral mechanism for RPC deferrals */
|
||||||
|
rqstp->rq_usedeferral = 1;
|
||||||
dprintk("nfsv4 compound returned %d\n", ntohl(status));
|
dprintk("nfsv4 compound returned %d\n", ntohl(status));
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
|
static struct nfsd4_operation nfsd4_ops[] = {
|
||||||
[OP_ACCESS] = {
|
[OP_ACCESS] = {
|
||||||
.op_func = (nfsd4op_func)nfsd4_access,
|
.op_func = (nfsd4op_func)nfsd4_access,
|
||||||
.op_name = "OP_ACCESS",
|
.op_name = "OP_ACCESS",
|
||||||
|
@ -1045,7 +1121,7 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
|
||||||
.op_name = "OP_PUTFH",
|
.op_name = "OP_PUTFH",
|
||||||
},
|
},
|
||||||
[OP_PUTPUBFH] = {
|
[OP_PUTPUBFH] = {
|
||||||
/* unsupported, just for future reference: */
|
.op_func = (nfsd4op_func)nfsd4_putrootfh,
|
||||||
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
|
||||||
.op_name = "OP_PUTPUBFH",
|
.op_name = "OP_PUTPUBFH",
|
||||||
},
|
},
|
||||||
|
@ -1119,6 +1195,28 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
|
||||||
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
|
||||||
.op_name = "OP_RELEASE_LOCKOWNER",
|
.op_name = "OP_RELEASE_LOCKOWNER",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/* NFSv4.1 operations */
|
||||||
|
[OP_EXCHANGE_ID] = {
|
||||||
|
.op_func = (nfsd4op_func)nfsd4_exchange_id,
|
||||||
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
|
||||||
|
.op_name = "OP_EXCHANGE_ID",
|
||||||
|
},
|
||||||
|
[OP_CREATE_SESSION] = {
|
||||||
|
.op_func = (nfsd4op_func)nfsd4_create_session,
|
||||||
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
|
||||||
|
.op_name = "OP_CREATE_SESSION",
|
||||||
|
},
|
||||||
|
[OP_DESTROY_SESSION] = {
|
||||||
|
.op_func = (nfsd4op_func)nfsd4_destroy_session,
|
||||||
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
|
||||||
|
.op_name = "OP_DESTROY_SESSION",
|
||||||
|
},
|
||||||
|
[OP_SEQUENCE] = {
|
||||||
|
.op_func = (nfsd4op_func)nfsd4_sequence,
|
||||||
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
|
||||||
|
.op_name = "OP_SEQUENCE",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *nfsd4_op_name(unsigned opnum)
|
static const char *nfsd4_op_name(unsigned opnum)
|
||||||
|
|
|
@ -182,36 +182,26 @@ out_unlock:
|
||||||
|
|
||||||
typedef int (recdir_func)(struct dentry *, struct dentry *);
|
typedef int (recdir_func)(struct dentry *, struct dentry *);
|
||||||
|
|
||||||
struct dentry_list {
|
struct name_list {
|
||||||
struct dentry *dentry;
|
char name[HEXDIR_LEN];
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dentry_list_arg {
|
|
||||||
struct list_head dentries;
|
|
||||||
struct dentry *parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
|
nfsd4_build_namelist(void *arg, const char *name, int namlen,
|
||||||
loff_t offset, u64 ino, unsigned int d_type)
|
loff_t offset, u64 ino, unsigned int d_type)
|
||||||
{
|
{
|
||||||
struct dentry_list_arg *dla = arg;
|
struct list_head *names = arg;
|
||||||
struct list_head *dentries = &dla->dentries;
|
struct name_list *entry;
|
||||||
struct dentry *parent = dla->parent;
|
|
||||||
struct dentry *dentry;
|
|
||||||
struct dentry_list *child;
|
|
||||||
|
|
||||||
if (name && isdotent(name, namlen))
|
if (namlen != HEXDIR_LEN - 1)
|
||||||
return 0;
|
return 0;
|
||||||
dentry = lookup_one_len(name, parent, namlen);
|
entry = kmalloc(sizeof(struct name_list), GFP_KERNEL);
|
||||||
if (IS_ERR(dentry))
|
if (entry == NULL)
|
||||||
return PTR_ERR(dentry);
|
|
||||||
child = kmalloc(sizeof(*child), GFP_KERNEL);
|
|
||||||
if (child == NULL)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
child->dentry = dentry;
|
memcpy(entry->name, name, HEXDIR_LEN - 1);
|
||||||
list_add(&child->list, dentries);
|
entry->name[HEXDIR_LEN - 1] = '\0';
|
||||||
|
list_add(&entry->list, names);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,11 +210,9 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
|
||||||
{
|
{
|
||||||
const struct cred *original_cred;
|
const struct cred *original_cred;
|
||||||
struct file *filp;
|
struct file *filp;
|
||||||
struct dentry_list_arg dla = {
|
LIST_HEAD(names);
|
||||||
.parent = dir,
|
struct name_list *entry;
|
||||||
};
|
struct dentry *dentry;
|
||||||
struct list_head *dentries = &dla.dentries;
|
|
||||||
struct dentry_list *child;
|
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (!rec_dir_init)
|
if (!rec_dir_init)
|
||||||
|
@ -233,31 +221,34 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
|
||||||
status = nfs4_save_creds(&original_cred);
|
status = nfs4_save_creds(&original_cred);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
return status;
|
return status;
|
||||||
INIT_LIST_HEAD(dentries);
|
|
||||||
|
|
||||||
filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
|
filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
|
||||||
current_cred());
|
current_cred());
|
||||||
status = PTR_ERR(filp);
|
status = PTR_ERR(filp);
|
||||||
if (IS_ERR(filp))
|
if (IS_ERR(filp))
|
||||||
goto out;
|
goto out;
|
||||||
INIT_LIST_HEAD(dentries);
|
status = vfs_readdir(filp, nfsd4_build_namelist, &names);
|
||||||
status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla);
|
|
||||||
fput(filp);
|
fput(filp);
|
||||||
while (!list_empty(dentries)) {
|
while (!list_empty(&names)) {
|
||||||
child = list_entry(dentries->next, struct dentry_list, list);
|
entry = list_entry(names.next, struct name_list, list);
|
||||||
status = f(dir, child->dentry);
|
|
||||||
|
dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
|
||||||
|
if (IS_ERR(dentry)) {
|
||||||
|
status = PTR_ERR(dentry);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
status = f(dir, dentry);
|
||||||
|
dput(dentry);
|
||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
list_del(&child->list);
|
list_del(&entry->list);
|
||||||
dput(child->dentry);
|
kfree(entry);
|
||||||
kfree(child);
|
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
while (!list_empty(dentries)) {
|
while (!list_empty(&names)) {
|
||||||
child = list_entry(dentries->next, struct dentry_list, list);
|
entry = list_entry(names.next, struct name_list, list);
|
||||||
list_del(&child->list);
|
list_del(&entry->list);
|
||||||
dput(child->dentry);
|
kfree(entry);
|
||||||
kfree(child);
|
|
||||||
}
|
}
|
||||||
nfs4_reset_creds(original_cred);
|
nfs4_reset_creds(original_cred);
|
||||||
return status;
|
return status;
|
||||||
|
@ -353,7 +344,8 @@ purge_old(struct dentry *parent, struct dentry *child)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (nfs4_has_reclaimed_state(child->d_name.name))
|
/* note: we currently use this path only for minorversion 0 */
|
||||||
|
if (nfs4_has_reclaimed_state(child->d_name.name, false))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
status = nfsd4_clear_clid_dir(parent, child);
|
status = nfsd4_clear_clid_dir(parent, child);
|
||||||
|
|
1196
fs/nfsd/nfs4state.c
1196
fs/nfsd/nfs4state.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -45,6 +45,7 @@
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/namei.h>
|
#include <linux/namei.h>
|
||||||
#include <linux/vfs.h>
|
#include <linux/vfs.h>
|
||||||
|
#include <linux/utsname.h>
|
||||||
#include <linux/sunrpc/xdr.h>
|
#include <linux/sunrpc/xdr.h>
|
||||||
#include <linux/sunrpc/svc.h>
|
#include <linux/sunrpc/svc.h>
|
||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
|
@ -188,6 +189,11 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int zero_clientid(clientid_t *clid)
|
||||||
|
{
|
||||||
|
return (clid->cl_boot == 0) && (clid->cl_id == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
defer_free(struct nfsd4_compoundargs *argp,
|
defer_free(struct nfsd4_compoundargs *argp,
|
||||||
void (*release)(const void *), void *p)
|
void (*release)(const void *), void *p)
|
||||||
|
@ -230,6 +236,7 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
|
||||||
|
|
||||||
bmval[0] = 0;
|
bmval[0] = 0;
|
||||||
bmval[1] = 0;
|
bmval[1] = 0;
|
||||||
|
bmval[2] = 0;
|
||||||
|
|
||||||
READ_BUF(4);
|
READ_BUF(4);
|
||||||
READ32(bmlen);
|
READ32(bmlen);
|
||||||
|
@ -241,13 +248,27 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
|
||||||
READ32(bmval[0]);
|
READ32(bmval[0]);
|
||||||
if (bmlen > 1)
|
if (bmlen > 1)
|
||||||
READ32(bmval[1]);
|
READ32(bmval[1]);
|
||||||
|
if (bmlen > 2)
|
||||||
|
READ32(bmval[2]);
|
||||||
|
|
||||||
DECODE_TAIL;
|
DECODE_TAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 nfsd_attrmask[] = {
|
||||||
|
NFSD_WRITEABLE_ATTRS_WORD0,
|
||||||
|
NFSD_WRITEABLE_ATTRS_WORD1,
|
||||||
|
NFSD_WRITEABLE_ATTRS_WORD2
|
||||||
|
};
|
||||||
|
|
||||||
|
static u32 nfsd41_ex_attrmask[] = {
|
||||||
|
NFSD_SUPPATTR_EXCLCREAT_WORD0,
|
||||||
|
NFSD_SUPPATTR_EXCLCREAT_WORD1,
|
||||||
|
NFSD_SUPPATTR_EXCLCREAT_WORD2
|
||||||
|
};
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr,
|
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable,
|
||||||
struct nfs4_acl **acl)
|
struct iattr *iattr, struct nfs4_acl **acl)
|
||||||
{
|
{
|
||||||
int expected_len, len = 0;
|
int expected_len, len = 0;
|
||||||
u32 dummy32;
|
u32 dummy32;
|
||||||
|
@ -263,9 +284,12 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
|
||||||
* According to spec, unsupported attributes return ERR_ATTRNOTSUPP;
|
* According to spec, unsupported attributes return ERR_ATTRNOTSUPP;
|
||||||
* read-only attributes return ERR_INVAL.
|
* read-only attributes return ERR_INVAL.
|
||||||
*/
|
*/
|
||||||
if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) || (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
|
if ((bmval[0] & ~nfsd_suppattrs0(argp->minorversion)) ||
|
||||||
|
(bmval[1] & ~nfsd_suppattrs1(argp->minorversion)) ||
|
||||||
|
(bmval[2] & ~nfsd_suppattrs2(argp->minorversion)))
|
||||||
return nfserr_attrnotsupp;
|
return nfserr_attrnotsupp;
|
||||||
if ((bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0) || (bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1))
|
if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
|
||||||
|
(bmval[2] & ~writable[2]))
|
||||||
return nfserr_inval;
|
return nfserr_inval;
|
||||||
|
|
||||||
READ_BUF(4);
|
READ_BUF(4);
|
||||||
|
@ -400,6 +424,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BUG_ON(bmval[2]); /* no such writeable attr supported yet */
|
||||||
if (len != expected_len)
|
if (len != expected_len)
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
|
|
||||||
|
@ -493,7 +518,9 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
|
||||||
if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
|
if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl)))
|
status = nfsd4_decode_fattr(argp, create->cr_bmval, nfsd_attrmask,
|
||||||
|
&create->cr_iattr, &create->cr_acl);
|
||||||
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
DECODE_TAIL;
|
DECODE_TAIL;
|
||||||
|
@ -583,6 +610,8 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
|
||||||
READ_BUF(lockt->lt_owner.len);
|
READ_BUF(lockt->lt_owner.len);
|
||||||
READMEM(lockt->lt_owner.data, lockt->lt_owner.len);
|
READMEM(lockt->lt_owner.data, lockt->lt_owner.len);
|
||||||
|
|
||||||
|
if (argp->minorversion && !zero_clientid(&lockt->lt_clientid))
|
||||||
|
return nfserr_inval;
|
||||||
DECODE_TAIL;
|
DECODE_TAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,13 +681,26 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
|
||||||
switch (open->op_createmode) {
|
switch (open->op_createmode) {
|
||||||
case NFS4_CREATE_UNCHECKED:
|
case NFS4_CREATE_UNCHECKED:
|
||||||
case NFS4_CREATE_GUARDED:
|
case NFS4_CREATE_GUARDED:
|
||||||
if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl)))
|
status = nfsd4_decode_fattr(argp, open->op_bmval,
|
||||||
|
nfsd_attrmask, &open->op_iattr, &open->op_acl);
|
||||||
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
break;
|
break;
|
||||||
case NFS4_CREATE_EXCLUSIVE:
|
case NFS4_CREATE_EXCLUSIVE:
|
||||||
READ_BUF(8);
|
READ_BUF(8);
|
||||||
COPYMEM(open->op_verf.data, 8);
|
COPYMEM(open->op_verf.data, 8);
|
||||||
break;
|
break;
|
||||||
|
case NFS4_CREATE_EXCLUSIVE4_1:
|
||||||
|
if (argp->minorversion < 1)
|
||||||
|
goto xdr_error;
|
||||||
|
READ_BUF(8);
|
||||||
|
COPYMEM(open->op_verf.data, 8);
|
||||||
|
status = nfsd4_decode_fattr(argp, open->op_bmval,
|
||||||
|
nfsd41_ex_attrmask, &open->op_iattr,
|
||||||
|
&open->op_acl);
|
||||||
|
if (status)
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
goto xdr_error;
|
goto xdr_error;
|
||||||
}
|
}
|
||||||
|
@ -851,7 +893,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
|
||||||
status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
|
status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
return nfsd4_decode_fattr(argp, setattr->sa_bmval,
|
return nfsd4_decode_fattr(argp, setattr->sa_bmval, nfsd_attrmask,
|
||||||
&setattr->sa_iattr, &setattr->sa_acl);
|
&setattr->sa_iattr, &setattr->sa_acl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -993,6 +1035,241 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel
|
||||||
READ_BUF(rlockowner->rl_owner.len);
|
READ_BUF(rlockowner->rl_owner.len);
|
||||||
READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len);
|
READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len);
|
||||||
|
|
||||||
|
if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid))
|
||||||
|
return nfserr_inval;
|
||||||
|
DECODE_TAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __be32
|
||||||
|
nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
|
||||||
|
struct nfsd4_exchange_id *exid)
|
||||||
|
{
|
||||||
|
int dummy;
|
||||||
|
DECODE_HEAD;
|
||||||
|
|
||||||
|
READ_BUF(NFS4_VERIFIER_SIZE);
|
||||||
|
COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE);
|
||||||
|
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(exid->clname.len);
|
||||||
|
|
||||||
|
READ_BUF(exid->clname.len);
|
||||||
|
SAVEMEM(exid->clname.data, exid->clname.len);
|
||||||
|
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(exid->flags);
|
||||||
|
|
||||||
|
/* Ignore state_protect4_a */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(exid->spa_how);
|
||||||
|
switch (exid->spa_how) {
|
||||||
|
case SP4_NONE:
|
||||||
|
break;
|
||||||
|
case SP4_MACH_CRED:
|
||||||
|
/* spo_must_enforce */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy * 4);
|
||||||
|
p += dummy;
|
||||||
|
|
||||||
|
/* spo_must_allow */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy * 4);
|
||||||
|
p += dummy;
|
||||||
|
break;
|
||||||
|
case SP4_SSV:
|
||||||
|
/* ssp_ops */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy * 4);
|
||||||
|
p += dummy;
|
||||||
|
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy * 4);
|
||||||
|
p += dummy;
|
||||||
|
|
||||||
|
/* ssp_hash_algs<> */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy);
|
||||||
|
p += XDR_QUADLEN(dummy);
|
||||||
|
|
||||||
|
/* ssp_encr_algs<> */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy);
|
||||||
|
p += XDR_QUADLEN(dummy);
|
||||||
|
|
||||||
|
/* ssp_window and ssp_num_gss_handles */
|
||||||
|
READ_BUF(8);
|
||||||
|
READ32(dummy);
|
||||||
|
READ32(dummy);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto xdr_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ignore Implementation ID */
|
||||||
|
READ_BUF(4); /* nfs_impl_id4 array length */
|
||||||
|
READ32(dummy);
|
||||||
|
|
||||||
|
if (dummy > 1)
|
||||||
|
goto xdr_error;
|
||||||
|
|
||||||
|
if (dummy == 1) {
|
||||||
|
/* nii_domain */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy);
|
||||||
|
p += XDR_QUADLEN(dummy);
|
||||||
|
|
||||||
|
/* nii_name */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy);
|
||||||
|
p += XDR_QUADLEN(dummy);
|
||||||
|
|
||||||
|
/* nii_date */
|
||||||
|
READ_BUF(12);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
DECODE_TAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __be32
|
||||||
|
nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
|
||||||
|
struct nfsd4_create_session *sess)
|
||||||
|
{
|
||||||
|
DECODE_HEAD;
|
||||||
|
|
||||||
|
u32 dummy;
|
||||||
|
char *machine_name;
|
||||||
|
int i;
|
||||||
|
int nr_secflavs;
|
||||||
|
|
||||||
|
READ_BUF(16);
|
||||||
|
COPYMEM(&sess->clientid, 8);
|
||||||
|
READ32(sess->seqid);
|
||||||
|
READ32(sess->flags);
|
||||||
|
|
||||||
|
/* Fore channel attrs */
|
||||||
|
READ_BUF(28);
|
||||||
|
READ32(dummy); /* headerpadsz is always 0 */
|
||||||
|
READ32(sess->fore_channel.maxreq_sz);
|
||||||
|
READ32(sess->fore_channel.maxresp_sz);
|
||||||
|
READ32(sess->fore_channel.maxresp_cached);
|
||||||
|
READ32(sess->fore_channel.maxops);
|
||||||
|
READ32(sess->fore_channel.maxreqs);
|
||||||
|
READ32(sess->fore_channel.nr_rdma_attrs);
|
||||||
|
if (sess->fore_channel.nr_rdma_attrs == 1) {
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(sess->fore_channel.rdma_attrs);
|
||||||
|
} else if (sess->fore_channel.nr_rdma_attrs > 1) {
|
||||||
|
dprintk("Too many fore channel attr bitmaps!\n");
|
||||||
|
goto xdr_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Back channel attrs */
|
||||||
|
READ_BUF(28);
|
||||||
|
READ32(dummy); /* headerpadsz is always 0 */
|
||||||
|
READ32(sess->back_channel.maxreq_sz);
|
||||||
|
READ32(sess->back_channel.maxresp_sz);
|
||||||
|
READ32(sess->back_channel.maxresp_cached);
|
||||||
|
READ32(sess->back_channel.maxops);
|
||||||
|
READ32(sess->back_channel.maxreqs);
|
||||||
|
READ32(sess->back_channel.nr_rdma_attrs);
|
||||||
|
if (sess->back_channel.nr_rdma_attrs == 1) {
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(sess->back_channel.rdma_attrs);
|
||||||
|
} else if (sess->back_channel.nr_rdma_attrs > 1) {
|
||||||
|
dprintk("Too many back channel attr bitmaps!\n");
|
||||||
|
goto xdr_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
READ_BUF(8);
|
||||||
|
READ32(sess->callback_prog);
|
||||||
|
|
||||||
|
/* callback_sec_params4 */
|
||||||
|
READ32(nr_secflavs);
|
||||||
|
for (i = 0; i < nr_secflavs; ++i) {
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
switch (dummy) {
|
||||||
|
case RPC_AUTH_NULL:
|
||||||
|
/* Nothing to read */
|
||||||
|
break;
|
||||||
|
case RPC_AUTH_UNIX:
|
||||||
|
READ_BUF(8);
|
||||||
|
/* stamp */
|
||||||
|
READ32(dummy);
|
||||||
|
|
||||||
|
/* machine name */
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy);
|
||||||
|
SAVEMEM(machine_name, dummy);
|
||||||
|
|
||||||
|
/* uid, gid */
|
||||||
|
READ_BUF(8);
|
||||||
|
READ32(sess->uid);
|
||||||
|
READ32(sess->gid);
|
||||||
|
|
||||||
|
/* more gids */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy * 4);
|
||||||
|
for (i = 0; i < dummy; ++i)
|
||||||
|
READ32(dummy);
|
||||||
|
break;
|
||||||
|
case RPC_AUTH_GSS:
|
||||||
|
dprintk("RPC_AUTH_GSS callback secflavor "
|
||||||
|
"not supported!\n");
|
||||||
|
READ_BUF(8);
|
||||||
|
/* gcbp_service */
|
||||||
|
READ32(dummy);
|
||||||
|
/* gcbp_handle_from_server */
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy);
|
||||||
|
p += XDR_QUADLEN(dummy);
|
||||||
|
/* gcbp_handle_from_client */
|
||||||
|
READ_BUF(4);
|
||||||
|
READ32(dummy);
|
||||||
|
READ_BUF(dummy);
|
||||||
|
p += XDR_QUADLEN(dummy);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintk("Illegal callback secflavor\n");
|
||||||
|
return nfserr_inval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DECODE_TAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __be32
|
||||||
|
nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
|
||||||
|
struct nfsd4_destroy_session *destroy_session)
|
||||||
|
{
|
||||||
|
DECODE_HEAD;
|
||||||
|
READ_BUF(NFS4_MAX_SESSIONID_LEN);
|
||||||
|
COPYMEM(destroy_session->sessionid.data, NFS4_MAX_SESSIONID_LEN);
|
||||||
|
|
||||||
|
DECODE_TAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __be32
|
||||||
|
nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
|
||||||
|
struct nfsd4_sequence *seq)
|
||||||
|
{
|
||||||
|
DECODE_HEAD;
|
||||||
|
|
||||||
|
READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
|
||||||
|
COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
|
||||||
|
READ32(seq->seqid);
|
||||||
|
READ32(seq->slotid);
|
||||||
|
READ32(seq->maxslots);
|
||||||
|
READ32(seq->cachethis);
|
||||||
|
|
||||||
DECODE_TAIL;
|
DECODE_TAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,7 +1282,7 @@ nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p)
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p)
|
nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p)
|
||||||
{
|
{
|
||||||
return nfserr_opnotsupp;
|
return nfserr_notsupp;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *);
|
typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *);
|
||||||
|
@ -1031,7 +1308,7 @@ static nfsd4_dec nfsd4_dec_ops[] = {
|
||||||
[OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm,
|
[OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm,
|
||||||
[OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
|
[OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
|
||||||
[OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
|
[OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
|
||||||
[OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp,
|
[OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_noop,
|
||||||
[OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
|
[OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
|
||||||
[OP_READ] = (nfsd4_dec)nfsd4_decode_read,
|
[OP_READ] = (nfsd4_dec)nfsd4_decode_read,
|
||||||
[OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
|
[OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
|
||||||
|
@ -1050,6 +1327,67 @@ static nfsd4_dec nfsd4_dec_ops[] = {
|
||||||
[OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner,
|
[OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static nfsd4_dec nfsd41_dec_ops[] = {
|
||||||
|
[OP_ACCESS] (nfsd4_dec)nfsd4_decode_access,
|
||||||
|
[OP_CLOSE] (nfsd4_dec)nfsd4_decode_close,
|
||||||
|
[OP_COMMIT] (nfsd4_dec)nfsd4_decode_commit,
|
||||||
|
[OP_CREATE] (nfsd4_dec)nfsd4_decode_create,
|
||||||
|
[OP_DELEGPURGE] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_DELEGRETURN] (nfsd4_dec)nfsd4_decode_delegreturn,
|
||||||
|
[OP_GETATTR] (nfsd4_dec)nfsd4_decode_getattr,
|
||||||
|
[OP_GETFH] (nfsd4_dec)nfsd4_decode_noop,
|
||||||
|
[OP_LINK] (nfsd4_dec)nfsd4_decode_link,
|
||||||
|
[OP_LOCK] (nfsd4_dec)nfsd4_decode_lock,
|
||||||
|
[OP_LOCKT] (nfsd4_dec)nfsd4_decode_lockt,
|
||||||
|
[OP_LOCKU] (nfsd4_dec)nfsd4_decode_locku,
|
||||||
|
[OP_LOOKUP] (nfsd4_dec)nfsd4_decode_lookup,
|
||||||
|
[OP_LOOKUPP] (nfsd4_dec)nfsd4_decode_noop,
|
||||||
|
[OP_NVERIFY] (nfsd4_dec)nfsd4_decode_verify,
|
||||||
|
[OP_OPEN] (nfsd4_dec)nfsd4_decode_open,
|
||||||
|
[OP_OPENATTR] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_OPEN_CONFIRM] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_OPEN_DOWNGRADE] (nfsd4_dec)nfsd4_decode_open_downgrade,
|
||||||
|
[OP_PUTFH] (nfsd4_dec)nfsd4_decode_putfh,
|
||||||
|
[OP_PUTPUBFH] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_PUTROOTFH] (nfsd4_dec)nfsd4_decode_noop,
|
||||||
|
[OP_READ] (nfsd4_dec)nfsd4_decode_read,
|
||||||
|
[OP_READDIR] (nfsd4_dec)nfsd4_decode_readdir,
|
||||||
|
[OP_READLINK] (nfsd4_dec)nfsd4_decode_noop,
|
||||||
|
[OP_REMOVE] (nfsd4_dec)nfsd4_decode_remove,
|
||||||
|
[OP_RENAME] (nfsd4_dec)nfsd4_decode_rename,
|
||||||
|
[OP_RENEW] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_RESTOREFH] (nfsd4_dec)nfsd4_decode_noop,
|
||||||
|
[OP_SAVEFH] (nfsd4_dec)nfsd4_decode_noop,
|
||||||
|
[OP_SECINFO] (nfsd4_dec)nfsd4_decode_secinfo,
|
||||||
|
[OP_SETATTR] (nfsd4_dec)nfsd4_decode_setattr,
|
||||||
|
[OP_SETCLIENTID] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_SETCLIENTID_CONFIRM](nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_VERIFY] (nfsd4_dec)nfsd4_decode_verify,
|
||||||
|
[OP_WRITE] (nfsd4_dec)nfsd4_decode_write,
|
||||||
|
[OP_RELEASE_LOCKOWNER] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
|
||||||
|
/* new operations for NFSv4.1 */
|
||||||
|
[OP_BACKCHANNEL_CTL] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_BIND_CONN_TO_SESSION](nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_EXCHANGE_ID] (nfsd4_dec)nfsd4_decode_exchange_id,
|
||||||
|
[OP_CREATE_SESSION] (nfsd4_dec)nfsd4_decode_create_session,
|
||||||
|
[OP_DESTROY_SESSION] (nfsd4_dec)nfsd4_decode_destroy_session,
|
||||||
|
[OP_FREE_STATEID] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_GET_DIR_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_GETDEVICEINFO] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_GETDEVICELIST] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_LAYOUTCOMMIT] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_LAYOUTGET] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_LAYOUTRETURN] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_SECINFO_NO_NAME] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_SEQUENCE] (nfsd4_dec)nfsd4_decode_sequence,
|
||||||
|
[OP_SET_SSV] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_TEST_STATEID] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_WANT_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_DESTROY_CLIENTID] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
[OP_RECLAIM_COMPLETE] (nfsd4_dec)nfsd4_decode_notsupp,
|
||||||
|
};
|
||||||
|
|
||||||
struct nfsd4_minorversion_ops {
|
struct nfsd4_minorversion_ops {
|
||||||
nfsd4_dec *decoders;
|
nfsd4_dec *decoders;
|
||||||
int nops;
|
int nops;
|
||||||
|
@ -1057,6 +1395,7 @@ struct nfsd4_minorversion_ops {
|
||||||
|
|
||||||
static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
|
static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
|
||||||
[0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
|
[0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
|
||||||
|
[1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
|
||||||
};
|
};
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
|
@ -1412,6 +1751,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
||||||
{
|
{
|
||||||
u32 bmval0 = bmval[0];
|
u32 bmval0 = bmval[0];
|
||||||
u32 bmval1 = bmval[1];
|
u32 bmval1 = bmval[1];
|
||||||
|
u32 bmval2 = bmval[2];
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
struct svc_fh tempfh;
|
struct svc_fh tempfh;
|
||||||
struct kstatfs statfs;
|
struct kstatfs statfs;
|
||||||
|
@ -1425,12 +1765,16 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
||||||
int err;
|
int err;
|
||||||
int aclsupport = 0;
|
int aclsupport = 0;
|
||||||
struct nfs4_acl *acl = NULL;
|
struct nfs4_acl *acl = NULL;
|
||||||
|
struct nfsd4_compoundres *resp = rqstp->rq_resp;
|
||||||
|
u32 minorversion = resp->cstate.minorversion;
|
||||||
|
|
||||||
BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
|
BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
|
||||||
BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
|
BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion));
|
||||||
BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
|
BUG_ON(bmval1 & ~nfsd_suppattrs1(minorversion));
|
||||||
|
BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
|
||||||
|
|
||||||
if (exp->ex_fslocs.migrated) {
|
if (exp->ex_fslocs.migrated) {
|
||||||
|
BUG_ON(bmval[2]);
|
||||||
status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
|
status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
|
||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1476,22 +1820,42 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
||||||
if ((buflen -= 16) < 0)
|
if ((buflen -= 16) < 0)
|
||||||
goto out_resource;
|
goto out_resource;
|
||||||
|
|
||||||
WRITE32(2);
|
if (unlikely(bmval2)) {
|
||||||
WRITE32(bmval0);
|
WRITE32(3);
|
||||||
WRITE32(bmval1);
|
WRITE32(bmval0);
|
||||||
|
WRITE32(bmval1);
|
||||||
|
WRITE32(bmval2);
|
||||||
|
} else if (likely(bmval1)) {
|
||||||
|
WRITE32(2);
|
||||||
|
WRITE32(bmval0);
|
||||||
|
WRITE32(bmval1);
|
||||||
|
} else {
|
||||||
|
WRITE32(1);
|
||||||
|
WRITE32(bmval0);
|
||||||
|
}
|
||||||
attrlenp = p++; /* to be backfilled later */
|
attrlenp = p++; /* to be backfilled later */
|
||||||
|
|
||||||
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
|
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
|
||||||
u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
|
u32 word0 = nfsd_suppattrs0(minorversion);
|
||||||
|
u32 word1 = nfsd_suppattrs1(minorversion);
|
||||||
|
u32 word2 = nfsd_suppattrs2(minorversion);
|
||||||
|
|
||||||
if ((buflen -= 12) < 0)
|
if ((buflen -= 12) < 0)
|
||||||
goto out_resource;
|
goto out_resource;
|
||||||
if (!aclsupport)
|
if (!aclsupport)
|
||||||
word0 &= ~FATTR4_WORD0_ACL;
|
word0 &= ~FATTR4_WORD0_ACL;
|
||||||
if (!exp->ex_fslocs.locations)
|
if (!exp->ex_fslocs.locations)
|
||||||
word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
|
word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
|
||||||
WRITE32(2);
|
if (!word2) {
|
||||||
WRITE32(word0);
|
WRITE32(2);
|
||||||
WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
|
WRITE32(word0);
|
||||||
|
WRITE32(word1);
|
||||||
|
} else {
|
||||||
|
WRITE32(3);
|
||||||
|
WRITE32(word0);
|
||||||
|
WRITE32(word1);
|
||||||
|
WRITE32(word2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (bmval0 & FATTR4_WORD0_TYPE) {
|
if (bmval0 & FATTR4_WORD0_TYPE) {
|
||||||
if ((buflen -= 4) < 0)
|
if ((buflen -= 4) < 0)
|
||||||
|
@ -1801,6 +2165,13 @@ out_acl:
|
||||||
}
|
}
|
||||||
WRITE64(stat.ino);
|
WRITE64(stat.ino);
|
||||||
}
|
}
|
||||||
|
if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
|
||||||
|
WRITE32(3);
|
||||||
|
WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
|
||||||
|
WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD1);
|
||||||
|
WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD2);
|
||||||
|
}
|
||||||
|
|
||||||
*attrlenp = htonl((char *)p - (char *)attrlenp - 4);
|
*attrlenp = htonl((char *)p - (char *)attrlenp - 4);
|
||||||
*countp = p - buffer;
|
*countp = p - buffer;
|
||||||
status = nfs_ok;
|
status = nfs_ok;
|
||||||
|
@ -2571,6 +2942,143 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w
|
||||||
return nfserr;
|
return nfserr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __be32
|
||||||
|
nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr,
|
||||||
|
struct nfsd4_exchange_id *exid)
|
||||||
|
{
|
||||||
|
ENCODE_HEAD;
|
||||||
|
char *major_id;
|
||||||
|
char *server_scope;
|
||||||
|
int major_id_sz;
|
||||||
|
int server_scope_sz;
|
||||||
|
uint64_t minor_id = 0;
|
||||||
|
|
||||||
|
if (nfserr)
|
||||||
|
return nfserr;
|
||||||
|
|
||||||
|
major_id = utsname()->nodename;
|
||||||
|
major_id_sz = strlen(major_id);
|
||||||
|
server_scope = utsname()->nodename;
|
||||||
|
server_scope_sz = strlen(server_scope);
|
||||||
|
|
||||||
|
RESERVE_SPACE(
|
||||||
|
8 /* eir_clientid */ +
|
||||||
|
4 /* eir_sequenceid */ +
|
||||||
|
4 /* eir_flags */ +
|
||||||
|
4 /* spr_how (SP4_NONE) */ +
|
||||||
|
8 /* so_minor_id */ +
|
||||||
|
4 /* so_major_id.len */ +
|
||||||
|
(XDR_QUADLEN(major_id_sz) * 4) +
|
||||||
|
4 /* eir_server_scope.len */ +
|
||||||
|
(XDR_QUADLEN(server_scope_sz) * 4) +
|
||||||
|
4 /* eir_server_impl_id.count (0) */);
|
||||||
|
|
||||||
|
WRITEMEM(&exid->clientid, 8);
|
||||||
|
WRITE32(exid->seqid);
|
||||||
|
WRITE32(exid->flags);
|
||||||
|
|
||||||
|
/* state_protect4_r. Currently only support SP4_NONE */
|
||||||
|
BUG_ON(exid->spa_how != SP4_NONE);
|
||||||
|
WRITE32(exid->spa_how);
|
||||||
|
|
||||||
|
/* The server_owner struct */
|
||||||
|
WRITE64(minor_id); /* Minor id */
|
||||||
|
/* major id */
|
||||||
|
WRITE32(major_id_sz);
|
||||||
|
WRITEMEM(major_id, major_id_sz);
|
||||||
|
|
||||||
|
/* Server scope */
|
||||||
|
WRITE32(server_scope_sz);
|
||||||
|
WRITEMEM(server_scope, server_scope_sz);
|
||||||
|
|
||||||
|
/* Implementation id */
|
||||||
|
WRITE32(0); /* zero length nfs_impl_id4 array */
|
||||||
|
ADJUST_ARGS();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __be32
|
||||||
|
nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr,
|
||||||
|
struct nfsd4_create_session *sess)
|
||||||
|
{
|
||||||
|
ENCODE_HEAD;
|
||||||
|
|
||||||
|
if (nfserr)
|
||||||
|
return nfserr;
|
||||||
|
|
||||||
|
RESERVE_SPACE(24);
|
||||||
|
WRITEMEM(sess->sessionid.data, NFS4_MAX_SESSIONID_LEN);
|
||||||
|
WRITE32(sess->seqid);
|
||||||
|
WRITE32(sess->flags);
|
||||||
|
ADJUST_ARGS();
|
||||||
|
|
||||||
|
RESERVE_SPACE(28);
|
||||||
|
WRITE32(0); /* headerpadsz */
|
||||||
|
WRITE32(sess->fore_channel.maxreq_sz);
|
||||||
|
WRITE32(sess->fore_channel.maxresp_sz);
|
||||||
|
WRITE32(sess->fore_channel.maxresp_cached);
|
||||||
|
WRITE32(sess->fore_channel.maxops);
|
||||||
|
WRITE32(sess->fore_channel.maxreqs);
|
||||||
|
WRITE32(sess->fore_channel.nr_rdma_attrs);
|
||||||
|
ADJUST_ARGS();
|
||||||
|
|
||||||
|
if (sess->fore_channel.nr_rdma_attrs) {
|
||||||
|
RESERVE_SPACE(4);
|
||||||
|
WRITE32(sess->fore_channel.rdma_attrs);
|
||||||
|
ADJUST_ARGS();
|
||||||
|
}
|
||||||
|
|
||||||
|
RESERVE_SPACE(28);
|
||||||
|
WRITE32(0); /* headerpadsz */
|
||||||
|
WRITE32(sess->back_channel.maxreq_sz);
|
||||||
|
WRITE32(sess->back_channel.maxresp_sz);
|
||||||
|
WRITE32(sess->back_channel.maxresp_cached);
|
||||||
|
WRITE32(sess->back_channel.maxops);
|
||||||
|
WRITE32(sess->back_channel.maxreqs);
|
||||||
|
WRITE32(sess->back_channel.nr_rdma_attrs);
|
||||||
|
ADJUST_ARGS();
|
||||||
|
|
||||||
|
if (sess->back_channel.nr_rdma_attrs) {
|
||||||
|
RESERVE_SPACE(4);
|
||||||
|
WRITE32(sess->back_channel.rdma_attrs);
|
||||||
|
ADJUST_ARGS();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __be32
|
||||||
|
nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
|
||||||
|
struct nfsd4_destroy_session *destroy_session)
|
||||||
|
{
|
||||||
|
return nfserr;
|
||||||
|
}
|
||||||
|
|
||||||
|
__be32
|
||||||
|
nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
|
||||||
|
struct nfsd4_sequence *seq)
|
||||||
|
{
|
||||||
|
ENCODE_HEAD;
|
||||||
|
|
||||||
|
if (nfserr)
|
||||||
|
return nfserr;
|
||||||
|
|
||||||
|
RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 20);
|
||||||
|
WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
|
||||||
|
WRITE32(seq->seqid);
|
||||||
|
WRITE32(seq->slotid);
|
||||||
|
WRITE32(seq->maxslots);
|
||||||
|
/*
|
||||||
|
* FIXME: for now:
|
||||||
|
* target_maxslots = maxslots
|
||||||
|
* status_flags = 0
|
||||||
|
*/
|
||||||
|
WRITE32(seq->maxslots);
|
||||||
|
WRITE32(0);
|
||||||
|
|
||||||
|
ADJUST_ARGS();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
|
nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
|
||||||
{
|
{
|
||||||
|
@ -2579,6 +3087,11 @@ nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
|
||||||
|
|
||||||
typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *);
|
typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1
|
||||||
|
* since we don't need to filter out obsolete ops as this is
|
||||||
|
* done in the decoding phase.
|
||||||
|
*/
|
||||||
static nfsd4_enc nfsd4_enc_ops[] = {
|
static nfsd4_enc nfsd4_enc_ops[] = {
|
||||||
[OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access,
|
[OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access,
|
||||||
[OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close,
|
[OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close,
|
||||||
|
@ -2617,8 +3130,77 @@ static nfsd4_enc nfsd4_enc_ops[] = {
|
||||||
[OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop,
|
[OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
[OP_WRITE] = (nfsd4_enc)nfsd4_encode_write,
|
[OP_WRITE] = (nfsd4_enc)nfsd4_encode_write,
|
||||||
[OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop,
|
[OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
|
||||||
|
/* NFSv4.1 operations */
|
||||||
|
[OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
|
||||||
|
[OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
|
||||||
|
[OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session,
|
||||||
|
[OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence,
|
||||||
|
[OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
|
[OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the total amount of memory that the compound response has taken
|
||||||
|
* after encoding the current operation.
|
||||||
|
*
|
||||||
|
* pad: add on 8 bytes for the next operation's op_code and status so that
|
||||||
|
* there is room to cache a failure on the next operation.
|
||||||
|
*
|
||||||
|
* Compare this length to the session se_fmaxresp_cached.
|
||||||
|
*
|
||||||
|
* Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so
|
||||||
|
* will be at least a page and will therefore hold the xdr_buf head.
|
||||||
|
*/
|
||||||
|
static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
struct xdr_buf *xb = &resp->rqstp->rq_res;
|
||||||
|
struct nfsd4_compoundargs *args = resp->rqstp->rq_argp;
|
||||||
|
struct nfsd4_session *session = NULL;
|
||||||
|
struct nfsd4_slot *slot = resp->cstate.slot;
|
||||||
|
u32 length, tlen = 0, pad = 8;
|
||||||
|
|
||||||
|
if (!nfsd4_has_session(&resp->cstate))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
session = resp->cstate.session;
|
||||||
|
if (session == NULL || slot->sl_cache_entry.ce_cachethis == 0)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (resp->opcnt >= args->opcnt)
|
||||||
|
pad = 0; /* this is the last operation */
|
||||||
|
|
||||||
|
if (xb->page_len == 0) {
|
||||||
|
length = (char *)resp->p - (char *)xb->head[0].iov_base + pad;
|
||||||
|
} else {
|
||||||
|
if (xb->tail[0].iov_base && xb->tail[0].iov_len > 0)
|
||||||
|
tlen = (char *)resp->p - (char *)xb->tail[0].iov_base;
|
||||||
|
|
||||||
|
length = xb->head[0].iov_len + xb->page_len + tlen + pad;
|
||||||
|
}
|
||||||
|
dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__,
|
||||||
|
length, xb->page_len, tlen, pad);
|
||||||
|
|
||||||
|
if (length <= session->se_fmaxresp_cached)
|
||||||
|
return status;
|
||||||
|
else
|
||||||
|
return nfserr_rep_too_big_to_cache;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
|
nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
|
||||||
{
|
{
|
||||||
|
@ -2635,6 +3217,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
|
||||||
BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
|
BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
|
||||||
!nfsd4_enc_ops[op->opnum]);
|
!nfsd4_enc_ops[op->opnum]);
|
||||||
op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u);
|
op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u);
|
||||||
|
/* nfsd4_check_drc_limit guarantees enough room for error status */
|
||||||
|
if (!op->status && nfsd4_check_drc_limit(resp))
|
||||||
|
op->status = nfserr_rep_too_big_to_cache;
|
||||||
status:
|
status:
|
||||||
/*
|
/*
|
||||||
* Note: We write the status directly, instead of using WRITE32(),
|
* Note: We write the status directly, instead of using WRITE32(),
|
||||||
|
@ -2735,6 +3320,18 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
|
||||||
iov = &rqstp->rq_res.head[0];
|
iov = &rqstp->rq_res.head[0];
|
||||||
iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
|
iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
|
||||||
BUG_ON(iov->iov_len > PAGE_SIZE);
|
BUG_ON(iov->iov_len > PAGE_SIZE);
|
||||||
|
if (nfsd4_has_session(&resp->cstate)) {
|
||||||
|
if (resp->cstate.status == nfserr_replay_cache &&
|
||||||
|
!nfsd4_not_cached(resp)) {
|
||||||
|
iov->iov_len = resp->cstate.iovlen;
|
||||||
|
} else {
|
||||||
|
nfsd4_store_cache_entry(resp);
|
||||||
|
dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
|
||||||
|
resp->cstate.slot->sl_inuse = 0;
|
||||||
|
}
|
||||||
|
if (resp->cstate.session)
|
||||||
|
nfsd4_put_session(resp->cstate.session);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ enum {
|
||||||
NFSD_FO_UnlockFS,
|
NFSD_FO_UnlockFS,
|
||||||
NFSD_Threads,
|
NFSD_Threads,
|
||||||
NFSD_Pool_Threads,
|
NFSD_Pool_Threads,
|
||||||
|
NFSD_Pool_Stats,
|
||||||
NFSD_Versions,
|
NFSD_Versions,
|
||||||
NFSD_Ports,
|
NFSD_Ports,
|
||||||
NFSD_MaxBlkSize,
|
NFSD_MaxBlkSize,
|
||||||
|
@ -172,6 +173,16 @@ static const struct file_operations exports_operations = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
|
||||||
|
|
||||||
|
static struct file_operations pool_stats_operations = {
|
||||||
|
.open = nfsd_pool_stats_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = seq_release,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
/*
|
/*
|
||||||
* payload - write methods
|
* payload - write methods
|
||||||
|
@ -781,8 +792,9 @@ out_free:
|
||||||
static ssize_t __write_versions(struct file *file, char *buf, size_t size)
|
static ssize_t __write_versions(struct file *file, char *buf, size_t size)
|
||||||
{
|
{
|
||||||
char *mesg = buf;
|
char *mesg = buf;
|
||||||
char *vers, sign;
|
char *vers, *minorp, sign;
|
||||||
int len, num;
|
int len, num;
|
||||||
|
unsigned minor;
|
||||||
ssize_t tlen = 0;
|
ssize_t tlen = 0;
|
||||||
char *sep;
|
char *sep;
|
||||||
|
|
||||||
|
@ -803,9 +815,20 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
|
||||||
do {
|
do {
|
||||||
sign = *vers;
|
sign = *vers;
|
||||||
if (sign == '+' || sign == '-')
|
if (sign == '+' || sign == '-')
|
||||||
num = simple_strtol((vers+1), NULL, 0);
|
num = simple_strtol((vers+1), &minorp, 0);
|
||||||
else
|
else
|
||||||
num = simple_strtol(vers, NULL, 0);
|
num = simple_strtol(vers, &minorp, 0);
|
||||||
|
if (*minorp == '.') {
|
||||||
|
if (num < 4)
|
||||||
|
return -EINVAL;
|
||||||
|
minor = simple_strtoul(minorp+1, NULL, 0);
|
||||||
|
if (minor == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
if (nfsd_minorversion(minor, sign == '-' ?
|
||||||
|
NFSD_CLEAR : NFSD_SET) < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
switch(num) {
|
switch(num) {
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -815,6 +838,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
next:
|
||||||
vers += len + 1;
|
vers += len + 1;
|
||||||
tlen += len;
|
tlen += len;
|
||||||
} while ((len = qword_get(&mesg, vers, size)) > 0);
|
} while ((len = qword_get(&mesg, vers, size)) > 0);
|
||||||
|
@ -833,6 +857,13 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
|
||||||
num);
|
num);
|
||||||
sep = " ";
|
sep = " ";
|
||||||
}
|
}
|
||||||
|
if (nfsd_vers(4, NFSD_AVAIL))
|
||||||
|
for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++)
|
||||||
|
len += sprintf(buf+len, " %c4.%u",
|
||||||
|
(nfsd_vers(4, NFSD_TEST) &&
|
||||||
|
nfsd_minorversion(minor, NFSD_TEST)) ?
|
||||||
|
'+' : '-',
|
||||||
|
minor);
|
||||||
len += sprintf(buf+len, "\n");
|
len += sprintf(buf+len, "\n");
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
@ -1248,6 +1279,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
|
||||||
[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
|
[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
|
||||||
[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
|
[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
|
||||||
[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
|
[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
|
||||||
|
[NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
|
||||||
[NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
|
[NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
|
||||||
[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
|
[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
|
||||||
[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
|
[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
|
||||||
|
|
|
@ -180,6 +180,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
|
||||||
{
|
{
|
||||||
__be32 nfserr;
|
__be32 nfserr;
|
||||||
int stable = 1;
|
int stable = 1;
|
||||||
|
unsigned long cnt = argp->len;
|
||||||
|
|
||||||
dprintk("nfsd: WRITE %s %d bytes at %d\n",
|
dprintk("nfsd: WRITE %s %d bytes at %d\n",
|
||||||
SVCFH_fmt(&argp->fh),
|
SVCFH_fmt(&argp->fh),
|
||||||
|
@ -188,7 +189,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
|
||||||
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
|
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
|
||||||
argp->offset,
|
argp->offset,
|
||||||
rqstp->rq_vec, argp->vlen,
|
rqstp->rq_vec, argp->vlen,
|
||||||
argp->len,
|
&cnt,
|
||||||
&stable);
|
&stable);
|
||||||
return nfsd_return_attrs(nfserr, resp);
|
return nfsd_return_attrs(nfserr, resp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
#include <linux/fs_struct.h>
|
#include <linux/fs_struct.h>
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
|
#include <linux/swap.h>
|
||||||
|
|
||||||
#include <linux/sunrpc/types.h>
|
#include <linux/sunrpc/types.h>
|
||||||
#include <linux/sunrpc/stats.h>
|
#include <linux/sunrpc/stats.h>
|
||||||
|
@ -40,9 +41,6 @@
|
||||||
extern struct svc_program nfsd_program;
|
extern struct svc_program nfsd_program;
|
||||||
static int nfsd(void *vrqstp);
|
static int nfsd(void *vrqstp);
|
||||||
struct timeval nfssvc_boot;
|
struct timeval nfssvc_boot;
|
||||||
static atomic_t nfsd_busy;
|
|
||||||
static unsigned long nfsd_last_call;
|
|
||||||
static DEFINE_SPINLOCK(nfsd_call_lock);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nfsd_mutex protects nfsd_serv -- both the pointer itself and the members
|
* nfsd_mutex protects nfsd_serv -- both the pointer itself and the members
|
||||||
|
@ -123,6 +121,8 @@ struct svc_program nfsd_program = {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
u32 nfsd_supported_minorversion;
|
||||||
|
|
||||||
int nfsd_vers(int vers, enum vers_op change)
|
int nfsd_vers(int vers, enum vers_op change)
|
||||||
{
|
{
|
||||||
if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
|
if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
|
||||||
|
@ -149,6 +149,28 @@ int nfsd_vers(int vers, enum vers_op change)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nfsd_minorversion(u32 minorversion, enum vers_op change)
|
||||||
|
{
|
||||||
|
if (minorversion > NFSD_SUPPORTED_MINOR_VERSION)
|
||||||
|
return -1;
|
||||||
|
switch(change) {
|
||||||
|
case NFSD_SET:
|
||||||
|
nfsd_supported_minorversion = minorversion;
|
||||||
|
break;
|
||||||
|
case NFSD_CLEAR:
|
||||||
|
if (minorversion == 0)
|
||||||
|
return -1;
|
||||||
|
nfsd_supported_minorversion = minorversion - 1;
|
||||||
|
break;
|
||||||
|
case NFSD_TEST:
|
||||||
|
return minorversion <= nfsd_supported_minorversion;
|
||||||
|
case NFSD_AVAIL:
|
||||||
|
return minorversion <= NFSD_SUPPORTED_MINOR_VERSION;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximum number of nfsd processes
|
* Maximum number of nfsd processes
|
||||||
*/
|
*/
|
||||||
|
@ -200,6 +222,28 @@ void nfsd_reset_versions(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each session guarantees a negotiated per slot memory cache for replies
|
||||||
|
* which in turn consumes memory beyond the v2/v3/v4.0 server. A dedicated
|
||||||
|
* NFSv4.1 server might want to use more memory for a DRC than a machine
|
||||||
|
* with mutiple services.
|
||||||
|
*
|
||||||
|
* Impose a hard limit on the number of pages for the DRC which varies
|
||||||
|
* according to the machines free pages. This is of course only a default.
|
||||||
|
*
|
||||||
|
* For now this is a #defined shift which could be under admin control
|
||||||
|
* in the future.
|
||||||
|
*/
|
||||||
|
static void set_max_drc(void)
|
||||||
|
{
|
||||||
|
/* The percent of nr_free_buffer_pages used by the V4.1 server DRC */
|
||||||
|
#define NFSD_DRC_SIZE_SHIFT 7
|
||||||
|
nfsd_serv->sv_drc_max_pages = nr_free_buffer_pages()
|
||||||
|
>> NFSD_DRC_SIZE_SHIFT;
|
||||||
|
nfsd_serv->sv_drc_pages_used = 0;
|
||||||
|
dprintk("%s svc_drc_max_pages %u\n", __func__,
|
||||||
|
nfsd_serv->sv_drc_max_pages);
|
||||||
|
}
|
||||||
|
|
||||||
int nfsd_create_serv(void)
|
int nfsd_create_serv(void)
|
||||||
{
|
{
|
||||||
|
@ -227,11 +271,12 @@ int nfsd_create_serv(void)
|
||||||
nfsd_max_blksize /= 2;
|
nfsd_max_blksize /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_set(&nfsd_busy, 0);
|
|
||||||
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
|
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
|
||||||
nfsd_last_thread, nfsd, THIS_MODULE);
|
nfsd_last_thread, nfsd, THIS_MODULE);
|
||||||
if (nfsd_serv == NULL)
|
if (nfsd_serv == NULL)
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
else
|
||||||
|
set_max_drc();
|
||||||
|
|
||||||
do_gettimeofday(&nfssvc_boot); /* record boot time */
|
do_gettimeofday(&nfssvc_boot); /* record boot time */
|
||||||
return err;
|
return err;
|
||||||
|
@ -375,26 +420,6 @@ nfsd_svc(unsigned short port, int nrservs)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
update_thread_usage(int busy_threads)
|
|
||||||
{
|
|
||||||
unsigned long prev_call;
|
|
||||||
unsigned long diff;
|
|
||||||
int decile;
|
|
||||||
|
|
||||||
spin_lock(&nfsd_call_lock);
|
|
||||||
prev_call = nfsd_last_call;
|
|
||||||
nfsd_last_call = jiffies;
|
|
||||||
decile = busy_threads*10/nfsdstats.th_cnt;
|
|
||||||
if (decile>0 && decile <= 10) {
|
|
||||||
diff = nfsd_last_call - prev_call;
|
|
||||||
if ( (nfsdstats.th_usage[decile-1] += diff) >= NFSD_USAGE_WRAP)
|
|
||||||
nfsdstats.th_usage[decile-1] -= NFSD_USAGE_WRAP;
|
|
||||||
if (decile == 10)
|
|
||||||
nfsdstats.th_fullcnt++;
|
|
||||||
}
|
|
||||||
spin_unlock(&nfsd_call_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the NFS server kernel thread
|
* This is the NFS server kernel thread
|
||||||
|
@ -460,8 +485,6 @@ nfsd(void *vrqstp)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_thread_usage(atomic_read(&nfsd_busy));
|
|
||||||
atomic_inc(&nfsd_busy);
|
|
||||||
|
|
||||||
/* Lock the export hash tables for reading. */
|
/* Lock the export hash tables for reading. */
|
||||||
exp_readlock();
|
exp_readlock();
|
||||||
|
@ -470,8 +493,6 @@ nfsd(void *vrqstp)
|
||||||
|
|
||||||
/* Unlock export hash tables */
|
/* Unlock export hash tables */
|
||||||
exp_readunlock();
|
exp_readunlock();
|
||||||
update_thread_usage(atomic_read(&nfsd_busy));
|
|
||||||
atomic_dec(&nfsd_busy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear signals before calling svc_exit_thread() */
|
/* Clear signals before calling svc_exit_thread() */
|
||||||
|
@ -539,6 +560,10 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
|
||||||
+ rqstp->rq_res.head[0].iov_len;
|
+ rqstp->rq_res.head[0].iov_len;
|
||||||
rqstp->rq_res.head[0].iov_len += sizeof(__be32);
|
rqstp->rq_res.head[0].iov_len += sizeof(__be32);
|
||||||
|
|
||||||
|
/* NFSv4.1 DRC requires statp */
|
||||||
|
if (rqstp->rq_vers == 4)
|
||||||
|
nfsd4_set_statp(rqstp, statp);
|
||||||
|
|
||||||
/* Now call the procedure handler, and encode NFS status. */
|
/* Now call the procedure handler, and encode NFS status. */
|
||||||
nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
|
nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
|
||||||
nfserr = map_new_errors(rqstp->rq_vers, nfserr);
|
nfserr = map_new_errors(rqstp->rq_vers, nfserr);
|
||||||
|
@ -570,3 +595,10 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
|
||||||
nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
|
nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nfsd_pool_stats_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
if (nfsd_serv == NULL)
|
||||||
|
return -ENODEV;
|
||||||
|
return svc_pool_stats_open(nfsd_serv, file);
|
||||||
|
}
|
||||||
|
|
|
@ -366,8 +366,9 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Revoke setuid/setgid on chown */
|
/* Revoke setuid/setgid on chown */
|
||||||
if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) ||
|
if (!S_ISDIR(inode->i_mode) &&
|
||||||
((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) {
|
(((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;
|
iap->ia_valid |= ATTR_KILL_PRIV;
|
||||||
if (iap->ia_valid & ATTR_MODE) {
|
if (iap->ia_valid & ATTR_MODE) {
|
||||||
/* we're setting mode too, just clear the s*id bits */
|
/* we're setting mode too, just clear the s*id bits */
|
||||||
|
@ -960,7 +961,7 @@ static void kill_suid(struct dentry *dentry)
|
||||||
static __be32
|
static __be32
|
||||||
nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
||||||
loff_t offset, struct kvec *vec, int vlen,
|
loff_t offset, struct kvec *vec, int vlen,
|
||||||
unsigned long cnt, int *stablep)
|
unsigned long *cnt, int *stablep)
|
||||||
{
|
{
|
||||||
struct svc_export *exp;
|
struct svc_export *exp;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
@ -974,7 +975,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
||||||
err = nfserr_perm;
|
err = nfserr_perm;
|
||||||
|
|
||||||
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
|
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
|
||||||
(!lock_may_write(file->f_path.dentry->d_inode, offset, cnt)))
|
(!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt)))
|
||||||
goto out;
|
goto out;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1009,7 +1010,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
||||||
host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
|
host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
|
||||||
set_fs(oldfs);
|
set_fs(oldfs);
|
||||||
if (host_err >= 0) {
|
if (host_err >= 0) {
|
||||||
nfsdstats.io_write += cnt;
|
nfsdstats.io_write += host_err;
|
||||||
fsnotify_modify(file->f_path.dentry);
|
fsnotify_modify(file->f_path.dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1054,9 +1055,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintk("nfsd: write complete host_err=%d\n", host_err);
|
dprintk("nfsd: write complete host_err=%d\n", host_err);
|
||||||
if (host_err >= 0)
|
if (host_err >= 0) {
|
||||||
err = 0;
|
err = 0;
|
||||||
else
|
*cnt = host_err;
|
||||||
|
} else
|
||||||
err = nfserrno(host_err);
|
err = nfserrno(host_err);
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
|
@ -1098,7 +1100,7 @@ out:
|
||||||
*/
|
*/
|
||||||
__be32
|
__be32
|
||||||
nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
||||||
loff_t offset, struct kvec *vec, int vlen, unsigned long cnt,
|
loff_t offset, struct kvec *vec, int vlen, unsigned long *cnt,
|
||||||
int *stablep)
|
int *stablep)
|
||||||
{
|
{
|
||||||
__be32 err = 0;
|
__be32 err = 0;
|
||||||
|
@ -1179,6 +1181,21 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* HPUX client sometimes creates a file in mode 000, and sets size to 0.
|
||||||
|
* setting size to 0 may fail for some specific file systems by the permission
|
||||||
|
* checking which requires WRITE permission but the mode is 000.
|
||||||
|
* we ignore the resizing(to 0) on the just new created file, since the size is
|
||||||
|
* 0 after file created.
|
||||||
|
*
|
||||||
|
* call this only after vfs_create() is called.
|
||||||
|
* */
|
||||||
|
static void
|
||||||
|
nfsd_check_ignore_resizing(struct iattr *iap)
|
||||||
|
{
|
||||||
|
if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
|
||||||
|
iap->ia_valid &= ~ATTR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a file (regular, directory, device, fifo); UNIX sockets
|
* Create a file (regular, directory, device, fifo); UNIX sockets
|
||||||
* not yet implemented.
|
* not yet implemented.
|
||||||
|
@ -1274,6 +1291,8 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
|
host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
|
||||||
|
if (!host_err)
|
||||||
|
nfsd_check_ignore_resizing(iap);
|
||||||
break;
|
break;
|
||||||
case S_IFDIR:
|
case S_IFDIR:
|
||||||
host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
|
host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
|
||||||
|
@ -1427,6 +1446,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
/* setattr will sync the child (or not) */
|
/* setattr will sync the child (or not) */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nfsd_check_ignore_resizing(iap);
|
||||||
|
|
||||||
if (createmode == NFS3_CREATE_EXCLUSIVE) {
|
if (createmode == NFS3_CREATE_EXCLUSIVE) {
|
||||||
/* Cram the verifier into atime/mtime */
|
/* Cram the verifier into atime/mtime */
|
||||||
iap->ia_valid = ATTR_MTIME|ATTR_ATIME
|
iap->ia_valid = ATTR_MTIME|ATTR_ATIME
|
||||||
|
|
|
@ -25,13 +25,13 @@ struct svc_rqst;
|
||||||
#define NLM_MAXCOOKIELEN 32
|
#define NLM_MAXCOOKIELEN 32
|
||||||
#define NLM_MAXSTRLEN 1024
|
#define NLM_MAXSTRLEN 1024
|
||||||
|
|
||||||
#define nlm_granted __constant_htonl(NLM_LCK_GRANTED)
|
#define nlm_granted cpu_to_be32(NLM_LCK_GRANTED)
|
||||||
#define nlm_lck_denied __constant_htonl(NLM_LCK_DENIED)
|
#define nlm_lck_denied cpu_to_be32(NLM_LCK_DENIED)
|
||||||
#define nlm_lck_denied_nolocks __constant_htonl(NLM_LCK_DENIED_NOLOCKS)
|
#define nlm_lck_denied_nolocks cpu_to_be32(NLM_LCK_DENIED_NOLOCKS)
|
||||||
#define nlm_lck_blocked __constant_htonl(NLM_LCK_BLOCKED)
|
#define nlm_lck_blocked cpu_to_be32(NLM_LCK_BLOCKED)
|
||||||
#define nlm_lck_denied_grace_period __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD)
|
#define nlm_lck_denied_grace_period cpu_to_be32(NLM_LCK_DENIED_GRACE_PERIOD)
|
||||||
|
|
||||||
#define nlm_drop_reply __constant_htonl(30000)
|
#define nlm_drop_reply cpu_to_be32(30000)
|
||||||
|
|
||||||
/* Lock info passed via NLM */
|
/* Lock info passed via NLM */
|
||||||
struct nlm_lock {
|
struct nlm_lock {
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
#include <linux/lockd/xdr.h>
|
#include <linux/lockd/xdr.h>
|
||||||
|
|
||||||
/* error codes new to NLMv4 */
|
/* error codes new to NLMv4 */
|
||||||
#define nlm4_deadlock __constant_htonl(NLM_DEADLCK)
|
#define nlm4_deadlock cpu_to_be32(NLM_DEADLCK)
|
||||||
#define nlm4_rofs __constant_htonl(NLM_ROFS)
|
#define nlm4_rofs cpu_to_be32(NLM_ROFS)
|
||||||
#define nlm4_stale_fh __constant_htonl(NLM_STALE_FH)
|
#define nlm4_stale_fh cpu_to_be32(NLM_STALE_FH)
|
||||||
#define nlm4_fbig __constant_htonl(NLM_FBIG)
|
#define nlm4_fbig cpu_to_be32(NLM_FBIG)
|
||||||
#define nlm4_failed __constant_htonl(NLM_FAILED)
|
#define nlm4_failed cpu_to_be32(NLM_FAILED)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,6 @@
|
||||||
NFSERR_FILE_OPEN = 10046, /* v4 */
|
NFSERR_FILE_OPEN = 10046, /* v4 */
|
||||||
NFSERR_ADMIN_REVOKED = 10047, /* v4 */
|
NFSERR_ADMIN_REVOKED = 10047, /* v4 */
|
||||||
NFSERR_CB_PATH_DOWN = 10048, /* v4 */
|
NFSERR_CB_PATH_DOWN = 10048, /* v4 */
|
||||||
NFSERR_REPLAY_ME = 10049 /* v4 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* NFSv2 file types - beware, these are not the same in NFSv3 */
|
/* NFSv2 file types - beware, these are not the same in NFSv3 */
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define NFS4_FHSIZE 128
|
#define NFS4_FHSIZE 128
|
||||||
#define NFS4_MAXPATHLEN PATH_MAX
|
#define NFS4_MAXPATHLEN PATH_MAX
|
||||||
#define NFS4_MAXNAMLEN NAME_MAX
|
#define NFS4_MAXNAMLEN NAME_MAX
|
||||||
|
#define NFS4_MAX_SESSIONID_LEN 16
|
||||||
|
|
||||||
#define NFS4_ACCESS_READ 0x0001
|
#define NFS4_ACCESS_READ 0x0001
|
||||||
#define NFS4_ACCESS_LOOKUP 0x0002
|
#define NFS4_ACCESS_LOOKUP 0x0002
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
#define NFS4_OPEN_RESULT_CONFIRM 0x0002
|
#define NFS4_OPEN_RESULT_CONFIRM 0x0002
|
||||||
#define NFS4_OPEN_RESULT_LOCKTYPE_POSIX 0x0004
|
#define NFS4_OPEN_RESULT_LOCKTYPE_POSIX 0x0004
|
||||||
|
|
||||||
|
#define NFS4_SHARE_ACCESS_MASK 0x000F
|
||||||
#define NFS4_SHARE_ACCESS_READ 0x0001
|
#define NFS4_SHARE_ACCESS_READ 0x0001
|
||||||
#define NFS4_SHARE_ACCESS_WRITE 0x0002
|
#define NFS4_SHARE_ACCESS_WRITE 0x0002
|
||||||
#define NFS4_SHARE_ACCESS_BOTH 0x0003
|
#define NFS4_SHARE_ACCESS_BOTH 0x0003
|
||||||
|
@ -45,6 +47,19 @@
|
||||||
#define NFS4_SHARE_DENY_WRITE 0x0002
|
#define NFS4_SHARE_DENY_WRITE 0x0002
|
||||||
#define NFS4_SHARE_DENY_BOTH 0x0003
|
#define NFS4_SHARE_DENY_BOTH 0x0003
|
||||||
|
|
||||||
|
/* nfs41 */
|
||||||
|
#define NFS4_SHARE_WANT_MASK 0xFF00
|
||||||
|
#define NFS4_SHARE_WANT_NO_PREFERENCE 0x0000
|
||||||
|
#define NFS4_SHARE_WANT_READ_DELEG 0x0100
|
||||||
|
#define NFS4_SHARE_WANT_WRITE_DELEG 0x0200
|
||||||
|
#define NFS4_SHARE_WANT_ANY_DELEG 0x0300
|
||||||
|
#define NFS4_SHARE_WANT_NO_DELEG 0x0400
|
||||||
|
#define NFS4_SHARE_WANT_CANCEL 0x0500
|
||||||
|
|
||||||
|
#define NFS4_SHARE_WHEN_MASK 0xF0000
|
||||||
|
#define NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL 0x10000
|
||||||
|
#define NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED 0x20000
|
||||||
|
|
||||||
#define NFS4_SET_TO_SERVER_TIME 0
|
#define NFS4_SET_TO_SERVER_TIME 0
|
||||||
#define NFS4_SET_TO_CLIENT_TIME 1
|
#define NFS4_SET_TO_CLIENT_TIME 1
|
||||||
|
|
||||||
|
@ -88,6 +103,31 @@
|
||||||
#define NFS4_ACE_GENERIC_EXECUTE 0x001200A0
|
#define NFS4_ACE_GENERIC_EXECUTE 0x001200A0
|
||||||
#define NFS4_ACE_MASK_ALL 0x001F01FF
|
#define NFS4_ACE_MASK_ALL 0x001F01FF
|
||||||
|
|
||||||
|
#define EXCHGID4_FLAG_SUPP_MOVED_REFER 0x00000001
|
||||||
|
#define EXCHGID4_FLAG_SUPP_MOVED_MIGR 0x00000002
|
||||||
|
#define EXCHGID4_FLAG_USE_NON_PNFS 0x00010000
|
||||||
|
#define EXCHGID4_FLAG_USE_PNFS_MDS 0x00020000
|
||||||
|
#define EXCHGID4_FLAG_USE_PNFS_DS 0x00040000
|
||||||
|
#define EXCHGID4_FLAG_UPD_CONFIRMED_REC_A 0x40000000
|
||||||
|
#define EXCHGID4_FLAG_CONFIRMED_R 0x80000000
|
||||||
|
/*
|
||||||
|
* Since the validity of these bits depends on whether
|
||||||
|
* they're set in the argument or response, have separate
|
||||||
|
* invalid flag masks for arg (_A) and resp (_R).
|
||||||
|
*/
|
||||||
|
#define EXCHGID4_FLAG_MASK_A 0x40070003
|
||||||
|
#define EXCHGID4_FLAG_MASK_R 0x80070003
|
||||||
|
|
||||||
|
#define SEQ4_STATUS_CB_PATH_DOWN 0x00000001
|
||||||
|
#define SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING 0x00000002
|
||||||
|
#define SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED 0x00000004
|
||||||
|
#define SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED 0x00000008
|
||||||
|
#define SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED 0x00000010
|
||||||
|
#define SEQ4_STATUS_ADMIN_STATE_REVOKED 0x00000020
|
||||||
|
#define SEQ4_STATUS_RECALLABLE_STATE_REVOKED 0x00000040
|
||||||
|
#define SEQ4_STATUS_LEASE_MOVED 0x00000080
|
||||||
|
#define SEQ4_STATUS_RESTART_RECLAIM_NEEDED 0x00000100
|
||||||
|
|
||||||
#define NFS4_MAX_UINT64 (~(u64)0)
|
#define NFS4_MAX_UINT64 (~(u64)0)
|
||||||
|
|
||||||
enum nfs4_acl_whotype {
|
enum nfs4_acl_whotype {
|
||||||
|
@ -154,6 +194,28 @@ enum nfs_opnum4 {
|
||||||
OP_VERIFY = 37,
|
OP_VERIFY = 37,
|
||||||
OP_WRITE = 38,
|
OP_WRITE = 38,
|
||||||
OP_RELEASE_LOCKOWNER = 39,
|
OP_RELEASE_LOCKOWNER = 39,
|
||||||
|
|
||||||
|
/* nfs41 */
|
||||||
|
OP_BACKCHANNEL_CTL = 40,
|
||||||
|
OP_BIND_CONN_TO_SESSION = 41,
|
||||||
|
OP_EXCHANGE_ID = 42,
|
||||||
|
OP_CREATE_SESSION = 43,
|
||||||
|
OP_DESTROY_SESSION = 44,
|
||||||
|
OP_FREE_STATEID = 45,
|
||||||
|
OP_GET_DIR_DELEGATION = 46,
|
||||||
|
OP_GETDEVICEINFO = 47,
|
||||||
|
OP_GETDEVICELIST = 48,
|
||||||
|
OP_LAYOUTCOMMIT = 49,
|
||||||
|
OP_LAYOUTGET = 50,
|
||||||
|
OP_LAYOUTRETURN = 51,
|
||||||
|
OP_SECINFO_NO_NAME = 52,
|
||||||
|
OP_SEQUENCE = 53,
|
||||||
|
OP_SET_SSV = 54,
|
||||||
|
OP_TEST_STATEID = 55,
|
||||||
|
OP_WANT_DELEGATION = 56,
|
||||||
|
OP_DESTROY_CLIENTID = 57,
|
||||||
|
OP_RECLAIM_COMPLETE = 58,
|
||||||
|
|
||||||
OP_ILLEGAL = 10044,
|
OP_ILLEGAL = 10044,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -230,7 +292,48 @@ enum nfsstat4 {
|
||||||
NFS4ERR_DEADLOCK = 10045,
|
NFS4ERR_DEADLOCK = 10045,
|
||||||
NFS4ERR_FILE_OPEN = 10046,
|
NFS4ERR_FILE_OPEN = 10046,
|
||||||
NFS4ERR_ADMIN_REVOKED = 10047,
|
NFS4ERR_ADMIN_REVOKED = 10047,
|
||||||
NFS4ERR_CB_PATH_DOWN = 10048
|
NFS4ERR_CB_PATH_DOWN = 10048,
|
||||||
|
|
||||||
|
/* nfs41 */
|
||||||
|
NFS4ERR_BADIOMODE = 10049,
|
||||||
|
NFS4ERR_BADLAYOUT = 10050,
|
||||||
|
NFS4ERR_BAD_SESSION_DIGEST = 10051,
|
||||||
|
NFS4ERR_BADSESSION = 10052,
|
||||||
|
NFS4ERR_BADSLOT = 10053,
|
||||||
|
NFS4ERR_COMPLETE_ALREADY = 10054,
|
||||||
|
NFS4ERR_CONN_NOT_BOUND_TO_SESSION = 10055,
|
||||||
|
NFS4ERR_DELEG_ALREADY_WANTED = 10056,
|
||||||
|
NFS4ERR_BACK_CHAN_BUSY = 10057, /* backchan reqs outstanding */
|
||||||
|
NFS4ERR_LAYOUTTRYLATER = 10058,
|
||||||
|
NFS4ERR_LAYOUTUNAVAILABLE = 10059,
|
||||||
|
NFS4ERR_NOMATCHING_LAYOUT = 10060,
|
||||||
|
NFS4ERR_RECALLCONFLICT = 10061,
|
||||||
|
NFS4ERR_UNKNOWN_LAYOUTTYPE = 10062,
|
||||||
|
NFS4ERR_SEQ_MISORDERED = 10063, /* unexpected seq.id in req */
|
||||||
|
NFS4ERR_SEQUENCE_POS = 10064, /* [CB_]SEQ. op not 1st op */
|
||||||
|
NFS4ERR_REQ_TOO_BIG = 10065, /* request too big */
|
||||||
|
NFS4ERR_REP_TOO_BIG = 10066, /* reply too big */
|
||||||
|
NFS4ERR_REP_TOO_BIG_TO_CACHE = 10067, /* rep. not all cached */
|
||||||
|
NFS4ERR_RETRY_UNCACHED_REP = 10068, /* retry & rep. uncached */
|
||||||
|
NFS4ERR_UNSAFE_COMPOUND = 10069, /* retry/recovery too hard */
|
||||||
|
NFS4ERR_TOO_MANY_OPS = 10070, /* too many ops in [CB_]COMP */
|
||||||
|
NFS4ERR_OP_NOT_IN_SESSION = 10071, /* op needs [CB_]SEQ. op */
|
||||||
|
NFS4ERR_HASH_ALG_UNSUPP = 10072, /* hash alg. not supp. */
|
||||||
|
/* Error 10073 is unused. */
|
||||||
|
NFS4ERR_CLIENTID_BUSY = 10074, /* clientid has state */
|
||||||
|
NFS4ERR_PNFS_IO_HOLE = 10075, /* IO to _SPARSE file hole */
|
||||||
|
NFS4ERR_SEQ_FALSE_RETRY = 10076, /* retry not origional */
|
||||||
|
NFS4ERR_BAD_HIGH_SLOT = 10077, /* sequence arg bad */
|
||||||
|
NFS4ERR_DEADSESSION = 10078, /* persistent session dead */
|
||||||
|
NFS4ERR_ENCR_ALG_UNSUPP = 10079, /* SSV alg mismatch */
|
||||||
|
NFS4ERR_PNFS_NO_LAYOUT = 10080, /* direct I/O with no layout */
|
||||||
|
NFS4ERR_NOT_ONLY_OP = 10081, /* bad compound */
|
||||||
|
NFS4ERR_WRONG_CRED = 10082, /* permissions:state change */
|
||||||
|
NFS4ERR_WRONG_TYPE = 10083, /* current operation mismatch */
|
||||||
|
NFS4ERR_DIRDELEG_UNAVAIL = 10084, /* no directory delegation */
|
||||||
|
NFS4ERR_REJECT_DELEG = 10085, /* on callback */
|
||||||
|
NFS4ERR_RETURNCONFLICT = 10086, /* outstanding layoutreturn */
|
||||||
|
NFS4ERR_DELEG_REVOKED = 10087, /* deleg./layout revoked */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -265,7 +368,13 @@ enum opentype4 {
|
||||||
enum createmode4 {
|
enum createmode4 {
|
||||||
NFS4_CREATE_UNCHECKED = 0,
|
NFS4_CREATE_UNCHECKED = 0,
|
||||||
NFS4_CREATE_GUARDED = 1,
|
NFS4_CREATE_GUARDED = 1,
|
||||||
NFS4_CREATE_EXCLUSIVE = 2
|
NFS4_CREATE_EXCLUSIVE = 2,
|
||||||
|
/*
|
||||||
|
* New to NFSv4.1. If session is persistent,
|
||||||
|
* GUARDED4 MUST be used. Otherwise, use
|
||||||
|
* EXCLUSIVE4_1 instead of EXCLUSIVE4.
|
||||||
|
*/
|
||||||
|
NFS4_CREATE_EXCLUSIVE4_1 = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum limit_by4 {
|
enum limit_by4 {
|
||||||
|
@ -301,6 +410,8 @@ enum lock_type4 {
|
||||||
#define FATTR4_WORD0_UNIQUE_HANDLES (1UL << 9)
|
#define FATTR4_WORD0_UNIQUE_HANDLES (1UL << 9)
|
||||||
#define FATTR4_WORD0_LEASE_TIME (1UL << 10)
|
#define FATTR4_WORD0_LEASE_TIME (1UL << 10)
|
||||||
#define FATTR4_WORD0_RDATTR_ERROR (1UL << 11)
|
#define FATTR4_WORD0_RDATTR_ERROR (1UL << 11)
|
||||||
|
/* Mandatory in NFSv4.1 */
|
||||||
|
#define FATTR4_WORD2_SUPPATTR_EXCLCREAT (1UL << 11)
|
||||||
|
|
||||||
/* Recommended Attributes */
|
/* Recommended Attributes */
|
||||||
#define FATTR4_WORD0_ACL (1UL << 12)
|
#define FATTR4_WORD0_ACL (1UL << 12)
|
||||||
|
@ -391,6 +502,29 @@ enum {
|
||||||
NFSPROC4_CLNT_GETACL,
|
NFSPROC4_CLNT_GETACL,
|
||||||
NFSPROC4_CLNT_SETACL,
|
NFSPROC4_CLNT_SETACL,
|
||||||
NFSPROC4_CLNT_FS_LOCATIONS,
|
NFSPROC4_CLNT_FS_LOCATIONS,
|
||||||
|
|
||||||
|
/* nfs41 */
|
||||||
|
NFSPROC4_CLNT_EXCHANGE_ID,
|
||||||
|
NFSPROC4_CLNT_CREATE_SESSION,
|
||||||
|
NFSPROC4_CLNT_DESTROY_SESSION,
|
||||||
|
NFSPROC4_CLNT_SEQUENCE,
|
||||||
|
NFSPROC4_CLNT_GET_LEASE_TIME,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* nfs41 types */
|
||||||
|
struct nfs4_sessionid {
|
||||||
|
unsigned char data[NFS4_MAX_SESSIONID_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Create Session Flags */
|
||||||
|
#define SESSION4_PERSIST 0x001
|
||||||
|
#define SESSION4_BACK_CHAN 0x002
|
||||||
|
#define SESSION4_RDMA 0x004
|
||||||
|
|
||||||
|
enum state_protect_how4 {
|
||||||
|
SP4_NONE = 0,
|
||||||
|
SP4_MACH_CRED = 1,
|
||||||
|
SP4_SSV = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -76,4 +76,12 @@ 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 *);
|
||||||
|
|
||||||
|
#ifdef CONFIG_NFSD_V4
|
||||||
|
void nfsd4_set_statp(struct svc_rqst *rqstp, __be32 *statp);
|
||||||
|
#else /* CONFIG_NFSD_V4 */
|
||||||
|
static inline void nfsd4_set_statp(struct svc_rqst *rqstp, __be32 *statp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NFSD_V4 */
|
||||||
|
|
||||||
#endif /* NFSCACHE_H */
|
#endif /* NFSCACHE_H */
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
/*
|
/*
|
||||||
* nfsd version
|
* nfsd version
|
||||||
*/
|
*/
|
||||||
#define NFSD_SUPPORTED_MINOR_VERSION 0
|
#define NFSD_SUPPORTED_MINOR_VERSION 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags for nfsd_permission
|
* Flags for nfsd_permission
|
||||||
|
@ -53,6 +53,7 @@ typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
|
||||||
extern struct svc_program nfsd_program;
|
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 u32 nfsd_supported_minorversion;
|
||||||
extern struct mutex nfsd_mutex;
|
extern struct mutex nfsd_mutex;
|
||||||
extern struct svc_serv *nfsd_serv;
|
extern struct svc_serv *nfsd_serv;
|
||||||
|
|
||||||
|
@ -105,7 +106,7 @@ void nfsd_close(struct file *);
|
||||||
__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
|
__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
|
||||||
loff_t, struct kvec *, int, unsigned long *);
|
loff_t, struct kvec *, int, unsigned long *);
|
||||||
__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
|
__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
|
||||||
loff_t, struct kvec *,int, unsigned long, int *);
|
loff_t, struct kvec *,int, unsigned long *, int *);
|
||||||
__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
|
__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
|
||||||
char *, int *);
|
char *, int *);
|
||||||
__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
|
__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
|
||||||
|
@ -149,6 +150,7 @@ int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
|
||||||
|
|
||||||
enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
|
enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
|
||||||
int nfsd_vers(int vers, enum vers_op change);
|
int nfsd_vers(int vers, enum vers_op change);
|
||||||
|
int nfsd_minorversion(u32 minorversion, enum vers_op change);
|
||||||
void nfsd_reset_versions(void);
|
void nfsd_reset_versions(void);
|
||||||
int nfsd_create_serv(void);
|
int nfsd_create_serv(void);
|
||||||
|
|
||||||
|
@ -186,78 +188,119 @@ void nfsd_lockd_shutdown(void);
|
||||||
/*
|
/*
|
||||||
* These macros provide pre-xdr'ed values for faster operation.
|
* These macros provide pre-xdr'ed values for faster operation.
|
||||||
*/
|
*/
|
||||||
#define nfs_ok __constant_htonl(NFS_OK)
|
#define nfs_ok cpu_to_be32(NFS_OK)
|
||||||
#define nfserr_perm __constant_htonl(NFSERR_PERM)
|
#define nfserr_perm cpu_to_be32(NFSERR_PERM)
|
||||||
#define nfserr_noent __constant_htonl(NFSERR_NOENT)
|
#define nfserr_noent cpu_to_be32(NFSERR_NOENT)
|
||||||
#define nfserr_io __constant_htonl(NFSERR_IO)
|
#define nfserr_io cpu_to_be32(NFSERR_IO)
|
||||||
#define nfserr_nxio __constant_htonl(NFSERR_NXIO)
|
#define nfserr_nxio cpu_to_be32(NFSERR_NXIO)
|
||||||
#define nfserr_eagain __constant_htonl(NFSERR_EAGAIN)
|
#define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN)
|
||||||
#define nfserr_acces __constant_htonl(NFSERR_ACCES)
|
#define nfserr_acces cpu_to_be32(NFSERR_ACCES)
|
||||||
#define nfserr_exist __constant_htonl(NFSERR_EXIST)
|
#define nfserr_exist cpu_to_be32(NFSERR_EXIST)
|
||||||
#define nfserr_xdev __constant_htonl(NFSERR_XDEV)
|
#define nfserr_xdev cpu_to_be32(NFSERR_XDEV)
|
||||||
#define nfserr_nodev __constant_htonl(NFSERR_NODEV)
|
#define nfserr_nodev cpu_to_be32(NFSERR_NODEV)
|
||||||
#define nfserr_notdir __constant_htonl(NFSERR_NOTDIR)
|
#define nfserr_notdir cpu_to_be32(NFSERR_NOTDIR)
|
||||||
#define nfserr_isdir __constant_htonl(NFSERR_ISDIR)
|
#define nfserr_isdir cpu_to_be32(NFSERR_ISDIR)
|
||||||
#define nfserr_inval __constant_htonl(NFSERR_INVAL)
|
#define nfserr_inval cpu_to_be32(NFSERR_INVAL)
|
||||||
#define nfserr_fbig __constant_htonl(NFSERR_FBIG)
|
#define nfserr_fbig cpu_to_be32(NFSERR_FBIG)
|
||||||
#define nfserr_nospc __constant_htonl(NFSERR_NOSPC)
|
#define nfserr_nospc cpu_to_be32(NFSERR_NOSPC)
|
||||||
#define nfserr_rofs __constant_htonl(NFSERR_ROFS)
|
#define nfserr_rofs cpu_to_be32(NFSERR_ROFS)
|
||||||
#define nfserr_mlink __constant_htonl(NFSERR_MLINK)
|
#define nfserr_mlink cpu_to_be32(NFSERR_MLINK)
|
||||||
#define nfserr_opnotsupp __constant_htonl(NFSERR_OPNOTSUPP)
|
#define nfserr_opnotsupp cpu_to_be32(NFSERR_OPNOTSUPP)
|
||||||
#define nfserr_nametoolong __constant_htonl(NFSERR_NAMETOOLONG)
|
#define nfserr_nametoolong cpu_to_be32(NFSERR_NAMETOOLONG)
|
||||||
#define nfserr_notempty __constant_htonl(NFSERR_NOTEMPTY)
|
#define nfserr_notempty cpu_to_be32(NFSERR_NOTEMPTY)
|
||||||
#define nfserr_dquot __constant_htonl(NFSERR_DQUOT)
|
#define nfserr_dquot cpu_to_be32(NFSERR_DQUOT)
|
||||||
#define nfserr_stale __constant_htonl(NFSERR_STALE)
|
#define nfserr_stale cpu_to_be32(NFSERR_STALE)
|
||||||
#define nfserr_remote __constant_htonl(NFSERR_REMOTE)
|
#define nfserr_remote cpu_to_be32(NFSERR_REMOTE)
|
||||||
#define nfserr_wflush __constant_htonl(NFSERR_WFLUSH)
|
#define nfserr_wflush cpu_to_be32(NFSERR_WFLUSH)
|
||||||
#define nfserr_badhandle __constant_htonl(NFSERR_BADHANDLE)
|
#define nfserr_badhandle cpu_to_be32(NFSERR_BADHANDLE)
|
||||||
#define nfserr_notsync __constant_htonl(NFSERR_NOT_SYNC)
|
#define nfserr_notsync cpu_to_be32(NFSERR_NOT_SYNC)
|
||||||
#define nfserr_badcookie __constant_htonl(NFSERR_BAD_COOKIE)
|
#define nfserr_badcookie cpu_to_be32(NFSERR_BAD_COOKIE)
|
||||||
#define nfserr_notsupp __constant_htonl(NFSERR_NOTSUPP)
|
#define nfserr_notsupp cpu_to_be32(NFSERR_NOTSUPP)
|
||||||
#define nfserr_toosmall __constant_htonl(NFSERR_TOOSMALL)
|
#define nfserr_toosmall cpu_to_be32(NFSERR_TOOSMALL)
|
||||||
#define nfserr_serverfault __constant_htonl(NFSERR_SERVERFAULT)
|
#define nfserr_serverfault cpu_to_be32(NFSERR_SERVERFAULT)
|
||||||
#define nfserr_badtype __constant_htonl(NFSERR_BADTYPE)
|
#define nfserr_badtype cpu_to_be32(NFSERR_BADTYPE)
|
||||||
#define nfserr_jukebox __constant_htonl(NFSERR_JUKEBOX)
|
#define nfserr_jukebox cpu_to_be32(NFSERR_JUKEBOX)
|
||||||
#define nfserr_denied __constant_htonl(NFSERR_DENIED)
|
#define nfserr_denied cpu_to_be32(NFSERR_DENIED)
|
||||||
#define nfserr_deadlock __constant_htonl(NFSERR_DEADLOCK)
|
#define nfserr_deadlock cpu_to_be32(NFSERR_DEADLOCK)
|
||||||
#define nfserr_expired __constant_htonl(NFSERR_EXPIRED)
|
#define nfserr_expired cpu_to_be32(NFSERR_EXPIRED)
|
||||||
#define nfserr_bad_cookie __constant_htonl(NFSERR_BAD_COOKIE)
|
#define nfserr_bad_cookie cpu_to_be32(NFSERR_BAD_COOKIE)
|
||||||
#define nfserr_same __constant_htonl(NFSERR_SAME)
|
#define nfserr_same cpu_to_be32(NFSERR_SAME)
|
||||||
#define nfserr_clid_inuse __constant_htonl(NFSERR_CLID_INUSE)
|
#define nfserr_clid_inuse cpu_to_be32(NFSERR_CLID_INUSE)
|
||||||
#define nfserr_stale_clientid __constant_htonl(NFSERR_STALE_CLIENTID)
|
#define nfserr_stale_clientid cpu_to_be32(NFSERR_STALE_CLIENTID)
|
||||||
#define nfserr_resource __constant_htonl(NFSERR_RESOURCE)
|
#define nfserr_resource cpu_to_be32(NFSERR_RESOURCE)
|
||||||
#define nfserr_moved __constant_htonl(NFSERR_MOVED)
|
#define nfserr_moved cpu_to_be32(NFSERR_MOVED)
|
||||||
#define nfserr_nofilehandle __constant_htonl(NFSERR_NOFILEHANDLE)
|
#define nfserr_nofilehandle cpu_to_be32(NFSERR_NOFILEHANDLE)
|
||||||
#define nfserr_minor_vers_mismatch __constant_htonl(NFSERR_MINOR_VERS_MISMATCH)
|
#define nfserr_minor_vers_mismatch cpu_to_be32(NFSERR_MINOR_VERS_MISMATCH)
|
||||||
#define nfserr_share_denied __constant_htonl(NFSERR_SHARE_DENIED)
|
#define nfserr_share_denied cpu_to_be32(NFSERR_SHARE_DENIED)
|
||||||
#define nfserr_stale_stateid __constant_htonl(NFSERR_STALE_STATEID)
|
#define nfserr_stale_stateid cpu_to_be32(NFSERR_STALE_STATEID)
|
||||||
#define nfserr_old_stateid __constant_htonl(NFSERR_OLD_STATEID)
|
#define nfserr_old_stateid cpu_to_be32(NFSERR_OLD_STATEID)
|
||||||
#define nfserr_bad_stateid __constant_htonl(NFSERR_BAD_STATEID)
|
#define nfserr_bad_stateid cpu_to_be32(NFSERR_BAD_STATEID)
|
||||||
#define nfserr_bad_seqid __constant_htonl(NFSERR_BAD_SEQID)
|
#define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID)
|
||||||
#define nfserr_symlink __constant_htonl(NFSERR_SYMLINK)
|
#define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK)
|
||||||
#define nfserr_not_same __constant_htonl(NFSERR_NOT_SAME)
|
#define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME)
|
||||||
#define nfserr_restorefh __constant_htonl(NFSERR_RESTOREFH)
|
#define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH)
|
||||||
#define nfserr_attrnotsupp __constant_htonl(NFSERR_ATTRNOTSUPP)
|
#define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP)
|
||||||
#define nfserr_bad_xdr __constant_htonl(NFSERR_BAD_XDR)
|
#define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR)
|
||||||
#define nfserr_openmode __constant_htonl(NFSERR_OPENMODE)
|
#define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE)
|
||||||
#define nfserr_locks_held __constant_htonl(NFSERR_LOCKS_HELD)
|
#define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD)
|
||||||
#define nfserr_op_illegal __constant_htonl(NFSERR_OP_ILLEGAL)
|
#define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL)
|
||||||
#define nfserr_grace __constant_htonl(NFSERR_GRACE)
|
#define nfserr_grace cpu_to_be32(NFSERR_GRACE)
|
||||||
#define nfserr_no_grace __constant_htonl(NFSERR_NO_GRACE)
|
#define nfserr_no_grace cpu_to_be32(NFSERR_NO_GRACE)
|
||||||
#define nfserr_reclaim_bad __constant_htonl(NFSERR_RECLAIM_BAD)
|
#define nfserr_reclaim_bad cpu_to_be32(NFSERR_RECLAIM_BAD)
|
||||||
#define nfserr_badname __constant_htonl(NFSERR_BADNAME)
|
#define nfserr_badname cpu_to_be32(NFSERR_BADNAME)
|
||||||
#define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN)
|
#define nfserr_cb_path_down cpu_to_be32(NFSERR_CB_PATH_DOWN)
|
||||||
#define nfserr_locked __constant_htonl(NFSERR_LOCKED)
|
#define nfserr_locked cpu_to_be32(NFSERR_LOCKED)
|
||||||
#define nfserr_wrongsec __constant_htonl(NFSERR_WRONGSEC)
|
#define nfserr_wrongsec cpu_to_be32(NFSERR_WRONGSEC)
|
||||||
#define nfserr_replay_me __constant_htonl(NFSERR_REPLAY_ME)
|
#define nfserr_badiomode cpu_to_be32(NFS4ERR_BADIOMODE)
|
||||||
|
#define nfserr_badlayout cpu_to_be32(NFS4ERR_BADLAYOUT)
|
||||||
|
#define nfserr_bad_session_digest cpu_to_be32(NFS4ERR_BAD_SESSION_DIGEST)
|
||||||
|
#define nfserr_badsession cpu_to_be32(NFS4ERR_BADSESSION)
|
||||||
|
#define nfserr_badslot cpu_to_be32(NFS4ERR_BADSLOT)
|
||||||
|
#define nfserr_complete_already cpu_to_be32(NFS4ERR_COMPLETE_ALREADY)
|
||||||
|
#define nfserr_conn_not_bound_to_session cpu_to_be32(NFS4ERR_CONN_NOT_BOUND_TO_SESSION)
|
||||||
|
#define nfserr_deleg_already_wanted cpu_to_be32(NFS4ERR_DELEG_ALREADY_WANTED)
|
||||||
|
#define nfserr_back_chan_busy cpu_to_be32(NFS4ERR_BACK_CHAN_BUSY)
|
||||||
|
#define nfserr_layouttrylater cpu_to_be32(NFS4ERR_LAYOUTTRYLATER)
|
||||||
|
#define nfserr_layoutunavailable cpu_to_be32(NFS4ERR_LAYOUTUNAVAILABLE)
|
||||||
|
#define nfserr_nomatching_layout cpu_to_be32(NFS4ERR_NOMATCHING_LAYOUT)
|
||||||
|
#define nfserr_recallconflict cpu_to_be32(NFS4ERR_RECALLCONFLICT)
|
||||||
|
#define nfserr_unknown_layouttype cpu_to_be32(NFS4ERR_UNKNOWN_LAYOUTTYPE)
|
||||||
|
#define nfserr_seq_misordered cpu_to_be32(NFS4ERR_SEQ_MISORDERED)
|
||||||
|
#define nfserr_sequence_pos cpu_to_be32(NFS4ERR_SEQUENCE_POS)
|
||||||
|
#define nfserr_req_too_big cpu_to_be32(NFS4ERR_REQ_TOO_BIG)
|
||||||
|
#define nfserr_rep_too_big cpu_to_be32(NFS4ERR_REP_TOO_BIG)
|
||||||
|
#define nfserr_rep_too_big_to_cache cpu_to_be32(NFS4ERR_REP_TOO_BIG_TO_CACHE)
|
||||||
|
#define nfserr_retry_uncached_rep cpu_to_be32(NFS4ERR_RETRY_UNCACHED_REP)
|
||||||
|
#define nfserr_unsafe_compound cpu_to_be32(NFS4ERR_UNSAFE_COMPOUND)
|
||||||
|
#define nfserr_too_many_ops cpu_to_be32(NFS4ERR_TOO_MANY_OPS)
|
||||||
|
#define nfserr_op_not_in_session cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION)
|
||||||
|
#define nfserr_hash_alg_unsupp cpu_to_be32(NFS4ERR_HASH_ALG_UNSUPP)
|
||||||
|
#define nfserr_clientid_busy cpu_to_be32(NFS4ERR_CLIENTID_BUSY)
|
||||||
|
#define nfserr_pnfs_io_hole cpu_to_be32(NFS4ERR_PNFS_IO_HOLE)
|
||||||
|
#define nfserr_seq_false_retry cpu_to_be32(NFS4ERR_SEQ_FALSE_RETRY)
|
||||||
|
#define nfserr_bad_high_slot cpu_to_be32(NFS4ERR_BAD_HIGH_SLOT)
|
||||||
|
#define nfserr_deadsession cpu_to_be32(NFS4ERR_DEADSESSION)
|
||||||
|
#define nfserr_encr_alg_unsupp cpu_to_be32(NFS4ERR_ENCR_ALG_UNSUPP)
|
||||||
|
#define nfserr_pnfs_no_layout cpu_to_be32(NFS4ERR_PNFS_NO_LAYOUT)
|
||||||
|
#define nfserr_not_only_op cpu_to_be32(NFS4ERR_NOT_ONLY_OP)
|
||||||
|
#define nfserr_wrong_cred cpu_to_be32(NFS4ERR_WRONG_CRED)
|
||||||
|
#define nfserr_wrong_type cpu_to_be32(NFS4ERR_WRONG_TYPE)
|
||||||
|
#define nfserr_dirdeleg_unavail cpu_to_be32(NFS4ERR_DIRDELEG_UNAVAIL)
|
||||||
|
#define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG)
|
||||||
|
#define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT)
|
||||||
|
#define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED)
|
||||||
|
|
||||||
/* error codes for internal use */
|
/* error codes for internal use */
|
||||||
/* if a request fails due to kmalloc failure, it gets dropped.
|
/* if a request fails due to kmalloc failure, it gets dropped.
|
||||||
* Client should resend eventually
|
* Client should resend eventually
|
||||||
*/
|
*/
|
||||||
#define nfserr_dropit __constant_htonl(30000)
|
#define nfserr_dropit cpu_to_be32(30000)
|
||||||
/* end-of-file indicator in readdir */
|
/* end-of-file indicator in readdir */
|
||||||
#define nfserr_eof __constant_htonl(30001)
|
#define nfserr_eof cpu_to_be32(30001)
|
||||||
|
/* replay detected */
|
||||||
|
#define nfserr_replay_me cpu_to_be32(11001)
|
||||||
|
/* nfs41 replay detected */
|
||||||
|
#define nfserr_replay_cache cpu_to_be32(11002)
|
||||||
|
|
||||||
/* Check for dir entries '.' and '..' */
|
/* Check for dir entries '.' and '..' */
|
||||||
#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
|
#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
|
||||||
|
@ -300,7 +343,7 @@ extern struct timeval nfssvc_boot;
|
||||||
* TIME_BACKUP (unlikely to be supported any time soon)
|
* TIME_BACKUP (unlikely to be supported any time soon)
|
||||||
* TIME_CREATE (unlikely to be supported any time soon)
|
* TIME_CREATE (unlikely to be supported any time soon)
|
||||||
*/
|
*/
|
||||||
#define NFSD_SUPPORTED_ATTRS_WORD0 \
|
#define NFSD4_SUPPORTED_ATTRS_WORD0 \
|
||||||
(FATTR4_WORD0_SUPPORTED_ATTRS | FATTR4_WORD0_TYPE | FATTR4_WORD0_FH_EXPIRE_TYPE \
|
(FATTR4_WORD0_SUPPORTED_ATTRS | FATTR4_WORD0_TYPE | FATTR4_WORD0_FH_EXPIRE_TYPE \
|
||||||
| FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | FATTR4_WORD0_LINK_SUPPORT \
|
| FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | FATTR4_WORD0_LINK_SUPPORT \
|
||||||
| FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR | FATTR4_WORD0_FSID \
|
| FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR | FATTR4_WORD0_FSID \
|
||||||
|
@ -312,7 +355,7 @@ extern struct timeval nfssvc_boot;
|
||||||
| FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \
|
| FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \
|
||||||
| FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL)
|
| FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL)
|
||||||
|
|
||||||
#define NFSD_SUPPORTED_ATTRS_WORD1 \
|
#define NFSD4_SUPPORTED_ATTRS_WORD1 \
|
||||||
(FATTR4_WORD1_MODE | FATTR4_WORD1_NO_TRUNC | FATTR4_WORD1_NUMLINKS \
|
(FATTR4_WORD1_MODE | FATTR4_WORD1_NO_TRUNC | FATTR4_WORD1_NUMLINKS \
|
||||||
| FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \
|
| FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \
|
||||||
| FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \
|
| FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \
|
||||||
|
@ -320,6 +363,35 @@ extern struct timeval nfssvc_boot;
|
||||||
| FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \
|
| FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \
|
||||||
| FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
|
| FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
|
||||||
|
|
||||||
|
#define NFSD4_SUPPORTED_ATTRS_WORD2 0
|
||||||
|
|
||||||
|
#define NFSD4_1_SUPPORTED_ATTRS_WORD0 \
|
||||||
|
NFSD4_SUPPORTED_ATTRS_WORD0
|
||||||
|
|
||||||
|
#define NFSD4_1_SUPPORTED_ATTRS_WORD1 \
|
||||||
|
NFSD4_SUPPORTED_ATTRS_WORD1
|
||||||
|
|
||||||
|
#define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
|
||||||
|
(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
|
||||||
|
|
||||||
|
static inline u32 nfsd_suppattrs0(u32 minorversion)
|
||||||
|
{
|
||||||
|
return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
|
||||||
|
: NFSD4_SUPPORTED_ATTRS_WORD0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 nfsd_suppattrs1(u32 minorversion)
|
||||||
|
{
|
||||||
|
return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD1
|
||||||
|
: NFSD4_SUPPORTED_ATTRS_WORD1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 nfsd_suppattrs2(u32 minorversion)
|
||||||
|
{
|
||||||
|
return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
|
||||||
|
: NFSD4_SUPPORTED_ATTRS_WORD2;
|
||||||
|
}
|
||||||
|
|
||||||
/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
|
/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
|
||||||
#define NFSD_WRITEONLY_ATTRS_WORD1 \
|
#define NFSD_WRITEONLY_ATTRS_WORD1 \
|
||||||
(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
|
(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
|
||||||
|
@ -330,6 +402,19 @@ extern struct timeval nfssvc_boot;
|
||||||
#define NFSD_WRITEABLE_ATTRS_WORD1 \
|
#define NFSD_WRITEABLE_ATTRS_WORD1 \
|
||||||
(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
|
(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
|
||||||
| FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
|
| FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
|
||||||
|
#define NFSD_WRITEABLE_ATTRS_WORD2 0
|
||||||
|
|
||||||
|
#define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
|
||||||
|
NFSD_WRITEABLE_ATTRS_WORD0
|
||||||
|
/*
|
||||||
|
* we currently store the exclusive create verifier in the v_{a,m}time
|
||||||
|
* attributes so the client can't set these at create time using EXCLUSIVE4_1
|
||||||
|
*/
|
||||||
|
#define NFSD_SUPPATTR_EXCLCREAT_WORD1 \
|
||||||
|
(NFSD_WRITEABLE_ATTRS_WORD1 & \
|
||||||
|
~(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET))
|
||||||
|
#define NFSD_SUPPATTR_EXCLCREAT_WORD2 \
|
||||||
|
NFSD_WRITEABLE_ATTRS_WORD2
|
||||||
|
|
||||||
#endif /* CONFIG_NFSD_V4 */
|
#endif /* CONFIG_NFSD_V4 */
|
||||||
|
|
||||||
|
|
|
@ -269,6 +269,13 @@ fh_copy(struct svc_fh *dst, struct svc_fh *src)
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src)
|
||||||
|
{
|
||||||
|
dst->fh_size = src->fh_size;
|
||||||
|
memcpy(&dst->fh_base, &src->fh_base, src->fh_size);
|
||||||
|
}
|
||||||
|
|
||||||
static __inline__ struct svc_fh *
|
static __inline__ struct svc_fh *
|
||||||
fh_init(struct svc_fh *fhp, int maxsize)
|
fh_init(struct svc_fh *fhp, int maxsize)
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,8 +66,7 @@ struct nfs4_cb_recall {
|
||||||
u32 cbr_ident;
|
u32 cbr_ident;
|
||||||
int cbr_trunc;
|
int cbr_trunc;
|
||||||
stateid_t cbr_stateid;
|
stateid_t cbr_stateid;
|
||||||
u32 cbr_fhlen;
|
struct knfsd_fh cbr_fh;
|
||||||
char cbr_fhval[NFS4_FHSIZE];
|
|
||||||
struct nfs4_delegation *cbr_dp;
|
struct nfs4_delegation *cbr_dp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,8 +85,7 @@ struct nfs4_delegation {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define dl_stateid dl_recall.cbr_stateid
|
#define dl_stateid dl_recall.cbr_stateid
|
||||||
#define dl_fhlen dl_recall.cbr_fhlen
|
#define dl_fh dl_recall.cbr_fh
|
||||||
#define dl_fhval dl_recall.cbr_fhval
|
|
||||||
|
|
||||||
/* client delegation callback info */
|
/* client delegation callback info */
|
||||||
struct nfs4_callback {
|
struct nfs4_callback {
|
||||||
|
@ -101,6 +99,64 @@ struct nfs4_callback {
|
||||||
struct rpc_clnt * cb_client;
|
struct rpc_clnt * cb_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Maximum number of slots per session. 128 is useful for long haul TCP */
|
||||||
|
#define NFSD_MAX_SLOTS_PER_SESSION 128
|
||||||
|
/* Maximum number of pages per slot cache entry */
|
||||||
|
#define NFSD_PAGES_PER_SLOT 1
|
||||||
|
/* Maximum number of operations per session compound */
|
||||||
|
#define NFSD_MAX_OPS_PER_COMPOUND 16
|
||||||
|
|
||||||
|
struct nfsd4_cache_entry {
|
||||||
|
__be32 ce_status;
|
||||||
|
struct kvec ce_datav; /* encoded NFSv4.1 data in rq_res.head[0] */
|
||||||
|
struct page *ce_respages[NFSD_PAGES_PER_SLOT + 1];
|
||||||
|
int ce_cachethis;
|
||||||
|
short ce_resused;
|
||||||
|
int ce_opcnt;
|
||||||
|
int ce_rpchdrlen;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nfsd4_slot {
|
||||||
|
bool sl_inuse;
|
||||||
|
u32 sl_seqid;
|
||||||
|
struct nfsd4_cache_entry sl_cache_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nfsd4_session {
|
||||||
|
struct kref se_ref;
|
||||||
|
struct list_head se_hash; /* hash by sessionid */
|
||||||
|
struct list_head se_perclnt;
|
||||||
|
u32 se_flags;
|
||||||
|
struct nfs4_client *se_client; /* for expire_client */
|
||||||
|
struct nfs4_sessionid se_sessionid;
|
||||||
|
u32 se_fmaxreq_sz;
|
||||||
|
u32 se_fmaxresp_sz;
|
||||||
|
u32 se_fmaxresp_cached;
|
||||||
|
u32 se_fmaxops;
|
||||||
|
u32 se_fnumslots;
|
||||||
|
struct nfsd4_slot se_slots[]; /* forward channel slots */
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nfsd4_put_session(struct nfsd4_session *ses)
|
||||||
|
{
|
||||||
|
extern void free_session(struct kref *kref);
|
||||||
|
kref_put(&ses->se_ref, free_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nfsd4_get_session(struct nfsd4_session *ses)
|
||||||
|
{
|
||||||
|
kref_get(&ses->se_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* formatted contents of nfs4_sessionid */
|
||||||
|
struct nfsd4_sessionid {
|
||||||
|
clientid_t clientid;
|
||||||
|
u32 sequence;
|
||||||
|
u32 reserved;
|
||||||
|
};
|
||||||
|
|
||||||
#define HEXDIR_LEN 33 /* hex version of 16 byte md5 of cl_name plus '\0' */
|
#define HEXDIR_LEN 33 /* hex version of 16 byte md5 of cl_name plus '\0' */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -132,6 +188,12 @@ struct nfs4_client {
|
||||||
struct nfs4_callback cl_callback; /* callback info */
|
struct nfs4_callback cl_callback; /* callback info */
|
||||||
atomic_t cl_count; /* ref count */
|
atomic_t cl_count; /* ref count */
|
||||||
u32 cl_firststate; /* recovery dir creation */
|
u32 cl_firststate; /* recovery dir creation */
|
||||||
|
|
||||||
|
/* for nfs41 */
|
||||||
|
struct list_head cl_sessions;
|
||||||
|
struct nfsd4_slot cl_slot; /* create_session slot */
|
||||||
|
u32 cl_exchange_flags;
|
||||||
|
struct nfs4_sessionid cl_sessionid;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* struct nfs4_client_reset
|
/* struct nfs4_client_reset
|
||||||
|
@ -168,8 +230,7 @@ struct nfs4_replay {
|
||||||
unsigned int rp_buflen;
|
unsigned int rp_buflen;
|
||||||
char *rp_buf;
|
char *rp_buf;
|
||||||
unsigned intrp_allocated;
|
unsigned intrp_allocated;
|
||||||
int rp_openfh_len;
|
struct knfsd_fh rp_openfh;
|
||||||
char rp_openfh[NFS4_FHSIZE];
|
|
||||||
char rp_ibuf[NFSD4_REPLAY_ISIZE];
|
char rp_ibuf[NFSD4_REPLAY_ISIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -217,7 +278,7 @@ struct nfs4_stateowner {
|
||||||
* share_acces, share_deny on the file.
|
* share_acces, share_deny on the file.
|
||||||
*/
|
*/
|
||||||
struct nfs4_file {
|
struct nfs4_file {
|
||||||
struct kref fi_ref;
|
atomic_t fi_ref;
|
||||||
struct list_head fi_hash; /* hash by "struct inode *" */
|
struct list_head fi_hash; /* hash by "struct inode *" */
|
||||||
struct list_head fi_stateids;
|
struct list_head fi_stateids;
|
||||||
struct list_head fi_delegations;
|
struct list_head fi_delegations;
|
||||||
|
@ -259,14 +320,13 @@ struct nfs4_stateid {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* flags for preprocess_seqid_op() */
|
/* flags for preprocess_seqid_op() */
|
||||||
#define CHECK_FH 0x00000001
|
#define HAS_SESSION 0x00000001
|
||||||
#define CONFIRM 0x00000002
|
#define CONFIRM 0x00000002
|
||||||
#define OPEN_STATE 0x00000004
|
#define OPEN_STATE 0x00000004
|
||||||
#define LOCK_STATE 0x00000008
|
#define LOCK_STATE 0x00000008
|
||||||
#define RD_STATE 0x00000010
|
#define RD_STATE 0x00000010
|
||||||
#define WR_STATE 0x00000020
|
#define WR_STATE 0x00000020
|
||||||
#define CLOSE_STATE 0x00000040
|
#define CLOSE_STATE 0x00000040
|
||||||
#define DELEG_RET 0x00000080
|
|
||||||
|
|
||||||
#define seqid_mutating_err(err) \
|
#define seqid_mutating_err(err) \
|
||||||
(((err) != nfserr_stale_clientid) && \
|
(((err) != nfserr_stale_clientid) && \
|
||||||
|
@ -274,7 +334,9 @@ struct nfs4_stateid {
|
||||||
((err) != nfserr_stale_stateid) && \
|
((err) != nfserr_stale_stateid) && \
|
||||||
((err) != nfserr_bad_stateid))
|
((err) != nfserr_bad_stateid))
|
||||||
|
|
||||||
extern __be32 nfs4_preprocess_stateid_op(struct svc_fh *current_fh,
|
struct nfsd4_compound_state;
|
||||||
|
|
||||||
|
extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
|
||||||
stateid_t *stateid, int flags, struct file **filp);
|
stateid_t *stateid, int flags, struct file **filp);
|
||||||
extern void nfs4_lock_state(void);
|
extern void nfs4_lock_state(void);
|
||||||
extern void nfs4_unlock_state(void);
|
extern void nfs4_unlock_state(void);
|
||||||
|
@ -290,7 +352,7 @@ extern void nfsd4_init_recdir(char *recdir_name);
|
||||||
extern int nfsd4_recdir_load(void);
|
extern int nfsd4_recdir_load(void);
|
||||||
extern void nfsd4_shutdown_recdir(void);
|
extern void nfsd4_shutdown_recdir(void);
|
||||||
extern int nfs4_client_to_reclaim(const char *name);
|
extern int nfs4_client_to_reclaim(const char *name);
|
||||||
extern int nfs4_has_reclaimed_state(const char *name);
|
extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
|
||||||
extern void nfsd4_recdir_purge_old(void);
|
extern void nfsd4_recdir_purge_old(void);
|
||||||
extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
|
extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
|
||||||
extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
|
extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
|
|
||||||
#include <linux/nfs4.h>
|
#include <linux/nfs4.h>
|
||||||
|
|
||||||
|
/* thread usage wraps very million seconds (approx one fortnight) */
|
||||||
|
#define NFSD_USAGE_WRAP (HZ*1000000)
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
struct nfsd_stats {
|
struct nfsd_stats {
|
||||||
unsigned int rchits; /* repcache hits */
|
unsigned int rchits; /* repcache hits */
|
||||||
unsigned int rcmisses; /* repcache hits */
|
unsigned int rcmisses; /* repcache hits */
|
||||||
|
@ -35,10 +40,6 @@ struct nfsd_stats {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* thread usage wraps very million seconds (approx one fortnight) */
|
|
||||||
#define NFSD_USAGE_WRAP (HZ*1000000)
|
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
|
||||||
|
|
||||||
extern struct nfsd_stats nfsdstats;
|
extern struct nfsd_stats nfsdstats;
|
||||||
extern struct svc_stat nfsd_svcstats;
|
extern struct svc_stat nfsd_svcstats;
|
||||||
|
|
|
@ -45,11 +45,23 @@
|
||||||
#define XDR_LEN(n) (((n) + 3) & ~3)
|
#define XDR_LEN(n) (((n) + 3) & ~3)
|
||||||
|
|
||||||
struct nfsd4_compound_state {
|
struct nfsd4_compound_state {
|
||||||
struct svc_fh current_fh;
|
struct svc_fh current_fh;
|
||||||
struct svc_fh save_fh;
|
struct svc_fh save_fh;
|
||||||
struct nfs4_stateowner *replay_owner;
|
struct nfs4_stateowner *replay_owner;
|
||||||
|
/* For sessions DRC */
|
||||||
|
struct nfsd4_session *session;
|
||||||
|
struct nfsd4_slot *slot;
|
||||||
|
__be32 *statp;
|
||||||
|
size_t iovlen;
|
||||||
|
u32 minorversion;
|
||||||
|
u32 status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs)
|
||||||
|
{
|
||||||
|
return cs->slot != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct nfsd4_change_info {
|
struct nfsd4_change_info {
|
||||||
u32 atomic;
|
u32 atomic;
|
||||||
u32 before_ctime_sec;
|
u32 before_ctime_sec;
|
||||||
|
@ -90,7 +102,7 @@ struct nfsd4_create {
|
||||||
u32 specdata2;
|
u32 specdata2;
|
||||||
} dev; /* NF4BLK, NF4CHR */
|
} dev; /* NF4BLK, NF4CHR */
|
||||||
} u;
|
} u;
|
||||||
u32 cr_bmval[2]; /* request */
|
u32 cr_bmval[3]; /* request */
|
||||||
struct iattr cr_iattr; /* request */
|
struct iattr cr_iattr; /* request */
|
||||||
struct nfsd4_change_info cr_cinfo; /* response */
|
struct nfsd4_change_info cr_cinfo; /* response */
|
||||||
struct nfs4_acl *cr_acl;
|
struct nfs4_acl *cr_acl;
|
||||||
|
@ -105,7 +117,7 @@ struct nfsd4_delegreturn {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nfsd4_getattr {
|
struct nfsd4_getattr {
|
||||||
u32 ga_bmval[2]; /* request */
|
u32 ga_bmval[3]; /* request */
|
||||||
struct svc_fh *ga_fhp; /* response */
|
struct svc_fh *ga_fhp; /* response */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -206,11 +218,9 @@ struct nfsd4_open {
|
||||||
stateid_t op_delegate_stateid; /* request - response */
|
stateid_t op_delegate_stateid; /* request - response */
|
||||||
u32 op_create; /* request */
|
u32 op_create; /* request */
|
||||||
u32 op_createmode; /* request */
|
u32 op_createmode; /* request */
|
||||||
u32 op_bmval[2]; /* request */
|
u32 op_bmval[3]; /* request */
|
||||||
union { /* request */
|
struct iattr iattr; /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */
|
||||||
struct iattr iattr; /* UNCHECKED4,GUARDED4 */
|
nfs4_verifier verf; /* EXCLUSIVE4 */
|
||||||
nfs4_verifier verf; /* EXCLUSIVE4 */
|
|
||||||
} u;
|
|
||||||
clientid_t op_clientid; /* request */
|
clientid_t op_clientid; /* request */
|
||||||
struct xdr_netobj op_owner; /* request */
|
struct xdr_netobj op_owner; /* request */
|
||||||
u32 op_seqid; /* request */
|
u32 op_seqid; /* request */
|
||||||
|
@ -224,8 +234,8 @@ struct nfsd4_open {
|
||||||
struct nfs4_stateowner *op_stateowner; /* used during processing */
|
struct nfs4_stateowner *op_stateowner; /* used during processing */
|
||||||
struct nfs4_acl *op_acl;
|
struct nfs4_acl *op_acl;
|
||||||
};
|
};
|
||||||
#define op_iattr u.iattr
|
#define op_iattr iattr
|
||||||
#define op_verf u.verf
|
#define op_verf verf
|
||||||
|
|
||||||
struct nfsd4_open_confirm {
|
struct nfsd4_open_confirm {
|
||||||
stateid_t oc_req_stateid /* request */;
|
stateid_t oc_req_stateid /* request */;
|
||||||
|
@ -259,7 +269,7 @@ struct nfsd4_readdir {
|
||||||
nfs4_verifier rd_verf; /* request */
|
nfs4_verifier rd_verf; /* request */
|
||||||
u32 rd_dircount; /* request */
|
u32 rd_dircount; /* request */
|
||||||
u32 rd_maxcount; /* request */
|
u32 rd_maxcount; /* request */
|
||||||
u32 rd_bmval[2]; /* request */
|
u32 rd_bmval[3]; /* request */
|
||||||
struct svc_rqst *rd_rqstp; /* response */
|
struct svc_rqst *rd_rqstp; /* response */
|
||||||
struct svc_fh * rd_fhp; /* response */
|
struct svc_fh * rd_fhp; /* response */
|
||||||
|
|
||||||
|
@ -301,7 +311,7 @@ struct nfsd4_secinfo {
|
||||||
|
|
||||||
struct nfsd4_setattr {
|
struct nfsd4_setattr {
|
||||||
stateid_t sa_stateid; /* request */
|
stateid_t sa_stateid; /* request */
|
||||||
u32 sa_bmval[2]; /* request */
|
u32 sa_bmval[3]; /* request */
|
||||||
struct iattr sa_iattr; /* request */
|
struct iattr sa_iattr; /* request */
|
||||||
struct nfs4_acl *sa_acl;
|
struct nfs4_acl *sa_acl;
|
||||||
};
|
};
|
||||||
|
@ -327,7 +337,7 @@ struct nfsd4_setclientid_confirm {
|
||||||
|
|
||||||
/* also used for NVERIFY */
|
/* also used for NVERIFY */
|
||||||
struct nfsd4_verify {
|
struct nfsd4_verify {
|
||||||
u32 ve_bmval[2]; /* request */
|
u32 ve_bmval[3]; /* request */
|
||||||
u32 ve_attrlen; /* request */
|
u32 ve_attrlen; /* request */
|
||||||
char * ve_attrval; /* request */
|
char * ve_attrval; /* request */
|
||||||
};
|
};
|
||||||
|
@ -344,6 +354,54 @@ struct nfsd4_write {
|
||||||
nfs4_verifier wr_verifier; /* response */
|
nfs4_verifier wr_verifier; /* response */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nfsd4_exchange_id {
|
||||||
|
nfs4_verifier verifier;
|
||||||
|
struct xdr_netobj clname;
|
||||||
|
u32 flags;
|
||||||
|
clientid_t clientid;
|
||||||
|
u32 seqid;
|
||||||
|
int spa_how;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nfsd4_channel_attrs {
|
||||||
|
u32 headerpadsz;
|
||||||
|
u32 maxreq_sz;
|
||||||
|
u32 maxresp_sz;
|
||||||
|
u32 maxresp_cached;
|
||||||
|
u32 maxops;
|
||||||
|
u32 maxreqs;
|
||||||
|
u32 nr_rdma_attrs;
|
||||||
|
u32 rdma_attrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nfsd4_create_session {
|
||||||
|
clientid_t clientid;
|
||||||
|
struct nfs4_sessionid sessionid;
|
||||||
|
u32 seqid;
|
||||||
|
u32 flags;
|
||||||
|
struct nfsd4_channel_attrs fore_channel;
|
||||||
|
struct nfsd4_channel_attrs back_channel;
|
||||||
|
u32 callback_prog;
|
||||||
|
u32 uid;
|
||||||
|
u32 gid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nfsd4_sequence {
|
||||||
|
struct nfs4_sessionid sessionid; /* request/response */
|
||||||
|
u32 seqid; /* request/response */
|
||||||
|
u32 slotid; /* request/response */
|
||||||
|
u32 maxslots; /* request/response */
|
||||||
|
u32 cachethis; /* request */
|
||||||
|
#if 0
|
||||||
|
u32 target_maxslots; /* response */
|
||||||
|
u32 status_flags; /* response */
|
||||||
|
#endif /* not yet */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nfsd4_destroy_session {
|
||||||
|
struct nfs4_sessionid sessionid;
|
||||||
|
};
|
||||||
|
|
||||||
struct nfsd4_op {
|
struct nfsd4_op {
|
||||||
int opnum;
|
int opnum;
|
||||||
__be32 status;
|
__be32 status;
|
||||||
|
@ -378,6 +436,12 @@ struct nfsd4_op {
|
||||||
struct nfsd4_verify verify;
|
struct nfsd4_verify verify;
|
||||||
struct nfsd4_write write;
|
struct nfsd4_write write;
|
||||||
struct nfsd4_release_lockowner release_lockowner;
|
struct nfsd4_release_lockowner release_lockowner;
|
||||||
|
|
||||||
|
/* NFSv4.1 */
|
||||||
|
struct nfsd4_exchange_id exchange_id;
|
||||||
|
struct nfsd4_create_session create_session;
|
||||||
|
struct nfsd4_destroy_session destroy_session;
|
||||||
|
struct nfsd4_sequence sequence;
|
||||||
} u;
|
} u;
|
||||||
struct nfs4_replay * replay;
|
struct nfs4_replay * replay;
|
||||||
};
|
};
|
||||||
|
@ -416,9 +480,22 @@ struct nfsd4_compoundres {
|
||||||
u32 taglen;
|
u32 taglen;
|
||||||
char * tag;
|
char * tag;
|
||||||
u32 opcnt;
|
u32 opcnt;
|
||||||
__be32 * tagp; /* where to encode tag and opcount */
|
__be32 * tagp; /* tag, opcount encode location */
|
||||||
|
struct nfsd4_compound_state cstate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp)
|
||||||
|
{
|
||||||
|
struct nfsd4_compoundargs *args = resp->rqstp->rq_argp;
|
||||||
|
return args->opcnt == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
|
||||||
|
{
|
||||||
|
return !resp->cstate.slot->sl_cache_entry.ce_cachethis ||
|
||||||
|
nfsd4_is_solo_sequence(resp);
|
||||||
|
}
|
||||||
|
|
||||||
#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)
|
#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -448,7 +525,23 @@ extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
|
||||||
extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
||||||
struct nfsd4_compound_state *,
|
struct nfsd4_compound_state *,
|
||||||
struct nfsd4_setclientid_confirm *setclientid_confirm);
|
struct nfsd4_setclientid_confirm *setclientid_confirm);
|
||||||
extern __be32 nfsd4_process_open1(struct nfsd4_open *open);
|
extern void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp);
|
||||||
|
extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
|
||||||
|
struct nfsd4_sequence *seq);
|
||||||
|
extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||||
|
struct nfsd4_compound_state *,
|
||||||
|
struct nfsd4_exchange_id *);
|
||||||
|
extern __be32 nfsd4_create_session(struct svc_rqst *,
|
||||||
|
struct nfsd4_compound_state *,
|
||||||
|
struct nfsd4_create_session *);
|
||||||
|
extern __be32 nfsd4_sequence(struct svc_rqst *,
|
||||||
|
struct nfsd4_compound_state *,
|
||||||
|
struct nfsd4_sequence *);
|
||||||
|
extern __be32 nfsd4_destroy_session(struct svc_rqst *,
|
||||||
|
struct nfsd4_compound_state *,
|
||||||
|
struct nfsd4_destroy_session *);
|
||||||
|
extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *,
|
||||||
|
struct nfsd4_open *open);
|
||||||
extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
|
extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
|
||||||
struct svc_fh *current_fh, struct nfsd4_open *open);
|
struct svc_fh *current_fh, struct nfsd4_open *open);
|
||||||
extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
|
extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
|
||||||
|
|
|
@ -24,6 +24,15 @@
|
||||||
*/
|
*/
|
||||||
typedef int (*svc_thread_fn)(void *);
|
typedef int (*svc_thread_fn)(void *);
|
||||||
|
|
||||||
|
/* statistics for svc_pool structures */
|
||||||
|
struct svc_pool_stats {
|
||||||
|
unsigned long packets;
|
||||||
|
unsigned long sockets_queued;
|
||||||
|
unsigned long threads_woken;
|
||||||
|
unsigned long overloads_avoided;
|
||||||
|
unsigned long threads_timedout;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* RPC service thread pool.
|
* RPC service thread pool.
|
||||||
|
@ -41,6 +50,8 @@ struct svc_pool {
|
||||||
struct list_head sp_sockets; /* pending sockets */
|
struct list_head sp_sockets; /* pending sockets */
|
||||||
unsigned int sp_nrthreads; /* # of threads in pool */
|
unsigned int sp_nrthreads; /* # of threads in pool */
|
||||||
struct list_head sp_all_threads; /* all server threads */
|
struct list_head sp_all_threads; /* all server threads */
|
||||||
|
int sp_nwaking; /* number of threads woken but not yet active */
|
||||||
|
struct svc_pool_stats sp_stats; /* statistics on pool operation */
|
||||||
} ____cacheline_aligned_in_smp;
|
} ____cacheline_aligned_in_smp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -83,6 +94,8 @@ struct svc_serv {
|
||||||
struct module * sv_module; /* optional module to count when
|
struct module * sv_module; /* optional module to count when
|
||||||
* adding threads */
|
* adding threads */
|
||||||
svc_thread_fn sv_function; /* main function for threads */
|
svc_thread_fn sv_function; /* main function for threads */
|
||||||
|
unsigned int sv_drc_max_pages; /* Total pages for DRC */
|
||||||
|
unsigned int sv_drc_pages_used;/* DRC pages used */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -218,6 +231,7 @@ struct svc_rqst {
|
||||||
struct svc_cred rq_cred; /* auth info */
|
struct svc_cred rq_cred; /* auth info */
|
||||||
void * rq_xprt_ctxt; /* transport specific context ptr */
|
void * rq_xprt_ctxt; /* transport specific context ptr */
|
||||||
struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */
|
struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */
|
||||||
|
int rq_usedeferral; /* use deferral */
|
||||||
|
|
||||||
size_t rq_xprt_hlen; /* xprt header len */
|
size_t rq_xprt_hlen; /* xprt header len */
|
||||||
struct xdr_buf rq_arg;
|
struct xdr_buf rq_arg;
|
||||||
|
@ -263,6 +277,7 @@ struct svc_rqst {
|
||||||
* cache pages */
|
* cache pages */
|
||||||
wait_queue_head_t rq_wait; /* synchronization */
|
wait_queue_head_t rq_wait; /* synchronization */
|
||||||
struct task_struct *rq_task; /* service thread */
|
struct task_struct *rq_task; /* service thread */
|
||||||
|
int rq_waking; /* 1 if thread is being woken */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -393,6 +408,7 @@ struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
|
||||||
void (*shutdown)(struct svc_serv *),
|
void (*shutdown)(struct svc_serv *),
|
||||||
svc_thread_fn, struct module *);
|
svc_thread_fn, struct module *);
|
||||||
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
|
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
|
||||||
|
int svc_pool_stats_open(struct svc_serv *serv, struct file *file);
|
||||||
void svc_destroy(struct svc_serv *);
|
void svc_destroy(struct svc_serv *);
|
||||||
int svc_process(struct svc_rqst *);
|
int svc_process(struct svc_rqst *);
|
||||||
int svc_register(const struct svc_serv *, const int,
|
int svc_register(const struct svc_serv *, const int,
|
||||||
|
|
|
@ -69,27 +69,27 @@ struct xdr_buf {
|
||||||
* pre-xdr'ed macros.
|
* pre-xdr'ed macros.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define xdr_zero __constant_htonl(0)
|
#define xdr_zero cpu_to_be32(0)
|
||||||
#define xdr_one __constant_htonl(1)
|
#define xdr_one cpu_to_be32(1)
|
||||||
#define xdr_two __constant_htonl(2)
|
#define xdr_two cpu_to_be32(2)
|
||||||
|
|
||||||
#define rpc_success __constant_htonl(RPC_SUCCESS)
|
#define rpc_success cpu_to_be32(RPC_SUCCESS)
|
||||||
#define rpc_prog_unavail __constant_htonl(RPC_PROG_UNAVAIL)
|
#define rpc_prog_unavail cpu_to_be32(RPC_PROG_UNAVAIL)
|
||||||
#define rpc_prog_mismatch __constant_htonl(RPC_PROG_MISMATCH)
|
#define rpc_prog_mismatch cpu_to_be32(RPC_PROG_MISMATCH)
|
||||||
#define rpc_proc_unavail __constant_htonl(RPC_PROC_UNAVAIL)
|
#define rpc_proc_unavail cpu_to_be32(RPC_PROC_UNAVAIL)
|
||||||
#define rpc_garbage_args __constant_htonl(RPC_GARBAGE_ARGS)
|
#define rpc_garbage_args cpu_to_be32(RPC_GARBAGE_ARGS)
|
||||||
#define rpc_system_err __constant_htonl(RPC_SYSTEM_ERR)
|
#define rpc_system_err cpu_to_be32(RPC_SYSTEM_ERR)
|
||||||
#define rpc_drop_reply __constant_htonl(RPC_DROP_REPLY)
|
#define rpc_drop_reply cpu_to_be32(RPC_DROP_REPLY)
|
||||||
|
|
||||||
#define rpc_auth_ok __constant_htonl(RPC_AUTH_OK)
|
#define rpc_auth_ok cpu_to_be32(RPC_AUTH_OK)
|
||||||
#define rpc_autherr_badcred __constant_htonl(RPC_AUTH_BADCRED)
|
#define rpc_autherr_badcred cpu_to_be32(RPC_AUTH_BADCRED)
|
||||||
#define rpc_autherr_rejectedcred __constant_htonl(RPC_AUTH_REJECTEDCRED)
|
#define rpc_autherr_rejectedcred cpu_to_be32(RPC_AUTH_REJECTEDCRED)
|
||||||
#define rpc_autherr_badverf __constant_htonl(RPC_AUTH_BADVERF)
|
#define rpc_autherr_badverf cpu_to_be32(RPC_AUTH_BADVERF)
|
||||||
#define rpc_autherr_rejectedverf __constant_htonl(RPC_AUTH_REJECTEDVERF)
|
#define rpc_autherr_rejectedverf cpu_to_be32(RPC_AUTH_REJECTEDVERF)
|
||||||
#define rpc_autherr_tooweak __constant_htonl(RPC_AUTH_TOOWEAK)
|
#define rpc_autherr_tooweak cpu_to_be32(RPC_AUTH_TOOWEAK)
|
||||||
#define rpcsec_gsserr_credproblem __constant_htonl(RPCSEC_GSS_CREDPROBLEM)
|
#define rpcsec_gsserr_credproblem cpu_to_be32(RPCSEC_GSS_CREDPROBLEM)
|
||||||
#define rpcsec_gsserr_ctxproblem __constant_htonl(RPCSEC_GSS_CTXPROBLEM)
|
#define rpcsec_gsserr_ctxproblem cpu_to_be32(RPCSEC_GSS_CTXPROBLEM)
|
||||||
#define rpc_autherr_oldseqnum __constant_htonl(101)
|
#define rpc_autherr_oldseqnum cpu_to_be32(101)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous XDR helper functions
|
* Miscellaneous XDR helper functions
|
||||||
|
|
|
@ -1008,6 +1008,8 @@ svc_process(struct svc_rqst *rqstp)
|
||||||
rqstp->rq_res.tail[0].iov_len = 0;
|
rqstp->rq_res.tail[0].iov_len = 0;
|
||||||
/* Will be turned off only in gss privacy case: */
|
/* Will be turned off only in gss privacy case: */
|
||||||
rqstp->rq_splice_ok = 1;
|
rqstp->rq_splice_ok = 1;
|
||||||
|
/* Will be turned off only when NFSv4 Sessions are used */
|
||||||
|
rqstp->rq_usedeferral = 1;
|
||||||
|
|
||||||
/* Setup reply header */
|
/* Setup reply header */
|
||||||
rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
|
rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
|
||||||
|
@ -1078,7 +1080,6 @@ svc_process(struct svc_rqst *rqstp)
|
||||||
procp = versp->vs_proc + proc;
|
procp = versp->vs_proc + proc;
|
||||||
if (proc >= versp->vs_nproc || !procp->pc_func)
|
if (proc >= versp->vs_nproc || !procp->pc_func)
|
||||||
goto err_bad_proc;
|
goto err_bad_proc;
|
||||||
rqstp->rq_server = serv;
|
|
||||||
rqstp->rq_procinfo = procp;
|
rqstp->rq_procinfo = procp;
|
||||||
|
|
||||||
/* Syntactic check complete */
|
/* Syntactic check complete */
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
|
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
|
||||||
|
|
||||||
|
#define SVC_MAX_WAKING 5
|
||||||
|
|
||||||
static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
|
static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
|
||||||
static int svc_deferred_recv(struct svc_rqst *rqstp);
|
static int svc_deferred_recv(struct svc_rqst *rqstp);
|
||||||
static struct cache_deferred_req *svc_defer(struct cache_req *req);
|
static struct cache_deferred_req *svc_defer(struct cache_req *req);
|
||||||
|
@ -301,6 +303,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
|
||||||
struct svc_pool *pool;
|
struct svc_pool *pool;
|
||||||
struct svc_rqst *rqstp;
|
struct svc_rqst *rqstp;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
int thread_avail;
|
||||||
|
|
||||||
if (!(xprt->xpt_flags &
|
if (!(xprt->xpt_flags &
|
||||||
((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED))))
|
((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED))))
|
||||||
|
@ -312,18 +315,14 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
|
||||||
|
|
||||||
spin_lock_bh(&pool->sp_lock);
|
spin_lock_bh(&pool->sp_lock);
|
||||||
|
|
||||||
if (!list_empty(&pool->sp_threads) &&
|
|
||||||
!list_empty(&pool->sp_sockets))
|
|
||||||
printk(KERN_ERR
|
|
||||||
"svc_xprt_enqueue: "
|
|
||||||
"threads and transports both waiting??\n");
|
|
||||||
|
|
||||||
if (test_bit(XPT_DEAD, &xprt->xpt_flags)) {
|
if (test_bit(XPT_DEAD, &xprt->xpt_flags)) {
|
||||||
/* Don't enqueue dead transports */
|
/* Don't enqueue dead transports */
|
||||||
dprintk("svc: transport %p is dead, not enqueued\n", xprt);
|
dprintk("svc: transport %p is dead, not enqueued\n", xprt);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pool->sp_stats.packets++;
|
||||||
|
|
||||||
/* Mark transport as busy. It will remain in this state until
|
/* Mark transport as busy. It will remain in this state until
|
||||||
* the provider calls svc_xprt_received. We update XPT_BUSY
|
* the provider calls svc_xprt_received. We update XPT_BUSY
|
||||||
* atomically because it also guards against trying to enqueue
|
* atomically because it also guards against trying to enqueue
|
||||||
|
@ -356,7 +355,15 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
|
||||||
}
|
}
|
||||||
|
|
||||||
process:
|
process:
|
||||||
if (!list_empty(&pool->sp_threads)) {
|
/* Work out whether threads are available */
|
||||||
|
thread_avail = !list_empty(&pool->sp_threads); /* threads are asleep */
|
||||||
|
if (pool->sp_nwaking >= SVC_MAX_WAKING) {
|
||||||
|
/* too many threads are runnable and trying to wake up */
|
||||||
|
thread_avail = 0;
|
||||||
|
pool->sp_stats.overloads_avoided++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread_avail) {
|
||||||
rqstp = list_entry(pool->sp_threads.next,
|
rqstp = list_entry(pool->sp_threads.next,
|
||||||
struct svc_rqst,
|
struct svc_rqst,
|
||||||
rq_list);
|
rq_list);
|
||||||
|
@ -371,11 +378,15 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
|
||||||
svc_xprt_get(xprt);
|
svc_xprt_get(xprt);
|
||||||
rqstp->rq_reserved = serv->sv_max_mesg;
|
rqstp->rq_reserved = serv->sv_max_mesg;
|
||||||
atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
|
atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
|
||||||
|
rqstp->rq_waking = 1;
|
||||||
|
pool->sp_nwaking++;
|
||||||
|
pool->sp_stats.threads_woken++;
|
||||||
BUG_ON(xprt->xpt_pool != pool);
|
BUG_ON(xprt->xpt_pool != pool);
|
||||||
wake_up(&rqstp->rq_wait);
|
wake_up(&rqstp->rq_wait);
|
||||||
} else {
|
} else {
|
||||||
dprintk("svc: transport %p put into queue\n", xprt);
|
dprintk("svc: transport %p put into queue\n", xprt);
|
||||||
list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
|
list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
|
||||||
|
pool->sp_stats.sockets_queued++;
|
||||||
BUG_ON(xprt->xpt_pool != pool);
|
BUG_ON(xprt->xpt_pool != pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,6 +599,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||||
int pages;
|
int pages;
|
||||||
struct xdr_buf *arg;
|
struct xdr_buf *arg;
|
||||||
DECLARE_WAITQUEUE(wait, current);
|
DECLARE_WAITQUEUE(wait, current);
|
||||||
|
long time_left;
|
||||||
|
|
||||||
dprintk("svc: server %p waiting for data (to = %ld)\n",
|
dprintk("svc: server %p waiting for data (to = %ld)\n",
|
||||||
rqstp, timeout);
|
rqstp, timeout);
|
||||||
|
@ -636,6 +648,11 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
|
|
||||||
spin_lock_bh(&pool->sp_lock);
|
spin_lock_bh(&pool->sp_lock);
|
||||||
|
if (rqstp->rq_waking) {
|
||||||
|
rqstp->rq_waking = 0;
|
||||||
|
pool->sp_nwaking--;
|
||||||
|
BUG_ON(pool->sp_nwaking < 0);
|
||||||
|
}
|
||||||
xprt = svc_xprt_dequeue(pool);
|
xprt = svc_xprt_dequeue(pool);
|
||||||
if (xprt) {
|
if (xprt) {
|
||||||
rqstp->rq_xprt = xprt;
|
rqstp->rq_xprt = xprt;
|
||||||
|
@ -668,12 +685,14 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||||
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);
|
||||||
|
|
||||||
schedule_timeout(timeout);
|
time_left = schedule_timeout(timeout);
|
||||||
|
|
||||||
try_to_freeze();
|
try_to_freeze();
|
||||||
|
|
||||||
spin_lock_bh(&pool->sp_lock);
|
spin_lock_bh(&pool->sp_lock);
|
||||||
remove_wait_queue(&rqstp->rq_wait, &wait);
|
remove_wait_queue(&rqstp->rq_wait, &wait);
|
||||||
|
if (!time_left)
|
||||||
|
pool->sp_stats.threads_timedout++;
|
||||||
|
|
||||||
xprt = rqstp->rq_xprt;
|
xprt = rqstp->rq_xprt;
|
||||||
if (!xprt) {
|
if (!xprt) {
|
||||||
|
@ -958,7 +977,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)
|
||||||
struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
|
struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
|
||||||
struct svc_deferred_req *dr;
|
struct svc_deferred_req *dr;
|
||||||
|
|
||||||
if (rqstp->rq_arg.page_len)
|
if (rqstp->rq_arg.page_len || !rqstp->rq_usedeferral)
|
||||||
return NULL; /* if more than a page, give up FIXME */
|
return NULL; /* if more than a page, give up FIXME */
|
||||||
if (rqstp->rq_deferred) {
|
if (rqstp->rq_deferred) {
|
||||||
dr = rqstp->rq_deferred;
|
dr = rqstp->rq_deferred;
|
||||||
|
@ -1112,3 +1131,93 @@ int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen)
|
||||||
return totlen;
|
return totlen;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(svc_xprt_names);
|
EXPORT_SYMBOL_GPL(svc_xprt_names);
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void *svc_pool_stats_start(struct seq_file *m, loff_t *pos)
|
||||||
|
{
|
||||||
|
unsigned int pidx = (unsigned int)*pos;
|
||||||
|
struct svc_serv *serv = m->private;
|
||||||
|
|
||||||
|
dprintk("svc_pool_stats_start, *pidx=%u\n", pidx);
|
||||||
|
|
||||||
|
lock_kernel();
|
||||||
|
/* bump up the pseudo refcount while traversing */
|
||||||
|
svc_get(serv);
|
||||||
|
unlock_kernel();
|
||||||
|
|
||||||
|
if (!pidx)
|
||||||
|
return SEQ_START_TOKEN;
|
||||||
|
return (pidx > serv->sv_nrpools ? NULL : &serv->sv_pools[pidx-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *svc_pool_stats_next(struct seq_file *m, void *p, loff_t *pos)
|
||||||
|
{
|
||||||
|
struct svc_pool *pool = p;
|
||||||
|
struct svc_serv *serv = m->private;
|
||||||
|
|
||||||
|
dprintk("svc_pool_stats_next, *pos=%llu\n", *pos);
|
||||||
|
|
||||||
|
if (p == SEQ_START_TOKEN) {
|
||||||
|
pool = &serv->sv_pools[0];
|
||||||
|
} else {
|
||||||
|
unsigned int pidx = (pool - &serv->sv_pools[0]);
|
||||||
|
if (pidx < serv->sv_nrpools-1)
|
||||||
|
pool = &serv->sv_pools[pidx+1];
|
||||||
|
else
|
||||||
|
pool = NULL;
|
||||||
|
}
|
||||||
|
++*pos;
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void svc_pool_stats_stop(struct seq_file *m, void *p)
|
||||||
|
{
|
||||||
|
struct svc_serv *serv = m->private;
|
||||||
|
|
||||||
|
lock_kernel();
|
||||||
|
/* this function really, really should have been called svc_put() */
|
||||||
|
svc_destroy(serv);
|
||||||
|
unlock_kernel();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int svc_pool_stats_show(struct seq_file *m, void *p)
|
||||||
|
{
|
||||||
|
struct svc_pool *pool = p;
|
||||||
|
|
||||||
|
if (p == SEQ_START_TOKEN) {
|
||||||
|
seq_puts(m, "# pool packets-arrived sockets-enqueued threads-woken overloads-avoided threads-timedout\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
seq_printf(m, "%u %lu %lu %lu %lu %lu\n",
|
||||||
|
pool->sp_id,
|
||||||
|
pool->sp_stats.packets,
|
||||||
|
pool->sp_stats.sockets_queued,
|
||||||
|
pool->sp_stats.threads_woken,
|
||||||
|
pool->sp_stats.overloads_avoided,
|
||||||
|
pool->sp_stats.threads_timedout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct seq_operations svc_pool_stats_seq_ops = {
|
||||||
|
.start = svc_pool_stats_start,
|
||||||
|
.next = svc_pool_stats_next,
|
||||||
|
.stop = svc_pool_stats_stop,
|
||||||
|
.show = svc_pool_stats_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
int svc_pool_stats_open(struct svc_serv *serv, struct file *file)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = seq_open(file, &svc_pool_stats_seq_ops);
|
||||||
|
if (!err)
|
||||||
|
((struct seq_file *) file->private_data)->private = serv;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(svc_pool_stats_open);
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -345,7 +345,6 @@ static void svc_sock_setbufsize(struct socket *sock, unsigned int snd,
|
||||||
lock_sock(sock->sk);
|
lock_sock(sock->sk);
|
||||||
sock->sk->sk_sndbuf = snd * 2;
|
sock->sk->sk_sndbuf = snd * 2;
|
||||||
sock->sk->sk_rcvbuf = rcv * 2;
|
sock->sk->sk_rcvbuf = rcv * 2;
|
||||||
sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK;
|
|
||||||
release_sock(sock->sk);
|
release_sock(sock->sk);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -797,23 +796,6 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
|
||||||
test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags),
|
test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags),
|
||||||
test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags));
|
test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags));
|
||||||
|
|
||||||
if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
|
|
||||||
/* sndbuf needs to have room for one request
|
|
||||||
* per thread, otherwise we can stall even when the
|
|
||||||
* network isn't a bottleneck.
|
|
||||||
*
|
|
||||||
* We count all threads rather than threads in a
|
|
||||||
* particular pool, which provides an upper bound
|
|
||||||
* on the number of threads which will access the socket.
|
|
||||||
*
|
|
||||||
* rcvbuf just needs to be able to hold a few requests.
|
|
||||||
* Normally they will be removed from the queue
|
|
||||||
* as soon a a complete request arrives.
|
|
||||||
*/
|
|
||||||
svc_sock_setbufsize(svsk->sk_sock,
|
|
||||||
(serv->sv_nrthreads+3) * serv->sv_max_mesg,
|
|
||||||
3 * serv->sv_max_mesg);
|
|
||||||
|
|
||||||
clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
||||||
|
|
||||||
/* Receive data. If we haven't got the record length yet, get
|
/* Receive data. If we haven't got the record length yet, get
|
||||||
|
@ -1061,15 +1043,6 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
|
||||||
|
|
||||||
tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
|
tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
|
||||||
|
|
||||||
/* initialise setting must have enough space to
|
|
||||||
* receive and respond to one request.
|
|
||||||
* svc_tcp_recvfrom will re-adjust if necessary
|
|
||||||
*/
|
|
||||||
svc_sock_setbufsize(svsk->sk_sock,
|
|
||||||
3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
|
|
||||||
3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
|
|
||||||
|
|
||||||
set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
|
|
||||||
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
|
||||||
if (sk->sk_state != TCP_ESTABLISHED)
|
if (sk->sk_state != TCP_ESTABLISHED)
|
||||||
set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
|
set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
|
||||||
|
@ -1139,8 +1112,14 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
|
||||||
/* Initialize the socket */
|
/* Initialize the socket */
|
||||||
if (sock->type == SOCK_DGRAM)
|
if (sock->type == SOCK_DGRAM)
|
||||||
svc_udp_init(svsk, serv);
|
svc_udp_init(svsk, serv);
|
||||||
else
|
else {
|
||||||
|
/* initialise setting must have enough space to
|
||||||
|
* receive and respond to one request.
|
||||||
|
*/
|
||||||
|
svc_sock_setbufsize(svsk->sk_sock, 4 * serv->sv_max_mesg,
|
||||||
|
4 * serv->sv_max_mesg);
|
||||||
svc_tcp_init(svsk, serv);
|
svc_tcp_init(svsk, serv);
|
||||||
|
}
|
||||||
|
|
||||||
dprintk("svc: svc_setup_socket created %p (inet %p)\n",
|
dprintk("svc: svc_setup_socket created %p (inet %p)\n",
|
||||||
svsk, svsk->sk_sk);
|
svsk, svsk->sk_sk);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче