Commit 24717cfb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfsd-5.10' of git://linux-nfs.org/~bfields/linux

Pull nfsd updates from Bruce Fields:
 "The one new feature this time, from Anna Schumaker, is READ_PLUS,
  which has the same arguments as READ but allows the server to return
  an array of data and hole extents.

  Otherwise it's a lot of cleanup and bugfixes"

* tag 'nfsd-5.10' of git://linux-nfs.org/~bfields/linux: (43 commits)
  NFSv4.2: Fix NFS4ERR_STALE error when doing inter server copy
  SUNRPC: fix copying of multiple pages in gss_read_proxy_verf()
  sunrpc: raise kernel RPC channel buffer size
  svcrdma: fix bounce buffers for unaligned offsets and multiple pages
  nfsd: remove unneeded break
  net/sunrpc: Fix return value for sysctl sunrpc.transports
  NFSD: Encode a full READ_PLUS reply
  NFSD: Return both a hole and a data segment
  NFSD: Add READ_PLUS hole segment encoding
  NFSD: Add READ_PLUS data support
  NFSD: Hoist status code encoding into XDR encoder functions
  NFSD: Map nfserr_wrongsec outside of nfsd_dispatch
  NFSD: Remove the RETURN_STATUS() macro
  NFSD: Call NFSv2 encoders on error returns
  NFSD: Fix .pc_release method for NFSv2
  NFSD: Remove vestigial typedefs
  NFSD: Refactor nfsd_dispatch() error paths
  NFSD: Clean up nfsd_dispatch() variables
  NFSD: Clean up stale comments in nfsd_dispatch()
  NFSD: Clean up switch statement in nfsd_dispatch()
  ...
