2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Server-side procedures for NFSv4.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2002 The Regents of the University of Michigan.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Kendrick Smith <kmsmith@umich.edu>
|
|
|
|
* Andy Adamson <andros@umich.edu>
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the University nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
2018-03-22 05:19:02 +08:00
|
|
|
#include <linux/fs_struct.h>
|
2005-06-24 13:03:13 +08:00
|
|
|
#include <linux/file.h>
|
2014-11-08 03:44:27 +08:00
|
|
|
#include <linux/falloc.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2018-07-21 06:19:20 +08:00
|
|
|
#include <linux/kthread.h>
|
2019-10-05 04:34:26 +08:00
|
|
|
#include <linux/sunrpc/addr.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
#include "idmap.h"
|
2009-12-04 02:30:56 +08:00
|
|
|
#include "cache.h"
|
|
|
|
#include "xdr4.h"
|
2009-11-05 07:12:35 +08:00
|
|
|
#include "vfs.h"
|
2012-02-14 05:55:24 +08:00
|
|
|
#include "current_stateid.h"
|
2012-11-14 23:22:07 +08:00
|
|
|
#include "netns.h"
|
2013-12-20 21:16:55 +08:00
|
|
|
#include "acl.h"
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
#include "pnfs.h"
|
2014-08-17 08:02:22 +08:00
|
|
|
#include "trace.h"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-05-03 01:19:10 +08:00
|
|
|
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
|
|
|
#include <linux/security.h>
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
|
|
|
|
{
|
2015-03-18 06:25:59 +08:00
|
|
|
struct inode *inode = d_inode(resfh->fh_dentry);
|
2013-05-03 01:19:10 +08:00
|
|
|
int status;
|
|
|
|
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_lock(inode);
|
2013-05-03 01:19:10 +08:00
|
|
|
status = security_inode_setsecctx(resfh->fh_dentry,
|
|
|
|
label->data, label->len);
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_unlock(inode);
|
2013-05-03 01:19:10 +08:00
|
|
|
|
|
|
|
if (status)
|
|
|
|
/*
|
|
|
|
* XXX: We should really fail the whole open, but we may
|
|
|
|
* already have created a new file, so it may be too
|
|
|
|
* late. For now this seems the least of evils:
|
|
|
|
*/
|
|
|
|
bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline void
|
|
|
|
nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
|
|
|
|
{ }
|
|
|
|
#endif
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
|
|
|
|
2009-05-16 16:22:31 +08:00
|
|
|
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
|
|
|
|
check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
|
|
u32 *bmval, u32 *writable)
|
|
|
|
{
|
|
|
|
struct dentry *dentry = cstate->current_fh.fh_dentry;
|
2017-01-04 01:30:11 +08:00
|
|
|
struct svc_export *exp = cstate->current_fh.fh_export;
|
2009-05-16 16:22:31 +08:00
|
|
|
|
2016-10-19 02:18:40 +08:00
|
|
|
if (!nfsd_attrs_supported(cstate->minorversion, bmval))
|
2009-05-16 16:22:31 +08:00
|
|
|
return nfserr_attrnotsupp;
|
2016-10-19 02:18:40 +08:00
|
|
|
if ((bmval[0] & FATTR4_WORD0_ACL) && !IS_POSIXACL(d_inode(dentry)))
|
|
|
|
return nfserr_attrnotsupp;
|
2017-01-04 01:30:11 +08:00
|
|
|
if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) &&
|
|
|
|
!(exp->ex_flags & NFSEXP_SECURITY_LABEL))
|
|
|
|
return nfserr_attrnotsupp;
|
2016-10-19 02:18:40 +08:00
|
|
|
if (writable && !bmval_is_subset(bmval, writable))
|
|
|
|
return nfserr_inval;
|
2016-01-13 03:24:14 +08:00
|
|
|
if (writable && (bmval[2] & FATTR4_WORD2_MODE_UMASK) &&
|
|
|
|
(bmval[1] & FATTR4_WORD1_MODE))
|
|
|
|
return nfserr_inval;
|
2009-05-16 16:22:31 +08:00
|
|
|
return nfs_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __be32
|
|
|
|
nfsd4_check_open_attributes(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
|
|
|
|
{
|
|
|
|
__be32 status = nfs_ok;
|
|
|
|
|
|
|
|
if (open->op_create == NFS4_OPEN_CREATE) {
|
|
|
|
if (open->op_createmode == NFS4_CREATE_UNCHECKED
|
|
|
|
|| open->op_createmode == NFS4_CREATE_GUARDED)
|
|
|
|
status = check_attr_support(rqstp, cstate,
|
|
|
|
open->op_bmval, nfsd_attrmask);
|
|
|
|
else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1)
|
|
|
|
status = check_attr_support(rqstp, cstate,
|
|
|
|
open->op_bmval, nfsd41_ex_attrmask);
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2009-07-06 17:24:16 +08:00
|
|
|
static int
|
|
|
|
is_create_with_attrs(struct nfsd4_open *open)
|
|
|
|
{
|
|
|
|
return open->op_create == NFS4_OPEN_CREATE
|
|
|
|
&& (open->op_createmode == NFS4_CREATE_UNCHECKED
|
|
|
|
|| open->op_createmode == NFS4_CREATE_GUARDED
|
|
|
|
|| open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if error occurs when setting the acl, just clear the acl bit
|
|
|
|
* in the returned attr bitmap.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|
|
|
struct nfs4_acl *acl, u32 *bmval)
|
|
|
|
{
|
|
|
|
__be32 status;
|
|
|
|
|
|
|
|
status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
|
|
|
|
if (status)
|
|
|
|
/*
|
|
|
|
* We should probably fail the whole open at this point,
|
|
|
|
* but we've already created the file, so it's too late;
|
|
|
|
* So this seems the least of evils:
|
|
|
|
*/
|
|
|
|
bmval[0] &= ~FATTR4_WORD0_ACL;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static inline void
|
|
|
|
fh_dup2(struct svc_fh *dst, struct svc_fh *src)
|
|
|
|
{
|
|
|
|
fh_put(dst);
|
|
|
|
dget(src->fh_dentry);
|
|
|
|
if (src->fh_export)
|
2014-06-10 22:06:44 +08:00
|
|
|
exp_get(src->fh_export);
|
2005-04-17 06:20:36 +08:00
|
|
|
*dst = *src;
|
|
|
|
}
|
|
|
|
|
2006-10-20 14:28:59 +08:00
|
|
|
static __be32
|
2006-10-17 15:10:13 +08:00
|
|
|
do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (open->op_truncate &&
|
|
|
|
!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
|
|
|
|
return nfserr_inval;
|
|
|
|
|
2011-08-25 22:48:39 +08:00
|
|
|
accmode |= NFSD_MAY_READ_IF_EXEC;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
|
2008-06-16 19:20:29 +08:00
|
|
|
accmode |= NFSD_MAY_READ;
|
2006-10-17 15:10:14 +08:00
|
|
|
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
|
2008-06-16 19:20:29 +08:00
|
|
|
accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC);
|
2009-12-02 08:42:57 +08:00
|
|
|
if (open->op_share_deny & NFS4_SHARE_DENY_READ)
|
2008-06-16 19:20:29 +08:00
|
|
|
accmode |= NFSD_MAY_WRITE;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2011-08-16 04:55:02 +08:00
|
|
|
static __be32 nfsd_check_obj_isreg(struct svc_fh *fh)
|
|
|
|
{
|
2015-03-18 06:25:59 +08:00
|
|
|
umode_t mode = d_inode(fh->fh_dentry)->i_mode;
|
2011-08-16 04:55:02 +08:00
|
|
|
|
|
|
|
if (S_ISREG(mode))
|
|
|
|
return nfs_ok;
|
|
|
|
if (S_ISDIR(mode))
|
|
|
|
return nfserr_isdir;
|
|
|
|
/*
|
|
|
|
* Using err_symlink as our catch-all case may look odd; but
|
|
|
|
* there's no other obvious error for this case in 4.0, and we
|
|
|
|
* happen to know that it will cause the linux v4 client to do
|
|
|
|
* the right thing on attempts to open something other than a
|
|
|
|
* regular file.
|
|
|
|
*/
|
|
|
|
return nfserr_symlink;
|
|
|
|
}
|
|
|
|
|
2013-03-23 06:03:49 +08:00
|
|
|
static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh *resfh)
|
|
|
|
{
|
|
|
|
if (nfsd4_has_session(cstate))
|
|
|
|
return;
|
|
|
|
fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
|
|
|
|
&resfh->fh_handle);
|
|
|
|
}
|
|
|
|
|
2006-10-20 14:28:59 +08:00
|
|
|
static __be32
|
2012-01-28 06:26:06 +08:00
|
|
|
do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh **resfh)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2013-03-23 06:03:49 +08:00
|
|
|
struct svc_fh *current_fh = &cstate->current_fh;
|
2012-12-08 04:40:55 +08:00
|
|
|
int accmode;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-01-28 06:26:06 +08:00
|
|
|
*resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
|
|
|
|
if (!*resfh)
|
2012-01-28 05:49:55 +08:00
|
|
|
return nfserr_jukebox;
|
2012-01-28 06:26:06 +08:00
|
|
|
fh_init(*resfh, NFS4_FHSIZE);
|
2019-12-25 11:19:35 +08:00
|
|
|
open->op_truncate = false;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (open->op_create) {
|
2009-04-03 13:29:17 +08:00
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Note: create modes (UNCHECKED,GUARDED...) are the same
|
2011-04-20 17:06:25 +08:00
|
|
|
* in NFSv4 as in v3 except EXCLUSIVE4_1.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2018-03-22 05:19:02 +08:00
|
|
|
current->fs->umask = open->op_umask;
|
2011-04-20 17:06:25 +08:00
|
|
|
status = do_nfsd_create(rqstp, current_fh, open->op_fname.data,
|
2005-04-17 06:20:36 +08:00
|
|
|
open->op_fname.len, &open->op_iattr,
|
2012-01-28 06:26:06 +08:00
|
|
|
*resfh, open->op_createmode,
|
2007-07-31 15:37:51 +08:00
|
|
|
(u32 *)open->op_verf.data,
|
2011-10-13 23:37:11 +08:00
|
|
|
&open->op_truncate, &open->op_created);
|
2018-03-22 05:19:02 +08:00
|
|
|
current->fs->umask = 0;
|
2007-07-31 15:37:51 +08:00
|
|
|
|
2013-05-03 01:19:10 +08:00
|
|
|
if (!status && open->op_label.len)
|
2012-01-28 06:26:06 +08:00
|
|
|
nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval);
|
2013-05-03 01:19:10 +08:00
|
|
|
|
2009-02-03 04:12:27 +08:00
|
|
|
/*
|
2015-07-30 21:55:02 +08:00
|
|
|
* Following rfc 3530 14.2.16, and rfc 5661 18.16.4
|
|
|
|
* use the returned bitmask to indicate which attributes
|
|
|
|
* we used to store the verifier:
|
2007-07-31 15:37:51 +08:00
|
|
|
*/
|
2015-07-30 21:55:02 +08:00
|
|
|
if (nfsd_create_is_exclusive(open->op_createmode) && status == 0)
|
|
|
|
open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
|
|
|
|
FATTR4_WORD1_TIME_MODIFY);
|
2014-01-25 07:04:40 +08:00
|
|
|
} else
|
|
|
|
/*
|
|
|
|
* Note this may exit with the parent still locked.
|
|
|
|
* We will hold the lock until nfsd4_open's final
|
|
|
|
* lookup, to prevent renames or unlinks until we've had
|
|
|
|
* a chance to an acquire a delegation if appropriate.
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
status = nfsd_lookup(rqstp, current_fh,
|
2012-01-28 06:26:06 +08:00
|
|
|
open->op_fname.data, open->op_fname.len, *resfh);
|
2012-04-10 06:06:49 +08:00
|
|
|
if (status)
|
|
|
|
goto out;
|
2012-01-28 06:26:06 +08:00
|
|
|
status = nfsd_check_obj_isreg(*resfh);
|
2006-11-09 09:44:39 +08:00
|
|
|
if (status)
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-07-06 17:24:16 +08:00
|
|
|
if (is_create_with_attrs(open) && open->op_acl != NULL)
|
2012-01-28 06:26:06 +08:00
|
|
|
do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval);
|
2009-07-06 17:24:16 +08:00
|
|
|
|
2012-01-28 06:26:06 +08:00
|
|
|
nfsd4_set_open_owner_reply_cache(cstate, open, *resfh);
|
2012-12-08 04:40:55 +08:00
|
|
|
accmode = NFSD_MAY_NOP;
|
2013-06-20 03:47:37 +08:00
|
|
|
if (open->op_created ||
|
|
|
|
open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
|
2012-12-08 04:40:55 +08:00
|
|
|
accmode |= NFSD_MAY_OWNER_OVERRIDE;
|
2012-01-28 06:26:06 +08:00
|
|
|
status = do_open_permission(rqstp, *resfh, open, accmode);
|
2012-01-28 05:26:02 +08:00
|
|
|
set_change_info(&open->op_cinfo, current_fh);
|
2006-11-09 09:44:39 +08:00
|
|
|
out:
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-10-20 14:28:59 +08:00
|
|
|
static __be32
|
2013-03-23 06:03:49 +08:00
|
|
|
do_open_fhandle(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2013-03-23 06:03:49 +08:00
|
|
|
struct svc_fh *current_fh = &cstate->current_fh;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2013-05-04 04:09:09 +08:00
|
|
|
int accmode = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* We don't know the target directory, and therefore can not
|
|
|
|
* set the change info
|
|
|
|
*/
|
|
|
|
|
|
|
|
memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));
|
|
|
|
|
2013-03-23 06:03:49 +08:00
|
|
|
nfsd4_set_open_owner_reply_cache(cstate, open, current_fh);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
|
|
|
|
(open->op_iattr.ia_size == 0);
|
2013-05-04 04:09:09 +08:00
|
|
|
/*
|
|
|
|
* In the delegation case, the client is telling us about an
|
|
|
|
* open that it *already* performed locally, some time ago. We
|
|
|
|
* should let it succeed now if possible.
|
|
|
|
*
|
|
|
|
* In the case of a CLAIM_FH open, on the other hand, the client
|
|
|
|
* may be counting on us to enforce permissions (the Linux 4.1
|
|
|
|
* client uses this for normal opens, for example).
|
|
|
|
*/
|
|
|
|
if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH)
|
|
|
|
accmode = NFSD_MAY_OWNER_OVERRIDE;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-05-04 04:09:09 +08:00
|
|
|
status = do_open_permission(rqstp, current_fh, open, accmode);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2009-04-03 13:28:50 +08:00
|
|
|
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;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_open *open = &u->open;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2012-01-28 06:26:06 +08:00
|
|
|
struct svc_fh *resfh = NULL;
|
2012-11-14 23:22:07 +08:00
|
|
|
struct net *net = SVC_NET(rqstp);
|
|
|
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
2018-06-09 00:28:47 +08:00
|
|
|
bool reclaim = false;
|
2009-04-03 13:28:45 +08:00
|
|
|
|
2011-07-31 11:33:59 +08:00
|
|
|
dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
(int)open->op_fname.len, open->op_fname.data,
|
2011-07-31 11:33:59 +08:00
|
|
|
open->op_openowner);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* This check required by spec. */
|
|
|
|
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
|
|
|
|
return nfserr_inval;
|
|
|
|
|
2019-12-25 11:19:35 +08:00
|
|
|
open->op_created = false;
|
2011-07-14 15:06:26 +08:00
|
|
|
/*
|
|
|
|
* RFC5661 18.51.3
|
|
|
|
* Before RECLAIM_COMPLETE done, server should deny new lock
|
|
|
|
*/
|
|
|
|
if (nfsd4_has_session(cstate) &&
|
2012-03-21 21:52:02 +08:00
|
|
|
!test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
|
|
|
|
&cstate->session->se_client->cl_flags) &&
|
2011-07-14 15:06:26 +08:00
|
|
|
open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
|
|
|
return nfserr_grace;
|
|
|
|
|
2009-04-03 13:28:50 +08:00
|
|
|
if (nfsd4_has_session(cstate))
|
|
|
|
copy_clientid(&open->op_clientid, cstate->session);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* check seqid for replay. set nfs4_owner */
|
2015-07-13 17:32:05 +08:00
|
|
|
status = nfsd4_process_open1(cstate, open, nn);
|
2006-10-20 14:29:03 +08:00
|
|
|
if (status == nfserr_replay_me) {
|
2011-07-31 11:33:59 +08:00
|
|
|
struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay;
|
2006-12-13 16:35:27 +08:00
|
|
|
fh_put(&cstate->current_fh);
|
2009-02-03 06:23:10 +08:00
|
|
|
fh_copy_shallow(&cstate->current_fh.fh_handle,
|
|
|
|
&rp->rp_openfh);
|
2008-06-16 19:20:29 +08:00
|
|
|
status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (status)
|
|
|
|
dprintk("nfsd4_open: replay failed"
|
|
|
|
" restoring previous filehandle\n");
|
|
|
|
else
|
2006-10-20 14:29:03 +08:00
|
|
|
status = nfserr_replay_me;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
if (status)
|
|
|
|
goto out;
|
2013-03-01 04:51:49 +08:00
|
|
|
if (open->op_xdr_error) {
|
|
|
|
status = open->op_xdr_error;
|
|
|
|
goto out;
|
|
|
|
}
|
2006-01-19 09:43:36 +08:00
|
|
|
|
2009-05-16 16:22:31 +08:00
|
|
|
status = nfsd4_check_open_attributes(rqstp, cstate, open);
|
|
|
|
if (status)
|
|
|
|
goto out;
|
|
|
|
|
2006-01-19 09:43:36 +08:00
|
|
|
/* Openowner is now set, so sequence id will get bumped. Now we need
|
|
|
|
* these checks before we do any creates: */
|
2006-02-08 04:58:32 +08:00
|
|
|
status = nfserr_grace;
|
2015-08-07 00:47:02 +08:00
|
|
|
if (opens_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
2006-02-08 04:58:32 +08:00
|
|
|
goto out;
|
|
|
|
status = nfserr_no_grace;
|
2015-08-07 00:47:02 +08:00
|
|
|
if (!opens_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
2006-02-08 04:58:32 +08:00
|
|
|
goto out;
|
2006-01-19 09:43:36 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
switch (open->op_claim_type) {
|
2005-06-24 13:02:56 +08:00
|
|
|
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
|
2005-04-17 06:20:36 +08:00
|
|
|
case NFS4_OPEN_CLAIM_NULL:
|
2012-01-28 06:26:06 +08:00
|
|
|
status = do_open_lookup(rqstp, cstate, open, &resfh);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (status)
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
case NFS4_OPEN_CLAIM_PREVIOUS:
|
2012-11-14 23:22:07 +08:00
|
|
|
status = nfs4_check_open_reclaim(&open->op_clientid,
|
2014-06-30 23:48:47 +08:00
|
|
|
cstate, nn);
|
2011-11-23 10:48:40 +08:00
|
|
|
if (status)
|
|
|
|
goto out;
|
2014-05-30 21:09:28 +08:00
|
|
|
open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
|
2018-06-09 00:28:47 +08:00
|
|
|
reclaim = true;
|
2019-01-23 16:48:28 +08:00
|
|
|
/* fall through */
|
2011-10-19 23:52:12 +08:00
|
|
|
case NFS4_OPEN_CLAIM_FH:
|
|
|
|
case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
|
2013-03-23 06:03:49 +08:00
|
|
|
status = do_open_fhandle(rqstp, cstate, open);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (status)
|
|
|
|
goto out;
|
2012-01-28 06:26:06 +08:00
|
|
|
resfh = &cstate->current_fh;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
2011-10-19 23:52:12 +08:00
|
|
|
case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
|
2005-04-17 06:20:36 +08:00
|
|
|
case NFS4_OPEN_CLAIM_DELEGATE_PREV:
|
2007-07-28 04:10:37 +08:00
|
|
|
dprintk("NFSD: unsupported OPEN claim type %d\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
open->op_claim_type);
|
|
|
|
status = nfserr_notsupp;
|
|
|
|
goto out;
|
|
|
|
default:
|
2007-07-28 04:10:37 +08:00
|
|
|
dprintk("NFSD: Invalid OPEN claim type %d\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
open->op_claim_type);
|
|
|
|
status = nfserr_inval;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* nfsd4_process_open2() does the actual opening of the file. If
|
|
|
|
* successful, it (1) truncates the file if open->op_truncate was
|
|
|
|
* set, (2) sets open->op_stateid, (3) sets open->op_delegation.
|
|
|
|
*/
|
2012-01-28 06:26:06 +08:00
|
|
|
status = nfsd4_process_open2(rqstp, resfh, open);
|
2014-07-30 09:37:44 +08:00
|
|
|
WARN(status && open->op_created,
|
|
|
|
"nfsd4_process_open2 failed to open newly-created file! status=%u\n",
|
|
|
|
be32_to_cpu(status));
|
2018-06-09 00:28:47 +08:00
|
|
|
if (reclaim && !status)
|
|
|
|
nn->somebody_reclaimed = true;
|
2005-04-17 06:20:36 +08:00
|
|
|
out:
|
2012-01-28 06:26:06 +08:00
|
|
|
if (resfh && resfh != &cstate->current_fh) {
|
|
|
|
fh_dup2(&cstate->current_fh, resfh);
|
|
|
|
fh_put(resfh);
|
|
|
|
kfree(resfh);
|
|
|
|
}
|
2015-03-23 22:53:44 +08:00
|
|
|
nfsd4_cleanup_open_state(cstate, open);
|
2013-04-02 04:37:12 +08:00
|
|
|
nfsd4_bump_seqid(cstate, status);
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2013-03-01 04:51:49 +08:00
|
|
|
/*
|
|
|
|
* OPEN is the only seqid-mutating operation whose decoding can fail
|
|
|
|
* with a seqid-mutating error (specifically, decoding of user names in
|
|
|
|
* the attributes). Therefore we have to do some processing to look up
|
|
|
|
* the stateowner so that we can bump the seqid.
|
|
|
|
*/
|
|
|
|
static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_op *op)
|
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_open *open = &op->u.open;
|
2013-03-01 04:51:49 +08:00
|
|
|
|
|
|
|
if (!seqid_mutating_err(ntohl(op->status)))
|
|
|
|
return op->status;
|
|
|
|
if (nfsd4_has_session(cstate))
|
|
|
|
return op->status;
|
|
|
|
open->op_xdr_error = op->status;
|
2017-05-09 02:58:35 +08:00
|
|
|
return nfsd4_open(rqstp, cstate, &op->u);
|
2013-03-01 04:51:49 +08:00
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* filehandle-manipulating ops.
|
|
|
|
*/
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:38 +08:00
|
|
|
nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
u->getfh = &cstate->current_fh;
|
2005-04-17 06:20:36 +08:00
|
|
|
return nfs_ok;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_putfh *putfh = &u->putfh;
|
2019-10-07 22:56:48 +08:00
|
|
|
__be32 ret;
|
2017-05-09 02:58:35 +08:00
|
|
|
|
2006-12-13 16:35:27 +08:00
|
|
|
fh_put(&cstate->current_fh);
|
|
|
|
cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
|
|
|
|
memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
|
|
|
|
putfh->pf_fhlen);
|
2019-10-07 22:56:48 +08:00
|
|
|
ret = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
|
|
|
|
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
|
|
|
if (ret == nfserr_stale && putfh->no_verify) {
|
|
|
|
SET_FH_FLAG(&cstate->current_fh, NFSD4_FH_FOREIGN);
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return ret;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:38 +08:00
|
|
|
nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-12-13 16:35:27 +08:00
|
|
|
fh_put(&cstate->current_fh);
|
2007-07-17 19:04:43 +08:00
|
|
|
status = exp_pseudoroot(rqstp, &cstate->current_fh);
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:38 +08:00
|
|
|
nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2006-12-13 16:35:27 +08:00
|
|
|
if (!cstate->save_fh.fh_dentry)
|
2005-04-17 06:20:36 +08:00
|
|
|
return nfserr_restorefh;
|
|
|
|
|
2006-12-13 16:35:27 +08:00
|
|
|
fh_dup2(&cstate->current_fh, &cstate->save_fh);
|
2018-09-14 01:58:24 +08:00
|
|
|
if (HAS_CSTATE_FLAG(cstate, SAVED_STATE_ID_FLAG)) {
|
2012-02-14 05:55:32 +08:00
|
|
|
memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t));
|
2018-09-14 01:58:24 +08:00
|
|
|
SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG);
|
2012-02-14 05:55:32 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
return nfs_ok;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:38 +08:00
|
|
|
nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2006-12-13 16:35:27 +08:00
|
|
|
fh_dup2(&cstate->save_fh, &cstate->current_fh);
|
2018-09-14 01:58:24 +08:00
|
|
|
if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG)) {
|
2012-02-14 05:55:32 +08:00
|
|
|
memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t));
|
2018-09-14 01:58:24 +08:00
|
|
|
SET_CSTATE_FLAG(cstate, SAVED_STATE_ID_FLAG);
|
2012-02-14 05:55:32 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
return nfs_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* misc nfsv4 ops
|
|
|
|
*/
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_access *access = &u->access;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (access->ac_req_access & ~NFS3_ACCESS_FULL)
|
|
|
|
return nfserr_inval;
|
|
|
|
|
|
|
|
access->ac_resp_access = access->ac_req_access;
|
2006-12-13 16:35:27 +08:00
|
|
|
return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access,
|
|
|
|
&access->ac_supported);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2012-12-06 19:23:19 +08:00
|
|
|
static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
|
2012-03-03 06:13:50 +08:00
|
|
|
{
|
2019-09-03 01:02:56 +08:00
|
|
|
__be32 *verf = (__be32 *)verifier->data;
|
2012-03-03 06:13:50 +08:00
|
|
|
|
2019-09-03 01:02:56 +08:00
|
|
|
BUILD_BUG_ON(2*sizeof(*verf) != sizeof(verifier->data));
|
|
|
|
|
|
|
|
nfsd_copy_boot_verifier(verf, net_generic(net, nfsd_net_id));
|
2012-03-03 06:13:50 +08:00
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_commit *commit = &u->commit;
|
|
|
|
|
2011-08-16 06:39:32 +08:00
|
|
|
return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
|
2020-01-07 02:40:36 +08:00
|
|
|
commit->co_count,
|
|
|
|
(__be32 *)commit->co_verf.data);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-10-20 14:28:59 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_create *create = &u->create;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct svc_fh resfh;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
dev_t rdev;
|
|
|
|
|
|
|
|
fh_init(&resfh, NFS4_FHSIZE);
|
|
|
|
|
2016-07-22 04:00:12 +08:00
|
|
|
status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_NOP);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2009-05-16 16:22:31 +08:00
|
|
|
status = check_attr_support(rqstp, cstate, create->cr_bmval,
|
|
|
|
nfsd_attrmask);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2018-03-22 05:19:02 +08:00
|
|
|
current->fs->umask = create->cr_umask;
|
2005-04-17 06:20:36 +08:00
|
|
|
switch (create->cr_type) {
|
|
|
|
case NF4LNK:
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_symlink(rqstp, &cstate->current_fh,
|
|
|
|
create->cr_name, create->cr_namelen,
|
2014-07-01 17:48:02 +08:00
|
|
|
create->cr_data, &resfh);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NF4BLK:
|
2018-03-22 05:19:02 +08:00
|
|
|
status = nfserr_inval;
|
2005-04-17 06:20:36 +08:00
|
|
|
rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
|
|
|
|
if (MAJOR(rdev) != create->cr_specdata1 ||
|
|
|
|
MINOR(rdev) != create->cr_specdata2)
|
2018-03-22 05:19:02 +08:00
|
|
|
goto out_umask;
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_create(rqstp, &cstate->current_fh,
|
|
|
|
create->cr_name, create->cr_namelen,
|
|
|
|
&create->cr_iattr, S_IFBLK, rdev, &resfh);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NF4CHR:
|
2018-03-22 05:19:02 +08:00
|
|
|
status = nfserr_inval;
|
2005-04-17 06:20:36 +08:00
|
|
|
rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
|
|
|
|
if (MAJOR(rdev) != create->cr_specdata1 ||
|
|
|
|
MINOR(rdev) != create->cr_specdata2)
|
2018-03-22 05:19:02 +08:00
|
|
|
goto out_umask;
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_create(rqstp, &cstate->current_fh,
|
|
|
|
create->cr_name, create->cr_namelen,
|
|
|
|
&create->cr_iattr,S_IFCHR, rdev, &resfh);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NF4SOCK:
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_create(rqstp, &cstate->current_fh,
|
|
|
|
create->cr_name, create->cr_namelen,
|
|
|
|
&create->cr_iattr, S_IFSOCK, 0, &resfh);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NF4FIFO:
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_create(rqstp, &cstate->current_fh,
|
|
|
|
create->cr_name, create->cr_namelen,
|
|
|
|
&create->cr_iattr, S_IFIFO, 0, &resfh);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NF4DIR:
|
|
|
|
create->cr_iattr.ia_valid &= ~ATTR_SIZE;
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_create(rqstp, &cstate->current_fh,
|
|
|
|
create->cr_name, create->cr_namelen,
|
|
|
|
&create->cr_iattr, S_IFDIR, 0, &resfh);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
status = nfserr_badtype;
|
|
|
|
}
|
|
|
|
|
2009-07-06 17:24:16 +08:00
|
|
|
if (status)
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-05-03 01:19:10 +08:00
|
|
|
if (create->cr_label.len)
|
|
|
|
nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval);
|
|
|
|
|
2009-07-06 17:24:16 +08:00
|
|
|
if (create->cr_acl != NULL)
|
|
|
|
do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
|
|
|
|
create->cr_bmval);
|
|
|
|
|
|
|
|
fh_unlock(&cstate->current_fh);
|
|
|
|
set_change_info(&create->cr_cinfo, &cstate->current_fh);
|
|
|
|
fh_dup2(&cstate->current_fh, &resfh);
|
|
|
|
out:
|
2005-04-17 06:20:36 +08:00
|
|
|
fh_put(&resfh);
|
2018-03-22 05:19:02 +08:00
|
|
|
out_umask:
|
|
|
|
current->fs->umask = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_getattr *getattr = &u->getattr;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-06-16 19:20:29 +08:00
|
|
|
status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
|
|
|
|
return nfserr_inval;
|
|
|
|
|
2016-10-19 02:18:40 +08:00
|
|
|
getattr->ga_bmval[0] &= nfsd_suppattrs[cstate->minorversion][0];
|
|
|
|
getattr->ga_bmval[1] &= nfsd_suppattrs[cstate->minorversion][1];
|
|
|
|
getattr->ga_bmval[2] &= nfsd_suppattrs[cstate->minorversion][2];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-12-13 16:35:27 +08:00
|
|
|
getattr->ga_fhp = &cstate->current_fh;
|
2005-04-17 06:20:36 +08:00
|
|
|
return nfs_ok;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_link *link = &u->link;
|
2017-09-16 04:02:52 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_link(rqstp, &cstate->current_fh,
|
|
|
|
link->li_name, link->li_namelen, &cstate->save_fh);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!status)
|
2006-12-13 16:35:27 +08:00
|
|
|
set_change_info(&link->li_cinfo, &cstate->current_fh);
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2010-12-16 23:06:27 +08:00
|
|
|
static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct svc_fh tmp_fh;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 ret;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
fh_init(&tmp_fh, NFS4_FHSIZE);
|
2007-07-17 19:04:43 +08:00
|
|
|
ret = exp_pseudoroot(rqstp, &tmp_fh);
|
|
|
|
if (ret)
|
2005-04-17 06:20:36 +08:00
|
|
|
return ret;
|
2010-12-16 23:06:27 +08:00
|
|
|
if (tmp_fh.fh_dentry == fh->fh_dentry) {
|
2005-04-17 06:20:36 +08:00
|
|
|
fh_put(&tmp_fh);
|
|
|
|
return nfserr_noent;
|
|
|
|
}
|
|
|
|
fh_put(&tmp_fh);
|
2010-12-16 23:06:27 +08:00
|
|
|
return nfsd_lookup(rqstp, fh, "..", 2, fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
static __be32
|
|
|
|
nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2010-12-16 23:06:27 +08:00
|
|
|
{
|
|
|
|
return nfsd4_do_lookupp(rqstp, &cstate->current_fh);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2006-12-13 16:35:27 +08:00
|
|
|
return nfsd_lookup(rqstp, &cstate->current_fh,
|
2017-05-09 02:58:35 +08:00
|
|
|
u->lookup.lo_name, u->lookup.lo_len,
|
2006-12-13 16:35:27 +08:00
|
|
|
&cstate->current_fh);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_read *read = &u->read;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2019-08-19 02:18:54 +08:00
|
|
|
read->rd_nf = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (read->rd_offset >= OFFSET_MAX)
|
|
|
|
return nfserr_inval;
|
|
|
|
|
2018-03-29 01:29:11 +08:00
|
|
|
trace_nfsd_read_start(rqstp, &cstate->current_fh,
|
|
|
|
read->rd_offset, read->rd_length);
|
|
|
|
|
2012-12-05 07:03:46 +08:00
|
|
|
/*
|
|
|
|
* If we do a zero copy read, then a client will see read data
|
|
|
|
* that reflects the state of the file *after* performing the
|
|
|
|
* following compound.
|
|
|
|
*
|
|
|
|
* To ensure proper ordering, we therefore turn off zero copy if
|
|
|
|
* the client wants us to do more in this compound:
|
|
|
|
*/
|
|
|
|
if (!nfsd4_last_compound_op(rqstp))
|
2014-11-19 20:51:18 +08:00
|
|
|
clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
|
2012-12-05 07:03:46 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* check stateid */
|
2015-12-03 19:59:51 +08:00
|
|
|
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
|
|
|
&read->rd_stateid, RD_STATE,
|
2019-10-05 04:34:26 +08:00
|
|
|
&read->rd_nf, NULL);
|
2015-06-18 22:45:00 +08:00
|
|
|
if (status) {
|
2005-04-17 06:20:36 +08:00
|
|
|
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
status = nfs_ok;
|
|
|
|
out:
|
|
|
|
read->rd_rqstp = rqstp;
|
2006-12-13 16:35:27 +08:00
|
|
|
read->rd_fhp = &cstate->current_fh;
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2017-05-06 05:09:37 +08:00
|
|
|
|
|
|
|
static void
|
|
|
|
nfsd4_read_release(union nfsd4_op_u *u)
|
|
|
|
{
|
2019-08-19 02:18:54 +08:00
|
|
|
if (u->read.rd_nf)
|
|
|
|
nfsd_file_put(u->read.rd_nf);
|
2018-03-29 01:29:11 +08:00
|
|
|
trace_nfsd_read_done(u->read.rd_rqstp, u->read.rd_fhp,
|
|
|
|
u->read.rd_offset, u->read.rd_length);
|
2017-05-06 05:09:37 +08:00
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_readdir *readdir = &u->readdir;
|
2005-04-17 06:20:36 +08:00
|
|
|
u64 cookie = readdir->rd_cookie;
|
|
|
|
static const nfs4_verifier zeroverf;
|
|
|
|
|
|
|
|
/* no need to check permission - this will be done in nfsd_readdir() */
|
|
|
|
|
|
|
|
if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
|
|
|
|
return nfserr_inval;
|
|
|
|
|
2016-10-19 02:18:40 +08:00
|
|
|
readdir->rd_bmval[0] &= nfsd_suppattrs[cstate->minorversion][0];
|
|
|
|
readdir->rd_bmval[1] &= nfsd_suppattrs[cstate->minorversion][1];
|
|
|
|
readdir->rd_bmval[2] &= nfsd_suppattrs[cstate->minorversion][2];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2011-08-08 23:38:08 +08:00
|
|
|
if ((cookie == 1) || (cookie == 2) ||
|
2005-04-17 06:20:36 +08:00
|
|
|
(cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
|
|
|
|
return nfserr_bad_cookie;
|
|
|
|
|
|
|
|
readdir->rd_rqstp = rqstp;
|
2006-12-13 16:35:27 +08:00
|
|
|
readdir->rd_fhp = &cstate->current_fh;
|
2005-04-17 06:20:36 +08:00
|
|
|
return nfs_ok;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
u->readlink.rl_rqstp = rqstp;
|
|
|
|
u->readlink.rl_fhp = &cstate->current_fh;
|
2005-04-17 06:20:36 +08:00
|
|
|
return nfs_ok;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_remove *remove = &u->remove;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-08-07 00:47:02 +08:00
|
|
|
if (opens_in_grace(SVC_NET(rqstp)))
|
2005-06-24 13:03:00 +08:00
|
|
|
return nfserr_grace;
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
|
|
|
|
remove->rm_name, remove->rm_namelen);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!status) {
|
2006-12-13 16:35:27 +08:00
|
|
|
fh_unlock(&cstate->current_fh);
|
|
|
|
set_change_info(&remove->rm_cinfo, &cstate->current_fh);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_rename *rename = &u->rename;
|
2017-09-16 04:02:52 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2018-11-07 00:47:20 +08:00
|
|
|
if (opens_in_grace(SVC_NET(rqstp)))
|
2005-06-24 13:03:00 +08:00
|
|
|
return nfserr_grace;
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
|
|
|
|
rename->rn_snamelen, &cstate->current_fh,
|
2005-04-17 06:20:36 +08:00
|
|
|
rename->rn_tname, rename->rn_tnamelen);
|
2013-05-01 03:28:51 +08:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
set_change_info(&rename->rn_sinfo, &cstate->current_fh);
|
|
|
|
set_change_info(&rename->rn_tinfo, &cstate->save_fh);
|
|
|
|
return nfs_ok;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-07-17 19:04:51 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2007-07-17 19:04:51 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_secinfo *secinfo = &u->secinfo;
|
2007-07-17 19:04:51 +08:00
|
|
|
struct svc_export *exp;
|
|
|
|
struct dentry *dentry;
|
|
|
|
__be32 err;
|
|
|
|
|
2011-04-09 23:28:53 +08:00
|
|
|
err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2007-07-17 19:04:51 +08:00
|
|
|
err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
|
|
|
|
secinfo->si_name, secinfo->si_namelen,
|
|
|
|
&exp, &dentry);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2016-03-03 08:36:21 +08:00
|
|
|
fh_unlock(&cstate->current_fh);
|
2015-03-18 06:25:59 +08:00
|
|
|
if (d_really_is_negative(dentry)) {
|
2007-07-17 19:04:51 +08:00
|
|
|
exp_put(exp);
|
|
|
|
err = nfserr_noent;
|
|
|
|
} else
|
|
|
|
secinfo->si_exp = exp;
|
|
|
|
dput(dentry);
|
2010-12-16 22:57:15 +08:00
|
|
|
if (cstate->minorversion)
|
|
|
|
/* See rfc 5661 section 2.6.3.1.1.8 */
|
|
|
|
fh_put(&cstate->current_fh);
|
2007-07-17 19:04:51 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2010-12-16 22:51:13 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2010-12-16 22:51:13 +08:00
|
|
|
{
|
|
|
|
__be32 err;
|
|
|
|
|
2017-05-09 02:58:35 +08:00
|
|
|
switch (u->secinfo_no_name.sin_style) {
|
2010-12-16 22:51:13 +08:00
|
|
|
case NFS4_SECINFO_STYLE4_CURRENT_FH:
|
|
|
|
break;
|
|
|
|
case NFS4_SECINFO_STYLE4_PARENT:
|
|
|
|
err = nfsd4_do_lookupp(rqstp, &cstate->current_fh);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return nfserr_inval;
|
|
|
|
}
|
2014-06-10 22:06:44 +08:00
|
|
|
|
2017-05-09 02:58:35 +08:00
|
|
|
u->secinfo_no_name.sin_exp = exp_get(cstate->current_fh.fh_export);
|
2010-12-16 22:51:13 +08:00
|
|
|
fh_put(&cstate->current_fh);
|
|
|
|
return nfs_ok;
|
|
|
|
}
|
|
|
|
|
2017-05-06 05:09:37 +08:00
|
|
|
static void
|
|
|
|
nfsd4_secinfo_release(union nfsd4_op_u *u)
|
|
|
|
{
|
|
|
|
if (u->secinfo.si_exp)
|
|
|
|
exp_put(u->secinfo.si_exp);
|
|
|
|
}
|
|
|
|
|
2017-09-29 15:01:10 +08:00
|
|
|
static void
|
|
|
|
nfsd4_secinfo_no_name_release(union nfsd4_op_u *u)
|
|
|
|
{
|
|
|
|
if (u->secinfo_no_name.sin_exp)
|
|
|
|
exp_put(u->secinfo_no_name.sin_exp);
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_setattr *setattr = &u->setattr;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status = nfs_ok;
|
2012-04-13 11:47:00 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
|
2015-06-18 22:45:00 +08:00
|
|
|
status = nfs4_preprocess_stateid_op(rqstp, cstate,
|
2015-12-03 19:59:51 +08:00
|
|
|
&cstate->current_fh, &setattr->sa_stateid,
|
2019-10-05 04:34:26 +08:00
|
|
|
WR_STATE, NULL, NULL);
|
2006-01-19 09:43:33 +08:00
|
|
|
if (status) {
|
2006-10-02 17:17:41 +08:00
|
|
|
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
|
2006-01-19 09:43:33 +08:00
|
|
|
return status;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2012-04-13 11:47:00 +08:00
|
|
|
err = fh_want_write(&cstate->current_fh);
|
|
|
|
if (err)
|
|
|
|
return nfserrno(err);
|
2005-04-17 06:20:36 +08:00
|
|
|
status = nfs_ok;
|
2009-05-16 16:22:31 +08:00
|
|
|
|
|
|
|
status = check_attr_support(rqstp, cstate, setattr->sa_bmval,
|
|
|
|
nfsd_attrmask);
|
|
|
|
if (status)
|
|
|
|
goto out;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (setattr->sa_acl != NULL)
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
|
|
|
|
setattr->sa_acl);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (status)
|
2008-02-16 06:37:38 +08:00
|
|
|
goto out;
|
2013-05-03 01:19:10 +08:00
|
|
|
if (setattr->sa_label.len)
|
|
|
|
status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
|
|
|
|
&setattr->sa_label);
|
|
|
|
if (status)
|
|
|
|
goto out;
|
2006-12-13 16:35:27 +08:00
|
|
|
status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
|
2019-11-04 00:50:18 +08:00
|
|
|
0, (time64_t)0);
|
2008-02-16 06:37:38 +08:00
|
|
|
out:
|
2011-11-24 01:03:18 +08:00
|
|
|
fh_drop_write(&cstate->current_fh);
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:29 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:27 +08:00
|
|
|
nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_write *write = &u->write;
|
2005-04-17 06:20:36 +08:00
|
|
|
stateid_t *stateid = &write->wr_stateid;
|
2019-08-19 02:18:54 +08:00
|
|
|
struct nfsd_file *nf = NULL;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status = nfs_ok;
|
2009-03-06 09:16:14 +08:00
|
|
|
unsigned long cnt;
|
2012-11-16 03:52:19 +08:00
|
|
|
int nvecs;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (write->wr_offset >= OFFSET_MAX)
|
|
|
|
return nfserr_inval;
|
|
|
|
|
2018-03-27 22:53:27 +08:00
|
|
|
cnt = write->wr_buflen;
|
|
|
|
trace_nfsd_write_start(rqstp, &cstate->current_fh,
|
|
|
|
write->wr_offset, cnt);
|
2015-12-03 19:59:51 +08:00
|
|
|
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
2019-10-05 04:34:26 +08:00
|
|
|
stateid, WR_STATE, &nf, NULL);
|
2006-01-19 09:43:33 +08:00
|
|
|
if (status) {
|
|
|
|
dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
write->wr_how_written = write->wr_stable_how;
|
|
|
|
|
2018-07-27 23:19:05 +08:00
|
|
|
nvecs = svc_fill_write_vector(rqstp, write->wr_pagelist,
|
|
|
|
&write->wr_head, write->wr_buflen);
|
2012-11-16 03:52:19 +08:00
|
|
|
WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));
|
|
|
|
|
2020-01-07 02:40:29 +08:00
|
|
|
status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf,
|
2015-06-18 22:45:00 +08:00
|
|
|
write->wr_offset, rqstp->rq_vec, nvecs, &cnt,
|
2020-01-07 02:40:37 +08:00
|
|
|
write->wr_how_written,
|
|
|
|
(__be32 *)write->wr_verifier.data);
|
2019-08-19 02:18:54 +08:00
|
|
|
nfsd_file_put(nf);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-03-06 09:16:14 +08:00
|
|
|
write->wr_bytes_written = cnt;
|
2018-03-27 22:53:27 +08:00
|
|
|
trace_nfsd_write_done(rqstp, &cstate->current_fh,
|
|
|
|
write->wr_offset, cnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2015-12-03 19:59:52 +08:00
|
|
|
static __be32
|
2016-09-08 03:57:30 +08:00
|
|
|
nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2019-08-19 02:18:54 +08:00
|
|
|
stateid_t *src_stateid, struct nfsd_file **src,
|
|
|
|
stateid_t *dst_stateid, struct nfsd_file **dst)
|
2015-12-03 19:59:52 +08:00
|
|
|
{
|
|
|
|
__be32 status;
|
|
|
|
|
2018-11-09 00:11:36 +08:00
|
|
|
if (!cstate->save_fh.fh_dentry)
|
|
|
|
return nfserr_nofilehandle;
|
|
|
|
|
2015-12-03 19:59:52 +08:00
|
|
|
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
|
2019-10-05 04:34:26 +08:00
|
|
|
src_stateid, RD_STATE, src, NULL);
|
2015-12-03 19:59:52 +08:00
|
|
|
if (status) {
|
|
|
|
dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
2019-10-05 04:34:26 +08:00
|
|
|
dst_stateid, WR_STATE, dst, NULL);
|
2015-12-03 19:59:52 +08:00
|
|
|
if (status) {
|
|
|
|
dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
|
|
|
|
goto out_put_src;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fix up for NFS-specific error code */
|
2019-08-19 02:18:54 +08:00
|
|
|
if (!S_ISREG(file_inode((*src)->nf_file)->i_mode) ||
|
|
|
|
!S_ISREG(file_inode((*dst)->nf_file)->i_mode)) {
|
2015-12-03 19:59:52 +08:00
|
|
|
status = nfserr_wrong_type;
|
|
|
|
goto out_put_dst;
|
|
|
|
}
|
|
|
|
|
2016-09-08 03:57:30 +08:00
|
|
|
out:
|
|
|
|
return status;
|
|
|
|
out_put_dst:
|
2019-08-19 02:18:54 +08:00
|
|
|
nfsd_file_put(*dst);
|
2016-09-08 03:57:30 +08:00
|
|
|
out_put_src:
|
2019-08-19 02:18:54 +08:00
|
|
|
nfsd_file_put(*src);
|
2016-09-08 03:57:30 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __be32
|
|
|
|
nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2016-09-08 03:57:30 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_clone *clone = &u->clone;
|
2019-08-19 02:18:54 +08:00
|
|
|
struct nfsd_file *src, *dst;
|
2016-09-08 03:57:30 +08:00
|
|
|
__be32 status;
|
|
|
|
|
|
|
|
status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
|
|
|
|
&clone->cl_dst_stateid, &dst);
|
|
|
|
if (status)
|
|
|
|
goto out;
|
|
|
|
|
2020-01-07 02:40:32 +08:00
|
|
|
status = nfsd4_clone_file_range(src, clone->cl_src_pos,
|
|
|
|
dst, clone->cl_dst_pos, clone->cl_count,
|
2019-11-28 06:05:51 +08:00
|
|
|
EX_ISSYNC(cstate->current_fh.fh_export));
|
2015-12-03 19:59:52 +08:00
|
|
|
|
2019-08-19 02:18:54 +08:00
|
|
|
nfsd_file_put(dst);
|
|
|
|
nfsd_file_put(src);
|
2015-12-03 19:59:52 +08:00
|
|
|
out:
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2018-07-21 06:19:20 +08:00
|
|
|
void nfs4_put_copy(struct nfsd4_copy *copy)
|
|
|
|
{
|
|
|
|
if (!refcount_dec_and_test(©->refcount))
|
|
|
|
return;
|
|
|
|
kfree(copy);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
check_and_set_stop_copy(struct nfsd4_copy *copy)
|
|
|
|
{
|
|
|
|
bool value;
|
|
|
|
|
|
|
|
spin_lock(©->cp_clp->async_lock);
|
|
|
|
value = copy->stopped;
|
|
|
|
if (!copy->stopped)
|
|
|
|
copy->stopped = true;
|
|
|
|
spin_unlock(©->cp_clp->async_lock);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void nfsd4_stop_copy(struct nfsd4_copy *copy)
|
|
|
|
{
|
|
|
|
/* only 1 thread should stop the copy */
|
|
|
|
if (!check_and_set_stop_copy(copy))
|
|
|
|
kthread_stop(copy->copy_task);
|
|
|
|
nfs4_put_copy(copy);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct nfsd4_copy *nfsd4_get_copy(struct nfs4_client *clp)
|
|
|
|
{
|
|
|
|
struct nfsd4_copy *copy = NULL;
|
|
|
|
|
|
|
|
spin_lock(&clp->async_lock);
|
|
|
|
if (!list_empty(&clp->async_copies)) {
|
|
|
|
copy = list_first_entry(&clp->async_copies, struct nfsd4_copy,
|
|
|
|
copies);
|
|
|
|
refcount_inc(©->refcount);
|
|
|
|
}
|
|
|
|
spin_unlock(&clp->async_lock);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nfsd4_shutdown_copy(struct nfs4_client *clp)
|
|
|
|
{
|
|
|
|
struct nfsd4_copy *copy;
|
|
|
|
|
|
|
|
while ((copy = nfsd4_get_copy(clp)) != NULL)
|
|
|
|
nfsd4_stop_copy(copy);
|
|
|
|
}
|
2019-10-09 23:50:48 +08:00
|
|
|
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
|
|
|
|
|
|
|
extern struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
|
|
|
|
struct nfs_fh *src_fh,
|
|
|
|
nfs4_stateid *stateid);
|
|
|
|
extern void nfs42_ssc_close(struct file *filep);
|
|
|
|
|
|
|
|
extern void nfs_sb_deactive(struct super_block *sb);
|
|
|
|
|
|
|
|
#define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Support one copy source server for now.
|
|
|
|
*/
|
|
|
|
static __be32
|
|
|
|
nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
|
|
|
|
struct vfsmount **mount)
|
|
|
|
{
|
|
|
|
struct file_system_type *type;
|
|
|
|
struct vfsmount *ss_mnt;
|
|
|
|
struct nfs42_netaddr *naddr;
|
|
|
|
struct sockaddr_storage tmp_addr;
|
|
|
|
size_t tmp_addrlen, match_netid_len = 3;
|
|
|
|
char *startsep = "", *endsep = "", *match_netid = "tcp";
|
|
|
|
char *ipaddr, *dev_name, *raw_data;
|
2019-12-05 04:13:53 +08:00
|
|
|
int len, raw_len;
|
|
|
|
__be32 status = nfserr_inval;
|
2019-10-09 23:50:48 +08:00
|
|
|
|
|
|
|
naddr = &nss->u.nl4_addr;
|
|
|
|
tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->addr,
|
|
|
|
naddr->addr_len,
|
|
|
|
(struct sockaddr *)&tmp_addr,
|
|
|
|
sizeof(tmp_addr));
|
|
|
|
if (tmp_addrlen == 0)
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
if (tmp_addr.ss_family == AF_INET6) {
|
|
|
|
startsep = "[";
|
|
|
|
endsep = "]";
|
|
|
|
match_netid = "tcp6";
|
|
|
|
match_netid_len = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (naddr->netid_len != match_netid_len ||
|
|
|
|
strncmp(naddr->netid, match_netid, naddr->netid_len))
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
/* Construct the raw data for the vfs_kern_mount call */
|
|
|
|
len = RPC_MAX_ADDRBUFLEN + 1;
|
|
|
|
ipaddr = kzalloc(len, GFP_KERNEL);
|
|
|
|
if (!ipaddr)
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
rpc_ntop((struct sockaddr *)&tmp_addr, ipaddr, len);
|
|
|
|
|
|
|
|
/* 2 for ipv6 endsep and startsep. 3 for ":/" and trailing '/0'*/
|
|
|
|
|
|
|
|
raw_len = strlen(NFSD42_INTERSSC_MOUNTOPS) + strlen(ipaddr);
|
|
|
|
raw_data = kzalloc(raw_len, GFP_KERNEL);
|
|
|
|
if (!raw_data)
|
|
|
|
goto out_free_ipaddr;
|
|
|
|
|
|
|
|
snprintf(raw_data, raw_len, NFSD42_INTERSSC_MOUNTOPS, ipaddr);
|
|
|
|
|
2019-12-05 04:13:53 +08:00
|
|
|
status = nfserr_nodev;
|
2019-10-09 23:50:48 +08:00
|
|
|
type = get_fs_type("nfs");
|
|
|
|
if (!type)
|
|
|
|
goto out_free_rawdata;
|
|
|
|
|
|
|
|
/* Set the server:<export> for the vfs_kern_mount call */
|
|
|
|
dev_name = kzalloc(len + 5, GFP_KERNEL);
|
|
|
|
if (!dev_name)
|
|
|
|
goto out_free_rawdata;
|
|
|
|
snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep);
|
|
|
|
|
|
|
|
/* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
|
|
|
|
ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data);
|
|
|
|
module_put(type->owner);
|
|
|
|
if (IS_ERR(ss_mnt))
|
|
|
|
goto out_free_devname;
|
|
|
|
|
|
|
|
status = 0;
|
|
|
|
*mount = ss_mnt;
|
|
|
|
|
|
|
|
out_free_devname:
|
|
|
|
kfree(dev_name);
|
|
|
|
out_free_rawdata:
|
|
|
|
kfree(raw_data);
|
|
|
|
out_free_ipaddr:
|
|
|
|
kfree(ipaddr);
|
|
|
|
out_err:
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
|
|
|
|
{
|
|
|
|
nfs_sb_deactive(ss_mnt->mnt_sb);
|
|
|
|
mntput(ss_mnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nfsd4_setup_inter_ssc
|
|
|
|
*
|
|
|
|
* Verify COPY destination stateid.
|
|
|
|
* Connect to the source server with NFSv4.1.
|
|
|
|
* Create the source struct file for nfsd_copy_range.
|
|
|
|
* Called with COPY cstate:
|
|
|
|
* SAVED_FH: source filehandle
|
|
|
|
* CURRENT_FH: destination filehandle
|
|
|
|
*/
|
|
|
|
static __be32
|
|
|
|
nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_compound_state *cstate,
|
|
|
|
struct nfsd4_copy *copy, struct vfsmount **mount)
|
|
|
|
{
|
|
|
|
struct svc_fh *s_fh = NULL;
|
|
|
|
stateid_t *s_stid = ©->cp_src_stateid;
|
2019-12-05 04:13:53 +08:00
|
|
|
__be32 status = nfserr_inval;
|
2019-10-09 23:50:48 +08:00
|
|
|
|
|
|
|
/* Verify the destination stateid and set dst struct file*/
|
|
|
|
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
|
|
|
©->cp_dst_stateid,
|
|
|
|
WR_STATE, ©->nf_dst, NULL);
|
|
|
|
if (status)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
status = nfsd4_interssc_connect(©->cp_src, rqstp, mount);
|
|
|
|
if (status)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
s_fh = &cstate->save_fh;
|
|
|
|
|
|
|
|
copy->c_fh.size = s_fh->fh_handle.fh_size;
|
|
|
|
memcpy(copy->c_fh.data, &s_fh->fh_handle.fh_base, copy->c_fh.size);
|
2019-12-05 04:13:53 +08:00
|
|
|
copy->stateid.seqid = cpu_to_be32(s_stid->si_generation);
|
2019-10-09 23:50:48 +08:00
|
|
|
memcpy(copy->stateid.other, (void *)&s_stid->si_opaque,
|
|
|
|
sizeof(stateid_opaque_t));
|
|
|
|
|
|
|
|
status = 0;
|
|
|
|
out:
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
|
|
|
|
struct nfsd_file *dst)
|
|
|
|
{
|
|
|
|
nfs42_ssc_close(src->nf_file);
|
|
|
|
nfsd_file_put(src);
|
|
|
|
nfsd_file_put(dst);
|
|
|
|
mntput(ss_mnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* CONFIG_NFSD_V4_2_INTER_SSC */
|
|
|
|
|
|
|
|
static __be32
|
|
|
|
nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_compound_state *cstate,
|
|
|
|
struct nfsd4_copy *copy,
|
|
|
|
struct vfsmount **mount)
|
|
|
|
{
|
|
|
|
*mount = NULL;
|
2019-12-05 04:13:53 +08:00
|
|
|
return nfserr_inval;
|
2019-10-09 23:50:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
|
|
|
|
struct nfsd_file *dst)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
|
|
|
|
struct nfs_fh *src_fh,
|
|
|
|
nfs4_stateid *stateid)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NFSD_V4_2_INTER_SSC */
|
|
|
|
|
|
|
|
static __be32
|
|
|
|
nfsd4_setup_intra_ssc(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_compound_state *cstate,
|
|
|
|
struct nfsd4_copy *copy)
|
|
|
|
{
|
|
|
|
return nfsd4_verify_copy(rqstp, cstate, ©->cp_src_stateid,
|
|
|
|
©->nf_src, ©->cp_dst_stateid,
|
|
|
|
©->nf_dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst)
|
|
|
|
{
|
|
|
|
nfsd_file_put(src);
|
|
|
|
nfsd_file_put(dst);
|
|
|
|
}
|
2018-07-21 06:19:20 +08:00
|
|
|
|
|
|
|
static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
|
|
|
|
{
|
|
|
|
struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb);
|
|
|
|
|
|
|
|
nfs4_put_copy(copy);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,
|
|
|
|
struct rpc_task *task)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = {
|
|
|
|
.release = nfsd4_cb_offload_release,
|
|
|
|
.done = nfsd4_cb_offload_done
|
|
|
|
};
|
|
|
|
|
|
|
|
static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync)
|
|
|
|
{
|
|
|
|
copy->cp_res.wr_stable_how = NFS_UNSTABLE;
|
|
|
|
copy->cp_synchronous = sync;
|
|
|
|
gen_boot_verifier(©->cp_res.wr_verifier, copy->cp_clp->net);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
|
|
|
|
{
|
|
|
|
ssize_t bytes_copied = 0;
|
|
|
|
size_t bytes_total = copy->cp_count;
|
|
|
|
u64 src_pos = copy->cp_src_pos;
|
|
|
|
u64 dst_pos = copy->cp_dst_pos;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (kthread_should_stop())
|
|
|
|
break;
|
2019-08-19 02:18:54 +08:00
|
|
|
bytes_copied = nfsd_copy_file_range(copy->nf_src->nf_file,
|
|
|
|
src_pos, copy->nf_dst->nf_file, dst_pos,
|
|
|
|
bytes_total);
|
2018-07-21 06:19:20 +08:00
|
|
|
if (bytes_copied <= 0)
|
|
|
|
break;
|
|
|
|
bytes_total -= bytes_copied;
|
|
|
|
copy->cp_res.wr_bytes_written += bytes_copied;
|
|
|
|
src_pos += bytes_copied;
|
|
|
|
dst_pos += bytes_copied;
|
|
|
|
} while (bytes_total > 0 && !copy->cp_synchronous);
|
|
|
|
return bytes_copied;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
|
|
|
|
{
|
|
|
|
__be32 status;
|
|
|
|
ssize_t bytes;
|
|
|
|
|
|
|
|
bytes = _nfsd_copy_file_range(copy);
|
|
|
|
/* for async copy, we ignore the error, client can always retry
|
|
|
|
* to get the error
|
|
|
|
*/
|
|
|
|
if (bytes < 0 && !copy->cp_res.wr_bytes_written)
|
|
|
|
status = nfserrno(bytes);
|
|
|
|
else {
|
|
|
|
nfsd4_init_copy_res(copy, sync);
|
|
|
|
status = nfs_ok;
|
|
|
|
}
|
|
|
|
|
2019-10-09 23:50:48 +08:00
|
|
|
if (!copy->cp_intra) /* Inter server SSC */
|
|
|
|
nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src,
|
|
|
|
copy->nf_dst);
|
|
|
|
else
|
|
|
|
nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
|
|
|
|
|
2018-07-21 06:19:20 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2019-10-09 23:50:48 +08:00
|
|
|
static int dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
|
2018-07-21 06:19:20 +08:00
|
|
|
{
|
|
|
|
dst->cp_src_pos = src->cp_src_pos;
|
|
|
|
dst->cp_dst_pos = src->cp_dst_pos;
|
|
|
|
dst->cp_count = src->cp_count;
|
|
|
|
dst->cp_synchronous = src->cp_synchronous;
|
|
|
|
memcpy(&dst->cp_res, &src->cp_res, sizeof(src->cp_res));
|
|
|
|
memcpy(&dst->fh, &src->fh, sizeof(src->fh));
|
|
|
|
dst->cp_clp = src->cp_clp;
|
2019-08-19 02:18:54 +08:00
|
|
|
dst->nf_dst = nfsd_file_get(src->nf_dst);
|
2019-10-09 23:50:48 +08:00
|
|
|
dst->cp_intra = src->cp_intra;
|
|
|
|
if (src->cp_intra) /* for inter, file_src doesn't exist yet */
|
|
|
|
dst->nf_src = nfsd_file_get(src->nf_src);
|
|
|
|
|
2018-07-21 06:19:20 +08:00
|
|
|
memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
|
2019-10-09 23:50:48 +08:00
|
|
|
memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server));
|
|
|
|
memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid));
|
|
|
|
memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh));
|
|
|
|
dst->ss_mnt = src->ss_mnt;
|
|
|
|
|
|
|
|
return 0;
|
2018-07-21 06:19:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cleanup_async_copy(struct nfsd4_copy *copy)
|
|
|
|
{
|
2019-10-05 04:34:26 +08:00
|
|
|
nfs4_free_copy_state(copy);
|
2019-08-19 02:18:54 +08:00
|
|
|
nfsd_file_put(copy->nf_dst);
|
2019-12-05 04:13:54 +08:00
|
|
|
if (copy->cp_intra)
|
|
|
|
nfsd_file_put(copy->nf_src);
|
2018-07-21 06:19:20 +08:00
|
|
|
spin_lock(©->cp_clp->async_lock);
|
|
|
|
list_del(©->copies);
|
|
|
|
spin_unlock(©->cp_clp->async_lock);
|
|
|
|
nfs4_put_copy(copy);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nfsd4_do_async_copy(void *data)
|
|
|
|
{
|
|
|
|
struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
|
|
|
|
struct nfsd4_copy *cb_copy;
|
|
|
|
|
2019-10-09 23:50:48 +08:00
|
|
|
if (!copy->cp_intra) { /* Inter server SSC */
|
|
|
|
copy->nf_src = kzalloc(sizeof(struct nfsd_file), GFP_KERNEL);
|
|
|
|
if (!copy->nf_src) {
|
|
|
|
copy->nfserr = nfserr_serverfault;
|
|
|
|
nfsd4_interssc_disconnect(copy->ss_mnt);
|
|
|
|
goto do_callback;
|
|
|
|
}
|
|
|
|
copy->nf_src->nf_file = nfs42_ssc_open(copy->ss_mnt, ©->c_fh,
|
|
|
|
©->stateid);
|
|
|
|
if (IS_ERR(copy->nf_src->nf_file)) {
|
|
|
|
copy->nfserr = nfserr_offload_denied;
|
|
|
|
nfsd4_interssc_disconnect(copy->ss_mnt);
|
|
|
|
goto do_callback;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-21 06:19:20 +08:00
|
|
|
copy->nfserr = nfsd4_do_copy(copy, 0);
|
2019-10-09 23:50:48 +08:00
|
|
|
do_callback:
|
2018-07-21 06:19:20 +08:00
|
|
|
cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
|
|
|
|
if (!cb_copy)
|
|
|
|
goto out;
|
|
|
|
memcpy(&cb_copy->cp_res, ©->cp_res, sizeof(copy->cp_res));
|
|
|
|
cb_copy->cp_clp = copy->cp_clp;
|
|
|
|
cb_copy->nfserr = copy->nfserr;
|
|
|
|
memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh));
|
|
|
|
nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp,
|
|
|
|
&nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD);
|
|
|
|
nfsd4_run_cb(&cb_copy->cp_cb);
|
|
|
|
out:
|
2019-10-09 23:50:48 +08:00
|
|
|
if (!copy->cp_intra)
|
|
|
|
kfree(copy->nf_src);
|
2018-07-21 06:19:20 +08:00
|
|
|
cleanup_async_copy(copy);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-08 03:57:30 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2016-09-08 03:57:30 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_copy *copy = &u->copy;
|
2016-09-08 03:57:30 +08:00
|
|
|
__be32 status;
|
2018-07-21 06:19:20 +08:00
|
|
|
struct nfsd4_copy *async_copy = NULL;
|
2016-09-08 03:57:30 +08:00
|
|
|
|
2019-10-09 23:50:48 +08:00
|
|
|
if (!copy->cp_intra) { /* Inter server SSC */
|
|
|
|
if (!inter_copy_offload_enable || copy->cp_synchronous) {
|
|
|
|
status = nfserr_notsupp;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
status = nfsd4_setup_inter_ssc(rqstp, cstate, copy,
|
|
|
|
©->ss_mnt);
|
|
|
|
if (status)
|
|
|
|
return nfserr_offload_denied;
|
|
|
|
} else {
|
|
|
|
status = nfsd4_setup_intra_ssc(rqstp, cstate, copy);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
}
|
2016-09-08 03:57:30 +08:00
|
|
|
|
2018-07-21 06:19:20 +08:00
|
|
|
copy->cp_clp = cstate->clp;
|
|
|
|
memcpy(©->fh, &cstate->current_fh.fh_handle,
|
|
|
|
sizeof(struct knfsd_fh));
|
|
|
|
if (!copy->cp_synchronous) {
|
|
|
|
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
2016-09-08 03:57:30 +08:00
|
|
|
|
2018-07-21 06:19:20 +08:00
|
|
|
status = nfserrno(-ENOMEM);
|
|
|
|
async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
|
|
|
|
if (!async_copy)
|
2019-10-09 23:50:48 +08:00
|
|
|
goto out_err;
|
|
|
|
if (!nfs4_init_copy_state(nn, copy))
|
|
|
|
goto out_err;
|
2018-07-21 06:19:20 +08:00
|
|
|
refcount_set(&async_copy->refcount, 1);
|
|
|
|
memcpy(©->cp_res.cb_stateid, ©->cp_stateid,
|
|
|
|
sizeof(copy->cp_stateid));
|
2019-10-09 23:50:48 +08:00
|
|
|
status = dup_copy_fields(copy, async_copy);
|
|
|
|
if (status)
|
|
|
|
goto out_err;
|
2018-07-21 06:19:20 +08:00
|
|
|
async_copy->copy_task = kthread_create(nfsd4_do_async_copy,
|
|
|
|
async_copy, "%s", "copy thread");
|
|
|
|
if (IS_ERR(async_copy->copy_task))
|
|
|
|
goto out_err;
|
|
|
|
spin_lock(&async_copy->cp_clp->async_lock);
|
|
|
|
list_add(&async_copy->copies,
|
|
|
|
&async_copy->cp_clp->async_copies);
|
|
|
|
spin_unlock(&async_copy->cp_clp->async_lock);
|
|
|
|
wake_up_process(async_copy->copy_task);
|
2016-09-08 03:57:30 +08:00
|
|
|
status = nfs_ok;
|
2019-10-09 23:50:48 +08:00
|
|
|
} else {
|
2018-07-21 06:19:20 +08:00
|
|
|
status = nfsd4_do_copy(copy, 1);
|
2019-10-09 23:50:48 +08:00
|
|
|
}
|
2016-09-08 03:57:30 +08:00
|
|
|
out:
|
|
|
|
return status;
|
2018-07-21 06:19:20 +08:00
|
|
|
out_err:
|
2019-12-05 04:13:54 +08:00
|
|
|
if (async_copy)
|
|
|
|
cleanup_async_copy(async_copy);
|
2019-10-09 23:50:48 +08:00
|
|
|
status = nfserrno(-ENOMEM);
|
|
|
|
if (!copy->cp_intra)
|
|
|
|
nfsd4_interssc_disconnect(copy->ss_mnt);
|
2018-07-21 06:19:20 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nfsd4_copy *
|
|
|
|
find_async_copy(struct nfs4_client *clp, stateid_t *stateid)
|
|
|
|
{
|
|
|
|
struct nfsd4_copy *copy;
|
|
|
|
|
|
|
|
spin_lock(&clp->async_lock);
|
|
|
|
list_for_each_entry(copy, &clp->async_copies, copies) {
|
2019-10-09 23:50:48 +08:00
|
|
|
if (memcmp(©->cp_stateid.stid, stateid, NFS4_STATEID_SIZE))
|
2018-07-21 06:19:20 +08:00
|
|
|
continue;
|
|
|
|
refcount_inc(©->refcount);
|
|
|
|
spin_unlock(&clp->async_lock);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
spin_unlock(&clp->async_lock);
|
|
|
|
return NULL;
|
2016-09-08 03:57:30 +08:00
|
|
|
}
|
|
|
|
|
2018-07-21 06:19:19 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_offload_cancel(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_compound_state *cstate,
|
|
|
|
union nfsd4_op_u *u)
|
|
|
|
{
|
2018-07-21 06:19:20 +08:00
|
|
|
struct nfsd4_offload_status *os = &u->offload_status;
|
|
|
|
struct nfsd4_copy *copy;
|
|
|
|
struct nfs4_client *clp = cstate->clp;
|
|
|
|
|
|
|
|
copy = find_async_copy(clp, &os->stateid);
|
2019-10-09 23:50:48 +08:00
|
|
|
if (!copy) {
|
|
|
|
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
|
|
|
|
|
|
|
return manage_cpntf_state(nn, &os->stateid, clp, NULL);
|
|
|
|
} else
|
2018-07-21 06:19:20 +08:00
|
|
|
nfsd4_stop_copy(copy);
|
|
|
|
|
2019-10-09 23:50:48 +08:00
|
|
|
return nfs_ok;
|
2018-07-21 06:19:19 +08:00
|
|
|
}
|
|
|
|
|
2019-08-08 23:14:59 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
|
|
union nfsd4_op_u *u)
|
|
|
|
{
|
2019-10-05 04:34:26 +08:00
|
|
|
struct nfsd4_copy_notify *cn = &u->copy_notify;
|
|
|
|
__be32 status;
|
|
|
|
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
|
|
|
struct nfs4_stid *stid;
|
|
|
|
struct nfs4_cpntf_state *cps;
|
|
|
|
struct nfs4_client *clp = cstate->clp;
|
|
|
|
|
|
|
|
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
|
|
|
&cn->cpn_src_stateid, RD_STATE, NULL,
|
|
|
|
&stid);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
cn->cpn_sec = nn->nfsd4_lease;
|
|
|
|
cn->cpn_nsec = 0;
|
|
|
|
|
|
|
|
status = nfserrno(-ENOMEM);
|
|
|
|
cps = nfs4_alloc_init_cpntf_state(nn, stid);
|
|
|
|
if (!cps)
|
|
|
|
goto out;
|
|
|
|
memcpy(&cn->cpn_cnr_stateid, &cps->cp_stateid.stid, sizeof(stateid_t));
|
|
|
|
memcpy(&cps->cp_p_stateid, &stid->sc_stateid, sizeof(stateid_t));
|
|
|
|
memcpy(&cps->cp_p_clid, &clp->cl_clientid, sizeof(clientid_t));
|
|
|
|
|
|
|
|
/* For now, only return one server address in cpn_src, the
|
|
|
|
* address used by the client to connect to this server.
|
|
|
|
*/
|
|
|
|
cn->cpn_src.nl4_type = NL4_NETADDR;
|
|
|
|
status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr,
|
|
|
|
&cn->cpn_src.u.nl4_addr);
|
|
|
|
WARN_ON_ONCE(status);
|
|
|
|
if (status) {
|
|
|
|
nfs4_put_cpntf_state(nn, cps);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
nfs4_put_stid(stid);
|
|
|
|
return status;
|
2019-08-08 23:14:59 +08:00
|
|
|
}
|
|
|
|
|
2014-11-08 03:44:26 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
|
|
struct nfsd4_fallocate *fallocate, int flags)
|
|
|
|
{
|
2018-11-07 06:44:03 +08:00
|
|
|
__be32 status;
|
2019-08-19 02:18:54 +08:00
|
|
|
struct nfsd_file *nf;
|
2014-11-08 03:44:26 +08:00
|
|
|
|
2015-12-03 19:59:51 +08:00
|
|
|
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
2014-11-08 03:44:26 +08:00
|
|
|
&fallocate->falloc_stateid,
|
2019-10-05 04:34:26 +08:00
|
|
|
WR_STATE, &nf, NULL);
|
2014-11-08 03:44:26 +08:00
|
|
|
if (status != nfs_ok) {
|
|
|
|
dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2019-08-19 02:18:54 +08:00
|
|
|
status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, nf->nf_file,
|
2014-11-08 03:44:26 +08:00
|
|
|
fallocate->falloc_offset,
|
|
|
|
fallocate->falloc_length,
|
|
|
|
flags);
|
2019-08-19 02:18:54 +08:00
|
|
|
nfsd_file_put(nf);
|
2014-11-08 03:44:26 +08:00
|
|
|
return status;
|
|
|
|
}
|
2018-07-21 06:19:18 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_offload_status(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_compound_state *cstate,
|
|
|
|
union nfsd4_op_u *u)
|
|
|
|
{
|
2018-07-21 06:19:20 +08:00
|
|
|
struct nfsd4_offload_status *os = &u->offload_status;
|
|
|
|
__be32 status = 0;
|
|
|
|
struct nfsd4_copy *copy;
|
|
|
|
struct nfs4_client *clp = cstate->clp;
|
|
|
|
|
|
|
|
copy = find_async_copy(clp, &os->stateid);
|
|
|
|
if (copy) {
|
|
|
|
os->count = copy->cp_res.wr_bytes_written;
|
|
|
|
nfs4_put_copy(copy);
|
|
|
|
} else
|
|
|
|
status = nfserr_bad_stateid;
|
|
|
|
|
|
|
|
return status;
|
2018-07-21 06:19:18 +08:00
|
|
|
}
|
2014-11-08 03:44:26 +08:00
|
|
|
|
|
|
|
static __be32
|
|
|
|
nfsd4_allocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2014-11-08 03:44:26 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
return nfsd4_fallocate(rqstp, cstate, &u->allocate, 0);
|
2014-11-08 03:44:26 +08:00
|
|
|
}
|
|
|
|
|
2014-11-08 03:44:27 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_deallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2014-11-08 03:44:27 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
return nfsd4_fallocate(rqstp, cstate, &u->deallocate,
|
2014-11-08 03:44:27 +08:00
|
|
|
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE);
|
|
|
|
}
|
|
|
|
|
2014-09-27 01:58:27 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2014-09-27 01:58:27 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_seek *seek = &u->seek;
|
2014-09-27 01:58:27 +08:00
|
|
|
int whence;
|
|
|
|
__be32 status;
|
2019-08-19 02:18:54 +08:00
|
|
|
struct nfsd_file *nf;
|
2014-09-27 01:58:27 +08:00
|
|
|
|
2015-12-03 19:59:51 +08:00
|
|
|
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
2014-09-27 01:58:27 +08:00
|
|
|
&seek->seek_stateid,
|
2019-10-05 04:34:26 +08:00
|
|
|
RD_STATE, &nf, NULL);
|
2014-09-27 01:58:27 +08:00
|
|
|
if (status) {
|
|
|
|
dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n");
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (seek->seek_whence) {
|
|
|
|
case NFS4_CONTENT_DATA:
|
|
|
|
whence = SEEK_DATA;
|
|
|
|
break;
|
|
|
|
case NFS4_CONTENT_HOLE:
|
|
|
|
whence = SEEK_HOLE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
status = nfserr_union_notsupp;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: This call does change file->f_pos, but nothing in NFSD
|
|
|
|
* should ever file->f_pos.
|
|
|
|
*/
|
2019-08-19 02:18:54 +08:00
|
|
|
seek->seek_pos = vfs_llseek(nf->nf_file, seek->seek_offset, whence);
|
2014-09-27 01:58:27 +08:00
|
|
|
if (seek->seek_pos < 0)
|
|
|
|
status = nfserrno(seek->seek_pos);
|
2019-08-19 02:18:54 +08:00
|
|
|
else if (seek->seek_pos >= i_size_read(file_inode(nf->nf_file)))
|
2014-09-27 01:58:27 +08:00
|
|
|
seek->seek_eof = true;
|
|
|
|
|
|
|
|
out:
|
2019-08-19 02:18:54 +08:00
|
|
|
nfsd_file_put(nf);
|
2014-09-27 01:58:27 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* This routine never returns NFS_OK! If there are no other errors, it
|
|
|
|
* will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the
|
|
|
|
* attributes matched. VERIFY is implemented by mapping NFSERR_SAME
|
|
|
|
* to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
|
|
|
|
*/
|
2006-10-20 14:28:59 +08:00
|
|
|
static __be32
|
2006-12-13 16:35:31 +08:00
|
|
|
_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2006-12-13 16:35:27 +08:00
|
|
|
struct nfsd4_verify *verify)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2006-10-20 14:28:58 +08:00
|
|
|
__be32 *buf, *p;
|
2005-04-17 06:20:36 +08:00
|
|
|
int count;
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-06-16 19:20:29 +08:00
|
|
|
status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2009-05-16 16:22:31 +08:00
|
|
|
status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
|
|
|
|
|| (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
|
|
|
|
return nfserr_inval;
|
|
|
|
if (verify->ve_attrlen & 3)
|
|
|
|
return nfserr_inval;
|
|
|
|
|
|
|
|
/* count in words:
|
|
|
|
* bitmap_len(1) + bitmap(2) + attr_len(1) = 4
|
|
|
|
*/
|
|
|
|
count = 4 + (verify->ve_attrlen >> 2);
|
|
|
|
buf = kmalloc(count << 2, GFP_KERNEL);
|
|
|
|
if (!buf)
|
2011-08-11 07:07:33 +08:00
|
|
|
return nfserr_jukebox;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-12-15 06:57:50 +08:00
|
|
|
p = buf;
|
2013-08-27 04:04:46 +08:00
|
|
|
status = nfsd4_encode_fattr_to_buf(&p, count, &cstate->current_fh,
|
2006-12-13 16:35:27 +08:00
|
|
|
cstate->current_fh.fh_export,
|
2013-08-27 04:04:46 +08:00
|
|
|
cstate->current_fh.fh_dentry,
|
|
|
|
verify->ve_bmval,
|
2007-11-28 03:34:05 +08:00
|
|
|
rqstp, 0);
|
2013-08-22 03:32:50 +08:00
|
|
|
/*
|
|
|
|
* If nfsd4_encode_fattr() ran out of space, assume that's because
|
|
|
|
* the attributes are longer (hence different) than those given:
|
|
|
|
*/
|
2012-12-15 06:57:50 +08:00
|
|
|
if (status == nfserr_resource)
|
2005-04-17 06:20:36 +08:00
|
|
|
status = nfserr_not_same;
|
|
|
|
if (status)
|
|
|
|
goto out_kfree;
|
|
|
|
|
2009-04-03 13:29:08 +08:00
|
|
|
/* skip bitmap */
|
|
|
|
p = buf + 1 + ntohl(buf[0]);
|
2005-04-17 06:20:36 +08:00
|
|
|
status = nfserr_not_same;
|
|
|
|
if (ntohl(*p++) != verify->ve_attrlen)
|
|
|
|
goto out_kfree;
|
|
|
|
if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen))
|
|
|
|
status = nfserr_same;
|
|
|
|
|
|
|
|
out_kfree:
|
|
|
|
kfree(buf);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-12-13 16:35:31 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2006-12-13 16:35:31 +08:00
|
|
|
{
|
|
|
|
__be32 status;
|
|
|
|
|
2017-05-09 02:58:35 +08:00
|
|
|
status = _nfsd4_verify(rqstp, cstate, &u->verify);
|
2006-12-13 16:35:31 +08:00
|
|
|
return status == nfserr_not_same ? nfs_ok : status;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __be32
|
|
|
|
nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
2017-05-09 02:58:35 +08:00
|
|
|
union nfsd4_op_u *u)
|
2006-12-13 16:35:31 +08:00
|
|
|
{
|
|
|
|
__be32 status;
|
|
|
|
|
2017-05-09 02:58:35 +08:00
|
|
|
status = _nfsd4_verify(rqstp, cstate, &u->nverify);
|
2006-12-13 16:35:31 +08:00
|
|
|
return status == nfserr_same ? nfs_ok : status;
|
|
|
|
}
|
|
|
|
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
#ifdef CONFIG_NFSD_PNFS
|
|
|
|
static const struct nfsd4_layout_ops *
|
|
|
|
nfsd4_layout_verify(struct svc_export *exp, unsigned int layout_type)
|
|
|
|
{
|
2016-07-11 03:55:58 +08:00
|
|
|
if (!exp->ex_layout_types) {
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
dprintk("%s: export does not support pNFS\n", __func__);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-05-06 04:07:55 +08:00
|
|
|
if (layout_type >= LAYOUT_TYPE_MAX ||
|
|
|
|
!(exp->ex_layout_types & (1 << layout_type))) {
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
dprintk("%s: layout type %d not supported\n",
|
|
|
|
__func__, layout_type);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nfsd4_layout_ops[layout_type];
|
|
|
|
}
|
|
|
|
|
|
|
|
static __be32
|
|
|
|
nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_getdeviceinfo *gdp = &u->getdeviceinfo;
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
const struct nfsd4_layout_ops *ops;
|
|
|
|
struct nfsd4_deviceid_map *map;
|
|
|
|
struct svc_export *exp;
|
|
|
|
__be32 nfserr;
|
|
|
|
|
|
|
|
dprintk("%s: layout_type %u dev_id [0x%llx:0x%x] maxcnt %u\n",
|
|
|
|
__func__,
|
|
|
|
gdp->gd_layout_type,
|
|
|
|
gdp->gd_devid.fsid_idx, gdp->gd_devid.generation,
|
|
|
|
gdp->gd_maxcount);
|
|
|
|
|
|
|
|
map = nfsd4_find_devid_map(gdp->gd_devid.fsid_idx);
|
|
|
|
if (!map) {
|
|
|
|
dprintk("%s: couldn't find device ID to export mapping!\n",
|
|
|
|
__func__);
|
|
|
|
return nfserr_noent;
|
|
|
|
}
|
|
|
|
|
|
|
|
exp = rqst_exp_find(rqstp, map->fsid_type, map->fsid);
|
|
|
|
if (IS_ERR(exp)) {
|
|
|
|
dprintk("%s: could not find device id\n", __func__);
|
|
|
|
return nfserr_noent;
|
|
|
|
}
|
|
|
|
|
|
|
|
nfserr = nfserr_layoutunavailable;
|
|
|
|
ops = nfsd4_layout_verify(exp, gdp->gd_layout_type);
|
|
|
|
if (!ops)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
nfserr = nfs_ok;
|
2016-03-05 03:46:17 +08:00
|
|
|
if (gdp->gd_maxcount != 0) {
|
|
|
|
nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb,
|
2016-06-15 04:41:27 +08:00
|
|
|
rqstp, cstate->session->se_client, gdp);
|
2016-03-05 03:46:17 +08:00
|
|
|
}
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
|
|
|
|
gdp->gd_notify_types &= ops->notify_types;
|
|
|
|
out:
|
2015-03-15 23:12:15 +08:00
|
|
|
exp_put(exp);
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
return nfserr;
|
|
|
|
}
|
|
|
|
|
2017-05-06 05:09:37 +08:00
|
|
|
static void
|
|
|
|
nfsd4_getdeviceinfo_release(union nfsd4_op_u *u)
|
|
|
|
{
|
|
|
|
kfree(u->getdeviceinfo.gd_device);
|
|
|
|
}
|
|
|
|
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_layoutget(struct svc_rqst *rqstp,
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_layoutget *lgp = &u->layoutget;
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
struct svc_fh *current_fh = &cstate->current_fh;
|
|
|
|
const struct nfsd4_layout_ops *ops;
|
|
|
|
struct nfs4_layout_stateid *ls;
|
|
|
|
__be32 nfserr;
|
2017-12-19 22:35:25 +08:00
|
|
|
int accmode = NFSD_MAY_READ_IF_EXEC;
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
|
|
|
|
switch (lgp->lg_seg.iomode) {
|
|
|
|
case IOMODE_READ:
|
2017-12-19 22:35:25 +08:00
|
|
|
accmode |= NFSD_MAY_READ;
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
break;
|
|
|
|
case IOMODE_RW:
|
2017-12-19 22:35:25 +08:00
|
|
|
accmode |= NFSD_MAY_READ | NFSD_MAY_WRITE;
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dprintk("%s: invalid iomode %d\n",
|
|
|
|
__func__, lgp->lg_seg.iomode);
|
|
|
|
nfserr = nfserr_badiomode;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
nfserr = fh_verify(rqstp, current_fh, 0, accmode);
|
|
|
|
if (nfserr)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
nfserr = nfserr_layoutunavailable;
|
|
|
|
ops = nfsd4_layout_verify(current_fh->fh_export, lgp->lg_layout_type);
|
|
|
|
if (!ops)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify minlength and range as per RFC5661:
|
|
|
|
* o If loga_length is less than loga_minlength,
|
|
|
|
* the metadata server MUST return NFS4ERR_INVAL.
|
|
|
|
* o If the sum of loga_offset and loga_minlength exceeds
|
|
|
|
* NFS4_UINT64_MAX, and loga_minlength is not
|
|
|
|
* NFS4_UINT64_MAX, the error NFS4ERR_INVAL MUST result.
|
|
|
|
* o If the sum of loga_offset and loga_length exceeds
|
|
|
|
* NFS4_UINT64_MAX, and loga_length is not NFS4_UINT64_MAX,
|
|
|
|
* the error NFS4ERR_INVAL MUST result.
|
|
|
|
*/
|
|
|
|
nfserr = nfserr_inval;
|
|
|
|
if (lgp->lg_seg.length < lgp->lg_minlength ||
|
|
|
|
(lgp->lg_minlength != NFS4_MAX_UINT64 &&
|
|
|
|
lgp->lg_minlength > NFS4_MAX_UINT64 - lgp->lg_seg.offset) ||
|
|
|
|
(lgp->lg_seg.length != NFS4_MAX_UINT64 &&
|
|
|
|
lgp->lg_seg.length > NFS4_MAX_UINT64 - lgp->lg_seg.offset))
|
|
|
|
goto out;
|
|
|
|
if (lgp->lg_seg.length == 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lgp->lg_sid,
|
|
|
|
true, lgp->lg_layout_type, &ls);
|
2014-08-17 08:02:22 +08:00
|
|
|
if (nfserr) {
|
2018-03-27 22:53:11 +08:00
|
|
|
trace_nfsd_layout_get_lookup_fail(&lgp->lg_sid);
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
goto out;
|
2014-08-17 08:02:22 +08:00
|
|
|
}
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
|
2014-09-23 18:38:48 +08:00
|
|
|
nfserr = nfserr_recallconflict;
|
|
|
|
if (atomic_read(&ls->ls_stid.sc_file->fi_lo_recalls))
|
|
|
|
goto out_put_stid;
|
|
|
|
|
2015-03-18 06:25:59 +08:00
|
|
|
nfserr = ops->proc_layoutget(d_inode(current_fh->fh_dentry),
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
current_fh, lgp);
|
|
|
|
if (nfserr)
|
|
|
|
goto out_put_stid;
|
|
|
|
|
|
|
|
nfserr = nfsd4_insert_layout(lgp, ls);
|
|
|
|
|
|
|
|
out_put_stid:
|
2015-09-17 19:58:24 +08:00
|
|
|
mutex_unlock(&ls->ls_mutex);
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
nfs4_put_stid(&ls->ls_stid);
|
|
|
|
out:
|
|
|
|
return nfserr;
|
|
|
|
}
|
|
|
|
|
2017-05-06 05:09:37 +08:00
|
|
|
static void
|
|
|
|
nfsd4_layoutget_release(union nfsd4_op_u *u)
|
|
|
|
{
|
|
|
|
kfree(u->layoutget.lg_content);
|
|
|
|
}
|
|
|
|
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
static __be32
|
|
|
|
nfsd4_layoutcommit(struct svc_rqst *rqstp,
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_layoutcommit *lcp = &u->layoutcommit;
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
const struct nfsd4_layout_seg *seg = &lcp->lc_seg;
|
|
|
|
struct svc_fh *current_fh = &cstate->current_fh;
|
|
|
|
const struct nfsd4_layout_ops *ops;
|
|
|
|
loff_t new_size = lcp->lc_last_wr + 1;
|
|
|
|
struct inode *inode;
|
|
|
|
struct nfs4_layout_stateid *ls;
|
|
|
|
__be32 nfserr;
|
|
|
|
|
|
|
|
nfserr = fh_verify(rqstp, current_fh, 0, NFSD_MAY_WRITE);
|
|
|
|
if (nfserr)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
nfserr = nfserr_layoutunavailable;
|
|
|
|
ops = nfsd4_layout_verify(current_fh->fh_export, lcp->lc_layout_type);
|
|
|
|
if (!ops)
|
|
|
|
goto out;
|
2015-03-18 06:25:59 +08:00
|
|
|
inode = d_inode(current_fh->fh_dentry);
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
|
|
|
|
nfserr = nfserr_inval;
|
|
|
|
if (new_size <= seg->offset) {
|
|
|
|
dprintk("pnfsd: last write before layout segment\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (new_size > seg->offset + seg->length) {
|
|
|
|
dprintk("pnfsd: last write beyond layout segment\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (!lcp->lc_newoffset && new_size > i_size_read(inode)) {
|
|
|
|
dprintk("pnfsd: layoutcommit beyond EOF\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lcp->lc_sid,
|
|
|
|
false, lcp->lc_layout_type,
|
|
|
|
&ls);
|
|
|
|
if (nfserr) {
|
2018-03-27 22:53:11 +08:00
|
|
|
trace_nfsd_layout_commit_lookup_fail(&lcp->lc_sid);
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
/* fixup error code as per RFC5661 */
|
|
|
|
if (nfserr == nfserr_bad_stateid)
|
|
|
|
nfserr = nfserr_badlayout;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2015-09-17 19:58:24 +08:00
|
|
|
/* LAYOUTCOMMIT does not require any serialization */
|
|
|
|
mutex_unlock(&ls->ls_mutex);
|
|
|
|
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
if (new_size > i_size_read(inode)) {
|
|
|
|
lcp->lc_size_chg = 1;
|
|
|
|
lcp->lc_newsize = new_size;
|
|
|
|
} else {
|
|
|
|
lcp->lc_size_chg = 0;
|
|
|
|
}
|
|
|
|
|
2015-07-07 10:12:03 +08:00
|
|
|
nfserr = ops->proc_layoutcommit(inode, lcp);
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
nfs4_put_stid(&ls->ls_stid);
|
|
|
|
out:
|
|
|
|
return nfserr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static __be32
|
|
|
|
nfsd4_layoutreturn(struct svc_rqst *rqstp,
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
{
|
2017-05-09 02:58:35 +08:00
|
|
|
struct nfsd4_layoutreturn *lrp = &u->layoutreturn;
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
struct svc_fh *current_fh = &cstate->current_fh;
|
|
|
|
__be32 nfserr;
|
|
|
|
|
|
|
|
nfserr = fh_verify(rqstp, current_fh, 0, NFSD_MAY_NOP);
|
|
|
|
if (nfserr)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
nfserr = nfserr_layoutunavailable;
|
|
|
|
if (!nfsd4_layout_verify(current_fh->fh_export, lrp->lr_layout_type))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
switch (lrp->lr_seg.iomode) {
|
|
|
|
case IOMODE_READ:
|
|
|
|
case IOMODE_RW:
|
|
|
|
case IOMODE_ANY:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dprintk("%s: invalid iomode %d\n", __func__,
|
|
|
|
lrp->lr_seg.iomode);
|
|
|
|
nfserr = nfserr_inval;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (lrp->lr_return_type) {
|
|
|
|
case RETURN_FILE:
|
|
|
|
nfserr = nfsd4_return_file_layouts(rqstp, cstate, lrp);
|
|
|
|
break;
|
|
|
|
case RETURN_FSID:
|
|
|
|
case RETURN_ALL:
|
|
|
|
nfserr = nfsd4_return_client_layouts(rqstp, cstate, lrp);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dprintk("%s: invalid return_type %d\n", __func__,
|
|
|
|
lrp->lr_return_type);
|
|
|
|
nfserr = nfserr_inval;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
return nfserr;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NFSD_PNFS */
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* NULL call.
|
|
|
|
*/
|
2006-10-20 14:28:45 +08:00
|
|
|
static __be32
|
2017-05-08 23:35:49 +08:00
|
|
|
nfsd4_proc_null(struct svc_rqst *rqstp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
return nfs_ok;
|
|
|
|
}
|
|
|
|
|
2006-07-10 19:45:44 +08:00
|
|
|
static inline void nfsd4_increment_op_stats(u32 opnum)
|
|
|
|
{
|
|
|
|
if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP)
|
|
|
|
nfsdstats.nfs4_opcount[opnum]++;
|
|
|
|
}
|
|
|
|
|
2017-05-09 05:46:47 +08:00
|
|
|
static const struct nfsd4_operation nfsd4_ops[];
|
2006-12-13 16:35:38 +08:00
|
|
|
|
2008-08-09 00:26:42 +08:00
|
|
|
static const char *nfsd4_op_name(unsigned opnum);
|
2008-07-02 16:15:03 +08:00
|
|
|
|
2009-04-03 13:28:12 +08:00
|
|
|
/*
|
2010-04-22 00:27:19 +08:00
|
|
|
* Enforce NFSv4.1 COMPOUND ordering rules:
|
2009-04-03 13:28:12 +08:00
|
|
|
*
|
2010-04-22 00:27:19 +08:00
|
|
|
* Also note, enforced elsewhere:
|
|
|
|
* - SEQUENCE other than as first op results in
|
|
|
|
* NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().)
|
2010-10-05 11:12:59 +08:00
|
|
|
* - BIND_CONN_TO_SESSION must be the only op in its compound.
|
|
|
|
* (Enforced in nfsd4_bind_conn_to_session().)
|
2010-04-22 00:27:19 +08:00
|
|
|
* - DESTROY_SESSION must be the final operation in a compound, if
|
|
|
|
* sessionid's in SEQUENCE and DESTROY_SESSION are the same.
|
|
|
|
* (Enforced in nfsd4_destroy_session().)
|
2009-04-03 13:28:12 +08:00
|
|
|
*/
|
2010-04-22 00:27:19 +08:00
|
|
|
static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args)
|
2009-04-03 13:28:12 +08:00
|
|
|
{
|
2018-06-14 03:04:59 +08:00
|
|
|
struct nfsd4_op *first_op = &args->ops[0];
|
2010-04-22 00:27:19 +08:00
|
|
|
|
|
|
|
/* These ordering requirements don't apply to NFSv4.0: */
|
|
|
|
if (args->minorversion == 0)
|
|
|
|
return nfs_ok;
|
|
|
|
/* This is weird, but OK, not our problem: */
|
|
|
|
if (args->opcnt == 0)
|
|
|
|
return nfs_ok;
|
2018-06-14 03:04:59 +08:00
|
|
|
if (first_op->status == nfserr_op_illegal)
|
2010-04-22 00:27:19 +08:00
|
|
|
return nfs_ok;
|
2018-06-14 03:04:59 +08:00
|
|
|
if (!(nfsd4_ops[first_op->opnum].op_flags & ALLOWED_AS_FIRST_OP))
|
2010-04-22 00:27:19 +08:00
|
|
|
return nfserr_op_not_in_session;
|
2018-06-14 03:04:59 +08:00
|
|
|
if (first_op->opnum == OP_SEQUENCE)
|
2010-04-22 00:27:19 +08:00
|
|
|
return nfs_ok;
|
2018-06-14 03:04:59 +08:00
|
|
|
/*
|
|
|
|
* So first_op is something allowed outside a session, like
|
|
|
|
* EXCHANGE_ID; but then it has to be the only op in the
|
|
|
|
* compound:
|
|
|
|
*/
|
2010-04-22 00:27:19 +08:00
|
|
|
if (args->opcnt != 1)
|
|
|
|
return nfserr_not_only_op;
|
|
|
|
return nfs_ok;
|
2009-04-03 13:28:12 +08:00
|
|
|
}
|
|
|
|
|
2017-07-07 05:51:29 +08:00
|
|
|
const struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
|
2011-04-09 23:23:24 +08:00
|
|
|
{
|
|
|
|
return &nfsd4_ops[op->opnum];
|
|
|
|
}
|
|
|
|
|
2011-01-25 01:11:02 +08:00
|
|
|
bool nfsd4_cache_this_op(struct nfsd4_op *op)
|
|
|
|
{
|
2014-05-20 00:27:11 +08:00
|
|
|
if (op->opnum == OP_ILLEGAL)
|
|
|
|
return false;
|
2011-09-20 20:49:51 +08:00
|
|
|
return OPDESC(op)->op_flags & OP_CACHEME;
|
2011-01-25 01:11:02 +08:00
|
|
|
}
|
|
|
|
|
2011-04-09 05:00:50 +08:00
|
|
|
static bool need_wrongsec_check(struct svc_rqst *rqstp)
|
|
|
|
{
|
|
|
|
struct nfsd4_compoundres *resp = rqstp->rq_resp;
|
|
|
|
struct nfsd4_compoundargs *argp = rqstp->rq_argp;
|
|
|
|
struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
|
|
|
|
struct nfsd4_op *next = &argp->ops[resp->opcnt];
|
2017-05-09 05:46:47 +08:00
|
|
|
const struct nfsd4_operation *thisd = OPDESC(this);
|
|
|
|
const struct nfsd4_operation *nextd;
|
2011-04-09 05:00:50 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Most ops check wronsec on our own; only the putfh-like ops
|
|
|
|
* have special rules.
|
|
|
|
*/
|
|
|
|
if (!(thisd->op_flags & OP_IS_PUTFH_LIKE))
|
|
|
|
return false;
|
|
|
|
/*
|
|
|
|
* rfc 5661 2.6.3.1.1.6: don't bother erroring out a
|
|
|
|
* put-filehandle operation if we're not going to use the
|
|
|
|
* result:
|
|
|
|
*/
|
|
|
|
if (argp->opcnt == resp->opcnt)
|
|
|
|
return false;
|
2014-10-23 02:46:29 +08:00
|
|
|
if (next->opnum == OP_ILLEGAL)
|
|
|
|
return false;
|
2011-04-09 05:00:50 +08:00
|
|
|
nextd = OPDESC(next);
|
|
|
|
/*
|
|
|
|
* Rest of 2.6.3.1.1: certain operations will return WRONGSEC
|
|
|
|
* errors themselves as necessary; others should check for them
|
|
|
|
* now:
|
|
|
|
*/
|
|
|
|
return !(nextd->op_flags & OP_HANDLES_WRONGSEC);
|
|
|
|
}
|
|
|
|
|
2014-01-16 05:26:42 +08:00
|
|
|
static void svcxdr_init_encode(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_compoundres *resp)
|
|
|
|
{
|
|
|
|
struct xdr_stream *xdr = &resp->xdr;
|
|
|
|
struct xdr_buf *buf = &rqstp->rq_res;
|
|
|
|
struct kvec *head = buf->head;
|
|
|
|
|
|
|
|
xdr->buf = buf;
|
2013-08-28 09:32:25 +08:00
|
|
|
xdr->iov = head;
|
2014-01-16 05:26:42 +08:00
|
|
|
xdr->p = head->iov_base + head->iov_len;
|
2014-05-13 06:10:58 +08:00
|
|
|
xdr->end = head->iov_base + PAGE_SIZE - rqstp->rq_auth_slack;
|
2014-02-27 06:39:35 +08:00
|
|
|
/* Tail and page_len should be zero at this point: */
|
|
|
|
buf->len = buf->head[0].iov_len;
|
2013-08-27 04:04:46 +08:00
|
|
|
xdr->scratch.iov_len = 0;
|
2014-06-03 00:05:47 +08:00
|
|
|
xdr->page_ptr = buf->pages - 1;
|
2013-08-27 04:04:46 +08:00
|
|
|
buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages)
|
2014-05-13 06:10:58 +08:00
|
|
|
- rqstp->rq_auth_slack;
|
2014-01-16 05:26:42 +08:00
|
|
|
}
|
|
|
|
|
2019-10-07 22:56:48 +08:00
|
|
|
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
|
|
|
static void
|
|
|
|
check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
|
|
|
|
{
|
|
|
|
struct nfsd4_op *op, *current_op = NULL, *saved_op = NULL;
|
|
|
|
struct nfsd4_copy *copy;
|
|
|
|
struct nfsd4_putfh *putfh;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* traverse all operation and if it's a COPY compound, mark the
|
|
|
|
* source filehandle to skip verification
|
|
|
|
*/
|
|
|
|
for (i = 0; i < args->opcnt; i++) {
|
|
|
|
op = &args->ops[i];
|
|
|
|
if (op->opnum == OP_PUTFH)
|
|
|
|
current_op = op;
|
|
|
|
else if (op->opnum == OP_SAVEFH)
|
|
|
|
saved_op = current_op;
|
|
|
|
else if (op->opnum == OP_RESTOREFH)
|
|
|
|
current_op = saved_op;
|
|
|
|
else if (op->opnum == OP_COPY) {
|
|
|
|
copy = (struct nfsd4_copy *)&op->u;
|
|
|
|
if (!saved_op) {
|
|
|
|
op->status = nfserr_nofilehandle;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
putfh = (struct nfsd4_putfh *)&saved_op->u;
|
|
|
|
if (!copy->cp_intra)
|
|
|
|
putfh->no_verify = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static void
|
|
|
|
check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* COMPOUND call.
|
|
|
|
*/
|
2006-10-20 14:28:45 +08:00
|
|
|
static __be32
|
2017-05-08 23:35:49 +08:00
|
|
|
nfsd4_proc_compound(struct svc_rqst *rqstp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2017-05-08 23:35:49 +08:00
|
|
|
struct nfsd4_compoundargs *args = rqstp->rq_argp;
|
|
|
|
struct nfsd4_compoundres *resp = rqstp->rq_resp;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct nfsd4_op *op;
|
2009-03-28 16:30:52 +08:00
|
|
|
struct nfsd4_compound_state *cstate = &resp->cstate;
|
2014-03-26 17:10:37 +08:00
|
|
|
struct svc_fh *current_fh = &cstate->current_fh;
|
|
|
|
struct svc_fh *save_fh = &cstate->save_fh;
|
2019-04-09 23:46:19 +08:00
|
|
|
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
2006-10-20 14:28:59 +08:00
|
|
|
__be32 status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-01-16 05:26:42 +08:00
|
|
|
svcxdr_init_encode(rqstp, resp);
|
2014-01-16 04:17:58 +08:00
|
|
|
resp->tagp = resp->xdr.p;
|
2005-04-17 06:20:36 +08:00
|
|
|
/* reserve space for: taglen, tag, and opcnt */
|
2014-02-27 06:00:38 +08:00
|
|
|
xdr_reserve_space(&resp->xdr, 8 + args->taglen);
|
2005-04-17 06:20:36 +08:00
|
|
|
resp->taglen = args->taglen;
|
|
|
|
resp->tag = args->tag;
|
|
|
|
resp->rqstp = rqstp;
|
2014-03-26 17:10:37 +08:00
|
|
|
cstate->minorversion = args->minorversion;
|
|
|
|
fh_init(current_fh, NFS4_FHSIZE);
|
|
|
|
fh_init(save_fh, NFS4_FHSIZE);
|
2010-08-12 15:04:07 +08:00
|
|
|
/*
|
|
|
|
* Don't use the deferral mechanism for NFSv4; compounds make it
|
|
|
|
* too hard to avoid non-idempotency problems.
|
|
|
|
*/
|
2014-11-19 20:51:16 +08:00
|
|
|
clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* According to RFC3010, this takes precedence over all other errors.
|
|
|
|
*/
|
|
|
|
status = nfserr_minor_vers_mismatch;
|
2019-04-09 23:46:19 +08:00
|
|
|
if (nfsd_minorversion(nn, args->minorversion, NFSD_TEST) <= 0)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
2017-11-16 01:30:27 +08:00
|
|
|
status = nfserr_resource;
|
|
|
|
if (args->opcnt > NFSD_MAX_OPS_PER_COMPOUND)
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-04-22 00:27:19 +08:00
|
|
|
status = nfs41_check_op_ordering(args);
|
|
|
|
if (status) {
|
2009-04-03 13:28:12 +08:00
|
|
|
op = &args->ops[0];
|
2010-04-22 00:27:19 +08:00
|
|
|
op->status = status;
|
2018-06-14 03:21:35 +08:00
|
|
|
resp->opcnt = 1;
|
2009-04-03 13:28:12 +08:00
|
|
|
goto encode_op;
|
|
|
|
}
|
2019-10-07 22:56:48 +08:00
|
|
|
check_if_stalefh_allowed(args);
|
2009-04-03 13:28:12 +08:00
|
|
|
|
2018-03-27 22:53:54 +08:00
|
|
|
trace_nfsd_compound(rqstp, args->opcnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
while (!status && resp->opcnt < args->opcnt) {
|
|
|
|
op = &args->ops[resp->opcnt++];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The XDR decode routines may have pre-set op->status;
|
|
|
|
* for example, if there is a miscellaneous XDR error
|
|
|
|
* it will be set to nfserr_bad_xdr.
|
|
|
|
*/
|
2013-03-01 04:51:49 +08:00
|
|
|
if (op->status) {
|
|
|
|
if (op->opnum == OP_OPEN)
|
|
|
|
op->status = nfsd4_open_omfg(rqstp, cstate, op);
|
2005-04-17 06:20:36 +08:00
|
|
|
goto encode_op;
|
2013-03-01 04:51:49 +08:00
|
|
|
}
|
2019-10-07 22:56:48 +08:00
|
|
|
if (!current_fh->fh_dentry &&
|
|
|
|
!HAS_FH_FLAG(current_fh, NFSD4_FH_FOREIGN)) {
|
2017-07-07 05:51:29 +08:00
|
|
|
if (!(op->opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
|
2006-10-04 17:16:20 +08:00
|
|
|
op->status = nfserr_nofilehandle;
|
|
|
|
goto encode_op;
|
|
|
|
}
|
2019-10-07 22:56:48 +08:00
|
|
|
} else if (current_fh->fh_export &&
|
|
|
|
current_fh->fh_export->ex_fslocs.migrated &&
|
2017-07-07 05:51:29 +08:00
|
|
|
!(op->opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
|
2006-10-04 17:16:20 +08:00
|
|
|
op->status = nfserr_moved;
|
2005-04-17 06:20:36 +08:00
|
|
|
goto encode_op;
|
|
|
|
}
|
2006-12-13 16:35:38 +08:00
|
|
|
|
2014-03-29 10:23:47 +08:00
|
|
|
fh_clear_wcc(current_fh);
|
|
|
|
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
/* If op is non-idempotent */
|
2017-07-07 05:51:29 +08:00
|
|
|
if (op->opdesc->op_flags & OP_MODIFIES_SOMETHING) {
|
2014-01-29 05:01:04 +08:00
|
|
|
/*
|
2014-03-12 05:54:34 +08:00
|
|
|
* Don't execute this op if we couldn't encode a
|
|
|
|
* succesful reply:
|
|
|
|
*/
|
2017-07-07 05:51:29 +08:00
|
|
|
u32 plen = op->opdesc->op_rsize_bop(rqstp, op);
|
2014-03-12 05:54:34 +08:00
|
|
|
/*
|
|
|
|
* Plus if there's another operation, make sure
|
2014-01-29 05:01:04 +08:00
|
|
|
* we'll have space to at least encode an error:
|
|
|
|
*/
|
|
|
|
if (resp->opcnt < args->opcnt)
|
|
|
|
plen += COMPOUND_ERR_SLACK_SPACE;
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
op->status = nfsd4_check_resp_size(resp, plen);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (op->status)
|
|
|
|
goto encode_op;
|
|
|
|
|
2017-07-07 05:51:29 +08:00
|
|
|
if (op->opdesc->op_get_currentstateid)
|
|
|
|
op->opdesc->op_get_currentstateid(cstate, &op->u);
|
|
|
|
op->status = op->opdesc->op_func(rqstp, cstate, &op->u);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
nfsd4: fix null dereference on replay
if we receive a compound such that:
- the sessionid, slot, and sequence number in the SEQUENCE op
match a cached succesful reply with N ops, and
- the Nth operation of the compound is a PUTFH, PUTPUBFH,
PUTROOTFH, or RESTOREFH,
then nfsd4_sequence will return 0 and set cstate->status to
nfserr_replay_cache. The current filehandle will not be set. This will
cause us to call check_nfsd_access with first argument NULL.
To nfsd4_compound it looks like we just succesfully executed an
operation that set a filehandle, but the current filehandle is not set.
Fix this by moving the nfserr_replay_cache earlier. There was never any
reason to have it after the encode_op label, since the only case where
he hit that is when opdesc->op_func sets it.
Note that there are two ways we could hit this case:
- a client is resending a previously sent compound that ended
with one of the four PUTFH-like operations, or
- a client is sending a *new* compound that (incorrectly) shares
sessionid, slot, and sequence number with a previously sent
compound, and the length of the previously sent compound
happens to match the position of a PUTFH-like operation in the
new compound.
The second is obviously incorrect client behavior. The first is also
very strange--the only purpose of a PUTFH-like operation is to set the
current filehandle to be used by the following operation, so there's no
point in having it as the last in a compound.
So it's likely this requires a buggy or malicious client to reproduce.
Reported-by: Scott Mayhew <smayhew@redhat.com>
Cc: stable@kernel.vger.org
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2017-05-24 00:24:40 +08:00
|
|
|
/* Only from SEQUENCE */
|
|
|
|
if (cstate->status == nfserr_replay_cache) {
|
|
|
|
dprintk("%s NFS4.1 replay from cache\n", __func__);
|
|
|
|
status = op->status;
|
|
|
|
goto out;
|
|
|
|
}
|
2012-02-14 05:55:24 +08:00
|
|
|
if (!op->status) {
|
2017-07-07 05:51:29 +08:00
|
|
|
if (op->opdesc->op_set_currentstateid)
|
|
|
|
op->opdesc->op_set_currentstateid(cstate, &op->u);
|
2012-02-14 05:55:24 +08:00
|
|
|
|
2017-07-07 05:51:29 +08:00
|
|
|
if (op->opdesc->op_flags & OP_CLEAR_STATEID)
|
2012-02-14 05:55:32 +08:00
|
|
|
clear_current_stateid(cstate);
|
2012-02-14 05:55:24 +08:00
|
|
|
|
2019-12-07 05:07:32 +08:00
|
|
|
if (current_fh->fh_export &&
|
|
|
|
need_wrongsec_check(rqstp))
|
2014-03-26 17:10:37 +08:00
|
|
|
op->status = check_nfsd_access(current_fh->fh_export, rqstp);
|
2012-02-14 05:55:24 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
encode_op:
|
2006-10-20 14:29:03 +08:00
|
|
|
if (op->status == nfserr_replay_me) {
|
2006-12-13 16:35:28 +08:00
|
|
|
op->replay = &cstate->replay_owner->so_replay;
|
2014-01-31 06:18:38 +08:00
|
|
|
nfsd4_encode_replay(&resp->xdr, op);
|
2005-04-17 06:20:36 +08:00
|
|
|
status = op->status = op->replay->rp_status;
|
|
|
|
} else {
|
|
|
|
nfsd4_encode_operation(resp, op);
|
|
|
|
status = op->status;
|
|
|
|
}
|
2008-12-16 01:40:49 +08:00
|
|
|
|
2018-03-27 22:53:54 +08:00
|
|
|
trace_nfsd_compound_status(args->opcnt, resp->opcnt, status,
|
|
|
|
nfsd4_op_name(op->opnum));
|
2008-12-16 01:40:49 +08:00
|
|
|
|
2014-07-30 09:34:27 +08:00
|
|
|
nfsd4_cstate_clear_replay(cstate);
|
2006-07-10 19:45:44 +08:00
|
|
|
nfsd4_increment_op_stats(op->opnum);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2014-03-26 17:10:37 +08:00
|
|
|
cstate->status = status;
|
|
|
|
fh_put(current_fh);
|
|
|
|
fh_put(save_fh);
|
|
|
|
BUG_ON(cstate->replay_owner);
|
2005-04-17 06:20:36 +08:00
|
|
|
out:
|
2009-04-03 13:27:32 +08:00
|
|
|
/* Reset deferral mechanism for RPC deferrals */
|
2014-11-19 20:51:16 +08:00
|
|
|
set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
|
2008-05-06 05:17:44 +08:00
|
|
|
dprintk("nfsv4 compound returned %d\n", ntohl(status));
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
#define op_encode_hdr_size (2)
|
|
|
|
#define op_encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE))
|
|
|
|
#define op_encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE))
|
|
|
|
#define op_encode_change_info_maxsz (5)
|
|
|
|
#define nfs4_fattr_bitmap_maxsz (4)
|
|
|
|
|
2014-03-11 00:19:10 +08:00
|
|
|
/* We'll fall back on returning no lockowner if run out of space: */
|
|
|
|
#define op_encode_lockowner_maxsz (0)
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
#define op_encode_lock_denied_maxsz (8 + op_encode_lockowner_maxsz)
|
|
|
|
|
|
|
|
#define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
|
|
|
|
|
|
|
|
#define op_encode_ace_maxsz (3 + nfs4_owner_maxsz)
|
|
|
|
#define op_encode_delegation_maxsz (1 + op_encode_stateid_maxsz + 1 + \
|
|
|
|
op_encode_ace_maxsz)
|
|
|
|
|
|
|
|
#define op_encode_channel_attrs_maxsz (6 + 1 + 1)
|
|
|
|
|
|
|
|
static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
2017-02-03 22:36:00 +08:00
|
|
|
static inline u32 nfsd4_access_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
/* ac_supported, ac_resp_access */
|
|
|
|
return (op_encode_hdr_size + 2)* sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + op_encode_change_info_maxsz
|
|
|
|
+ nfs4_fattr_bitmap_maxsz) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
2014-03-24 00:01:48 +08:00
|
|
|
/*
|
|
|
|
* Note since this is an idempotent operation we won't insist on failing
|
|
|
|
* the op prematurely if the estimate is too large. We may turn off splice
|
|
|
|
* reads unnecessarily.
|
|
|
|
*/
|
|
|
|
static inline u32 nfsd4_getattr_rsize(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
u32 *bmap = op->u.getattr.ga_bmval;
|
|
|
|
u32 bmap0 = bmap[0], bmap1 = bmap[1], bmap2 = bmap[2];
|
|
|
|
u32 ret = 0;
|
|
|
|
|
|
|
|
if (bmap0 & FATTR4_WORD0_ACL)
|
|
|
|
return svc_max_payload(rqstp);
|
|
|
|
if (bmap0 & FATTR4_WORD0_FS_LOCATIONS)
|
|
|
|
return svc_max_payload(rqstp);
|
|
|
|
|
|
|
|
if (bmap1 & FATTR4_WORD1_OWNER) {
|
|
|
|
ret += IDMAP_NAMESZ + 4;
|
|
|
|
bmap1 &= ~FATTR4_WORD1_OWNER;
|
|
|
|
}
|
|
|
|
if (bmap1 & FATTR4_WORD1_OWNER_GROUP) {
|
|
|
|
ret += IDMAP_NAMESZ + 4;
|
|
|
|
bmap1 &= ~FATTR4_WORD1_OWNER_GROUP;
|
|
|
|
}
|
|
|
|
if (bmap0 & FATTR4_WORD0_FILEHANDLE) {
|
|
|
|
ret += NFS4_FHSIZE + 4;
|
|
|
|
bmap0 &= ~FATTR4_WORD0_FILEHANDLE;
|
|
|
|
}
|
|
|
|
if (bmap2 & FATTR4_WORD2_SECURITY_LABEL) {
|
2015-03-28 23:46:09 +08:00
|
|
|
ret += NFS4_MAXLABELLEN + 12;
|
2014-03-24 00:01:48 +08:00
|
|
|
bmap2 &= ~FATTR4_WORD2_SECURITY_LABEL;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Largest of remaining attributes are 16 bytes (e.g.,
|
|
|
|
* supported_attributes)
|
|
|
|
*/
|
|
|
|
ret += 16 * (hweight32(bmap0) + hweight32(bmap1) + hweight32(bmap2));
|
|
|
|
/* bitmask, length */
|
|
|
|
ret += 20;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-02-03 22:36:00 +08:00
|
|
|
static inline u32 nfsd4_getfh_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + 1) * sizeof(__be32) + NFS4_FHSIZE;
|
|
|
|
}
|
|
|
|
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + op_encode_change_info_maxsz)
|
|
|
|
* sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + op_encode_lock_denied_maxsz)
|
|
|
|
* sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + op_encode_stateid_maxsz
|
|
|
|
+ op_encode_change_info_maxsz + 1
|
|
|
|
+ nfs4_fattr_bitmap_maxsz
|
|
|
|
+ op_encode_delegation_maxsz) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
u32 maxcount = 0, rlen = 0;
|
|
|
|
|
|
|
|
maxcount = svc_max_payload(rqstp);
|
2014-06-10 18:08:19 +08:00
|
|
|
rlen = min(op->u.read.rd_length, maxcount);
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
|
2014-05-17 02:38:20 +08:00
|
|
|
return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32);
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
2014-06-10 18:08:19 +08:00
|
|
|
u32 maxcount = 0, rlen = 0;
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
|
2014-06-10 18:08:19 +08:00
|
|
|
maxcount = svc_max_payload(rqstp);
|
|
|
|
rlen = min(op->u.readdir.rd_maxcount, maxcount);
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
|
2014-01-21 05:37:11 +08:00
|
|
|
return (op_encode_hdr_size + op_encode_verifier_maxsz +
|
|
|
|
XDR_QUADLEN(rlen)) * sizeof(__be32);
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
}
|
|
|
|
|
2017-02-03 22:36:00 +08:00
|
|
|
static inline u32 nfsd4_readlink_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + 1) * sizeof(__be32) + PAGE_SIZE;
|
|
|
|
}
|
|
|
|
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + op_encode_change_info_maxsz)
|
|
|
|
* sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + op_encode_change_info_maxsz
|
|
|
|
+ op_encode_change_info_maxsz) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
2014-03-24 00:34:22 +08:00
|
|
|
static inline u32 nfsd4_sequence_rsize(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_op *op)
|
|
|
|
{
|
2014-08-22 03:04:31 +08:00
|
|
|
return (op_encode_hdr_size
|
|
|
|
+ XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) * sizeof(__be32);
|
2014-03-24 00:34:22 +08:00
|
|
|
}
|
|
|
|
|
2017-02-03 22:36:00 +08:00
|
|
|
static inline u32 nfsd4_test_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + 1 + op->u.test_stateid.ts_num_ids)
|
|
|
|
* sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
2017-02-03 22:36:00 +08:00
|
|
|
static inline u32 nfsd4_secinfo_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + RPC_AUTH_MAXFLAVOR *
|
|
|
|
(4 + XDR_QUADLEN(GSS_OID_MAX_LEN))) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
2014-03-11 02:17:55 +08:00
|
|
|
return (op_encode_hdr_size + 2 + XDR_QUADLEN(NFS4_VERIFIER_SIZE)) *
|
|
|
|
sizeof(__be32);
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
2014-05-17 09:24:56 +08:00
|
|
|
return (op_encode_hdr_size + 2 + op_encode_verifier_maxsz) * sizeof(__be32);
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\
|
2013-12-10 15:24:36 +08:00
|
|
|
1 + 1 + /* eir_flags, spr_how */\
|
|
|
|
4 + /* spo_must_enforce & _allow with bitmap */\
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
2 + /*eir_server_owner.so_minor_id */\
|
|
|
|
/* eir_server_owner.so_major_id<> */\
|
|
|
|
XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
|
|
|
|
/* eir_server_scope<> */\
|
|
|
|
XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
|
|
|
|
1 + /* eir_server_impl_id array length */\
|
|
|
|
0 /* ignored eir_server_impl_id contents */) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + \
|
|
|
|
XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\
|
|
|
|
2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + \
|
|
|
|
XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\
|
|
|
|
2 + /* csr_sequence, csr_flags */\
|
|
|
|
op_encode_channel_attrs_maxsz + \
|
|
|
|
op_encode_channel_attrs_maxsz) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
2016-09-08 03:57:30 +08:00
|
|
|
static inline u32 nfsd4_copy_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size +
|
|
|
|
1 /* wr_callback */ +
|
|
|
|
op_encode_stateid_maxsz /* wr_callback */ +
|
|
|
|
2 /* wr_count */ +
|
|
|
|
1 /* wr_committed */ +
|
|
|
|
op_encode_verifier_maxsz +
|
|
|
|
1 /* cr_consecutive */ +
|
|
|
|
1 /* cr_synchronous */) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
2018-07-21 06:19:18 +08:00
|
|
|
static inline u32 nfsd4_offload_status_rsize(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size +
|
|
|
|
2 /* osr_count */ +
|
|
|
|
1 /* osr_complete<1> optional 0 for now */) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
2019-08-08 23:14:59 +08:00
|
|
|
static inline u32 nfsd4_copy_notify_rsize(struct svc_rqst *rqstp,
|
|
|
|
struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size +
|
|
|
|
3 /* cnr_lease_time */ +
|
|
|
|
1 /* We support one cnr_source_server */ +
|
|
|
|
1 /* cnr_stateid seq */ +
|
|
|
|
op_encode_stateid_maxsz /* cnr_stateid */ +
|
|
|
|
1 /* num cnr_source_server*/ +
|
|
|
|
1 /* nl4_type */ +
|
|
|
|
1 /* nl4 size */ +
|
|
|
|
XDR_QUADLEN(NFS4_OPAQUE_LIMIT) /*nl4_loc + nl4_loc_sz */)
|
|
|
|
* sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
#ifdef CONFIG_NFSD_PNFS
|
2017-02-03 22:36:00 +08:00
|
|
|
static inline u32 nfsd4_getdeviceinfo_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
u32 maxcount = 0, rlen = 0;
|
|
|
|
|
|
|
|
maxcount = svc_max_payload(rqstp);
|
|
|
|
rlen = min(op->u.getdeviceinfo.gd_maxcount, maxcount);
|
|
|
|
|
|
|
|
return (op_encode_hdr_size +
|
|
|
|
1 /* gd_layout_type*/ +
|
|
|
|
XDR_QUADLEN(rlen) +
|
|
|
|
2 /* gd_notify_types */) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
/*
|
|
|
|
* At this stage we don't really know what layout driver will handle the request,
|
|
|
|
* so we need to define an arbitrary upper bound here.
|
|
|
|
*/
|
|
|
|
#define MAX_LAYOUT_SIZE 128
|
|
|
|
static inline u32 nfsd4_layoutget_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size +
|
|
|
|
1 /* logr_return_on_close */ +
|
|
|
|
op_encode_stateid_maxsz +
|
|
|
|
1 /* nr of layouts */ +
|
|
|
|
MAX_LAYOUT_SIZE) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_layoutcommit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size +
|
|
|
|
1 /* locr_newsize */ +
|
|
|
|
2 /* ns_size */) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 nfsd4_layoutreturn_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size +
|
|
|
|
1 /* lrs_stateid */ +
|
|
|
|
op_encode_stateid_maxsz) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NFSD_PNFS */
|
|
|
|
|
2017-02-03 22:36:00 +08:00
|
|
|
|
|
|
|
static inline u32 nfsd4_seek_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
return (op_encode_hdr_size + 3) * sizeof(__be32);
|
|
|
|
}
|
|
|
|
|
2017-05-09 05:46:47 +08:00
|
|
|
static const struct nfsd4_operation nfsd4_ops[] = {
|
2006-12-13 16:35:38 +08:00
|
|
|
[OP_ACCESS] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_access,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_ACCESS",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_access_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_CLOSE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_close,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_CLOSE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_status_stateid_rsize,
|
2017-05-09 02:37:33 +08:00
|
|
|
.op_get_currentstateid = nfsd4_get_closestateid,
|
2017-05-09 02:03:15 +08:00
|
|
|
.op_set_currentstateid = nfsd4_set_closestateid,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_COMMIT] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_commit,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_COMMIT",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_commit_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_CREATE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_create,
|
2012-02-14 05:55:29 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME | OP_CLEAR_STATEID,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_CREATE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_create_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_DELEGRETURN] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_delegreturn,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_DELEGRETURN",
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2017-05-09 02:37:33 +08:00
|
|
|
.op_get_currentstateid = nfsd4_get_delegreturnstateid,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_GETATTR] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_getattr,
|
2006-12-13 16:35:39 +08:00
|
|
|
.op_flags = ALLOWED_ON_ABSENT_FS,
|
2014-03-24 00:01:48 +08:00
|
|
|
.op_rsize_bop = nfsd4_getattr_rsize,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_GETATTR",
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_GETFH] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_getfh,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_GETFH",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_getfh_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_LINK] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_link,
|
2011-09-20 20:49:51 +08:00
|
|
|
.op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING
|
|
|
|
| OP_CACHEME,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_LINK",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_link_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_LOCK] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_lock,
|
2017-05-06 22:49:21 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING |
|
|
|
|
OP_NONTRIVIAL_ERROR_ENCODE,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_LOCK",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_lock_rsize,
|
2017-05-09 02:03:15 +08:00
|
|
|
.op_set_currentstateid = nfsd4_set_lockstateid,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_LOCKT] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_lockt,
|
2017-05-06 22:49:21 +08:00
|
|
|
.op_flags = OP_NONTRIVIAL_ERROR_ENCODE,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_LOCKT",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_lock_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_LOCKU] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_locku,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_LOCKU",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_status_stateid_rsize,
|
2017-05-09 02:37:33 +08:00
|
|
|
.op_get_currentstateid = nfsd4_get_lockustateid,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_LOOKUP] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_lookup,
|
2012-02-14 05:55:29 +08:00
|
|
|
.op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_LOOKUP",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_LOOKUPP] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_lookupp,
|
2012-02-14 05:55:29 +08:00
|
|
|
.op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_LOOKUPP",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_NVERIFY] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_nverify,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_NVERIFY",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_OPEN] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_open,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_OPEN",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_open_rsize,
|
2017-05-09 02:03:15 +08:00
|
|
|
.op_set_currentstateid = nfsd4_set_openstateid,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_OPEN_CONFIRM] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_open_confirm,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_OPEN_CONFIRM",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_status_stateid_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_OPEN_DOWNGRADE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_open_downgrade,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_OPEN_DOWNGRADE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_status_stateid_rsize,
|
2017-05-09 02:37:33 +08:00
|
|
|
.op_get_currentstateid = nfsd4_get_opendowngradestateid,
|
2017-05-09 02:03:15 +08:00
|
|
|
.op_set_currentstateid = nfsd4_set_opendowngradestateid,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_PUTFH] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_putfh,
|
2011-04-09 05:00:50 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
|
2014-03-08 00:43:58 +08:00
|
|
|
| OP_IS_PUTFH_LIKE | OP_CLEAR_STATEID,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_PUTFH",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
2006-12-13 16:35:39 +08:00
|
|
|
[OP_PUTPUBFH] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_putrootfh,
|
2011-04-09 05:00:50 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
|
2014-03-08 00:43:58 +08:00
|
|
|
| OP_IS_PUTFH_LIKE | OP_CLEAR_STATEID,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_PUTPUBFH",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:39 +08:00
|
|
|
},
|
2006-12-13 16:35:38 +08:00
|
|
|
[OP_PUTROOTFH] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_putrootfh,
|
2011-04-09 05:00:50 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
|
2014-03-08 00:43:58 +08:00
|
|
|
| OP_IS_PUTFH_LIKE | OP_CLEAR_STATEID,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_PUTROOTFH",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_READ] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_read,
|
2017-05-06 05:09:37 +08:00
|
|
|
.op_release = nfsd4_read_release,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_READ",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_read_rsize,
|
2017-05-09 02:37:33 +08:00
|
|
|
.op_get_currentstateid = nfsd4_get_readstateid,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_READDIR] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_readdir,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_READDIR",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_readdir_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_READLINK] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_readlink,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_READLINK",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_readlink_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_REMOVE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_remove,
|
2011-09-20 20:49:51 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_REMOVE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_remove_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_RENAME] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_rename,
|
2011-09-20 20:49:51 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_name = "OP_RENAME",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_rename_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_RENEW] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_renew,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
|
|
|
|
| OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_RENEW",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_RESTOREFH] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_restorefh,
|
2011-04-09 05:00:50 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
| OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_RESTOREFH",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_SAVEFH] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_savefh,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_SAVEFH",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
2007-07-17 19:04:51 +08:00
|
|
|
[OP_SECINFO] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_secinfo,
|
2017-05-06 05:09:37 +08:00
|
|
|
.op_release = nfsd4_secinfo_release,
|
2011-04-09 05:00:50 +08:00
|
|
|
.op_flags = OP_HANDLES_WRONGSEC,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_SECINFO",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_secinfo_rsize,
|
2007-07-17 19:04:51 +08:00
|
|
|
},
|
2006-12-13 16:35:38 +08:00
|
|
|
[OP_SETATTR] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_setattr,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_SETATTR",
|
2017-05-06 22:49:21 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME
|
|
|
|
| OP_NONTRIVIAL_ERROR_ENCODE,
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_setattr_rsize,
|
2017-05-09 02:37:33 +08:00
|
|
|
.op_get_currentstateid = nfsd4_get_setattrstateid,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_SETCLIENTID] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_setclientid,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
|
2017-05-06 22:49:21 +08:00
|
|
|
| OP_MODIFIES_SOMETHING | OP_CACHEME
|
|
|
|
| OP_NONTRIVIAL_ERROR_ENCODE,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_SETCLIENTID",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_setclientid_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_SETCLIENTID_CONFIRM] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_setclientid_confirm,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
|
2011-09-20 20:49:51 +08:00
|
|
|
| OP_MODIFIES_SOMETHING | OP_CACHEME,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_SETCLIENTID_CONFIRM",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_VERIFY] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_verify,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_VERIFY",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_WRITE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_write,
|
2011-09-20 20:49:51 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_WRITE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_write_rsize,
|
2017-05-09 02:37:33 +08:00
|
|
|
.op_get_currentstateid = nfsd4_get_writestateid,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
|
|
|
[OP_RELEASE_LOCKOWNER] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_release_lockowner,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
|
|
|
|
| OP_MODIFIES_SOMETHING,
|
2008-07-02 16:15:03 +08:00
|
|
|
.op_name = "OP_RELEASE_LOCKOWNER",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2006-12-13 16:35:38 +08:00
|
|
|
},
|
2009-04-03 13:27:58 +08:00
|
|
|
|
|
|
|
/* NFSv4.1 operations */
|
|
|
|
[OP_EXCHANGE_ID] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_exchange_id,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
|
|
|
|
| OP_MODIFIES_SOMETHING,
|
2009-04-03 13:27:58 +08:00
|
|
|
.op_name = "OP_EXCHANGE_ID",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_exchange_id_rsize,
|
2009-04-03 13:27:58 +08:00
|
|
|
},
|
2012-11-02 06:09:48 +08:00
|
|
|
[OP_BACKCHANNEL_CTL] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_backchannel_ctl,
|
2012-11-02 06:09:48 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
|
|
|
|
.op_name = "OP_BACKCHANNEL_CTL",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2012-11-02 06:09:48 +08:00
|
|
|
},
|
2010-10-05 11:12:59 +08:00
|
|
|
[OP_BIND_CONN_TO_SESSION] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_bind_conn_to_session,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
|
|
|
|
| OP_MODIFIES_SOMETHING,
|
2010-10-05 11:12:59 +08:00
|
|
|
.op_name = "OP_BIND_CONN_TO_SESSION",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_bind_conn_to_session_rsize,
|
2010-10-05 11:12:59 +08:00
|
|
|
},
|
2009-04-03 13:27:58 +08:00
|
|
|
[OP_CREATE_SESSION] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_create_session,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
|
|
|
|
| OP_MODIFIES_SOMETHING,
|
2009-04-03 13:27:58 +08:00
|
|
|
.op_name = "OP_CREATE_SESSION",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_create_session_rsize,
|
2009-04-03 13:27:58 +08:00
|
|
|
},
|
|
|
|
[OP_DESTROY_SESSION] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_destroy_session,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
|
|
|
|
| OP_MODIFIES_SOMETHING,
|
2009-04-03 13:27:58 +08:00
|
|
|
.op_name = "OP_DESTROY_SESSION",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2009-04-03 13:27:58 +08:00
|
|
|
},
|
|
|
|
[OP_SEQUENCE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_sequence,
|
2009-04-03 13:28:12 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
|
2009-04-03 13:27:58 +08:00
|
|
|
.op_name = "OP_SEQUENCE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_sequence_rsize,
|
2009-04-03 13:27:58 +08:00
|
|
|
},
|
2011-06-16 23:39:10 +08:00
|
|
|
[OP_DESTROY_CLIENTID] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_destroy_clientid,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
|
|
|
|
| OP_MODIFIES_SOMETHING,
|
2011-06-16 23:39:10 +08:00
|
|
|
.op_name = "OP_DESTROY_CLIENTID",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2011-06-16 23:39:10 +08:00
|
|
|
},
|
2010-04-20 03:11:28 +08:00
|
|
|
[OP_RECLAIM_COMPLETE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_reclaim_complete,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
|
2010-04-20 03:11:28 +08:00
|
|
|
.op_name = "OP_RECLAIM_COMPLETE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2010-04-20 03:11:28 +08:00
|
|
|
},
|
2010-12-16 22:51:13 +08:00
|
|
|
[OP_SECINFO_NO_NAME] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_secinfo_no_name,
|
2017-09-29 15:01:10 +08:00
|
|
|
.op_release = nfsd4_secinfo_no_name_release,
|
2011-04-09 05:00:50 +08:00
|
|
|
.op_flags = OP_HANDLES_WRONGSEC,
|
2010-12-16 22:51:13 +08:00
|
|
|
.op_name = "OP_SECINFO_NO_NAME",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_secinfo_rsize,
|
2010-12-16 22:51:13 +08:00
|
|
|
},
|
2011-07-13 22:50:48 +08:00
|
|
|
[OP_TEST_STATEID] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_test_stateid,
|
2011-07-13 22:50:48 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH,
|
|
|
|
.op_name = "OP_TEST_STATEID",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_test_stateid_rsize,
|
2011-07-13 22:50:48 +08:00
|
|
|
},
|
2011-07-13 23:04:21 +08:00
|
|
|
[OP_FREE_STATEID] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_free_stateid,
|
nfsd41: try to check reply size before operation
For checking the size of reply before calling a operation,
we need try to get maxsize of the operation's reply.
v3: using new method as Bruce said,
"we could handle operations in two different ways:
- For operations that actually change something (write, rename,
open, close, ...), do it the way we're doing it now: be
very careful to estimate the size of the response before even
processing the operation.
- For operations that don't change anything (read, getattr, ...)
just go ahead and do the operation. If you realize after the
fact that the response is too large, then return the error at
that point.
So we'd add another flag to op_flags: say, OP_MODIFIES_SOMETHING. And for
operations with OP_MODIFIES_SOMETHING set, we'd do the first thing. For
operations without it set, we'd do the second."
Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
[bfields@redhat.com: crash, don't attempt to handle, undefined op_rsize_bop]
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
2011-08-28 18:18:56 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
|
2011-07-13 23:04:21 +08:00
|
|
|
.op_name = "OP_FREE_STATEID",
|
2017-05-09 02:37:33 +08:00
|
|
|
.op_get_currentstateid = nfsd4_get_freestateid,
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2011-07-13 23:04:21 +08:00
|
|
|
},
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
#ifdef CONFIG_NFSD_PNFS
|
|
|
|
[OP_GETDEVICEINFO] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_getdeviceinfo,
|
2017-05-06 05:09:37 +08:00
|
|
|
.op_release = nfsd4_getdeviceinfo_release,
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
.op_flags = ALLOWED_WITHOUT_FH,
|
|
|
|
.op_name = "OP_GETDEVICEINFO",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_getdeviceinfo_rsize,
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
},
|
|
|
|
[OP_LAYOUTGET] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_layoutget,
|
2017-05-06 05:09:37 +08:00
|
|
|
.op_release = nfsd4_layoutget_release,
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
|
|
|
.op_name = "OP_LAYOUTGET",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_layoutget_rsize,
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
},
|
|
|
|
[OP_LAYOUTCOMMIT] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_layoutcommit,
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
|
|
|
.op_name = "OP_LAYOUTCOMMIT",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_layoutcommit_rsize,
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
},
|
|
|
|
[OP_LAYOUTRETURN] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_layoutreturn,
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
|
|
|
.op_name = "OP_LAYOUTRETURN",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_layoutreturn_rsize,
|
nfsd: implement pNFS operations
Add support for the GETDEVICEINFO, LAYOUTGET, LAYOUTCOMMIT and
LAYOUTRETURN NFSv4.1 operations, as well as backing code to manage
outstanding layouts and devices.
Layout management is very straight forward, with a nfs4_layout_stateid
structure that extends nfs4_stid to manage layout stateids as the
top-level structure. It is linked into the nfs4_file and nfs4_client
structures like the other stateids, and contains a linked list of
layouts that hang of the stateid. The actual layout operations are
implemented in layout drivers that are not part of this commit, but
will be added later.
The worst part of this commit is the management of the pNFS device IDs,
which suffers from a specification that is not sanely implementable due
to the fact that the device-IDs are global and not bound to an export,
and have a small enough size so that we can't store the fsid portion of
a file handle, and must never be reused. As we still do need perform all
export authentication and validation checks on a device ID passed to
GETDEVICEINFO we are caught between a rock and a hard place. To work
around this issue we add a new hash that maps from a 64-bit integer to a
fsid so that we can look up the export to authenticate against it,
a 32-bit integer as a generation that we can bump when changing the device,
and a currently unused 32-bit integer that could be used in the future
to handle more than a single device per export. Entries in this hash
table are never deleted as we can't reuse the ids anyway, and would have
a severe lifetime problem anyway as Linux export structures are temporary
structures that can go away under load.
Parts of the XDR data, structures and marshaling/unmarshaling code, as
well as many concepts are derived from the old pNFS server implementation
from Andy Adamson, Benny Halevy, Dean Hildebrand, Marc Eshel, Fred Isaman,
Mike Sager, Ricardo Labiaga and many others.
Signed-off-by: Christoph Hellwig <hch@lst.de>
2014-05-05 19:11:59 +08:00
|
|
|
},
|
|
|
|
#endif /* CONFIG_NFSD_PNFS */
|
2014-09-27 01:58:27 +08:00
|
|
|
|
|
|
|
/* NFSv4.2 operations */
|
2014-11-08 03:44:26 +08:00
|
|
|
[OP_ALLOCATE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_allocate,
|
2018-12-05 03:09:21 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2014-11-08 03:44:26 +08:00
|
|
|
.op_name = "OP_ALLOCATE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2014-11-08 03:44:26 +08:00
|
|
|
},
|
2014-11-08 03:44:27 +08:00
|
|
|
[OP_DEALLOCATE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_deallocate,
|
2018-12-05 03:09:21 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2014-11-08 03:44:27 +08:00
|
|
|
.op_name = "OP_DEALLOCATE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2014-11-08 03:44:27 +08:00
|
|
|
},
|
2015-12-03 19:59:52 +08:00
|
|
|
[OP_CLONE] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_clone,
|
2018-12-05 03:09:21 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2015-12-03 19:59:52 +08:00
|
|
|
.op_name = "OP_CLONE",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
2015-12-03 19:59:52 +08:00
|
|
|
},
|
2016-09-08 03:57:30 +08:00
|
|
|
[OP_COPY] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_copy,
|
2018-12-05 03:09:21 +08:00
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
2016-09-08 03:57:30 +08:00
|
|
|
.op_name = "OP_COPY",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_copy_rsize,
|
2016-09-08 03:57:30 +08:00
|
|
|
},
|
2014-09-27 01:58:27 +08:00
|
|
|
[OP_SEEK] = {
|
2017-05-09 02:58:35 +08:00
|
|
|
.op_func = nfsd4_seek,
|
2014-09-27 01:58:27 +08:00
|
|
|
.op_name = "OP_SEEK",
|
2017-05-09 02:42:10 +08:00
|
|
|
.op_rsize_bop = nfsd4_seek_rsize,
|
2014-09-27 01:58:27 +08:00
|
|
|
},
|
2018-07-21 06:19:18 +08:00
|
|
|
[OP_OFFLOAD_STATUS] = {
|
|
|
|
.op_func = nfsd4_offload_status,
|
|
|
|
.op_name = "OP_OFFLOAD_STATUS",
|
|
|
|
.op_rsize_bop = nfsd4_offload_status_rsize,
|
|
|
|
},
|
2018-07-21 06:19:19 +08:00
|
|
|
[OP_OFFLOAD_CANCEL] = {
|
|
|
|
.op_func = nfsd4_offload_cancel,
|
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
|
|
|
.op_name = "OP_OFFLOAD_CANCEL",
|
|
|
|
.op_rsize_bop = nfsd4_only_status_rsize,
|
|
|
|
},
|
2019-08-08 23:14:59 +08:00
|
|
|
[OP_COPY_NOTIFY] = {
|
|
|
|
.op_func = nfsd4_copy_notify,
|
|
|
|
.op_flags = OP_MODIFIES_SOMETHING,
|
|
|
|
.op_name = "OP_COPY_NOTIFY",
|
|
|
|
.op_rsize_bop = nfsd4_copy_notify_rsize,
|
|
|
|
},
|
2006-12-13 16:35:38 +08:00
|
|
|
};
|
|
|
|
|
2016-06-16 00:52:09 +08:00
|
|
|
/**
|
|
|
|
* nfsd4_spo_must_allow - Determine if the compound op contains an
|
|
|
|
* operation that is allowed to be sent with machine credentials
|
|
|
|
*
|
|
|
|
* @rqstp: a pointer to the struct svc_rqst
|
|
|
|
*
|
|
|
|
* Checks to see if the compound contains a spo_must_allow op
|
|
|
|
* and confirms that it was sent with the proper machine creds.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
|
|
|
|
{
|
|
|
|
struct nfsd4_compoundres *resp = rqstp->rq_resp;
|
|
|
|
struct nfsd4_compoundargs *argp = rqstp->rq_argp;
|
|
|
|
struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
|
|
|
|
struct nfsd4_compound_state *cstate = &resp->cstate;
|
|
|
|
struct nfs4_op_map *allow = &cstate->clp->cl_spo_must_allow;
|
|
|
|
u32 opiter;
|
|
|
|
|
|
|
|
if (!cstate->minorversion)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (cstate->spo_must_allowed == true)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
opiter = resp->opcnt;
|
|
|
|
while (opiter < argp->opcnt) {
|
|
|
|
this = &argp->ops[opiter++];
|
|
|
|
if (test_bit(this->opnum, allow->u.longs) &&
|
|
|
|
cstate->clp->cl_mach_cred &&
|
|
|
|
nfsd4_mach_creds_match(cstate->clp, rqstp)) {
|
|
|
|
cstate->spo_must_allowed = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cstate->spo_must_allowed = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-03-12 03:39:13 +08:00
|
|
|
int nfsd4_max_reply(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
|
|
|
{
|
2017-03-24 02:36:20 +08:00
|
|
|
if (op->opnum == OP_ILLEGAL || op->status == nfserr_notsupp)
|
2014-03-12 03:39:13 +08:00
|
|
|
return op_encode_hdr_size * sizeof(__be32);
|
2017-02-03 22:36:00 +08:00
|
|
|
|
|
|
|
BUG_ON(OPDESC(op)->op_rsize_bop == NULL);
|
|
|
|
return OPDESC(op)->op_rsize_bop(rqstp, op);
|
2014-03-12 03:39:13 +08:00
|
|
|
}
|
|
|
|
|
2014-03-07 09:39:29 +08:00
|
|
|
void warn_on_nonidempotent_op(struct nfsd4_op *op)
|
|
|
|
{
|
|
|
|
if (OPDESC(op)->op_flags & OP_MODIFIES_SOMETHING) {
|
|
|
|
pr_err("unable to encode reply to nonidempotent op %d (%s)\n",
|
|
|
|
op->opnum, nfsd4_op_name(op->opnum));
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-09 00:26:42 +08:00
|
|
|
static const char *nfsd4_op_name(unsigned opnum)
|
2008-07-02 16:15:03 +08:00
|
|
|
{
|
|
|
|
if (opnum < ARRAY_SIZE(nfsd4_ops))
|
|
|
|
return nfsd4_ops[opnum].op_name;
|
|
|
|
return "unknown_operation";
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
#define nfsd4_voidres nfsd4_voidargs
|
|
|
|
struct nfsd4_voidargs { int dummy; };
|
|
|
|
|
2017-05-12 22:11:49 +08:00
|
|
|
static const struct svc_procedure nfsd_procedures4[2] = {
|
2009-05-19 14:09:54 +08:00
|
|
|
[NFSPROC4_NULL] = {
|
2017-05-08 23:59:13 +08:00
|
|
|
.pc_func = nfsd4_proc_null,
|
2017-05-09 01:42:02 +08:00
|
|
|
.pc_encode = nfs4svc_encode_voidres,
|
2009-05-19 14:09:54 +08:00
|
|
|
.pc_argsize = sizeof(struct nfsd4_voidargs),
|
|
|
|
.pc_ressize = sizeof(struct nfsd4_voidres),
|
|
|
|
.pc_cachetype = RC_NOCACHE,
|
|
|
|
.pc_xdrressize = 1,
|
|
|
|
},
|
|
|
|
[NFSPROC4_COMPOUND] = {
|
2017-05-08 23:59:13 +08:00
|
|
|
.pc_func = nfsd4_proc_compound,
|
2017-05-09 01:01:48 +08:00
|
|
|
.pc_decode = nfs4svc_decode_compoundargs,
|
2017-05-09 01:42:02 +08:00
|
|
|
.pc_encode = nfs4svc_encode_compoundres,
|
2009-05-19 14:09:54 +08:00
|
|
|
.pc_argsize = sizeof(struct nfsd4_compoundargs),
|
|
|
|
.pc_ressize = sizeof(struct nfsd4_compoundres),
|
2011-07-17 05:15:10 +08:00
|
|
|
.pc_release = nfsd4_release_compoundargs,
|
2009-05-19 14:09:54 +08:00
|
|
|
.pc_cachetype = RC_NOCACHE,
|
|
|
|
.pc_xdrressize = NFSD_BUFSIZE/4,
|
|
|
|
},
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2017-05-09 05:40:27 +08:00
|
|
|
static unsigned int nfsd_count3[ARRAY_SIZE(nfsd_procedures4)];
|
2017-05-12 22:21:37 +08:00
|
|
|
const struct svc_version nfsd_version4 = {
|
2017-02-25 02:25:24 +08:00
|
|
|
.vs_vers = 4,
|
|
|
|
.vs_nproc = 2,
|
|
|
|
.vs_proc = nfsd_procedures4,
|
2017-05-09 05:40:27 +08:00
|
|
|
.vs_count = nfsd_count3,
|
2017-02-25 02:25:24 +08:00
|
|
|
.vs_dispatch = nfsd_dispatch,
|
|
|
|
.vs_xdrsize = NFS4_SVC_XDRSIZE,
|
|
|
|
.vs_rpcb_optnl = true,
|
|
|
|
.vs_need_cong_ctrl = true,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* c-basic-offset: 8
|
|
|
|
* End:
|
|
|
|
*/
|