mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
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. -----BEGIN PGP SIGNATURE----- iQJJBAABCAAzFiEEYtFWavXG9hZotryuJ5vNeUKO4b4FAl+Q5vsVHGJmaWVsZHNA ZmllbGRzZXMub3JnAAoJECebzXlCjuG+DUAP/RlALnXbaoWi8YCcEcc9U1LoQKbD CJpDR+FqCOyGwRuzWung/5pvkOO50fGEeAroos+2rF/NgRkQq8EFr9AuBhNOYUFE IZhWEOfu/r2ukXyBmcu21HGcWLwPnyJehvjuzTQW2wOHlBi/sdoL5Ap1sVlwVLj5 EZ5kqJLD+ioG2sufW99Spi55l1Cy+3Y0IhLSWl4ZAE6s8hmFSYAJZFsOeI0Afx57 USPTDRaeqjyEULkb+f8IhD0eRApOUo4evDn9dwQx+of7HPa1CiygctTKYwA3hnlc gXp2KpVA1REaiYVgOPwYlnqBmJ2K9X0wCRzcWy2razqEcVAX/2j7QCe9M2mn4DC8 xZ2q4SxgXu9yf0qfUSVnDxWmP6ipqq7OmsG0JXTFseGKBdpjJY1qHhyqanVAGvEg I+xHnnWfGwNCftwyA3mt3RfSFPsbLlSBIMZxvN4kn8aVlqszGITOQvTdQcLYA6kT xWllBf4XKVXMqF0PzerxPDmfzBfhx6b1VPWOIVcu7VLBg3IXoEB2G5xG8MUJiSch OUTCt41LUQkerQlnzaZYqwmFdSBfXJefmcE/x/vps4VtQ/fPHX1jQyD7iTu3HfSP bRlkKHvNVeTodlBDe/HTPiTA99MShhBJyvtV5wfzIqwjc1cNreed+ePppxn8mxJi SmQ2uZk/MpUl7/V0 =rcOj -----END PGP SIGNATURE----- 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() ...
This commit is contained in:
commit
24717cfbbb
@ -1,70 +0,0 @@
|
||||
===================
|
||||
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 @@ out:
|
||||
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 @@ out_filep:
|
||||
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
|
||||
|
94
fs/nfs_common/nfs_ssc.c
Normal file
94
fs/nfs_common/nfs_ssc.c
Normal file
@ -0,0 +1,94 @@
|
||||
// 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 @@ out_drop_lock:
|
||||
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)];
|
||||
|
@ -15,8 +15,6 @@
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
#define RETURN_STATUS(st) { resp->status = (st); return (st); }
|
||||
|
||||
static int nfs3_ftypes[] = {
|
||||
0, /* NF3NON */
|
||||
S_IFREG, /* NF3REG */
|
||||
@ -34,7 +32,7 @@ static int nfs3_ftypes[] = {
|
||||
static __be32
|
||||
nfsd3_proc_null(struct svc_rqst *rqstp)
|
||||
{
|
||||
return nfs_ok;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -45,20 +43,19 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: GETATTR(3) %s\n",
|
||||
SVCFH_fmt(&argp->fh));
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = fh_verify(rqstp, &resp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
if (nfserr)
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = fh_verify(rqstp, &resp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
nfserr = fh_getattr(&resp->fh, &resp->stat);
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -69,15 +66,14 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_sattrargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: SETATTR(3) %s\n",
|
||||
SVCFH_fmt(&argp->fh));
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
|
||||
argp->check_guard, argp->guardtime);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
|
||||
argp->check_guard, argp->guardtime);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -88,7 +84,6 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_diropargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: LOOKUP(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@ -98,11 +93,10 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp)
|
||||
fh_copy(&resp->dirfh, &argp->fh);
|
||||
fh_init(&resp->fh, NFS3_FHSIZE);
|
||||
|
||||
nfserr = nfsd_lookup(rqstp, &resp->dirfh,
|
||||
argp->name,
|
||||
argp->len,
|
||||
&resp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_lookup(rqstp, &resp->dirfh,
|
||||
argp->name, argp->len,
|
||||
&resp->fh);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -113,7 +107,6 @@ nfsd3_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(3) %s 0x%x\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@ -121,8 +114,8 @@ nfsd3_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);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -133,15 +126,14 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_readlinkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_readlinkres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
/* Read the symlink. */
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
resp->len = NFS3_MAXPATHLEN;
|
||||
nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -152,7 +144,6 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_readargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_readres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
u32 max_blocksize = svc_max_payload(rqstp);
|
||||
unsigned long cnt = min(argp->count, max_blocksize);
|
||||
|
||||
@ -169,12 +160,10 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
|
||||
svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_read(rqstp, &resp->fh,
|
||||
argp->offset,
|
||||
rqstp->rq_vec, argp->vlen,
|
||||
&resp->count,
|
||||
&resp->eof);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
|
||||
rqstp->rq_vec, argp->vlen, &resp->count,
|
||||
&resp->eof);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -185,7 +174,6 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_writeargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_writeres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
unsigned long cnt = argp->len;
|
||||
unsigned int nvecs;
|
||||
|
||||
@ -199,13 +187,16 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
|
||||
resp->committed = argp->stable;
|
||||
nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages,
|
||||
&argp->first, cnt);
|
||||
if (!nvecs)
|
||||
RETURN_STATUS(nfserr_io);
|
||||
nfserr = nfsd_write(rqstp, &resp->fh, argp->offset,
|
||||
rqstp->rq_vec, nvecs, &cnt,
|
||||
resp->committed, resp->verf);
|
||||
if (!nvecs) {
|
||||
resp->status = nfserr_io;
|
||||
goto out;
|
||||
}
|
||||
resp->status = nfsd_write(rqstp, &resp->fh, argp->offset,
|
||||
rqstp->rq_vec, nvecs, &cnt,
|
||||
resp->committed, resp->verf);
|
||||
resp->count = cnt;
|
||||
RETURN_STATUS(nfserr);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -220,7 +211,6 @@ nfsd3_proc_create(struct svc_rqst *rqstp)
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
svc_fh *dirfhp, *newfhp = NULL;
|
||||
struct iattr *attr;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: CREATE(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@ -241,11 +231,10 @@ nfsd3_proc_create(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
/* Now create the file and set attributes */
|
||||
nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
|
||||
attr, newfhp,
|
||||
argp->createmode, (u32 *)argp->verf, NULL, NULL);
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
|
||||
attr, newfhp, argp->createmode,
|
||||
(u32 *)argp->verf, NULL, NULL);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -256,7 +245,6 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_createargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: MKDIR(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@ -266,10 +254,10 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp)
|
||||
argp->attrs.ia_valid &= ~ATTR_SIZE;
|
||||
fh_copy(&resp->dirfh, &argp->fh);
|
||||
fh_init(&resp->fh, NFS3_FHSIZE);
|
||||
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
|
||||
&argp->attrs, S_IFDIR, 0, &resp->fh);
|
||||
resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
|
||||
&argp->attrs, S_IFDIR, 0, &resp->fh);
|
||||
fh_unlock(&resp->dirfh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
@ -277,18 +265,23 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
if (argp->tlen == 0)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
if (argp->tlen > NFS3_MAXPATHLEN)
|
||||
RETURN_STATUS(nfserr_nametoolong);
|
||||
if (argp->tlen == 0) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
if (argp->tlen > NFS3_MAXPATHLEN) {
|
||||
resp->status = nfserr_nametoolong;
|
||||
goto out;
|
||||
}
|
||||
|
||||
argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
|
||||
page_address(rqstp->rq_arg.pages[0]),
|
||||
argp->tlen);
|
||||
if (IS_ERR(argp->tname))
|
||||
RETURN_STATUS(nfserrno(PTR_ERR(argp->tname)));
|
||||
if (IS_ERR(argp->tname)) {
|
||||
resp->status = nfserrno(PTR_ERR(argp->tname));
|
||||
goto out;
|
||||
}
|
||||
|
||||
dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n",
|
||||
SVCFH_fmt(&argp->ffh),
|
||||
@ -297,10 +290,11 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
|
||||
|
||||
fh_copy(&resp->dirfh, &argp->ffh);
|
||||
fh_init(&resp->fh, NFS3_FHSIZE);
|
||||
nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
|
||||
argp->tname, &resp->fh);
|
||||
resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
|
||||
argp->flen, argp->tname, &resp->fh);
|
||||
kfree(argp->tname);
|
||||
RETURN_STATUS(nfserr);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -311,7 +305,6 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_mknodargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
int type;
|
||||
dev_t rdev = 0;
|
||||
|
||||
@ -323,22 +316,28 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp)
|
||||
fh_copy(&resp->dirfh, &argp->fh);
|
||||
fh_init(&resp->fh, NFS3_FHSIZE);
|
||||
|
||||
if (argp->ftype == 0 || argp->ftype >= NF3BAD)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
if (argp->ftype == 0 || argp->ftype >= NF3BAD) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
|
||||
rdev = MKDEV(argp->major, argp->minor);
|
||||
if (MAJOR(rdev) != argp->major ||
|
||||
MINOR(rdev) != argp->minor)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
} else
|
||||
if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
MINOR(rdev) != argp->minor) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
} else if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = nfs3_ftypes[argp->ftype];
|
||||
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
|
||||
&argp->attrs, type, rdev, &resp->fh);
|
||||
resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
|
||||
&argp->attrs, type, rdev, &resp->fh);
|
||||
fh_unlock(&resp->dirfh);
|
||||
RETURN_STATUS(nfserr);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -349,7 +348,6 @@ nfsd3_proc_remove(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_diropargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: REMOVE(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@ -358,9 +356,10 @@ nfsd3_proc_remove(struct svc_rqst *rqstp)
|
||||
|
||||
/* Unlink. -S_IFDIR means file must not be a directory */
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
|
||||
resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
|
||||
argp->name, argp->len);
|
||||
fh_unlock(&resp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -371,7 +370,6 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_diropargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: RMDIR(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@ -379,9 +377,10 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp)
|
||||
argp->name);
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
|
||||
resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
|
||||
argp->name, argp->len);
|
||||
fh_unlock(&resp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
@ -389,7 +388,6 @@ nfsd3_proc_rename(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_renameargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_renameres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: RENAME(3) %s %.*s ->\n",
|
||||
SVCFH_fmt(&argp->ffh),
|
||||
@ -402,9 +400,9 @@ nfsd3_proc_rename(struct svc_rqst *rqstp)
|
||||
|
||||
fh_copy(&resp->ffh, &argp->ffh);
|
||||
fh_copy(&resp->tfh, &argp->tfh);
|
||||
nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
|
||||
&resp->tfh, argp->tname, argp->tlen);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
|
||||
&resp->tfh, argp->tname, argp->tlen);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
@ -412,7 +410,6 @@ nfsd3_proc_link(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_linkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_linkres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: LINK(3) %s ->\n",
|
||||
SVCFH_fmt(&argp->ffh));
|
||||
@ -423,9 +420,9 @@ nfsd3_proc_link(struct svc_rqst *rqstp)
|
||||
|
||||
fh_copy(&resp->fh, &argp->ffh);
|
||||
fh_copy(&resp->tfh, &argp->tfh);
|
||||
nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
|
||||
&resp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
|
||||
&resp->fh);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -436,7 +433,6 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_readdirargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_readdirres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
int count = 0;
|
||||
struct page **p;
|
||||
caddr_t page_addr = NULL;
|
||||
@ -456,8 +452,8 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
||||
resp->common.err = nfs_ok;
|
||||
resp->buffer = argp->buffer;
|
||||
resp->rqstp = rqstp;
|
||||
nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
|
||||
&resp->common, nfs3svc_encode_entry);
|
||||
resp->status = nfsd_readdir(rqstp, &resp->fh, (loff_t *)&argp->cookie,
|
||||
&resp->common, nfs3svc_encode_entry);
|
||||
memcpy(resp->verf, argp->verf, 8);
|
||||
count = 0;
|
||||
for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
|
||||
@ -485,7 +481,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
||||
resp->offset = NULL;
|
||||
}
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -497,7 +493,6 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_readdirargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_readdirres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
int count = 0;
|
||||
loff_t offset;
|
||||
struct page **p;
|
||||
@ -520,17 +515,17 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
|
||||
resp->rqstp = rqstp;
|
||||
offset = argp->cookie;
|
||||
|
||||
nfserr = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
|
||||
if (nfserr)
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS)
|
||||
RETURN_STATUS(nfserr_notsupp);
|
||||
if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS) {
|
||||
resp->status = nfserr_notsupp;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nfserr = nfsd_readdir(rqstp, &resp->fh,
|
||||
&offset,
|
||||
&resp->common,
|
||||
nfs3svc_encode_entry_plus);
|
||||
resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
|
||||
&resp->common, nfs3svc_encode_entry_plus);
|
||||
memcpy(resp->verf, argp->verf, 8);
|
||||
for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
|
||||
page_addr = page_address(*p);
|
||||
@ -555,7 +550,8 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
|
||||
resp->offset = NULL;
|
||||
}
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -566,14 +562,13 @@ nfsd3_proc_fsstat(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd3_fsstatres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: FSSTAT(3) %s\n",
|
||||
SVCFH_fmt(&argp->fh));
|
||||
|
||||
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
|
||||
resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
|
||||
fh_put(&argp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -584,7 +579,6 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd3_fsinfores *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
u32 max_blocksize = svc_max_payload(rqstp);
|
||||
|
||||
dprintk("nfsd: FSINFO(3) %s\n",
|
||||
@ -600,13 +594,13 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
|
||||
resp->f_maxfilesize = ~(u32) 0;
|
||||
resp->f_properties = NFS3_FSF_DEFAULT;
|
||||
|
||||
nfserr = fh_verify(rqstp, &argp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
resp->status = fh_verify(rqstp, &argp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
|
||||
/* Check special features of the file system. May request
|
||||
* different read/write sizes for file systems known to have
|
||||
* problems with large blocks */
|
||||
if (nfserr == 0) {
|
||||
if (resp->status == nfs_ok) {
|
||||
struct super_block *sb = argp->fh.fh_dentry->d_sb;
|
||||
|
||||
/* Note that we don't care for remote fs's here */
|
||||
@ -617,7 +611,7 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
fh_put(&argp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -628,7 +622,6 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd3_pathconfres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: PATHCONF(3) %s\n",
|
||||
SVCFH_fmt(&argp->fh));
|
||||
@ -641,9 +634,9 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp)
|
||||
resp->p_case_insensitive = 0;
|
||||
resp->p_case_preserving = 1;
|
||||
|
||||
nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
|
||||
resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
|
||||
|
||||
if (nfserr == 0) {
|
||||
if (resp->status == nfs_ok) {
|
||||
struct super_block *sb = argp->fh.fh_dentry->d_sb;
|
||||
|
||||
/* Note that we don't care for remote fs's here */
|
||||
@ -660,10 +653,9 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
fh_put(&argp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Commit a file (range) to stable storage.
|
||||
*/
|
||||
@ -672,21 +664,22 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_commitargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_commitres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
argp->count,
|
||||
(unsigned long long) argp->offset);
|
||||
|
||||
if (argp->offset > NFS_OFFSET_MAX)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
if (argp->offset > NFS_OFFSET_MAX) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count,
|
||||
resp->verf);
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
|
||||
argp->count, resp->verf);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
|
||||
@ -716,6 +709,7 @@ struct nfsd3_voidargs { int dummy; };
|
||||
static const struct svc_procedure nfsd_procedures3[22] = {
|
||||
[NFS3PROC_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_voidres),
|
||||
|
@ -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 @@ out_err:
|
||||
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 @@ encode_op:
|
||||
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),
|
||||
|
@ -4513,7 +4513,8 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
|
||||
{
|
||||
struct nfs4_delegation *dp = cb_to_delegation(cb);
|
||||
|
||||
if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID)
|
||||
if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID ||
|
||||
dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID)
|
||||
return 1;
|
||||
|
||||
switch (task->tk_status) {
|
||||
@ -4597,7 +4598,8 @@ static bool nfsd_breaker_owns_lease(struct file_lock *fl)
|
||||
if (!i_am_nfsd())
|
||||
return NULL;
|
||||
rqst = kthread_data(current);
|
||||
if (!rqst->rq_lease_breaker)
|
||||
/* Note rq_prog == NFS_ACL_PROGRAM is also possible: */
|
||||
if (rqst->rq_prog != NFS_PROGRAM || rqst->rq_vers < 4)
|
||||
return NULL;
|
||||
clp = *(rqst->rq_lease_breaker);
|
||||
return dl->dl_stid.sc_client == clp;
|
||||
@ -4954,7 +4956,6 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
|
||||
writes--;
|
||||
if (fp->fi_fds[O_RDWR])
|
||||
writes--;
|
||||
WARN_ON_ONCE(writes < 0);
|
||||
if (writes > 0)
|
||||
return -EAGAIN;
|
||||
spin_lock(&fp->fi_lock);
|
||||
@ -5126,7 +5127,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
|
||||
|
||||
memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
|
||||
|
||||
trace_nfsd_deleg_open(&dp->dl_stid.sc_stateid);
|
||||
trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid);
|
||||
open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
return;
|
||||
@ -5243,7 +5244,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
|
||||
nfs4_open_delegation(current_fh, open, stp);
|
||||
nodeleg:
|
||||
status = nfs_ok;
|
||||
trace_nfsd_deleg_none(&stp->st_stid.sc_stateid);
|
||||
trace_nfsd_open(&stp->st_stid.sc_stateid);
|
||||
out:
|
||||
/* 4.1 client trying to upgrade/downgrade delegation? */
|
||||
if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
|
||||
@ -5722,7 +5723,6 @@ nfs4_find_file(struct nfs4_stid *s, int flags)
|
||||
return find_readable_file(s->sc_file);
|
||||
else
|
||||
return find_writeable_file(s->sc_file);
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -7253,599 +7253,6 @@ nfs4_check_open_reclaim(clientid_t *clid,
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_FAULT_INJECTION
|
||||
static inline void
|
||||
put_client(struct nfs4_client *clp)
|
||||
{
|
||||
atomic_dec(&clp->cl_rpc_users);
|
||||
}
|
||||
|
||||
static struct nfs4_client *
|
||||
nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
|
||||
return clp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_print_clients(void)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
u64 count = 0;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return 0;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
|
||||
pr_info("NFS Client: %s\n", buf);
|
||||
++count;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp) {
|
||||
if (mark_client_expired_locked(clp) == nfs_ok)
|
||||
++count;
|
||||
else
|
||||
clp = NULL;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
if (clp)
|
||||
expire_client(clp);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_clients(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp, *next;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
|
||||
if (mark_client_expired_locked(clp) == nfs_ok) {
|
||||
list_add(&clp->cl_lru, &reaplist);
|
||||
if (max != 0 && ++count >= max)
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
list_for_each_entry_safe(clp, next, &reaplist, cl_lru)
|
||||
expire_client(clp);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
|
||||
const char *type)
|
||||
{
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
|
||||
printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst,
|
||||
struct list_head *collect)
|
||||
{
|
||||
struct nfs4_client *clp = lst->st_stid.sc_client;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!collect)
|
||||
return;
|
||||
|
||||
lockdep_assert_held(&nn->client_lock);
|
||||
atomic_inc(&clp->cl_rpc_users);
|
||||
list_add(&lst->st_locks, collect);
|
||||
}
|
||||
|
||||
static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
|
||||
struct list_head *collect,
|
||||
bool (*func)(struct nfs4_ol_stateid *))
|
||||
{
|
||||
struct nfs4_openowner *oop;
|
||||
struct nfs4_ol_stateid *stp, *st_next;
|
||||
struct nfs4_ol_stateid *lst, *lst_next;
|
||||
u64 count = 0;
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
|
||||
list_for_each_entry_safe(stp, st_next,
|
||||
&oop->oo_owner.so_stateids, st_perstateowner) {
|
||||
list_for_each_entry_safe(lst, lst_next,
|
||||
&stp->st_locks, st_locks) {
|
||||
if (func) {
|
||||
if (func(lst))
|
||||
nfsd_inject_add_lock_to_list(lst,
|
||||
collect);
|
||||
}
|
||||
++count;
|
||||
/*
|
||||
* Despite the fact that these functions deal
|
||||
* with 64-bit integers for "count", we must
|
||||
* ensure that it doesn't blow up the
|
||||
* clp->cl_rpc_users. Throw a warning if we
|
||||
* start to approach INT_MAX here.
|
||||
*/
|
||||
WARN_ON_ONCE(count == (INT_MAX / 2));
|
||||
if (count == max)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
spin_unlock(&clp->cl_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect,
|
||||
u64 max)
|
||||
{
|
||||
return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid);
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_print_client_locks(struct nfs4_client *clp)
|
||||
{
|
||||
u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL);
|
||||
nfsd_print_count(clp, count, "locked files");
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_print_locks(void)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
u64 count = 0;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return 0;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru)
|
||||
count += nfsd_print_client_locks(clp);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_reap_locks(struct list_head *reaplist)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs4_ol_stateid *stp, *next;
|
||||
|
||||
list_for_each_entry_safe(stp, next, reaplist, st_locks) {
|
||||
list_del_init(&stp->st_locks);
|
||||
clp = stp->st_stid.sc_client;
|
||||
nfs4_put_stid(&stp->st_stid);
|
||||
put_client(clp);
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp)
|
||||
count = nfsd_collect_client_locks(clp, &reaplist, 0);
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_reap_locks(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_locks(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
count += nfsd_collect_client_locks(clp, &reaplist, max - count);
|
||||
if (max != 0 && count >= max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_reap_locks(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max,
|
||||
struct list_head *collect,
|
||||
void (*func)(struct nfs4_openowner *))
|
||||
{
|
||||
struct nfs4_openowner *oop, *next;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
u64 count = 0;
|
||||
|
||||
lockdep_assert_held(&nn->client_lock);
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
|
||||
if (func) {
|
||||
func(oop);
|
||||
if (collect) {
|
||||
atomic_inc(&clp->cl_rpc_users);
|
||||
list_add(&oop->oo_perclient, collect);
|
||||
}
|
||||
}
|
||||
++count;
|
||||
/*
|
||||
* Despite the fact that these functions deal with
|
||||
* 64-bit integers for "count", we must ensure that
|
||||
* it doesn't blow up the clp->cl_rpc_users. Throw a
|
||||
* warning if we start to approach INT_MAX here.
|
||||
*/
|
||||
WARN_ON_ONCE(count == (INT_MAX / 2));
|
||||
if (count == max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_print_client_openowners(struct nfs4_client *clp)
|
||||
{
|
||||
u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL);
|
||||
|
||||
nfsd_print_count(clp, count, "openowners");
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_collect_client_openowners(struct nfs4_client *clp,
|
||||
struct list_head *collect, u64 max)
|
||||
{
|
||||
return nfsd_foreach_client_openowner(clp, max, collect,
|
||||
unhash_openowner_locked);
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_print_openowners(void)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
u64 count = 0;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return 0;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru)
|
||||
count += nfsd_print_client_openowners(clp);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_reap_openowners(struct list_head *reaplist)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs4_openowner *oop, *next;
|
||||
|
||||
list_for_each_entry_safe(oop, next, reaplist, oo_perclient) {
|
||||
list_del_init(&oop->oo_perclient);
|
||||
clp = oop->oo_owner.so_client;
|
||||
release_openowner(oop);
|
||||
put_client(clp);
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr,
|
||||
size_t addr_size)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp)
|
||||
count = nfsd_collect_client_openowners(clp, &reaplist, 0);
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_reap_openowners(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_openowners(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
count += nfsd_collect_client_openowners(clp, &reaplist,
|
||||
max - count);
|
||||
if (max != 0 && count >= max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_reap_openowners(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
|
||||
struct list_head *victims)
|
||||
{
|
||||
struct nfs4_delegation *dp, *next;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
u64 count = 0;
|
||||
|
||||
lockdep_assert_held(&nn->client_lock);
|
||||
|
||||
spin_lock(&state_lock);
|
||||
list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
|
||||
if (victims) {
|
||||
/*
|
||||
* It's not safe to mess with delegations that have a
|
||||
* non-zero dl_time. They might have already been broken
|
||||
* and could be processed by the laundromat outside of
|
||||
* the state_lock. Just leave them be.
|
||||
*/
|
||||
if (dp->dl_time != 0)
|
||||
continue;
|
||||
|
||||
atomic_inc(&clp->cl_rpc_users);
|
||||
WARN_ON(!unhash_delegation_locked(dp));
|
||||
list_add(&dp->dl_recall_lru, victims);
|
||||
}
|
||||
++count;
|
||||
/*
|
||||
* Despite the fact that these functions deal with
|
||||
* 64-bit integers for "count", we must ensure that
|
||||
* it doesn't blow up the clp->cl_rpc_users. Throw a
|
||||
* warning if we start to approach INT_MAX here.
|
||||
*/
|
||||
WARN_ON_ONCE(count == (INT_MAX / 2));
|
||||
if (count == max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&state_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_print_client_delegations(struct nfs4_client *clp)
|
||||
{
|
||||
u64 count = nfsd_find_all_delegations(clp, 0, NULL);
|
||||
|
||||
nfsd_print_count(clp, count, "delegations");
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_print_delegations(void)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
u64 count = 0;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return 0;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru)
|
||||
count += nfsd_print_client_delegations(clp);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_forget_delegations(struct list_head *reaplist)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs4_delegation *dp, *next;
|
||||
|
||||
list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
|
||||
list_del_init(&dp->dl_recall_lru);
|
||||
clp = dp->dl_stid.sc_client;
|
||||
revoke_delegation(dp);
|
||||
put_client(clp);
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr,
|
||||
size_t addr_size)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp)
|
||||
count = nfsd_find_all_delegations(clp, 0, &reaplist);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
nfsd_forget_delegations(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_delegations(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
count += nfsd_find_all_delegations(clp, max - count, &reaplist);
|
||||
if (max != 0 && count >= max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_forget_delegations(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_recall_delegations(struct list_head *reaplist)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs4_delegation *dp, *next;
|
||||
|
||||
list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
|
||||
list_del_init(&dp->dl_recall_lru);
|
||||
clp = dp->dl_stid.sc_client;
|
||||
|
||||
trace_nfsd_deleg_recall(&dp->dl_stid.sc_stateid);
|
||||
|
||||
/*
|
||||
* We skipped all entries that had a zero dl_time before,
|
||||
* so we can now reset the dl_time back to 0. If a delegation
|
||||
* break comes in now, then it won't make any difference since
|
||||
* we're recalling it either way.
|
||||
*/
|
||||
spin_lock(&state_lock);
|
||||
dp->dl_time = 0;
|
||||
spin_unlock(&state_lock);
|
||||
nfsd_break_one_deleg(dp);
|
||||
put_client(clp);
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr,
|
||||
size_t addr_size)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp)
|
||||
count = nfsd_find_all_delegations(clp, 0, &reaplist);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
nfsd_recall_delegations(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_recall_delegations(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp, *next;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
|
||||
count += nfsd_find_all_delegations(clp, max - count, &reaplist);
|
||||
if (max != 0 && ++count >= max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_recall_delegations(&reaplist);
|
||||
return count;
|
||||
}
|
||||
#endif /* CONFIG_NFSD_FAULT_INJECTION */
|
||||
|
||||
/*
|
||||
* Since the lifetime of a delegation isn't limited to that of an open, a
|
||||
* client may quite reasonably hang on to a delegation as long as it has
|
||||
|
@ -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 @@ wreof:
|
||||
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)));
|
||||
if (!nn->drc_hashtbl)
|
||||
goto out_shrinker;
|
||||
}
|
||||
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 @@ out_free_lockd:
|
||||
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);
|
||||
|
@ -11,30 +11,14 @@
|
||||
#include "xdr.h"
|
||||
#include "vfs.h"
|
||||
|
||||
typedef struct svc_rqst svc_rqst;
|
||||
typedef struct svc_buf svc_buf;
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
|
||||
static __be32
|
||||
nfsd_proc_null(struct svc_rqst *rqstp)
|
||||
{
|
||||
return nfs_ok;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
|
||||
{
|
||||
if (err) return err;
|
||||
return fh_getattr(&resp->fh, &resp->stat);
|
||||
}
|
||||
static __be32
|
||||
nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
|
||||
{
|
||||
if (err) return err;
|
||||
return fh_getattr(&resp->fh, &resp->stat);
|
||||
}
|
||||
/*
|
||||
* Get a file's attributes
|
||||
* N.B. After this call resp->fh needs an fh_put
|
||||
@ -44,13 +28,17 @@ nfsd_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 | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
return nfsd_return_attrs(nfserr, resp);
|
||||
resp->status = fh_verify(rqstp, &resp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -64,7 +52,6 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
struct iattr *iap = &argp->attrs;
|
||||
struct svc_fh *fhp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@ -96,9 +83,9 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
|
||||
*/
|
||||
time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds();
|
||||
|
||||
nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
|
||||
if (nfserr)
|
||||
goto done;
|
||||
resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
if (delta < 0)
|
||||
delta = -delta;
|
||||
@ -113,9 +100,20 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
|
||||
}
|
||||
}
|
||||
|
||||
nfserr = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
|
||||
done:
|
||||
return nfsd_return_attrs(nfserr, resp);
|
||||
resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/* Obsolete, replaced by MNTPROC_MNT. */
|
||||
static __be32
|
||||
nfsd_proc_root(struct svc_rqst *rqstp)
|
||||
{
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -129,17 +127,20 @@ nfsd_proc_lookup(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_diropargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: LOOKUP %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh), argp->len, argp->name);
|
||||
|
||||
fh_init(&resp->fh, NFS_FHSIZE);
|
||||
nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
|
||||
&resp->fh);
|
||||
|
||||
resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
|
||||
&resp->fh);
|
||||
fh_put(&argp->fh);
|
||||
return nfsd_return_dirop(nfserr, resp);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -150,16 +151,15 @@ nfsd_proc_readlink(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_readlinkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_readlinkres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
/* Read the symlink. */
|
||||
resp->len = NFS_MAXPATHLEN;
|
||||
nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
|
||||
resp->status = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
|
||||
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -171,7 +171,6 @@ nfsd_proc_read(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_readargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_readres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
u32 eof;
|
||||
|
||||
dprintk("nfsd: READ %s %d bytes at %d\n",
|
||||
@ -193,14 +192,23 @@ nfsd_proc_read(struct svc_rqst *rqstp)
|
||||
svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
|
||||
|
||||
resp->count = argp->count;
|
||||
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset,
|
||||
rqstp->rq_vec, argp->vlen,
|
||||
&resp->count,
|
||||
&eof);
|
||||
resp->status = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset,
|
||||
rqstp->rq_vec, argp->vlen,
|
||||
&resp->count,
|
||||
&eof);
|
||||
if (resp->status == nfs_ok)
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
else if (resp->status == nfserr_jukebox)
|
||||
return rpc_drop_reply;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
if (nfserr) return nfserr;
|
||||
return fh_getattr(&resp->fh, &resp->stat);
|
||||
/* Reserved */
|
||||
static __be32
|
||||
nfsd_proc_writecache(struct svc_rqst *rqstp)
|
||||
{
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -212,7 +220,6 @@ nfsd_proc_write(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_writeargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
unsigned long cnt = argp->len;
|
||||
unsigned int nvecs;
|
||||
|
||||
@ -222,12 +229,20 @@ nfsd_proc_write(struct svc_rqst *rqstp)
|
||||
|
||||
nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages,
|
||||
&argp->first, cnt);
|
||||
if (!nvecs)
|
||||
return nfserr_io;
|
||||
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset, rqstp->rq_vec, nvecs,
|
||||
&cnt, NFS_DATA_SYNC, NULL);
|
||||
return nfsd_return_attrs(nfserr, resp);
|
||||
if (!nvecs) {
|
||||
resp->status = nfserr_io;
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset, rqstp->rq_vec, nvecs,
|
||||
&cnt, NFS_DATA_SYNC, NULL);
|
||||
if (resp->status == nfs_ok)
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
else if (resp->status == nfserr_jukebox)
|
||||
return rpc_drop_reply;
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -247,7 +262,6 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
struct inode *inode;
|
||||
struct dentry *dchild;
|
||||
int type, mode;
|
||||
__be32 nfserr;
|
||||
int hosterr;
|
||||
dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
|
||||
|
||||
@ -255,40 +269,40 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
SVCFH_fmt(dirfhp), argp->len, argp->name);
|
||||
|
||||
/* First verify the parent file handle */
|
||||
nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
|
||||
if (nfserr)
|
||||
resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
|
||||
if (resp->status != nfs_ok)
|
||||
goto done; /* must fh_put dirfhp even on error */
|
||||
|
||||
/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
|
||||
|
||||
nfserr = nfserr_exist;
|
||||
resp->status = nfserr_exist;
|
||||
if (isdotent(argp->name, argp->len))
|
||||
goto done;
|
||||
hosterr = fh_want_write(dirfhp);
|
||||
if (hosterr) {
|
||||
nfserr = nfserrno(hosterr);
|
||||
resp->status = nfserrno(hosterr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
fh_lock_nested(dirfhp, I_MUTEX_PARENT);
|
||||
dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
|
||||
if (IS_ERR(dchild)) {
|
||||
nfserr = nfserrno(PTR_ERR(dchild));
|
||||
resp->status = nfserrno(PTR_ERR(dchild));
|
||||
goto out_unlock;
|
||||
}
|
||||
fh_init(newfhp, NFS_FHSIZE);
|
||||
nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
|
||||
if (!nfserr && d_really_is_negative(dchild))
|
||||
nfserr = nfserr_noent;
|
||||
resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
|
||||
if (!resp->status && d_really_is_negative(dchild))
|
||||
resp->status = nfserr_noent;
|
||||
dput(dchild);
|
||||
if (nfserr) {
|
||||
if (nfserr != nfserr_noent)
|
||||
if (resp->status) {
|
||||
if (resp->status != nfserr_noent)
|
||||
goto out_unlock;
|
||||
/*
|
||||
* If the new file handle wasn't verified, we can't tell
|
||||
* whether the file exists or not. Time to bail ...
|
||||
*/
|
||||
nfserr = nfserr_acces;
|
||||
resp->status = nfserr_acces;
|
||||
if (!newfhp->fh_dentry) {
|
||||
printk(KERN_WARNING
|
||||
"nfsd_proc_create: file handle not verified\n");
|
||||
@ -321,11 +335,11 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
* echo thing > device-special-file-or-pipe
|
||||
* by doing a CREATE with type==0
|
||||
*/
|
||||
nfserr = nfsd_permission(rqstp,
|
||||
resp->status = nfsd_permission(rqstp,
|
||||
newfhp->fh_export,
|
||||
newfhp->fh_dentry,
|
||||
NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
|
||||
if (nfserr && nfserr != nfserr_rofs)
|
||||
if (resp->status && resp->status != nfserr_rofs)
|
||||
goto out_unlock;
|
||||
}
|
||||
} else
|
||||
@ -361,16 +375,17 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
attr->ia_valid &= ~ATTR_SIZE;
|
||||
|
||||
/* Make sure the type and device matches */
|
||||
nfserr = nfserr_exist;
|
||||
resp->status = nfserr_exist;
|
||||
if (inode && type != (inode->i_mode & S_IFMT))
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
nfserr = 0;
|
||||
resp->status = nfs_ok;
|
||||
if (!inode) {
|
||||
/* File doesn't exist. Create it and set attrs */
|
||||
nfserr = nfsd_create_locked(rqstp, dirfhp, argp->name,
|
||||
argp->len, attr, type, rdev, newfhp);
|
||||
resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name,
|
||||
argp->len, attr, type, rdev,
|
||||
newfhp);
|
||||
} else if (type == S_IFREG) {
|
||||
dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
|
||||
argp->name, attr->ia_valid, (long) attr->ia_size);
|
||||
@ -380,7 +395,8 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
*/
|
||||
attr->ia_valid &= ATTR_SIZE;
|
||||
if (attr->ia_valid)
|
||||
nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time64_t)0);
|
||||
resp->status = nfsd_setattr(rqstp, newfhp, attr, 0,
|
||||
(time64_t)0);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
@ -389,47 +405,52 @@ out_unlock:
|
||||
fh_drop_write(dirfhp);
|
||||
done:
|
||||
fh_put(dirfhp);
|
||||
return nfsd_return_dirop(nfserr, resp);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_proc_remove(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_diropargs *argp = rqstp->rq_argp;
|
||||
__be32 nfserr;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
|
||||
dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh),
|
||||
argp->len, argp->name);
|
||||
|
||||
/* Unlink. -SIFDIR means file must not be a directory */
|
||||
nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
|
||||
resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR,
|
||||
argp->name, argp->len);
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_proc_rename(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_renameargs *argp = rqstp->rq_argp;
|
||||
__be32 nfserr;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
|
||||
dprintk("nfsd: RENAME %s %.*s -> \n",
|
||||
SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
|
||||
dprintk("nfsd: -> %s %.*s\n",
|
||||
SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
|
||||
|
||||
nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
|
||||
&argp->tfh, argp->tname, argp->tlen);
|
||||
resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
|
||||
&argp->tfh, argp->tname, argp->tlen);
|
||||
fh_put(&argp->ffh);
|
||||
fh_put(&argp->tfh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_proc_link(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_linkargs *argp = rqstp->rq_argp;
|
||||
__be32 nfserr;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
|
||||
dprintk("nfsd: LINK %s ->\n",
|
||||
SVCFH_fmt(&argp->ffh));
|
||||
@ -438,41 +459,46 @@ nfsd_proc_link(struct svc_rqst *rqstp)
|
||||
argp->tlen,
|
||||
argp->tname);
|
||||
|
||||
nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
|
||||
&argp->ffh);
|
||||
resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
|
||||
&argp->ffh);
|
||||
fh_put(&argp->ffh);
|
||||
fh_put(&argp->tfh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_proc_symlink(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_symlinkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
struct svc_fh newfh;
|
||||
__be32 nfserr;
|
||||
|
||||
if (argp->tlen > NFS_MAXPATHLEN)
|
||||
return nfserr_nametoolong;
|
||||
if (argp->tlen > NFS_MAXPATHLEN) {
|
||||
resp->status = nfserr_nametoolong;
|
||||
goto out;
|
||||
}
|
||||
|
||||
argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
|
||||
page_address(rqstp->rq_arg.pages[0]),
|
||||
argp->tlen);
|
||||
if (IS_ERR(argp->tname))
|
||||
return nfserrno(PTR_ERR(argp->tname));
|
||||
if (IS_ERR(argp->tname)) {
|
||||
resp->status = nfserrno(PTR_ERR(argp->tname));
|
||||
goto out;
|
||||
}
|
||||
|
||||
dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
|
||||
SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
|
||||
argp->tlen, argp->tname);
|
||||
|
||||
fh_init(&newfh, NFS_FHSIZE);
|
||||
nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
|
||||
argp->tname, &newfh);
|
||||
resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
|
||||
argp->tname, &newfh);
|
||||
|
||||
kfree(argp->tname);
|
||||
fh_put(&argp->ffh);
|
||||
fh_put(&newfh);
|
||||
return nfserr;
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -484,7 +510,6 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_createargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
|
||||
|
||||
@ -495,10 +520,15 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
|
||||
|
||||
argp->attrs.ia_valid &= ~ATTR_SIZE;
|
||||
fh_init(&resp->fh, NFS_FHSIZE);
|
||||
nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
|
||||
&argp->attrs, S_IFDIR, 0, &resp->fh);
|
||||
resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
|
||||
&argp->attrs, S_IFDIR, 0, &resp->fh);
|
||||
fh_put(&argp->fh);
|
||||
return nfsd_return_dirop(nfserr, resp);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -508,13 +538,14 @@ static __be32
|
||||
nfsd_proc_rmdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_diropargs *argp = rqstp->rq_argp;
|
||||
__be32 nfserr;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
|
||||
dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
|
||||
|
||||
nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
|
||||
resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR,
|
||||
argp->name, argp->len);
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -526,7 +557,6 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
|
||||
struct nfsd_readdirargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_readdirres *resp = rqstp->rq_resp;
|
||||
int count;
|
||||
__be32 nfserr;
|
||||
loff_t offset;
|
||||
|
||||
dprintk("nfsd: READDIR %s %d bytes at %d\n",
|
||||
@ -547,15 +577,15 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
|
||||
resp->common.err = nfs_ok;
|
||||
/* Read directory and encode entries on the fly */
|
||||
offset = argp->cookie;
|
||||
nfserr = nfsd_readdir(rqstp, &argp->fh, &offset,
|
||||
&resp->common, nfssvc_encode_entry);
|
||||
resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
|
||||
&resp->common, nfssvc_encode_entry);
|
||||
|
||||
resp->count = resp->buffer - argp->buffer;
|
||||
if (resp->offset)
|
||||
*resp->offset = htonl(offset);
|
||||
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -566,14 +596,13 @@ nfsd_proc_statfs(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd_statfsres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
|
||||
NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
|
||||
NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -594,13 +623,13 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_argsize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST,
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
[NFSPROC_GETATTR] = {
|
||||
.pc_func = nfsd_proc_getattr,
|
||||
.pc_decode = nfssvc_decode_fhandle,
|
||||
.pc_encode = nfssvc_encode_attrstat,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_attrstat,
|
||||
.pc_argsize = sizeof(struct nfsd_fhandle),
|
||||
.pc_ressize = sizeof(struct nfsd_attrstat),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
@ -610,25 +639,26 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_func = nfsd_proc_setattr,
|
||||
.pc_decode = nfssvc_decode_sattrargs,
|
||||
.pc_encode = nfssvc_encode_attrstat,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_attrstat,
|
||||
.pc_argsize = sizeof(struct nfsd_sattrargs),
|
||||
.pc_ressize = sizeof(struct nfsd_attrstat),
|
||||
.pc_cachetype = RC_REPLBUFF,
|
||||
.pc_xdrressize = ST+AT,
|
||||
},
|
||||
[NFSPROC_ROOT] = {
|
||||
.pc_func = nfsd_proc_root,
|
||||
.pc_decode = nfssvc_decode_void,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST,
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
[NFSPROC_LOOKUP] = {
|
||||
.pc_func = nfsd_proc_lookup,
|
||||
.pc_decode = nfssvc_decode_diropargs,
|
||||
.pc_encode = nfssvc_encode_diropres,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_diropres,
|
||||
.pc_argsize = sizeof(struct nfsd_diropargs),
|
||||
.pc_ressize = sizeof(struct nfsd_diropres),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
@ -647,25 +677,26 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_func = nfsd_proc_read,
|
||||
.pc_decode = nfssvc_decode_readargs,
|
||||
.pc_encode = nfssvc_encode_readres,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_readres,
|
||||
.pc_argsize = sizeof(struct nfsd_readargs),
|
||||
.pc_ressize = sizeof(struct nfsd_readres),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
|
||||
},
|
||||
[NFSPROC_WRITECACHE] = {
|
||||
.pc_func = nfsd_proc_writecache,
|
||||
.pc_decode = nfssvc_decode_void,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST,
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
[NFSPROC_WRITE] = {
|
||||
.pc_func = nfsd_proc_write,
|
||||
.pc_decode = nfssvc_decode_writeargs,
|
||||
.pc_encode = nfssvc_encode_attrstat,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_attrstat,
|
||||
.pc_argsize = sizeof(struct nfsd_writeargs),
|
||||
.pc_ressize = sizeof(struct nfsd_attrstat),
|
||||
.pc_cachetype = RC_REPLBUFF,
|
||||
@ -675,7 +706,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_func = nfsd_proc_create,
|
||||
.pc_decode = nfssvc_decode_createargs,
|
||||
.pc_encode = nfssvc_encode_diropres,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_diropres,
|
||||
.pc_argsize = sizeof(struct nfsd_createargs),
|
||||
.pc_ressize = sizeof(struct nfsd_diropres),
|
||||
.pc_cachetype = RC_REPLBUFF,
|
||||
@ -684,36 +715,36 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
[NFSPROC_REMOVE] = {
|
||||
.pc_func = nfsd_proc_remove,
|
||||
.pc_decode = nfssvc_decode_diropargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_diropargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
[NFSPROC_RENAME] = {
|
||||
.pc_func = nfsd_proc_rename,
|
||||
.pc_decode = nfssvc_decode_renameargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_renameargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
[NFSPROC_LINK] = {
|
||||
.pc_func = nfsd_proc_link,
|
||||
.pc_decode = nfssvc_decode_linkargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_linkargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
[NFSPROC_SYMLINK] = {
|
||||
.pc_func = nfsd_proc_symlink,
|
||||
.pc_decode = nfssvc_decode_symlinkargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_symlinkargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
@ -721,7 +752,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_func = nfsd_proc_mkdir,
|
||||
.pc_decode = nfssvc_decode_createargs,
|
||||
.pc_encode = nfssvc_encode_diropres,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_diropres,
|
||||
.pc_argsize = sizeof(struct nfsd_createargs),
|
||||
.pc_ressize = sizeof(struct nfsd_diropres),
|
||||
.pc_cachetype = RC_REPLBUFF,
|
||||
@ -730,9 +761,9 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
[NFSPROC_RMDIR] = {
|
||||
.pc_func = nfsd_proc_rmdir,
|
||||
.pc_decode = nfssvc_decode_diropargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_diropargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
|
122
fs/nfsd/nfssvc.c
122
fs/nfsd/nfssvc.c
@ -960,15 +960,6 @@ out:
|
||||
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,80 +991,85 @@ 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);
|
||||
p = resv->iov_base + resv->iov_len;
|
||||
resv->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)) {
|
||||
dprintk("nfsd: Dropping request; may be revisited later\n");
|
||||
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
|
||||
return 0;
|
||||
}
|
||||
*statp = proc->pc_func(rqstp);
|
||||
if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags))
|
||||
goto out_update_drop;
|
||||
|
||||
if (rqstp->rq_proc != 0)
|
||||
*nfserrp++ = nfserr;
|
||||
if (!proc->pc_encode(rqstp, p))
|
||||
goto out_encode_err;
|
||||
|
||||
/* 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 */
|
||||
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);
|
||||
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;
|
||||
|
||||
out_encode_err:
|
||||
dprintk("nfsd: failed to encode result!\n");
|
||||
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
|
||||
*statp = rpc_system_err;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -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 @@ out:
|
||||
__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 *);
|
||||
|
67
include/linux/nfs_ssc.h
Normal file
67
include/linux/nfs_ssc.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* 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 @@ out_free:
|
||||
* 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 (delay)
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&cache_cleaner, delay);
|
||||
if (cache_clean() == -1)
|
||||
delay = round_jiffies_relative(30*HZ);
|
||||
else
|
||||
delay = 5;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,50 +0,0 @@
|
||||
#!/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
|
Loading…
Reference in New Issue
Block a user