parents 9b06f57b 0cfcd405
===================
NFS Fault Injection
===================
Fault injection is a method for forcing errors that may not normally occur, or
may be difficult to reproduce. Forcing these errors in a controlled environment
can help the developer find and fix bugs before their code is shipped in a
production system. Injecting an error on the Linux NFS server will allow us to
observe how the client reacts and if it manages to recover its state correctly.
NFSD_FAULT_INJECTION must be selected when configuring the kernel to use this
feature.
Using Fault Injection
=====================
On the client, mount the fault injection server through NFS v4.0+ and do some
work over NFS (open files, take locks, ...).
On the server, mount the debugfs filesystem to <debug_dir> and ls
<debug_dir>/nfsd. This will show a list of files that will be used for
injecting faults on the NFS server. As root, write a number n to the file
corresponding to the action you want the server to take. The server will then
process the first n items it finds. So if you want to forget 5 locks, echo '5'
to <debug_dir>/nfsd/forget_locks. A value of 0 will tell the server to forget
all corresponding items. A log message will be created containing the number
of items forgotten (check dmesg).
Go back to work on the client and check if the client recovered from the error
correctly.
Available Faults
================
forget_clients:
The NFS server keeps a list of clients that have placed a mount call. If
this list is cleared, the server will have no knowledge of who the client
is, forcing the client to reauthenticate with the server.
forget_openowners:
The NFS server keeps a list of what files are currently opened and who
they were opened by. Clearing this list will force the client to reopen
its files.
forget_locks:
The NFS server keeps a list of what files are currently locked in the VFS.
Clearing this list will force the client to reclaim its locks (files are
unlocked through the VFS as they are cleared from this list).
forget_delegations:
A delegation is used to assure the client that a file, or part of a file,
has not changed since the delegation was awarded. Clearing this list will
force the client to reacquire its delegation before accessing the file
again.
recall_delegations:
Delegations can be recalled by the server when another client attempts to
access a file. This test will notify the client that its delegation has
been revoked, forcing the client to reacquire the delegation before using
the file again.
tools/nfs/inject_faults.sh script
=================================
This script has been created to ease the fault injection process. This script
will detect the mounted debugfs directory and write to the files located there
based on the arguments passed by the user. For example, running
`inject_faults.sh forget_locks 1` as root will instruct the server to forget
one lock. Running `inject_faults forget_locks` will instruct the server to
forgetall locks.
......@@ -12,4 +12,3 @@ NFS
nfs-idmapper
pnfs-block-server
pnfs-scsi-server
fault_injection
......@@ -13,10 +13,9 @@ RPCGSS is specified in a few IETF documents:
- RFC2203 v1: https://tools.ietf.org/rfc/rfc2203.txt
- RFC5403 v2: https://tools.ietf.org/rfc/rfc5403.txt
and there is a 3rd version being proposed:
There is a third version that we don't currently implement:
- https://tools.ietf.org/id/draft-williams-rpcsecgssv3.txt
(At draft n. 02 at the time of writing)
- RFC7861 v3: https://tools.ietf.org/rfc/rfc7861.txt
Background
==========
......
......@@ -9556,6 +9556,7 @@ F: include/linux/sunrpc/
F: include/uapi/linux/nfsd/
F: include/uapi/linux/sunrpc/
F: net/sunrpc/
F: Documentation/filesystems/nfs/
KERNEL SELFTEST FRAMEWORK
M: Shuah Khan <shuah@kernel.org>
......@@ -12337,6 +12338,7 @@ F: include/linux/sunrpc/
F: include/uapi/linux/nfs*
F: include/uapi/linux/sunrpc/
F: net/sunrpc/
F: Documentation/filesystems/nfs/
NILFS2 FILESYSTEM
M: Ryusuke Konishi <konishi.ryusuke@gmail.com>
......
......@@ -486,65 +486,215 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
return rpc_success;
}
static __be32
nlm4svc_proc_unused(struct svc_rqst *rqstp)
{
return rpc_proc_unavail;
}
/*
* NLM Server procedures.
*/
#define nlm4svc_encode_norep nlm4svc_encode_void
#define nlm4svc_decode_norep nlm4svc_decode_void
#define nlm4svc_decode_testres nlm4svc_decode_void
#define nlm4svc_decode_lockres nlm4svc_decode_void
#define nlm4svc_decode_unlockres nlm4svc_decode_void
#define nlm4svc_decode_cancelres nlm4svc_decode_void
#define nlm4svc_decode_grantedres nlm4svc_decode_void
#define nlm4svc_proc_none nlm4svc_proc_null
#define nlm4svc_proc_test_res nlm4svc_proc_null
#define nlm4svc_proc_lock_res nlm4svc_proc_null
#define nlm4svc_proc_cancel_res nlm4svc_proc_null
#define nlm4svc_proc_unlock_res nlm4svc_proc_null
struct nlm_void { int dummy; };
#define PROC(name, xargt, xrest, argt, rest, respsize) \
{ .pc_func = nlm4svc_proc_##name, \
.pc_decode = nlm4svc_decode_##xargt, \
.pc_encode = nlm4svc_encode_##xrest, \
.pc_release = NULL, \
.pc_argsize = sizeof(struct nlm_##argt), \
.pc_ressize = sizeof(struct nlm_##rest), \
.pc_xdrressize = respsize, \
}
#define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */
#define No (1+1024/4) /* netobj */
#define St 1 /* status */
#define Rg 4 /* range (offset + length) */
const struct svc_procedure nlmsvc_procedures4[] = {
PROC(null, void, void, void, void, 1),
PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg),
PROC(lock, lockargs, res, args, res, Ck+St),
PROC(cancel, cancargs, res, args, res, Ck+St),
PROC(unlock, unlockargs, res, args, res, Ck+St),
PROC(granted, testargs, res, args, res, Ck+St),
PROC(test_msg, testargs, norep, args, void, 1),
PROC(lock_msg, lockargs, norep, args, void, 1),
PROC(cancel_msg, cancargs, norep, args, void, 1),
PROC(unlock_msg, unlockargs, norep, args, void, 1),
PROC(granted_msg, testargs, norep, args, void, 1),
PROC(test_res, testres, norep, res, void, 1),
PROC(lock_res, lockres, norep, res, void, 1),
PROC(cancel_res, cancelres, norep, res, void, 1),
PROC(unlock_res, unlockres, norep, res, void, 1),
PROC(granted_res, res, norep, res, void, 1),
/* statd callback */
PROC(sm_notify, reboot, void, reboot, void, 1),
PROC(none, void, void, void, void, 0),
PROC(none, void, void, void, void, 0),
PROC(none, void, void, void, void, 0),
PROC(share, shareargs, shareres, args, res, Ck+St+1),
PROC(unshare, shareargs, shareres, args, res, Ck+St+1),
PROC(nm_lock, lockargs, res, args, res, Ck+St),
PROC(free_all, notify, void, args, void, 1),
const struct svc_procedure nlmsvc_procedures4[24] = {
[NLMPROC_NULL] = {
.pc_func = nlm4svc_proc_null,
.pc_decode = nlm4svc_decode_void,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_void),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_TEST] = {
.pc_func = nlm4svc_proc_test,
.pc_decode = nlm4svc_decode_testargs,
.pc_encode = nlm4svc_encode_testres,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St+2+No+Rg,
},
[NLMPROC_LOCK] = {
.pc_func = nlm4svc_proc_lock,
.pc_decode = nlm4svc_decode_lockargs,
.pc_encode = nlm4svc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_CANCEL] = {
.pc_func = nlm4svc_proc_cancel,
.pc_decode = nlm4svc_decode_cancargs,
.pc_encode = nlm4svc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_UNLOCK] = {
.pc_func = nlm4svc_proc_unlock,
.pc_decode = nlm4svc_decode_unlockargs,
.pc_encode = nlm4svc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_GRANTED] = {
.pc_func = nlm4svc_proc_granted,
.pc_decode = nlm4svc_decode_testargs,
.pc_encode = nlm4svc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_TEST_MSG] = {
.pc_func = nlm4svc_proc_test_msg,
.pc_decode = nlm4svc_decode_testargs,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_LOCK_MSG] = {
.pc_func = nlm4svc_proc_lock_msg,
.pc_decode = nlm4svc_decode_lockargs,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_CANCEL_MSG] = {
.pc_func = nlm4svc_proc_cancel_msg,
.pc_decode = nlm4svc_decode_cancargs,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_UNLOCK_MSG] = {
.pc_func = nlm4svc_proc_unlock_msg,
.pc_decode = nlm4svc_decode_unlockargs,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_GRANTED_MSG] = {
.pc_func = nlm4svc_proc_granted_msg,
.pc_decode = nlm4svc_decode_testargs,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_TEST_RES] = {
.pc_func = nlm4svc_proc_null,
.pc_decode = nlm4svc_decode_void,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_LOCK_RES] = {
.pc_func = nlm4svc_proc_null,
.pc_decode = nlm4svc_decode_void,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_CANCEL_RES] = {
.pc_func = nlm4svc_proc_null,
.pc_decode = nlm4svc_decode_void,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_UNLOCK_RES] = {
.pc_func = nlm4svc_proc_null,
.pc_decode = nlm4svc_decode_void,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_GRANTED_RES] = {
.pc_func = nlm4svc_proc_granted_res,
.pc_decode = nlm4svc_decode_res,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_NSM_NOTIFY] = {
.pc_func = nlm4svc_proc_sm_notify,
.pc_decode = nlm4svc_decode_reboot,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_reboot),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[17] = {
.pc_func = nlm4svc_proc_unused,
.pc_decode = nlm4svc_decode_void,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_void),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = 0,
},
[18] = {
.pc_func = nlm4svc_proc_unused,
.pc_decode = nlm4svc_decode_void,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_void),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = 0,
},
[19] = {
.pc_func = nlm4svc_proc_unused,
.pc_decode = nlm4svc_decode_void,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_void),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = 0,
},
[NLMPROC_SHARE] = {
.pc_func = nlm4svc_proc_share,
.pc_decode = nlm4svc_decode_shareargs,
.pc_encode = nlm4svc_encode_shareres,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St+1,
},
[NLMPROC_UNSHARE] = {
.pc_func = nlm4svc_proc_unshare,
.pc_decode = nlm4svc_decode_shareargs,
.pc_encode = nlm4svc_encode_shareres,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St+1,
},
[NLMPROC_NM_LOCK] = {
.pc_func = nlm4svc_proc_nm_lock,
.pc_decode = nlm4svc_decode_lockargs,
.pc_encode = nlm4svc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_FREE_ALL] = {
.pc_func = nlm4svc_proc_free_all,
.pc_decode = nlm4svc_decode_notify,
.pc_encode = nlm4svc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
};
......@@ -529,66 +529,214 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp)
return rpc_success;
}
static __be32
nlmsvc_proc_unused(struct svc_rqst *rqstp)
{
return rpc_proc_unavail;
}
/*
* NLM Server procedures.
*/
#define nlmsvc_encode_norep nlmsvc_encode_void
#define nlmsvc_decode_norep nlmsvc_decode_void
#define nlmsvc_decode_testres nlmsvc_decode_void
#define nlmsvc_decode_lockres nlmsvc_decode_void
#define nlmsvc_decode_unlockres nlmsvc_decode_void
#define nlmsvc_decode_cancelres nlmsvc_decode_void
#define nlmsvc_decode_grantedres nlmsvc_decode_void
#define nlmsvc_proc_none nlmsvc_proc_null
#define nlmsvc_proc_test_res nlmsvc_proc_null
#define nlmsvc_proc_lock_res nlmsvc_proc_null
#define nlmsvc_proc_cancel_res nlmsvc_proc_null
#define nlmsvc_proc_unlock_res nlmsvc_proc_null
struct nlm_void { int dummy; };
#define PROC(name, xargt, xrest, argt, rest, respsize) \
{ .pc_func = nlmsvc_proc_##name, \
.pc_decode = nlmsvc_decode_##xargt, \
.pc_encode = nlmsvc_encode_##xrest, \
.pc_release = NULL, \
.pc_argsize = sizeof(struct nlm_##argt), \
.pc_ressize = sizeof(struct nlm_##rest), \
.pc_xdrressize = respsize, \
}
#define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */
#define St 1 /* status */
#define No (1+1024/4) /* Net Obj */
#define Rg 2 /* range - offset + size */
const struct svc_procedure nlmsvc_procedures[] = {
PROC(null, void, void, void, void, 1),
PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg),
PROC(lock, lockargs, res, args, res, Ck+St),
PROC(cancel, cancargs, res, args, res, Ck+St),
PROC(unlock, unlockargs, res, args, res, Ck+St),
PROC(granted, testargs, res, args, res, Ck+St),
PROC(test_msg, testargs, norep, args, void, 1),
PROC(lock_msg, lockargs, norep, args, void, 1),
PROC(cancel_msg, cancargs, norep, args, void, 1),
PROC(unlock_msg, unlockargs, norep, args, void, 1),
PROC(granted_msg, testargs, norep, args, void, 1),
PROC(test_res, testres, norep, res, void, 1),
PROC(lock_res, lockres, norep, res, void, 1),
PROC(cancel_res, cancelres, norep, res, void, 1),
PROC(unlock_res, unlockres, norep, res, void, 1),
PROC(granted_res, res, norep, res, void, 1),
/* statd callback */
PROC(sm_notify, reboot, void, reboot, void, 1),
PROC(none, void, void, void, void, 1),
PROC(none, void, void, void, void, 1),
PROC(none, void, void, void, void, 1),
PROC(share, shareargs, shareres, args, res, Ck+St+1),
PROC(unshare, shareargs, shareres, args, res, Ck+St+1),
PROC(nm_lock, lockargs, res, args, res, Ck+St),
PROC(free_all, notify, void, args, void, 0),
const struct svc_procedure nlmsvc_procedures[24] = {
[NLMPROC_NULL] = {
.pc_func = nlmsvc_proc_null,
.pc_decode = nlmsvc_decode_void,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_void),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_TEST] = {
.pc_func = nlmsvc_proc_test,
.pc_decode = nlmsvc_decode_testargs,
.pc_encode = nlmsvc_encode_testres,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St+2+No+Rg,
},
[NLMPROC_LOCK] = {
.pc_func = nlmsvc_proc_lock,
.pc_decode = nlmsvc_decode_lockargs,
.pc_encode = nlmsvc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_CANCEL] = {
.pc_func = nlmsvc_proc_cancel,
.pc_decode = nlmsvc_decode_cancargs,
.pc_encode = nlmsvc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_UNLOCK] = {
.pc_func = nlmsvc_proc_unlock,
.pc_decode = nlmsvc_decode_unlockargs,
.pc_encode = nlmsvc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_GRANTED] = {
.pc_func = nlmsvc_proc_granted,
.pc_decode = nlmsvc_decode_testargs,
.pc_encode = nlmsvc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_TEST_MSG] = {
.pc_func = nlmsvc_proc_test_msg,
.pc_decode = nlmsvc_decode_testargs,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_LOCK_MSG] = {
.pc_func = nlmsvc_proc_lock_msg,
.pc_decode = nlmsvc_decode_lockargs,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_CANCEL_MSG] = {
.pc_func = nlmsvc_proc_cancel_msg,
.pc_decode = nlmsvc_decode_cancargs,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_UNLOCK_MSG] = {
.pc_func = nlmsvc_proc_unlock_msg,
.pc_decode = nlmsvc_decode_unlockargs,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_GRANTED_MSG] = {
.pc_func = nlmsvc_proc_granted_msg,
.pc_decode = nlmsvc_decode_testargs,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_TEST_RES] = {
.pc_func = nlmsvc_proc_null,
.pc_decode = nlmsvc_decode_void,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_LOCK_RES] = {
.pc_func = nlmsvc_proc_null,
.pc_decode = nlmsvc_decode_void,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_CANCEL_RES] = {
.pc_func = nlmsvc_proc_null,
.pc_decode = nlmsvc_decode_void,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_UNLOCK_RES] = {
.pc_func = nlmsvc_proc_null,
.pc_decode = nlmsvc_decode_void,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_GRANTED_RES] = {
.pc_func = nlmsvc_proc_granted_res,
.pc_decode = nlmsvc_decode_res,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_res),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_NSM_NOTIFY] = {
.pc_func = nlmsvc_proc_sm_notify,
.pc_decode = nlmsvc_decode_reboot,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_reboot),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[17] = {
.pc_func = nlmsvc_proc_unused,
.pc_decode = nlmsvc_decode_void,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_void),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[18] = {
.pc_func = nlmsvc_proc_unused,
.pc_decode = nlmsvc_decode_void,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_void),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[19] = {
.pc_func = nlmsvc_proc_unused,
.pc_decode = nlmsvc_decode_void,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_void),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = St,
},
[NLMPROC_SHARE] = {
.pc_func = nlmsvc_proc_share,
.pc_decode = nlmsvc_decode_shareargs,
.pc_encode = nlmsvc_encode_shareres,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St+1,
},
[NLMPROC_UNSHARE] = {
.pc_func = nlmsvc_proc_unshare,
.pc_decode = nlmsvc_decode_shareargs,
.pc_encode = nlmsvc_encode_shareres,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St+1,
},
[NLMPROC_NM_LOCK] = {
.pc_func = nlmsvc_proc_nm_lock,
.pc_decode = nlmsvc_decode_lockargs,
.pc_encode = nlmsvc_encode_res,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_res),
.pc_xdrressize = Ck+St,
},
[NLMPROC_FREE_ALL] = {
.pc_func = nlmsvc_proc_free_all,
.pc_decode = nlmsvc_decode_notify,
.pc_encode = nlmsvc_encode_void,
.pc_argsize = sizeof(struct nlm_args),
.pc_ressize = sizeof(struct nlm_void),
.pc_xdrressize = 0,
},
};
......@@ -9,6 +9,7 @@
#include <linux/falloc.h>
#include <linux/mount.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_ssc.h>
#include "delegation.h"
#include "internal.h"
#include "iostat.h"
......@@ -315,9 +316,8 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
static int read_name_gen = 1;
#define SSC_READ_NAME_BODY "ssc_read_%d"
struct file *
nfs42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh,
nfs4_stateid *stateid)
static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt,
struct nfs_fh *src_fh, nfs4_stateid *stateid)
{
struct nfs_fattr fattr;
struct file *filep, *res;
......@@ -399,14 +399,40 @@ nfs42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh,
fput(filep);
goto out_free_name;
}
EXPORT_SYMBOL_GPL(nfs42_ssc_open);
void nfs42_ssc_close(struct file *filep)
static void __nfs42_ssc_close(struct file *filep)
{
struct nfs_open_context *ctx = nfs_file_open_context(filep);
ctx->state->flags = 0;
}
EXPORT_SYMBOL_GPL(nfs42_ssc_close);
static const struct nfs4_ssc_client_ops nfs4_ssc_clnt_ops_tbl = {
.sco_open = __nfs42_ssc_open,
.sco_close = __nfs42_ssc_close,
};
/**
* nfs42_ssc_register_ops - Wrapper to register NFS_V4 ops in nfs_common
*
* Return values:
* None
*/
void nfs42_ssc_register_ops(void)
{
nfs42_ssc_register(&nfs4_ssc_clnt_ops_tbl);
}
/**
* nfs42_ssc_unregister_ops - wrapper to un-register NFS_V4 ops in nfs_common
*
* Return values:
* None.
*/
void nfs42_ssc_unregister_ops(void)
{
nfs42_ssc_unregister(&nfs4_ssc_clnt_ops_tbl);
}
#endif /* CONFIG_NFS_V4_2 */
const struct file_operations nfs4_file_operations = {
......
......@@ -7,6 +7,7 @@
#include <linux/mount.h>
#include <linux/nfs4_mount.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_ssc.h>
#include "delegation.h"
#include "internal.h"
#include "nfs4_fs.h"
......@@ -279,6 +280,9 @@ static int __init init_nfs_v4(void)
if (err)
goto out2;
#ifdef CONFIG_NFS_V4_2
nfs42_ssc_register_ops();
#endif
register_nfs_version(&nfs_v4);
return 0;
out2:
......@@ -297,6 +301,7 @@ static void __exit exit_nfs_v4(void)
unregister_nfs_version(&nfs_v4);
#ifdef CONFIG_NFS_V4_2
nfs4_xattr_cache_exit();
nfs42_ssc_unregister_ops();
#endif
nfs4_unregister_sysctl();
nfs_idmap_quit();
......
......@@ -57,6 +57,7 @@
#include <linux/rcupdate.h>
#include <linux/uaccess.h>
#include <linux/nfs_ssc.h>
#include "nfs4_fs.h"
#include "callback.h"
......@@ -85,6 +86,10 @@ const struct super_operations nfs_sops = {
};
EXPORT_SYMBOL_GPL(nfs_sops);
static const struct nfs_ssc_client_ops nfs_ssc_clnt_ops_tbl = {
.sco_sb_deactive = nfs_sb_deactive,
};
#if IS_ENABLED(CONFIG_NFS_V4)
static int __init register_nfs4_fs(void)
{
......@@ -106,6 +111,16 @@ static void unregister_nfs4_fs(void)
}
#endif
static void nfs_ssc_register_ops(void)
{
nfs_ssc_register(&nfs_ssc_clnt_ops_tbl);
}
static void nfs_ssc_unregister_ops(void)
{
nfs_ssc_unregister(&nfs_ssc_clnt_ops_tbl);
}
static struct shrinker acl_shrinker = {
.count_objects = nfs_access_cache_count,
.scan_objects = nfs_access_cache_scan,
......@@ -133,6 +148,7 @@ int __init register_nfs_fs(void)
ret = register_shrinker(&acl_shrinker);
if (ret < 0)
goto error_3;
nfs_ssc_register_ops();
return 0;
error_3:
nfs_unregister_sysctl();
......@@ -152,6 +168,7 @@ void __exit unregister_nfs_fs(void)
unregister_shrinker(&acl_shrinker);
nfs_unregister_sysctl();
unregister_nfs4_fs();
nfs_ssc_unregister_ops();
unregister_filesystem(&nfs_fs_type);
}
......
......@@ -7,3 +7,4 @@ obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o
nfs_acl-objs := nfsacl.o
obj-$(CONFIG_GRACE_PERIOD) += grace.o
obj-$(CONFIG_GRACE_PERIOD) += nfs_ssc.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* fs/nfs_common/nfs_ssc_comm.c
*
* Helper for knfsd's SSC to access ops in NFS client modules
*
* Author: Dai Ngo <dai.ngo@oracle.com>
*
* Copyright (c) 2020, Oracle and/or its affiliates.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/nfs_ssc.h>
#include "../nfs/nfs4_fs.h"
MODULE_LICENSE("GPL");
struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl;
EXPORT_SYMBOL_GPL(nfs_ssc_client_tbl);
#ifdef CONFIG_NFS_V4_2
/**
* nfs42_ssc_register - install the NFS_V4 client ops in the nfs_ssc_client_tbl
* @ops: NFS_V4 ops to be installed
*
* Return values:
* None
*/
void nfs42_ssc_register(const struct nfs4_ssc_client_ops *ops)
{
nfs_ssc_client_tbl.ssc_nfs4_ops = ops;
}
EXPORT_SYMBOL_GPL(nfs42_ssc_register);
/**
* nfs42_ssc_unregister - uninstall the NFS_V4 client ops from
* the nfs_ssc_client_tbl
* @ops: ops to be uninstalled
*
* Return values:
* None
*/
void nfs42_ssc_unregister(const struct nfs4_ssc_client_ops *ops)
{
if (nfs_ssc_client_tbl.ssc_nfs4_ops != ops)
return;
nfs_ssc_client_tbl.ssc_nfs4_ops = NULL;
}
EXPORT_SYMBOL_GPL(nfs42_ssc_unregister);
#endif /* CONFIG_NFS_V4_2 */
#ifdef CONFIG_NFS_V4_2
/**
* nfs_ssc_register - install the NFS_FS client ops in the nfs_ssc_client_tbl
* @ops: NFS_FS ops to be installed
*
* Return values:
* None
*/
void nfs_ssc_register(const struct nfs_ssc_client_ops *ops)
{
nfs_ssc_client_tbl.ssc_nfs_ops = ops;
}
EXPORT_SYMBOL_GPL(nfs_ssc_register);
/**
* nfs_ssc_unregister - uninstall the NFS_FS client ops from
* the nfs_ssc_client_tbl
* @ops: ops to be uninstalled
*
* Return values:
* None
*/
void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops)
{
if (nfs_ssc_client_tbl.ssc_nfs_ops != ops)
return;
nfs_ssc_client_tbl.ssc_nfs_ops = NULL;
}
EXPORT_SYMBOL_GPL(nfs_ssc_unregister);
#else
void nfs_ssc_register(const struct nfs_ssc_client_ops *ops)
{
}
EXPORT_SYMBOL_GPL(nfs_ssc_register);
void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops)
{
}
EXPORT_SYMBOL_GPL(nfs_ssc_unregister);
#endif /* CONFIG_NFS_V4_2 */
......@@ -136,7 +136,7 @@ config NFSD_FLEXFILELAYOUT
config NFSD_V4_2_INTER_SSC
bool "NFSv4.2 inter server to server COPY"
depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2 && NFS_FS=y
depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2
help
This option enables support for NFSv4.2 inter server to
server copy where the destination server calls the NFSv4.2
......@@ -156,13 +156,3 @@ config NFSD_V4_SECURITY_LABEL
If you do not wish to enable fine-grained security labels SELinux or
Smack policies on NFSv4 files, say N.
config NFSD_FAULT_INJECTION
bool "NFS server manual fault injection"
depends on NFSD_V4 && DEBUG_KERNEL && DEBUG_FS && BROKEN
help
This option enables support for manually injecting faults
into the NFS server. This is intended to be used for
testing error recovery on the NFS client.
If unsure, say N.
......@@ -13,7 +13,6 @@ nfsd-y += trace.o
nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
export.o auth.o lockd.o nfscache.o nfsxdr.o \
stats.o filecache.o
nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o
nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
......
......@@ -1002,7 +1002,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
if (nfsd4_spo_must_allow(rqstp))
return 0;
return nfserr_wrongsec;
return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
}
/*
......
......@@ -889,7 +889,7 @@ nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head,
nf_node, lockdep_is_held(&nfsd_file_hashtbl[hashval].nfb_lock)) {
if ((need & nf->nf_may) != need)
if (nf->nf_may != need)
continue;
if (nf->nf_inode != inode)
continue;
......
......@@ -14,7 +14,6 @@
#include "vfs.h"
#define NFSDDBG_FACILITY NFSDDBG_PROC
#define RETURN_STATUS(st) { resp->status = (st); return (st); }
/*
* NULL call.
......@@ -22,7 +21,7 @@
static __be32
nfsacld_proc_null(struct svc_rqst *rqstp)
{
return nfs_ok;
return rpc_success;
}
/*
......@@ -35,24 +34,25 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
struct posix_acl *acl;
struct inode *inode;
svc_fh *fh;
__be32 nfserr = 0;
dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
fh = fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
if (nfserr)
RETURN_STATUS(nfserr);
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
if (resp->status != nfs_ok)
goto out;
inode = d_inode(fh->fh_dentry);
if (argp->mask & ~NFS_ACL_MASK)
RETURN_STATUS(nfserr_inval);
if (argp->mask & ~NFS_ACL_MASK) {
resp->status = nfserr_inval;
goto out;
}
resp->mask = argp->mask;
nfserr = fh_getattr(fh, &resp->stat);
if (nfserr)
RETURN_STATUS(nfserr);
resp->status = fh_getattr(fh, &resp->stat);
if (resp->status != nfs_ok)
goto out;
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
acl = get_acl(inode, ACL_TYPE_ACCESS);
......@@ -61,7 +61,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
}
if (IS_ERR(acl)) {
nfserr = nfserrno(PTR_ERR(acl));
resp->status = nfserrno(PTR_ERR(acl));
goto fail;
}
resp->acl_access = acl;
......@@ -71,19 +71,20 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
of a non-directory! */
acl = get_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(acl)) {
nfserr = nfserrno(PTR_ERR(acl));
resp->status = nfserrno(PTR_ERR(acl));
goto fail;
}
resp->acl_default = acl;
}
/* resp->acl_{access,default} are released in nfssvc_release_getacl. */
RETURN_STATUS(0);
out:
return rpc_success;
fail:
posix_acl_release(resp->acl_access);
posix_acl_release(resp->acl_default);
RETURN_STATUS(nfserr);
goto out;
}
/*
......@@ -95,14 +96,13 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
struct nfsd_attrstat *resp = rqstp->rq_resp;
struct inode *inode;
svc_fh *fh;
__be32 nfserr = 0;
int error;
dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
fh = fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
if (nfserr)
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
if (resp->status != nfs_ok)
goto out;
inode = d_inode(fh->fh_dentry);
......@@ -124,19 +124,20 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
fh_drop_write(fh);
nfserr = fh_getattr(fh, &resp->stat);
resp->status = fh_getattr(fh, &resp->stat);
out:
/* argp->acl_{access,default} may have been allocated in
nfssvc_decode_setaclargs. */
posix_acl_release(argp->acl_access);
posix_acl_release(argp->acl_default);
return nfserr;
return rpc_success;
out_drop_lock:
fh_unlock(fh);
fh_drop_write(fh);
out_errno:
nfserr = nfserrno(error);
resp->status = nfserrno(error);
goto out;
}
......@@ -147,15 +148,16 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp)
{
struct nfsd_fhandle *argp = rqstp->rq_argp;
struct nfsd_attrstat *resp = rqstp->rq_resp;
__be32 nfserr;
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
if (nfserr)
return nfserr;
nfserr = fh_getattr(&resp->fh, &resp->stat);
return nfserr;
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
if (resp->status != nfs_ok)
goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
return rpc_success;
}
/*
......@@ -165,7 +167,6 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
{
struct nfsd3_accessargs *argp = rqstp->rq_argp;
struct nfsd3_accessres *resp = rqstp->rq_resp;
__be32 nfserr;
dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
SVCFH_fmt(&argp->fh),
......@@ -173,16 +174,22 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
fh_copy(&resp->fh, &argp->fh);
resp->access = argp->access;
nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
if (nfserr)
return nfserr;
nfserr = fh_getattr(&resp->fh, &resp->stat);
return nfserr;
resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
if (resp->status != nfs_ok)
goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
return rpc_success;
}
/*
* XDR decode functions
*/
static int nfsaclsvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
{
return 1;
}
static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_getaclargs *argp = rqstp->rq_argp;
......@@ -268,6 +275,10 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
int n;
int w;
*p++ = resp->status;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
/*
* Since this is version 2, the check for nfserr in
* nfsd_dispatch actually ensures the following cannot happen.
......@@ -307,7 +318,12 @@ static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd_attrstat *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status != nfs_ok)
goto out;
p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
out:
return xdr_ressize_check(rqstp, p);
}
......@@ -316,8 +332,13 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_accessres *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status != nfs_ok)
goto out;
p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
*p++ = htonl(resp->access);
out:
return xdr_ressize_check(rqstp, p);
}
......@@ -347,36 +368,63 @@ static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
fh_put(&resp->fh);
}
#define nfsaclsvc_decode_voidargs NULL
#define nfsaclsvc_release_void NULL
#define nfsd3_fhandleargs nfsd_fhandle
#define nfsd3_attrstatres nfsd_attrstat
#define nfsd3_voidres nfsd3_voidargs
struct nfsd3_voidargs { int dummy; };
#define PROC(name, argt, rest, relt, cache, respsize) \
{ \
.pc_func = nfsacld_proc_##name, \
.pc_decode = nfsaclsvc_decode_##argt##args, \
.pc_encode = nfsaclsvc_encode_##rest##res, \
.pc_release = nfsaclsvc_release_##relt, \
.pc_argsize = sizeof(struct nfsd3_##argt##args), \
.pc_ressize = sizeof(struct nfsd3_##rest##res), \
.pc_cachetype = cache, \
.pc_xdrressize = respsize, \
}
#define ST 1 /* status*/
#define AT 21 /* attributes */
#define pAT (1+AT) /* post attributes - conditional */
#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
static const struct svc_procedure nfsd_acl_procedures2[] = {
PROC(null, void, void, void, RC_NOCACHE, ST),
PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
PROC(setacl, setacl, attrstat, attrstat, RC_NOCACHE, ST+AT),
PROC(getattr, fhandle, attrstat, attrstat, RC_NOCACHE, ST+AT),
PROC(access, access, access, access, RC_NOCACHE, ST+AT+1),
static const struct svc_procedure nfsd_acl_procedures2[5] = {
[ACLPROC2_NULL] = {
.pc_func = nfsacld_proc_null,
.pc_decode = nfsaclsvc_decode_voidarg,
.pc_encode = nfsaclsvc_encode_voidres,
.pc_argsize = sizeof(struct nfsd3_voidargs),
.pc_ressize = sizeof(struct nfsd3_voidargs),
.pc_cachetype = RC_NOCACHE,
.pc_xdrressize = ST,
},
[ACLPROC2_GETACL] = {
.pc_func = nfsacld_proc_getacl,
.pc_decode = nfsaclsvc_decode_getaclargs,
.pc_encode = nfsaclsvc_encode_getaclres,
.pc_release = nfsaclsvc_release_getacl,
.pc_argsize = sizeof(struct nfsd3_getaclargs),
.pc_ressize = sizeof(struct nfsd3_getaclres),
.pc_cachetype = RC_NOCACHE,
.pc_xdrressize = ST+1+2*(1+ACL),
},
[ACLPROC2_SETACL] = {
.pc_func = nfsacld_proc_setacl,
.pc_decode = nfsaclsvc_decode_setaclargs,
.pc_encode = nfsaclsvc_encode_attrstatres,
.pc_release = nfsaclsvc_release_attrstat,
.pc_argsize = sizeof(struct nfsd3_setaclargs),
.pc_ressize = sizeof(struct nfsd_attrstat),
.pc_cachetype = RC_NOCACHE,
.pc_xdrressize = ST+AT,
},
[ACLPROC2_GETATTR] = {
.pc_func = nfsacld_proc_getattr,
.pc_decode = nfsaclsvc_decode_fhandleargs,
.pc_encode = nfsaclsvc_encode_attrstatres,
.pc_release = nfsaclsvc_release_attrstat,
.pc_argsize = sizeof(struct nfsd_fhandle),
.pc_ressize = sizeof(struct nfsd_attrstat),
.pc_cachetype = RC_NOCACHE,
.pc_xdrressize = ST+AT,
},
[ACLPROC2_ACCESS] = {
.pc_func = nfsacld_proc_access,
.pc_decode = nfsaclsvc_decode_accessargs,
.pc_encode = nfsaclsvc_encode_accessres,
.pc_release = nfsaclsvc_release_access,
.pc_argsize = sizeof(struct nfsd3_accessargs),
.pc_ressize = sizeof(struct nfsd3_accessres),
.pc_cachetype = RC_NOCACHE,
.pc_xdrressize = ST+AT+1,
},
};
static unsigned int nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)];
......
......@@ -13,15 +13,13 @@
#include "xdr3.h"
#include "vfs.h"
#define RETURN_STATUS(st) { resp->status = (st); return (st); }
/*
* NULL call.
*/
static __be32
nfsd3_proc_null(struct svc_rqst *rqstp)
{
return nfs_ok;
return rpc_success;
}
/*
......@@ -34,17 +32,18 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
struct posix_acl *acl;
struct inode *inode;
svc_fh *fh;
__be32 nfserr = 0;
fh = fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
if (nfserr)
RETURN_STATUS(nfserr);
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
if (resp->status != nfs_ok)
goto out;
inode = d_inode(fh->fh_dentry);
if (argp->mask & ~NFS_ACL_MASK)
RETURN_STATUS(nfserr_inval);
if (argp->mask & ~NFS_ACL_MASK) {
resp->status = nfserr_inval;
goto out;
}
resp->mask = argp->mask;
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
......@@ -54,7 +53,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
}
if (IS_ERR(acl)) {
nfserr = nfserrno(PTR_ERR(acl));
resp->status = nfserrno(PTR_ERR(acl));
goto fail;
}
resp->acl_access = acl;
......@@ -64,19 +63,20 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
of a non-directory! */
acl = get_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(acl)) {
nfserr = nfserrno(PTR_ERR(acl));
resp->status = nfserrno(PTR_ERR(acl));
goto fail;
}
resp->acl_default = acl;
}
/* resp->acl_{access,default} are released in nfs3svc_release_getacl. */
RETURN_STATUS(0);
out:
return rpc_success;
fail:
posix_acl_release(resp->acl_access);
posix_acl_release(resp->acl_default);
RETURN_STATUS(nfserr);
goto out;
}
/*
......@@ -88,12 +88,11 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
struct nfsd3_attrstat *resp = rqstp->rq_resp;
struct inode *inode;
svc_fh *fh;
__be32 nfserr = 0;
int error;
fh = fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
if (nfserr)
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
if (resp->status != nfs_ok)
goto out;
inode = d_inode(fh->fh_dentry);
......@@ -113,13 +112,13 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
fh_unlock(fh);
fh_drop_write(fh);
out_errno:
nfserr = nfserrno(error);
resp->status = nfserrno(error);
out:
/* argp->acl_{access,default} may have been allocated in
nfs3svc_decode_setaclargs. */
posix_acl_release(argp->acl_access);
posix_acl_release(argp->acl_default);
RETURN_STATUS(nfserr);
return rpc_success;
}
/*
......@@ -174,6 +173,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
struct nfsd3_getaclres *resp = rqstp->rq_resp;
struct dentry *dentry = resp->fh.fh_dentry;
*p++ = resp->status;
p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0 && dentry && d_really_is_positive(dentry)) {
struct inode *inode = d_inode(dentry);
......@@ -218,8 +218,8 @@ static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_attrstat *resp = rqstp->rq_resp;
*p++ = resp->status;
p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
return xdr_ressize_check(rqstp, p);
}
......@@ -235,33 +235,43 @@ static void nfs3svc_release_getacl(struct svc_rqst *rqstp)
posix_acl_release(resp->acl_default);
}
#define nfs3svc_decode_voidargs NULL
#define nfs3svc_release_void NULL
#define nfsd3_setaclres nfsd3_attrstat
#define nfsd3_voidres nfsd3_voidargs
struct nfsd3_voidargs { int dummy; };
#define PROC(name, argt, rest, relt, cache, respsize) \
{ \
.pc_func = nfsd3_proc_##name, \
.pc_decode = nfs3svc_decode_##argt##args, \
.pc_encode = nfs3svc_encode_##rest##res, \
.pc_release = nfs3svc_release_##relt, \
.pc_argsize = sizeof(struct nfsd3_##argt##args), \
.pc_ressize = sizeof(struct nfsd3_##rest##res), \
.pc_cachetype = cache, \
.pc_xdrressize = respsize, \
}
#define ST 1 /* status*/
#define AT 21 /* attributes */
#define pAT (1+AT) /* post attributes - conditional */
#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
static const struct svc_procedure nfsd_acl_procedures3[] = {
PROC(null, void, void, void, RC_NOCACHE, ST),
PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT),
static const struct svc_procedure nfsd_acl_procedures3[3] = {
[ACLPROC3_NULL] = {
.pc_func = nfsd3_proc_null,
.pc_decode = nfs3svc_decode_voidarg,
.pc_encode = nfs3svc_encode_voidres,
.pc_argsize = sizeof(struct nfsd3_voidargs),
.pc_ressize = sizeof(struct nfsd3_voidargs),
.pc_cachetype = RC_NOCACHE,
.pc_xdrressize = ST,
},
[ACLPROC3_GETACL] = {
.pc_func = nfsd3_proc_getacl,
.pc_decode = nfs3svc_decode_getaclargs,
.pc_encode = nfs3svc_encode_getaclres,
.pc_release = nfs3svc_release_getacl,
.pc_argsize = sizeof(struct nfsd3_getaclargs),
.pc_ressize = sizeof(struct nfsd3_getaclres),
.pc_cachetype = RC_NOCACHE,
.pc_xdrressize = ST+1+2*(1+ACL),
},
[ACLPROC3_SETACL] = {
.pc_func = nfsd3_proc_setacl,
.pc_decode = nfs3svc_decode_setaclargs,
.pc_encode = nfs3svc_encode_setaclres,
.pc_release = nfs3svc_release_fhandle,
.pc_argsize = sizeof(struct nfsd3_setaclargs),
.pc_ressize = sizeof(struct nfsd3_attrstat),
.pc_cachetype = RC_NOCACHE,
.pc_xdrressize = ST+pAT,
},
};
static unsigned int nfsd_acl_count3[ARRAY_SIZE(nfsd_acl_procedures3)];
......
This diff is collapsed.
......@@ -304,6 +304,12 @@ void fill_post_wcc(struct svc_fh *fhp)
/*
* XDR decode functions
*/
int
nfs3svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
{
return 1;
}
int
nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p)
{
......@@ -635,10 +641,7 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p)
/*
* XDR encode functions
*/
/*
* There must be an encoding function for void results so svc_process
* will work properly.
*/
int
nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p)
{
......@@ -651,6 +654,7 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_attrstat *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status == 0) {
lease_get_mtime(d_inode(resp->fh.fh_dentry),
&resp->stat.mtime);
......@@ -665,6 +669,7 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_attrstat *resp = rqstp->rq_resp;
*p++ = resp->status;
p = encode_wcc_data(rqstp, p, &resp->fh);
return xdr_ressize_check(rqstp, p);
}
......@@ -675,6 +680,7 @@ nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_diropres *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status == 0) {
p = encode_fh(p, &resp->fh);
p = encode_post_op_attr(rqstp, p, &resp->fh);
......@@ -689,6 +695,7 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_accessres *resp = rqstp->rq_resp;
*p++ = resp->status;
p = encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0)
*p++ = htonl(resp->access);
......@@ -701,6 +708,7 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_readlinkres *resp = rqstp->rq_resp;
*p++ = resp->status;
p = encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0) {
*p++ = htonl(resp->len);
......@@ -723,6 +731,7 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_readres *resp = rqstp->rq_resp;
*p++ = resp->status;
p = encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0) {
*p++ = htonl(resp->count);
......@@ -748,6 +757,7 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_writeres *resp = rqstp->rq_resp;
*p++ = resp->status;
p = encode_wcc_data(rqstp, p, &resp->fh);
if (resp->status == 0) {
*p++ = htonl(resp->count);
......@@ -764,6 +774,7 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_diropres *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status == 0) {
*p++ = xdr_one;
p = encode_fh(p, &resp->fh);
......@@ -779,6 +790,7 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_renameres *resp = rqstp->rq_resp;
*p++ = resp->status;
p = encode_wcc_data(rqstp, p, &resp->ffh);
p = encode_wcc_data(rqstp, p, &resp->tfh);
return xdr_ressize_check(rqstp, p);
......@@ -790,6 +802,7 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_linkres *resp = rqstp->rq_resp;
*p++ = resp->status;
p = encode_post_op_attr(rqstp, p, &resp->fh);
p = encode_wcc_data(rqstp, p, &resp->tfh);
return xdr_ressize_check(rqstp, p);
......@@ -801,6 +814,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_readdirres *resp = rqstp->rq_resp;
*p++ = resp->status;
p = encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0) {
......@@ -1053,6 +1067,7 @@ nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p)
struct kstatfs *s = &resp->stats;
u64 bs = s->f_bsize;
*p++ = resp->status;
*p++ = xdr_zero; /* no post_op_attr */
if (resp->status == 0) {
......@@ -1073,6 +1088,7 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_fsinfores *resp = rqstp->rq_resp;
*p++ = resp->status;
*p++ = xdr_zero; /* no post_op_attr */
if (resp->status == 0) {
......@@ -1118,6 +1134,7 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_commitres *resp = rqstp->rq_resp;
*p++ = resp->status;
p = encode_wcc_data(rqstp, p, &resp->fh);
/* Write verifier */
if (resp->status == 0) {
......
......@@ -38,6 +38,7 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/sunrpc/addr.h>
#include <linux/nfs_ssc.h>
#include "idmap.h"
#include "cache.h"
......@@ -1247,7 +1248,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
static void
nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
{
nfs_sb_deactive(ss_mnt->mnt_sb);
nfs_do_sb_deactive(ss_mnt->mnt_sb);
mntput(ss_mnt);
}
......@@ -2165,7 +2166,7 @@ nfsd4_removexattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
static __be32
nfsd4_proc_null(struct svc_rqst *rqstp)
{
return nfs_ok;
return rpc_success;
}
static inline void nfsd4_increment_op_stats(u32 opnum)
......@@ -2457,15 +2458,14 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
nfsd4_increment_op_stats(op->opnum);
}
cstate->status = status;
fh_put(current_fh);
fh_put(save_fh);
BUG_ON(cstate->replay_owner);
out:
cstate->status = status;
/* Reset deferral mechanism for RPC deferrals */
set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
dprintk("nfsv4 compound returned %d\n", ntohl(status));
return status;
return rpc_success;
}
#define op_encode_hdr_size (2)
......@@ -2591,6 +2591,20 @@ static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32);
}
static inline u32 nfsd4_read_plus_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
{
u32 maxcount = svc_max_payload(rqstp);
u32 rlen = min(op->u.read.rd_length, maxcount);
/*
* If we detect that the file changed during hole encoding, then we
* recover by encoding the remaining reply as data. This means we need
* to set aside enough room to encode two data segments.
*/
u32 seg_len = 2 * (1 + 2 + 1);
return (op_encode_hdr_size + 2 + seg_len + XDR_QUADLEN(rlen)) * sizeof(__be32);
}
static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
{
u32 maxcount = 0, rlen = 0;
......@@ -3163,6 +3177,13 @@ static const struct nfsd4_operation nfsd4_ops[] = {
.op_name = "OP_COPY",
.op_rsize_bop = nfsd4_copy_rsize,
},
[OP_READ_PLUS] = {
.op_func = nfsd4_read,
.op_release = nfsd4_read_release,
.op_name = "OP_READ_PLUS",
.op_rsize_bop = nfsd4_read_plus_rsize,
.op_get_currentstateid = nfsd4_get_readstateid,
},
[OP_SEEK] = {
.op_func = nfsd4_seek,
.op_name = "OP_SEEK",
......@@ -3231,7 +3252,7 @@ bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
if (!cstate->minorversion)
return false;
if (cstate->spo_must_allowed == true)
if (cstate->spo_must_allowed)
return true;
opiter = resp->opcnt;
......@@ -3279,6 +3300,7 @@ struct nfsd4_voidargs { int dummy; };
static const struct svc_procedure nfsd_procedures4[2] = {
[NFSPROC4_NULL] = {
.pc_func = nfsd4_proc_null,
.pc_decode = nfs4svc_decode_voidarg,
.pc_encode = nfs4svc_encode_voidres,
.pc_argsize = sizeof(struct nfsd4_voidargs),
.pc_ressize = sizeof(struct nfsd4_voidres),
......
This diff is collapsed.
......@@ -1855,7 +1855,7 @@ static __be32
nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
struct nfsd4_copy_notify *cn)
{
int status;
__be32 status;
status = nfsd4_decode_stateid(argp, &cn->cpn_src_stateid);
if (status)
......@@ -2173,7 +2173,7 @@ static const nfsd4_dec nfsd4_dec_ops[] = {
[OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status,
[OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status,
[OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_read,
[OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek,
[OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone,
......@@ -2261,7 +2261,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
*/
cachethis |= nfsd4_cache_this_op(op);
if (op->opnum == OP_READ) {
if (op->opnum == OP_READ || op->opnum == OP_READ_PLUS) {
readcount++;
readbytes += nfsd4_max_reply(argp->rqstp, op);
} else
......@@ -3814,36 +3814,14 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
{
struct xdr_stream *xdr = &resp->xdr;
u32 eof;
int v;
int starting_len = xdr->buf->len - 8;
long len;
int thislen;
__be32 nfserr;
__be32 tmp;
__be32 *p;
int pad;
/*
* svcrdma requires every READ payload to start somewhere
* in xdr->pages.
*/
if (xdr->iov == xdr->buf->head) {
xdr->iov = NULL;
xdr->end = xdr->p;
}
len = maxcount;
v = 0;
while (len) {
thislen = min_t(long, len, PAGE_SIZE);
p = xdr_reserve_space(xdr, thislen);
WARN_ON_ONCE(!p);
resp->rqstp->rq_vec[v].iov_base = p;
resp->rqstp->rq_vec[v].iov_len = thislen;
v++;
len -= thislen;
}
read->rd_vlen = v;
read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount);
if (read->rd_vlen < 0)
return nfserr_resource;
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
......@@ -4619,6 +4597,149 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
return nfserr_resource;
p = xdr_encode_hyper(p, os->count);
*p++ = cpu_to_be32(0);
return nfserr;
}
static __be32
nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
struct nfsd4_read *read,
unsigned long *maxcount, u32 *eof,
loff_t *pos)
{
struct xdr_stream *xdr = &resp->xdr;
struct file *file = read->rd_nf->nf_file;
int starting_len = xdr->buf->len;
loff_t hole_pos;
__be32 nfserr;
__be32 *p, tmp;
__be64 tmp64;
hole_pos = pos ? *pos : vfs_llseek(file, read->rd_offset, SEEK_HOLE);
if (hole_pos > read->rd_offset)
*maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset);
*maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len));
/* Content type, offset, byte count */
p = xdr_reserve_space(xdr, 4 + 8 + 4);
if (!p)
return nfserr_resource;
read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, *maxcount);
if (read->rd_vlen < 0)
return nfserr_resource;
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof);
if (nfserr)
return nfserr;
tmp = htonl(NFS4_CONTENT_DATA);
write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
tmp64 = cpu_to_be64(read->rd_offset);
write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8);
tmp = htonl(*maxcount);
write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4);
return nfs_ok;
}
static __be32
nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp,
struct nfsd4_read *read,
unsigned long *maxcount, u32 *eof)
{
struct file *file = read->rd_nf->nf_file;
loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA);
loff_t f_size = i_size_read(file_inode(file));
unsigned long count;
__be32 *p;
if (data_pos == -ENXIO)
data_pos = f_size;
else if (data_pos <= read->rd_offset || (data_pos < f_size && data_pos % PAGE_SIZE))
return nfsd4_encode_read_plus_data(resp, read, maxcount, eof, &f_size);
count = data_pos - read->rd_offset;
/* Content type, offset, byte count */
p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8);
if (!p)
return nfserr_resource;
*p++ = htonl(NFS4_CONTENT_HOLE);
p = xdr_encode_hyper(p, read->rd_offset);
p = xdr_encode_hyper(p, count);
*eof = (read->rd_offset + count) >= f_size;
*maxcount = min_t(unsigned long, count, *maxcount);
return nfs_ok;
}
static __be32
nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_read *read)
{
unsigned long maxcount, count;
struct xdr_stream *xdr = &resp->xdr;
struct file *file;
int starting_len = xdr->buf->len;
int last_segment = xdr->buf->len;
int segments = 0;
__be32 *p, tmp;
bool is_data;
loff_t pos;
u32 eof;
if (nfserr)
return nfserr;
file = read->rd_nf->nf_file;
/* eof flag, segment count */
p = xdr_reserve_space(xdr, 4 + 4);
if (!p)
return nfserr_resource;
xdr_commit_encode(xdr);
maxcount = svc_max_payload(resp->rqstp);
maxcount = min_t(unsigned long, maxcount,
(xdr->buf->buflen - xdr->buf->len));
maxcount = min_t(unsigned long, maxcount, read->rd_length);
count = maxcount;
eof = read->rd_offset >= i_size_read(file_inode(file));
if (eof)
goto out;
pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE);
is_data = pos > read->rd_offset;
while (count > 0 && !eof) {
maxcount = count;
if (is_data)
nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof,
segments == 0 ? &pos : NULL);
else
nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof);
if (nfserr)
goto out;
count -= maxcount;
read->rd_offset += maxcount;
is_data = !is_data;
last_segment = xdr->buf->len;
segments++;
}
out:
if (nfserr && segments == 0)
xdr_truncate_encode(xdr, starting_len);
else {
tmp = htonl(eof);
write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
tmp = htonl(segments);
write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
if (nfserr) {
xdr_truncate_encode(xdr, last_segment);
nfserr = nfs_ok;
}
}
return nfserr;
}
......@@ -4679,7 +4800,7 @@ nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
/*
* Encode kmalloc-ed buffer in to XDR stream.
*/
static int
static __be32
nfsd4_vbuf_to_stream(struct xdr_stream *xdr, char *buf, u32 buflen)
{
u32 cplen;
......@@ -4795,7 +4916,7 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
u32 xdrlen, offset;
u64 cookie;
char *sp;
__be32 status;
__be32 status, tmp;
__be32 *p;
u32 nuser;
......@@ -4828,7 +4949,7 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
slen = strlen(sp);
/*
* Check if this a user. attribute, skip it if not.
* Check if this is a "user." attribute, skip it if not.
*/
if (strncmp(sp, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
goto contloop;
......@@ -4859,7 +4980,7 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
goto out;
}
p = xdr_encode_opaque(p, sp, slen);
xdr_encode_opaque(p, sp, slen);
xdrleft -= xdrlen;
count++;
......@@ -4888,8 +5009,8 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
cookie = offset + count;
write_bytes_to_xdr_buf(xdr->buf, cookie_offset, &cookie, 8);
count = htonl(count);
write_bytes_to_xdr_buf(xdr->buf, count_offset, &count, 4);
tmp = cpu_to_be32(count);
write_bytes_to_xdr_buf(xdr->buf, count_offset, &tmp, 4);
out:
if (listxattrs->lsxa_len)
kvfree(listxattrs->lsxa_buf);
......@@ -4996,7 +5117,7 @@ static const nfsd4_enc nfsd4_enc_ops[] = {
[OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop,
[OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop,
[OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status,
[OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop,
[OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_read_plus,
[OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek,
[OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop,
[OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop,
......@@ -5156,6 +5277,12 @@ void nfsd4_release_compoundargs(struct svc_rqst *rqstp)
}
}
int
nfs4svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
{
return 1;
}
int
nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p)
{
......@@ -5183,15 +5310,14 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p)
int
nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p)
{
/*
* All that remains is to write the tag and operation count...
*/
struct nfsd4_compoundres *resp = rqstp->rq_resp;
struct xdr_buf *buf = resp->xdr.buf;
WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len +
buf->tail[0].iov_len);
*p = resp->cstate.status;
rqstp->rq_next_page = resp->xdr.page_ptr + 1;
p = resp->tagp;
......
......@@ -172,14 +172,10 @@ int nfsd_reply_cache_init(struct nfsd_net *nn)
if (status)
goto out_nomem;
nn->drc_hashtbl = kcalloc(hashsize,
sizeof(*nn->drc_hashtbl), GFP_KERNEL);
if (!nn->drc_hashtbl) {
nn->drc_hashtbl = vzalloc(array_size(hashsize,
sizeof(*nn->drc_hashtbl)));
nn->drc_hashtbl = kvzalloc(array_size(hashsize,
sizeof(*nn->drc_hashtbl)), GFP_KERNEL);
if (!nn->drc_hashtbl)
goto out_shrinker;
}
for (i = 0; i < hashsize; i++) {
INIT_LIST_HEAD(&nn->drc_hashtbl[i].lru_head);
......
......@@ -1534,7 +1534,6 @@ static int __init init_nfsd(void)
retval = nfsd4_init_pnfs();
if (retval)
goto out_free_slabs;
nfsd_fault_inject_init(); /* nfsd fault injection controls */
nfsd_stat_init(); /* Statistics */
retval = nfsd_drc_slab_create();
if (retval)
......@@ -1555,7 +1554,6 @@ static int __init init_nfsd(void)
nfsd_drc_slab_free();
out_free_stat:
nfsd_stat_shutdown();
nfsd_fault_inject_cleanup();
nfsd4_exit_pnfs();
out_free_slabs:
nfsd4_free_slabs();
......@@ -1575,7 +1573,6 @@ static void __exit exit_nfsd(void)
nfsd_lockd_shutdown();
nfsd4_free_slabs();
nfsd4_exit_pnfs();
nfsd_fault_inject_cleanup();
unregister_filesystem(&nfsd_fs_type);
unregister_cld_notifier();
unregister_pernet_subsys(&nfsd_net_ops);
......
This diff is collapsed.
......@@ -960,15 +960,6 @@ nfsd(void *vrqstp)
return 0;
}
static __be32 map_new_errors(u32 vers, __be32 nfserr)
{
if (nfserr == nfserr_jukebox && vers == 2)
return nfserr_dropit;
if (nfserr == nfserr_wrongsec && vers < 4)
return nfserr_acces;
return nfserr;
}
/*
* A write procedure can have a large argument, and a read procedure can
* have a large reply, but no NFSv2 or NFSv3 procedure has argument and
......@@ -1000,81 +991,86 @@ static bool nfs_request_too_big(struct svc_rqst *rqstp,
return rqstp->rq_arg.len > PAGE_SIZE;
}
int
nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
/**
* nfsd_dispatch - Process an NFS or NFSACL Request
* @rqstp: incoming request
* @statp: pointer to location of accept_stat field in RPC Reply buffer
*
* This RPC dispatcher integrates the NFS server's duplicate reply cache.
*
* Return values:
* %0: Processing complete; do not send a Reply
* %1: Processing complete; send Reply in rqstp->rq_res
*/
int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
{
const struct svc_procedure *proc;
__be32 nfserr;
__be32 *nfserrp;
const struct svc_procedure *proc = rqstp->rq_procinfo;
struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0];
__be32 *p;
dprintk("nfsd_dispatch: vers %d proc %d\n",
rqstp->rq_vers, rqstp->rq_proc);
proc = rqstp->rq_procinfo;
if (nfs_request_too_big(rqstp, proc)) {
dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers);
*statp = rpc_garbage_args;
return 1;
}
rqstp->rq_lease_breaker = NULL;
if (nfs_request_too_big(rqstp, proc))
goto out_too_large;
/*
* Give the xdr decoder a chance to change this if it wants
* (necessary in the NFSv4.0 compound case)
*/
rqstp->rq_cachetype = proc->pc_cachetype;
/* Decode arguments */
if (proc->pc_decode &&
!proc->pc_decode(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base)) {
dprintk("nfsd: failed to decode arguments!\n");
*statp = rpc_garbage_args;
return 1;
}
if (!proc->pc_decode(rqstp, argv->iov_base))
goto out_decode_err;
/* Check whether we have this call in the cache. */
switch (nfsd_cache_lookup(rqstp)) {
case RC_DROPIT:
return 0;
case RC_DOIT:
break;
case RC_REPLY:
return 1;
case RC_DOIT:;
/* do it */
goto out_cached_reply;
case RC_DROPIT:
goto out_dropit;
}
/* need to grab the location to store the status, as
* nfsv4 does some encoding while processing
/*
* Need to grab the location to store the status, as
* NFSv4 does some encoding while processing
*/
nfserrp = rqstp->rq_res.head[0].iov_base
+ rqstp->rq_res.head[0].iov_len;
rqstp->rq_res.head[0].iov_len += sizeof(__be32);
/* Now call the procedure handler, and encode NFS status. */
nfserr = proc->pc_func(rqstp);
nfserr = map_new_errors(rqstp->rq_vers, nfserr);
if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) {
p = resv->iov_base + resv->iov_len;
resv->iov_len += sizeof(__be32);
*statp = proc->pc_func(rqstp);
if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags))
goto out_update_drop;
if (!proc->pc_encode(rqstp, p))
goto out_encode_err;
nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1);
out_cached_reply:
return 1;
out_too_large:
dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers);
*statp = rpc_garbage_args;
return 1;
out_decode_err:
dprintk("nfsd: failed to decode arguments!\n");
*statp = rpc_garbage_args;
return 1;
out_update_drop:
dprintk("nfsd: Dropping request; may be revisited later\n");
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
out_dropit:
return 0;
}
if (rqstp->rq_proc != 0)
*nfserrp++ = nfserr;
/* Encode result.
* For NFSv2, additional info is never returned in case of an error.
*/
if (!(nfserr && rqstp->rq_vers == 2)) {
if (proc->pc_encode && !proc->pc_encode(rqstp, nfserrp)) {
/* Failed to encode result. Release cache entry */
out_encode_err:
dprintk("nfsd: failed to encode result!\n");
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
*statp = rpc_system_err;
return 1;
}
}
/* Store reply in cache. */
nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1);
return 1;
}
int nfsd_pool_stats_open(struct inode *inode, struct file *file)
......
......@@ -429,12 +429,25 @@ nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
return xdr_ressize_check(rqstp, p);
}
int
nfssvc_encode_stat(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd_stat *resp = rqstp->rq_resp;
*p++ = resp->status;
return xdr_ressize_check(rqstp, p);
}
int
nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd_attrstat *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status != nfs_ok)
goto out;
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
out:
return xdr_ressize_check(rqstp, p);
}
......@@ -443,8 +456,12 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd_diropres *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status != nfs_ok)
goto out;
p = encode_fh(p, &resp->fh);
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
out:
return xdr_ressize_check(rqstp, p);
}
......@@ -453,6 +470,10 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd_readlinkres *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
*p++ = htonl(resp->len);
xdr_ressize_check(rqstp, p);
rqstp->rq_res.page_len = resp->len;
......@@ -470,6 +491,10 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd_readres *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
*p++ = htonl(resp->count);
xdr_ressize_check(rqstp, p);
......@@ -490,6 +515,10 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd_readdirres *resp = rqstp->rq_resp;
*p++ = resp->status;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
xdr_ressize_check(rqstp, p);
p = resp->buffer;
*p++ = 0; /* no more entries */
......@@ -505,6 +534,10 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p)
struct nfsd_statfsres *resp = rqstp->rq_resp;
struct kstatfs *stat = &resp->stats;
*p++ = resp->status;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
*p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */
*p++ = htonl(stat->f_bsize);
*p++ = htonl(stat->f_blocks);
......@@ -561,10 +594,23 @@ nfssvc_encode_entry(void *ccdv, const char *name,
/*
* XDR release functions
*/
void
nfssvc_release_fhandle(struct svc_rqst *rqstp)
void nfssvc_release_attrstat(struct svc_rqst *rqstp)
{
struct nfsd_fhandle *resp = rqstp->rq_resp;
struct nfsd_attrstat *resp = rqstp->rq_resp;
fh_put(&resp->fh);
}
void nfssvc_release_diropres(struct svc_rqst *rqstp)
{
struct nfsd_diropres *resp = rqstp->rq_resp;
fh_put(&resp->fh);
}
void nfssvc_release_readres(struct svc_rqst *rqstp)
{
struct nfsd_readres *resp = rqstp->rq_resp;
fh_put(&resp->fh);
}
......@@ -693,31 +693,4 @@ extern void nfsd4_client_record_remove(struct nfs4_client *clp);
extern int nfsd4_client_record_check(struct nfs4_client *clp);
extern void nfsd4_record_grace_done(struct nfsd_net *nn);
/* nfs fault injection functions */
#ifdef CONFIG_NFSD_FAULT_INJECTION
void nfsd_fault_inject_init(void);
void nfsd_fault_inject_cleanup(void);
u64 nfsd_inject_print_clients(void);
u64 nfsd_inject_forget_client(struct sockaddr_storage *, size_t);
u64 nfsd_inject_forget_clients(u64);
u64 nfsd_inject_print_locks(void);
u64 nfsd_inject_forget_client_locks(struct sockaddr_storage *, size_t);
u64 nfsd_inject_forget_locks(u64);
u64 nfsd_inject_print_openowners(void);
u64 nfsd_inject_forget_client_openowners(struct sockaddr_storage *, size_t);
u64 nfsd_inject_forget_openowners(u64);
u64 nfsd_inject_print_delegations(void);
u64 nfsd_inject_forget_client_delegations(struct sockaddr_storage *, size_t);
u64 nfsd_inject_forget_delegations(u64);
u64 nfsd_inject_recall_client_delegations(struct sockaddr_storage *, size_t);
u64 nfsd_inject_recall_delegations(u64);
#else /* CONFIG_NFSD_FAULT_INJECTION */
static inline void nfsd_fault_inject_init(void) {}
static inline void nfsd_fault_inject_cleanup(void) {}
#endif /* CONFIG_NFSD_FAULT_INJECTION */
#endif /* NFSD4_STATE_H */
......@@ -289,8 +289,8 @@ DEFINE_STATEID_EVENT(layout_recall_done);
DEFINE_STATEID_EVENT(layout_recall_fail);
DEFINE_STATEID_EVENT(layout_recall_release);
DEFINE_STATEID_EVENT(deleg_open);
DEFINE_STATEID_EVENT(deleg_none);
DEFINE_STATEID_EVENT(open);
DEFINE_STATEID_EVENT(deleg_read);
DEFINE_STATEID_EVENT(deleg_break);
DEFINE_STATEID_EVENT(deleg_recall);
......
......@@ -2259,7 +2259,8 @@ nfsd_listxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char **bufp,
__be32
nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
{
int err, ret;
__be32 err;
int ret;
err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE);
if (err)
......@@ -2283,7 +2284,8 @@ __be32
nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,
void *buf, u32 len, u32 flags)
{
int err, ret;
__be32 err;
int ret;
err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE);
if (err)
......
......@@ -82,27 +82,37 @@ struct nfsd_readdirargs {
__be32 * buffer;
};
struct nfsd_stat {
__be32 status;
};
struct nfsd_attrstat {
__be32 status;
struct svc_fh fh;
struct kstat stat;
};
struct nfsd_diropres {
__be32 status;
struct svc_fh fh;
struct kstat stat;
};
struct nfsd_readlinkres {
__be32 status;
int len;
};
struct nfsd_readres {
__be32 status;
struct svc_fh fh;
unsigned long count;
struct kstat stat;
};
struct nfsd_readdirres {
__be32 status;
int count;
struct readdir_cd common;
......@@ -112,6 +122,7 @@ struct nfsd_readdirres {
};
struct nfsd_statfsres {
__be32 status;
struct kstatfs stats;
};
......@@ -146,6 +157,7 @@ int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *);
int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *);
int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *);
int nfssvc_encode_void(struct svc_rqst *, __be32 *);
int nfssvc_encode_stat(struct svc_rqst *, __be32 *);
int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *);
int nfssvc_encode_diropres(struct svc_rqst *, __be32 *);
int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *);
......@@ -156,7 +168,9 @@ int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *);
int nfssvc_encode_entry(void *, const char *name,
int namlen, loff_t offset, u64 ino, unsigned int);
void nfssvc_release_fhandle(struct svc_rqst *);
void nfssvc_release_attrstat(struct svc_rqst *rqstp);
void nfssvc_release_diropres(struct svc_rqst *rqstp);
void nfssvc_release_readres(struct svc_rqst *rqstp);
/* Helper functions for NFSv2 ACL code */
__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat);
......
......@@ -273,6 +273,7 @@ union nfsd3_xdrstore {
#define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore)
int nfs3svc_decode_voidarg(struct svc_rqst *, __be32 *);
int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *);
int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *);
int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *);
......
......@@ -781,6 +781,7 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp);
int nfs4svc_decode_voidarg(struct svc_rqst *, __be32 *);
int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *);
int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *);
int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *);
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* include/linux/nfs_ssc.h
*
* Author: Dai Ngo <dai.ngo@oracle.com>
*
* Copyright (c) 2020, Oracle and/or its affiliates.
*/
#include <linux/nfs_fs.h>
extern struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl;
/*
* NFS_V4
*/
struct nfs4_ssc_client_ops {
struct file *(*sco_open)(struct vfsmount *ss_mnt,
struct nfs_fh *src_fh, nfs4_stateid *stateid);
void (*sco_close)(struct file *filep);
};
/*
* NFS_FS
*/
struct nfs_ssc_client_ops {
void (*sco_sb_deactive)(struct super_block *sb);
};
struct nfs_ssc_client_ops_tbl {
const struct nfs4_ssc_client_ops *ssc_nfs4_ops;
const struct nfs_ssc_client_ops *ssc_nfs_ops;
};
extern void nfs42_ssc_register_ops(void);
extern void nfs42_ssc_unregister_ops(void);
extern void nfs42_ssc_register(const struct nfs4_ssc_client_ops *ops);
extern void nfs42_ssc_unregister(const struct nfs4_ssc_client_ops *ops);
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
static inline struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
struct nfs_fh *src_fh, nfs4_stateid *stateid)
{
if (nfs_ssc_client_tbl.ssc_nfs4_ops)
return (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_open)(ss_mnt, src_fh, stateid);
return ERR_PTR(-EIO);
}
static inline void nfs42_ssc_close(struct file *filep)
{
if (nfs_ssc_client_tbl.ssc_nfs4_ops)
(*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep);
}
#endif
/*
* NFS_FS
*/
extern void nfs_ssc_register(const struct nfs_ssc_client_ops *ops);
extern void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops);
static inline void nfs_do_sb_deactive(struct super_block *sb)
{
if (nfs_ssc_client_tbl.ssc_nfs_ops)
(*nfs_ssc_client_tbl.ssc_nfs_ops->sco_sb_deactive)(sb);
}
......@@ -234,6 +234,8 @@ typedef int (*kxdrdproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf,
__be32 *p, struct rpc_rqst *rqst);
extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
extern int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec,
size_t nbytes);
extern void xdr_commit_encode(struct xdr_stream *xdr);
extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len);
extern int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen);
......
......@@ -9,11 +9,13 @@
#define NFS_ACL_PROGRAM 100227
#define ACLPROC2_NULL 0
#define ACLPROC2_GETACL 1
#define ACLPROC2_SETACL 2
#define ACLPROC2_GETATTR 3
#define ACLPROC2_ACCESS 4
#define ACLPROC3_NULL 0
#define ACLPROC3_GETACL 1
#define ACLPROC3_SETACL 2
......
......@@ -1147,9 +1147,9 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp,
struct gssp_in_token *in_token)
{
struct kvec *argv = &rqstp->rq_arg.head[0];
unsigned int page_base, length;
int pages, i, res;
size_t inlen;
unsigned int length, pgto_offs, pgfrom_offs;
int pages, i, res, pgto, pgfrom;
size_t inlen, to_offs, from_offs;
res = gss_read_common_verf(gc, argv, authp, in_handle);
if (res)
......@@ -1177,17 +1177,24 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp,
memcpy(page_address(in_token->pages[0]), argv->iov_base, length);
inlen -= length;
i = 1;
page_base = rqstp->rq_arg.page_base;
to_offs = length;
from_offs = rqstp->rq_arg.page_base;
while (inlen) {
length = min_t(unsigned int, inlen, PAGE_SIZE);
memcpy(page_address(in_token->pages[i]),
page_address(rqstp->rq_arg.pages[i]) + page_base,
pgto = to_offs >> PAGE_SHIFT;
pgfrom = from_offs >> PAGE_SHIFT;
pgto_offs = to_offs & ~PAGE_MASK;
pgfrom_offs = from_offs & ~PAGE_MASK;
length = min_t(unsigned int, inlen,
min_t(unsigned int, PAGE_SIZE - pgto_offs,
PAGE_SIZE - pgfrom_offs));
memcpy(page_address(in_token->pages[pgto]) + pgto_offs,
page_address(rqstp->rq_arg.pages[pgfrom]) + pgfrom_offs,
length);
to_offs += length;
from_offs += length;
inlen -= length;
page_base = 0;
i++;
}
return 0;
}
......
......@@ -111,7 +111,7 @@ struct rpc_rqst *xprt_alloc_bc_req(struct rpc_xprt *xprt, gfp_t gfp_flags)
* by the backchannel. This function can be called multiple times
* when creating new sessions that use the same rpc_xprt. The
* preallocated buffers are added to the pool of resources used by
* the rpc_xprt. Anyone of these resources may be used used by an
* the rpc_xprt. Any one of these resources may be used by an
* incoming callback request. It's up to the higher levels in the
* stack to enforce that the maximum number of session slots is not
* being exceeded.
......
......@@ -498,16 +498,17 @@ static int cache_clean(void)
*/
static void do_cache_clean(struct work_struct *work)
{
int delay = 5;
if (cache_clean() == -1)
delay = round_jiffies_relative(30*HZ);
int delay;
if (list_empty(&cache_list))
delay = 0;
return;
if (cache_clean() == -1)
delay = round_jiffies_relative(30*HZ);
else
delay = 5;
if (delay)
queue_delayed_work(system_power_efficient_wq,
&cache_cleaner, delay);
queue_delayed_work(system_power_efficient_wq, &cache_cleaner, delay);
}
......@@ -908,7 +909,7 @@ static ssize_t cache_do_downcall(char *kaddr, const char __user *buf,
static ssize_t cache_slow_downcall(const char __user *buf,
size_t count, struct cache_detail *cd)
{
static char write_buf[8192]; /* protected by queue_io_mutex */
static char write_buf[32768]; /* protected by queue_io_mutex */
ssize_t ret = -EINVAL;
if (count >= sizeof(write_buf))
......@@ -1436,10 +1437,10 @@ static int c_show(struct seq_file *m, void *p)
cache_get(cp);
if (cache_check(cd, cp, NULL))
/* cache_check does a cache_put on failure */
seq_printf(m, "# ");
seq_puts(m, "# ");
else {
if (cache_is_expired(cd, cp))
seq_printf(m, "# ");
seq_puts(m, "# ");
cache_put(cp, cd);
}
......
......@@ -70,7 +70,13 @@ static int proc_do_xprt(struct ctl_table *table, int write,
return 0;
}
len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
return memory_read_from_buffer(buffer, *lenp, ppos, tmpbuf, len);
*lenp = memory_read_from_buffer(buffer, *lenp, ppos, tmpbuf, len);
if (*lenp < 0) {
*lenp = 0;
return -EINVAL;
}
return 0;
}
static int
......
......@@ -792,6 +792,51 @@ __be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
}
EXPORT_SYMBOL_GPL(xdr_reserve_space);
/**
* xdr_reserve_space_vec - Reserves a large amount of buffer space for sending
* @xdr: pointer to xdr_stream
* @vec: pointer to a kvec array
* @nbytes: number of bytes to reserve
*
* Reserves enough buffer space to encode 'nbytes' of data and stores the
* pointers in 'vec'. The size argument passed to xdr_reserve_space() is
* determined based on the number of bytes remaining in the current page to
* avoid invalidating iov_base pointers when xdr_commit_encode() is called.
*/
int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec, size_t nbytes)
{
int thislen;
int v = 0;
__be32 *p;
/*
* svcrdma requires every READ payload to start somewhere
* in xdr->pages.
*/
if (xdr->iov == xdr->buf->head) {
xdr->iov = NULL;
xdr->end = xdr->p;
}
while (nbytes) {
thislen = xdr->buf->page_len % PAGE_SIZE;
thislen = min_t(size_t, nbytes, PAGE_SIZE - thislen);
p = xdr_reserve_space(xdr, thislen);
if (!p)
return -EIO;
vec[v].iov_base = p;
vec[v].iov_len = thislen;
v++;
nbytes -= thislen;
}
return v;
}
EXPORT_SYMBOL_GPL(xdr_reserve_space_vec);
/**
* xdr_truncate_encode - truncate an encode buffer
* @xdr: pointer to xdr_stream
......@@ -802,7 +847,7 @@ EXPORT_SYMBOL_GPL(xdr_reserve_space);
* head, tail, and page lengths are adjusted to correspond.
*
* If this means moving xdr->p to a different buffer, we assume that
* that the end pointer should be set to the end of the current page,
* the end pointer should be set to the end of the current page,
* except in the case of the head buffer when we assume the head
* buffer's current length represents the end of the available buffer.
*
......
......@@ -137,7 +137,7 @@ static int svc_rdma_rw_ctx_init(struct svcxprt_rdma *rdma,
}
/* A chunk context tracks all I/O for moving one Read or Write
* chunk. This is a a set of rdma_rw's that handle data movement
* chunk. This is a set of rdma_rw's that handle data movement
* for all segments of one chunk.
*
* These are small, acquired with a single allocator call, and
......
......@@ -638,10 +638,11 @@ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma,
while (remaining) {
len = min_t(u32, PAGE_SIZE - pageoff, remaining);
memcpy(dst, page_address(*ppages), len);
memcpy(dst, page_address(*ppages) + pageoff, len);
remaining -= len;
dst += len;
pageoff = 0;
ppages++;
}
}
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
#
# Script for easier NFSD fault injection
# Check that debugfs has been mounted
DEBUGFS=`cat /proc/mounts | grep debugfs`
if [ "$DEBUGFS" == "" ]; then
echo "debugfs does not appear to be mounted!"
echo "Please mount debugfs and try again"
exit 1
fi
# Check that the fault injection directory exists
DEBUGDIR=`echo $DEBUGFS | awk '{print $2}'`/nfsd
if [ ! -d "$DEBUGDIR" ]; then
echo "$DEBUGDIR does not exist"
echo "Check that your .config selects CONFIG_NFSD_FAULT_INJECTION"
exit 1
fi
function help()
{
echo "Usage $0 injection_type [count]"
echo ""
echo "Injection types are:"
ls $DEBUGDIR
exit 1
}
if [ $# == 0 ]; then
help
elif [ ! -f $DEBUGDIR/$1 ]; then
help
elif [ $# != 2 ]; then
COUNT=0
else
COUNT=$2
fi
BEFORE=`mktemp`
AFTER=`mktemp`
dmesg > $BEFORE
echo $COUNT > $DEBUGDIR/$1
dmesg > $AFTER
# Capture lines that only exist in the $AFTER file
diff $BEFORE $AFTER | grep ">"
rm -f $BEFORE $AFTER
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment