mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
Some highlights:
- add tracepoints for callbacks and for client creation and destruction - cache the mounts used for server-to-server copies - expose callback information in /proc/fs/nfsd/clients/*/info - don't hold locks unnecessarily while waiting for commits - update NLM to use xdr_stream, as we have for NFSv2/v3/v4 -----BEGIN PGP SIGNATURE----- iQJJBAABCAAzFiEEYtFWavXG9hZotryuJ5vNeUKO4b4FAmDlvjIVHGJmaWVsZHNA ZmllbGRzZXMub3JnAAoJECebzXlCjuG+0MoP/RJ8Q7zwIz6WFHn3bCRaEXpnnkAH mmMfELhmgvH0V5nXWbb2rAfhllY+/zeWtf8QHSEKUPCnVLmB7WeXKdjXSy7EnYJ8 R8DuuuII85McIrg93nJ8hxm4wXTaTZKXpS4Vxkuxc6YKxoeJoXOaTjbgRLIw8mfX w4wPfjAsnROboVxvDHUmBS9zNKaAi2dZ0jH2x2eS7eZSWzoJC30yd+pFSxyYoOac 3fZUntDskQDGIpXHuTf53WcaK7h1bUHrwS7Joez8Z0ctg4vcbJsfdhKZUZwAxOZh 3xWAgm3PFcze5xqHuX8BYBThHfB3uTeygZQRb3zI9sG2UQtQfundrtlxZRSjMMkC cwlSi2SQNL66EBIgOcS3U/9OeorLALnnRax1KWMWjpFzaBJJQTJDumwLRx4zogI1 Ouiu0fI+hApck+L+qCzJMidA2wxOBsDzH471YiGiqQSmgNZc6wBc+aC/JKN8QAWb jG53vvpa3gCZa8Rs3KyOoUvtcCCdiQc+nljbzqtVfIvvGa9MSixufa+U5fojLEO7 i8aangK+mteMxrrejEKvRu1efDIfpFq0HW7ev1mzW2Jl/AguDXM5XUeGK2mMMPtc WqT3arbtGVcXJN+Oh5TzTVuED/DecyO0Fig77G+WJTiWONgoHfs+E5nC4aHSpohn bMpmQMIOmTa5zgQP =BQyR -----END PGP SIGNATURE----- Merge tag 'nfsd-5.14' of git://linux-nfs.org/~bfields/linux Pull nfsd updates from Bruce Fields: - add tracepoints for callbacks and for client creation and destruction - cache the mounts used for server-to-server copies - expose callback information in /proc/fs/nfsd/clients/*/info - don't hold locks unnecessarily while waiting for commits - update NLM to use xdr_stream, as we have for NFSv2/v3/v4 * tag 'nfsd-5.14' of git://linux-nfs.org/~bfields/linux: (69 commits) nfsd: fix NULL dereference in nfs3svc_encode_getaclres NFSD: Prevent a possible oops in the nfs_dirent() tracepoint nfsd: remove redundant assignment to pointer 'this' nfsd: Reduce contention for the nfsd_file nf_rwsem lockd: Update the NLMv4 SHARE results encoder to use struct xdr_stream lockd: Update the NLMv4 nlm_res results encoder to use struct xdr_stream lockd: Update the NLMv4 TEST results encoder to use struct xdr_stream lockd: Update the NLMv4 void results encoder to use struct xdr_stream lockd: Update the NLMv4 FREE_ALL arguments decoder to use struct xdr_stream lockd: Update the NLMv4 SHARE arguments decoder to use struct xdr_stream lockd: Update the NLMv4 SM_NOTIFY arguments decoder to use struct xdr_stream lockd: Update the NLMv4 nlm_res arguments decoder to use struct xdr_stream lockd: Update the NLMv4 UNLOCK arguments decoder to use struct xdr_stream lockd: Update the NLMv4 CANCEL arguments decoder to use struct xdr_stream lockd: Update the NLMv4 LOCK arguments decoder to use struct xdr_stream lockd: Update the NLMv4 TEST arguments decoder to use struct xdr_stream lockd: Update the NLMv4 void arguments decoder to use struct xdr_stream lockd: Update the NLMv1 SHARE results encoder to use struct xdr_stream lockd: Update the NLMv1 nlm_res results encoder to use struct xdr_stream lockd: Update the NLMv1 TEST results encoder to use struct xdr_stream ...
This commit is contained in:
commit
0cc2ea8ceb
@ -766,6 +766,46 @@ static void __exit exit_nlm(void)
|
||||
module_init(init_nlm);
|
||||
module_exit(exit_nlm);
|
||||
|
||||
/**
|
||||
* nlmsvc_dispatch - Process an NLM Request
|
||||
* @rqstp: incoming request
|
||||
* @statp: pointer to location of accept_stat field in RPC Reply buffer
|
||||
*
|
||||
* Return values:
|
||||
* %0: Processing complete; do not send a Reply
|
||||
* %1: Processing complete; send Reply in rqstp->rq_res
|
||||
*/
|
||||
static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp)
|
||||
{
|
||||
const struct svc_procedure *procp = rqstp->rq_procinfo;
|
||||
struct kvec *argv = rqstp->rq_arg.head;
|
||||
struct kvec *resv = rqstp->rq_res.head;
|
||||
|
||||
svcxdr_init_decode(rqstp);
|
||||
if (!procp->pc_decode(rqstp, argv->iov_base))
|
||||
goto out_decode_err;
|
||||
|
||||
*statp = procp->pc_func(rqstp);
|
||||
if (*statp == rpc_drop_reply)
|
||||
return 0;
|
||||
if (*statp != rpc_success)
|
||||
return 1;
|
||||
|
||||
svcxdr_init_encode(rqstp);
|
||||
if (!procp->pc_encode(rqstp, resv->iov_base + resv->iov_len))
|
||||
goto out_encode_err;
|
||||
|
||||
return 1;
|
||||
|
||||
out_decode_err:
|
||||
*statp = rpc_garbage_args;
|
||||
return 1;
|
||||
|
||||
out_encode_err:
|
||||
*statp = rpc_system_err;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define NLM program and procedures
|
||||
*/
|
||||
@ -775,6 +815,7 @@ static const struct svc_version nlmsvc_version1 = {
|
||||
.vs_nproc = 17,
|
||||
.vs_proc = nlmsvc_procedures,
|
||||
.vs_count = nlmsvc_version1_count,
|
||||
.vs_dispatch = nlmsvc_dispatch,
|
||||
.vs_xdrsize = NLMSVC_XDRSIZE,
|
||||
};
|
||||
static unsigned int nlmsvc_version3_count[24];
|
||||
@ -783,6 +824,7 @@ static const struct svc_version nlmsvc_version3 = {
|
||||
.vs_nproc = 24,
|
||||
.vs_proc = nlmsvc_procedures,
|
||||
.vs_count = nlmsvc_version3_count,
|
||||
.vs_dispatch = nlmsvc_dispatch,
|
||||
.vs_xdrsize = NLMSVC_XDRSIZE,
|
||||
};
|
||||
#ifdef CONFIG_LOCKD_V4
|
||||
@ -792,6 +834,7 @@ static const struct svc_version nlmsvc_version4 = {
|
||||
.vs_nproc = 24,
|
||||
.vs_proc = nlmsvc_procedures4,
|
||||
.vs_count = nlmsvc_version4_count,
|
||||
.vs_dispatch = nlmsvc_dispatch,
|
||||
.vs_xdrsize = NLMSVC_XDRSIZE,
|
||||
};
|
||||
#endif
|
||||
|
151
fs/lockd/svcxdr.h
Normal file
151
fs/lockd/svcxdr.h
Normal file
@ -0,0 +1,151 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Encode/decode NLM basic data types
|
||||
*
|
||||
* Basic NLMv3 XDR data types are not defined in an IETF standards
|
||||
* document. X/Open has a description of these data types that
|
||||
* is useful. See Chapter 10 of "Protocols for Interworking:
|
||||
* XNFS, Version 3W".
|
||||
*
|
||||
* Basic NLMv4 XDR data types are defined in Appendix II.1.4 of
|
||||
* RFC 1813: "NFS Version 3 Protocol Specification".
|
||||
*
|
||||
* Author: Chuck Lever <chuck.lever@oracle.com>
|
||||
*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates.
|
||||
*/
|
||||
|
||||
#ifndef _LOCKD_SVCXDR_H_
|
||||
#define _LOCKD_SVCXDR_H_
|
||||
|
||||
static inline bool
|
||||
svcxdr_decode_stats(struct xdr_stream *xdr, __be32 *status)
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
if (!p)
|
||||
return false;
|
||||
*status = *p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_encode_stats(struct xdr_stream *xdr, __be32 status)
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
if (!p)
|
||||
return false;
|
||||
*p = status;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_decode_string(struct xdr_stream *xdr, char **data, unsigned int *data_len)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len > NLM_MAXSTRLEN)
|
||||
return false;
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
*data_len = len;
|
||||
*data = (char *)p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* NLM cookies are defined by specification to be a variable-length
|
||||
* XDR opaque no longer than 1024 bytes. However, this implementation
|
||||
* limits their length to 32 bytes, and treats zero-length cookies
|
||||
* specially.
|
||||
*/
|
||||
static inline bool
|
||||
svcxdr_decode_cookie(struct xdr_stream *xdr, struct nlm_cookie *cookie)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len > NLM_MAXCOOKIELEN)
|
||||
return false;
|
||||
if (!len)
|
||||
goto out_hpux;
|
||||
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
cookie->len = len;
|
||||
memcpy(cookie->data, p, len);
|
||||
|
||||
return true;
|
||||
|
||||
/* apparently HPUX can return empty cookies */
|
||||
out_hpux:
|
||||
cookie->len = 4;
|
||||
memset(cookie->data, 0, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_encode_cookie(struct xdr_stream *xdr, const struct nlm_cookie *cookie)
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
if (xdr_stream_encode_u32(xdr, cookie->len) < 0)
|
||||
return false;
|
||||
p = xdr_reserve_space(xdr, cookie->len);
|
||||
if (!p)
|
||||
return false;
|
||||
memcpy(p, cookie->data, cookie->len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_decode_owner(struct xdr_stream *xdr, struct xdr_netobj *obj)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len > XDR_MAX_NETOBJ)
|
||||
return false;
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
obj->len = len;
|
||||
obj->data = (u8 *)p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_encode_owner(struct xdr_stream *xdr, const struct xdr_netobj *obj)
|
||||
{
|
||||
unsigned int quadlen = XDR_QUADLEN(obj->len);
|
||||
__be32 *p;
|
||||
|
||||
if (xdr_stream_encode_u32(xdr, obj->len) < 0)
|
||||
return false;
|
||||
p = xdr_reserve_space(xdr, obj->len);
|
||||
if (!p)
|
||||
return false;
|
||||
p[quadlen - 1] = 0; /* XDR pad */
|
||||
memcpy(p, obj->data, obj->len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* _LOCKD_SVCXDR_H_ */
|
448
fs/lockd/xdr.c
448
fs/lockd/xdr.c
@ -19,7 +19,7 @@
|
||||
|
||||
#include <uapi/linux/nfs2.h>
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_XDR
|
||||
#include "svcxdr.h"
|
||||
|
||||
|
||||
static inline loff_t
|
||||
@ -42,311 +42,323 @@ loff_t_to_s32(loff_t offset)
|
||||
}
|
||||
|
||||
/*
|
||||
* XDR functions for basic NLM types
|
||||
* NLM file handles are defined by specification to be a variable-length
|
||||
* XDR opaque no longer than 1024 bytes. However, this implementation
|
||||
* constrains their length to exactly the length of an NFSv2 file
|
||||
* handle.
|
||||
*/
|
||||
static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
|
||||
static bool
|
||||
svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
|
||||
{
|
||||
unsigned int len;
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
len = ntohl(*p++);
|
||||
|
||||
if(len==0)
|
||||
{
|
||||
c->len=4;
|
||||
memset(c->data, 0, 4); /* hockeypux brain damage */
|
||||
}
|
||||
else if(len<=NLM_MAXCOOKIELEN)
|
||||
{
|
||||
c->len=len;
|
||||
memcpy(c->data, p, len);
|
||||
p+=XDR_QUADLEN(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintk("lockd: bad cookie size %d (only cookies under "
|
||||
"%d bytes are supported.)\n",
|
||||
len, NLM_MAXCOOKIELEN);
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len != NFS2_FHSIZE)
|
||||
return false;
|
||||
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
fh->size = NFS2_FHSIZE;
|
||||
memcpy(fh->data, p, len);
|
||||
memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline __be32 *
|
||||
nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
|
||||
static bool
|
||||
svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
|
||||
{
|
||||
*p++ = htonl(c->len);
|
||||
memcpy(p, c->data, c->len);
|
||||
p+=XDR_QUADLEN(c->len);
|
||||
return p;
|
||||
}
|
||||
struct file_lock *fl = &lock->fl;
|
||||
s32 start, len, end;
|
||||
|
||||
static __be32 *
|
||||
nlm_decode_fh(__be32 *p, struct nfs_fh *f)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
|
||||
dprintk("lockd: bad fhandle size %d (should be %d)\n",
|
||||
len, NFS2_FHSIZE);
|
||||
return NULL;
|
||||
}
|
||||
f->size = NFS2_FHSIZE;
|
||||
memset(f->data, 0, sizeof(f->data));
|
||||
memcpy(f->data, p, NFS2_FHSIZE);
|
||||
return p + XDR_QUADLEN(NFS2_FHSIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode and decode owner handle
|
||||
*/
|
||||
static inline __be32 *
|
||||
nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
|
||||
{
|
||||
return xdr_decode_netobj(p, oh);
|
||||
}
|
||||
|
||||
static inline __be32 *
|
||||
nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
|
||||
{
|
||||
return xdr_encode_netobj(p, oh);
|
||||
}
|
||||
|
||||
static __be32 *
|
||||
nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
|
||||
{
|
||||
struct file_lock *fl = &lock->fl;
|
||||
s32 start, len, end;
|
||||
|
||||
if (!(p = xdr_decode_string_inplace(p, &lock->caller,
|
||||
&lock->len,
|
||||
NLM_MAXSTRLEN))
|
||||
|| !(p = nlm_decode_fh(p, &lock->fh))
|
||||
|| !(p = nlm_decode_oh(p, &lock->oh)))
|
||||
return NULL;
|
||||
lock->svid = ntohl(*p++);
|
||||
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
|
||||
return false;
|
||||
if (!svcxdr_decode_fhandle(xdr, &lock->fh))
|
||||
return false;
|
||||
if (!svcxdr_decode_owner(xdr, &lock->oh))
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &start) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
|
||||
locks_init_lock(fl);
|
||||
fl->fl_flags = FL_POSIX;
|
||||
fl->fl_type = F_RDLCK; /* as good as anything else */
|
||||
start = ntohl(*p++);
|
||||
len = ntohl(*p++);
|
||||
fl->fl_type = F_RDLCK;
|
||||
end = start + len - 1;
|
||||
|
||||
fl->fl_start = s32_to_loff_t(start);
|
||||
|
||||
if (len == 0 || end < 0)
|
||||
fl->fl_end = OFFSET_MAX;
|
||||
else
|
||||
fl->fl_end = s32_to_loff_t(end);
|
||||
return p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode result of a TEST/TEST_MSG call
|
||||
*/
|
||||
static __be32 *
|
||||
nlm_encode_testres(__be32 *p, struct nlm_res *resp)
|
||||
static bool
|
||||
svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
|
||||
{
|
||||
s32 start, len;
|
||||
const struct file_lock *fl = &lock->fl;
|
||||
s32 start, len;
|
||||
|
||||
if (!(p = nlm_encode_cookie(p, &resp->cookie)))
|
||||
return NULL;
|
||||
*p++ = resp->status;
|
||||
/* exclusive */
|
||||
if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
|
||||
return false;
|
||||
if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
|
||||
return false;
|
||||
if (!svcxdr_encode_owner(xdr, &lock->oh))
|
||||
return false;
|
||||
start = loff_t_to_s32(fl->fl_start);
|
||||
if (fl->fl_end == OFFSET_MAX)
|
||||
len = 0;
|
||||
else
|
||||
len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
|
||||
if (xdr_stream_encode_u32(xdr, start) < 0)
|
||||
return false;
|
||||
if (xdr_stream_encode_u32(xdr, len) < 0)
|
||||
return false;
|
||||
|
||||
if (resp->status == nlm_lck_denied) {
|
||||
struct file_lock *fl = &resp->lock.fl;
|
||||
return true;
|
||||
}
|
||||
|
||||
*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
|
||||
*p++ = htonl(resp->lock.svid);
|
||||
|
||||
/* Encode owner handle. */
|
||||
if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
|
||||
return NULL;
|
||||
|
||||
start = loff_t_to_s32(fl->fl_start);
|
||||
if (fl->fl_end == OFFSET_MAX)
|
||||
len = 0;
|
||||
else
|
||||
len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
|
||||
|
||||
*p++ = htonl(start);
|
||||
*p++ = htonl(len);
|
||||
static bool
|
||||
svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
|
||||
{
|
||||
if (!svcxdr_encode_stats(xdr, resp->status))
|
||||
return false;
|
||||
switch (resp->status) {
|
||||
case nlm_lck_denied:
|
||||
if (!svcxdr_encode_holder(xdr, &resp->lock))
|
||||
return false;
|
||||
}
|
||||
|
||||
return p;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* First, the server side XDR functions
|
||||
* Decode Call arguments
|
||||
*/
|
||||
|
||||
int
|
||||
nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
u32 exclusive;
|
||||
u32 exclusive;
|
||||
|
||||
if (!(p = nlm_decode_cookie(p, &argp->cookie)))
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
|
||||
exclusive = ntohl(*p++);
|
||||
if (!(p = nlm_decode_lock(p, &argp->lock)))
|
||||
if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
|
||||
return 0;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return 0;
|
||||
if (exclusive)
|
||||
argp->lock.fl.fl_type = F_WRLCK;
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
if (!(p = nlm_encode_testres(p, resp)))
|
||||
return 0;
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
u32 exclusive;
|
||||
u32 exclusive;
|
||||
|
||||
if (!(p = nlm_decode_cookie(p, &argp->cookie)))
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
argp->block = ntohl(*p++);
|
||||
exclusive = ntohl(*p++);
|
||||
if (!(p = nlm_decode_lock(p, &argp->lock)))
|
||||
if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
|
||||
return 0;
|
||||
if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
|
||||
return 0;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return 0;
|
||||
if (exclusive)
|
||||
argp->lock.fl.fl_type = F_WRLCK;
|
||||
argp->reclaim = ntohl(*p++);
|
||||
argp->state = ntohl(*p++);
|
||||
if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
|
||||
return 0;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
|
||||
return 0;
|
||||
argp->monitor = 1; /* monitor client by default */
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
u32 exclusive;
|
||||
u32 exclusive;
|
||||
|
||||
if (!(p = nlm_decode_cookie(p, &argp->cookie)))
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
argp->block = ntohl(*p++);
|
||||
exclusive = ntohl(*p++);
|
||||
if (!(p = nlm_decode_lock(p, &argp->lock)))
|
||||
if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
|
||||
return 0;
|
||||
if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
|
||||
return 0;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return 0;
|
||||
if (exclusive)
|
||||
argp->lock.fl.fl_type = F_WRLCK;
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
|
||||
if (!(p = nlm_decode_cookie(p, &argp->cookie))
|
||||
|| !(p = nlm_decode_lock(p, &argp->lock)))
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return 0;
|
||||
argp->lock.fl.fl_type = F_UNLCK;
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
memset(lock, 0, sizeof(*lock));
|
||||
locks_init_lock(&lock->fl);
|
||||
lock->svid = ~(u32) 0;
|
||||
|
||||
if (!(p = nlm_decode_cookie(p, &argp->cookie))
|
||||
|| !(p = xdr_decode_string_inplace(p, &lock->caller,
|
||||
&lock->len, NLM_MAXSTRLEN))
|
||||
|| !(p = nlm_decode_fh(p, &lock->fh))
|
||||
|| !(p = nlm_decode_oh(p, &lock->oh)))
|
||||
return 0;
|
||||
argp->fsm_mode = ntohl(*p++);
|
||||
argp->fsm_access = ntohl(*p++);
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
if (!(p = nlm_encode_cookie(p, &resp->cookie)))
|
||||
return 0;
|
||||
*p++ = resp->status;
|
||||
*p++ = xdr_zero; /* sequence argument */
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
if (!(p = nlm_encode_cookie(p, &resp->cookie)))
|
||||
return 0;
|
||||
*p++ = resp->status;
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
if (!(p = xdr_decode_string_inplace(p, &lock->caller,
|
||||
&lock->len, NLM_MAXSTRLEN)))
|
||||
return 0;
|
||||
argp->state = ntohl(*p++);
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_reboot *argp = rqstp->rq_argp;
|
||||
|
||||
if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
|
||||
return 0;
|
||||
argp->state = ntohl(*p++);
|
||||
memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
|
||||
p += XDR_QUADLEN(SM_PRIV_SIZE);
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_res *resp = rqstp->rq_argp;
|
||||
|
||||
if (!(p = nlm_decode_cookie(p, &resp->cookie)))
|
||||
if (!svcxdr_decode_cookie(xdr, &resp->cookie))
|
||||
return 0;
|
||||
resp->status = *p++;
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
if (!svcxdr_decode_stats(xdr, &resp->status))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
|
||||
nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_reboot *argp = rqstp->rq_argp;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return 0;
|
||||
if (len > SM_MAXSTRLEN)
|
||||
return 0;
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return 0;
|
||||
argp->len = len;
|
||||
argp->mon = (char *)p;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
|
||||
return 0;
|
||||
p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
|
||||
if (!p)
|
||||
return 0;
|
||||
memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
memset(lock, 0, sizeof(*lock));
|
||||
locks_init_lock(&lock->fl);
|
||||
lock->svid = ~(u32)0;
|
||||
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
|
||||
return 0;
|
||||
if (!svcxdr_decode_fhandle(xdr, &lock->fh))
|
||||
return 0;
|
||||
if (!svcxdr_decode_owner(xdr, &lock->oh))
|
||||
return 0;
|
||||
/* XXX: Range checks are missing in the original code */
|
||||
if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
|
||||
return 0;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
|
||||
return 0;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encode Reply results
|
||||
*/
|
||||
|
||||
int
|
||||
nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_res_stream;
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
return svcxdr_encode_cookie(xdr, &resp->cookie) &&
|
||||
svcxdr_encode_testrply(xdr, resp);
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_res_stream;
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
return svcxdr_encode_cookie(xdr, &resp->cookie) &&
|
||||
svcxdr_encode_stats(xdr, resp->status);
|
||||
}
|
||||
|
||||
int
|
||||
nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_res_stream;
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
if (!svcxdr_encode_cookie(xdr, &resp->cookie))
|
||||
return 0;
|
||||
if (!svcxdr_encode_stats(xdr, resp->status))
|
||||
return 0;
|
||||
/* sequence */
|
||||
if (xdr_stream_encode_u32(xdr, 0) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
445
fs/lockd/xdr4.c
445
fs/lockd/xdr4.c
@ -18,7 +18,7 @@
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_XDR
|
||||
#include "svcxdr.h"
|
||||
|
||||
static inline loff_t
|
||||
s64_to_loff_t(__s64 offset)
|
||||
@ -41,309 +41,322 @@ loff_t_to_s64(loff_t offset)
|
||||
}
|
||||
|
||||
/*
|
||||
* XDR functions for basic NLM types
|
||||
* NLM file handles are defined by specification to be a variable-length
|
||||
* XDR opaque no longer than 1024 bytes. However, this implementation
|
||||
* limits their length to the size of an NFSv3 file handle.
|
||||
*/
|
||||
static __be32 *
|
||||
nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
|
||||
static bool
|
||||
svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
|
||||
{
|
||||
unsigned int len;
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
len = ntohl(*p++);
|
||||
|
||||
if(len==0)
|
||||
{
|
||||
c->len=4;
|
||||
memset(c->data, 0, 4); /* hockeypux brain damage */
|
||||
}
|
||||
else if(len<=NLM_MAXCOOKIELEN)
|
||||
{
|
||||
c->len=len;
|
||||
memcpy(c->data, p, len);
|
||||
p+=XDR_QUADLEN(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintk("lockd: bad cookie size %d (only cookies under "
|
||||
"%d bytes are supported.)\n",
|
||||
len, NLM_MAXCOOKIELEN);
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len > NFS_MAXFHSIZE)
|
||||
return false;
|
||||
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
fh->size = len;
|
||||
memcpy(fh->data, p, len);
|
||||
memset(fh->data + len, 0, sizeof(fh->data) - len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static __be32 *
|
||||
nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c)
|
||||
static bool
|
||||
svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
|
||||
{
|
||||
*p++ = htonl(c->len);
|
||||
memcpy(p, c->data, c->len);
|
||||
p+=XDR_QUADLEN(c->len);
|
||||
return p;
|
||||
}
|
||||
struct file_lock *fl = &lock->fl;
|
||||
u64 len, start;
|
||||
s64 end;
|
||||
|
||||
static __be32 *
|
||||
nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
|
||||
{
|
||||
memset(f->data, 0, sizeof(f->data));
|
||||
f->size = ntohl(*p++);
|
||||
if (f->size > NFS_MAXFHSIZE) {
|
||||
dprintk("lockd: bad fhandle size %d (should be <=%d)\n",
|
||||
f->size, NFS_MAXFHSIZE);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(f->data, p, f->size);
|
||||
return p + XDR_QUADLEN(f->size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode and decode owner handle
|
||||
*/
|
||||
static __be32 *
|
||||
nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh)
|
||||
{
|
||||
return xdr_decode_netobj(p, oh);
|
||||
}
|
||||
|
||||
static __be32 *
|
||||
nlm4_decode_lock(__be32 *p, struct nlm_lock *lock)
|
||||
{
|
||||
struct file_lock *fl = &lock->fl;
|
||||
__u64 len, start;
|
||||
__s64 end;
|
||||
|
||||
if (!(p = xdr_decode_string_inplace(p, &lock->caller,
|
||||
&lock->len, NLM_MAXSTRLEN))
|
||||
|| !(p = nlm4_decode_fh(p, &lock->fh))
|
||||
|| !(p = nlm4_decode_oh(p, &lock->oh)))
|
||||
return NULL;
|
||||
lock->svid = ntohl(*p++);
|
||||
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
|
||||
return false;
|
||||
if (!svcxdr_decode_fhandle(xdr, &lock->fh))
|
||||
return false;
|
||||
if (!svcxdr_decode_owner(xdr, &lock->oh))
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_u64(xdr, &start) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_u64(xdr, &len) < 0)
|
||||
return false;
|
||||
|
||||
locks_init_lock(fl);
|
||||
fl->fl_flags = FL_POSIX;
|
||||
fl->fl_type = F_RDLCK; /* as good as anything else */
|
||||
p = xdr_decode_hyper(p, &start);
|
||||
p = xdr_decode_hyper(p, &len);
|
||||
fl->fl_type = F_RDLCK;
|
||||
end = start + len - 1;
|
||||
|
||||
fl->fl_start = s64_to_loff_t(start);
|
||||
|
||||
if (len == 0 || end < 0)
|
||||
fl->fl_end = OFFSET_MAX;
|
||||
else
|
||||
fl->fl_end = s64_to_loff_t(end);
|
||||
return p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode result of a TEST/TEST_MSG call
|
||||
*/
|
||||
static __be32 *
|
||||
nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
|
||||
static bool
|
||||
svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
|
||||
{
|
||||
s64 start, len;
|
||||
const struct file_lock *fl = &lock->fl;
|
||||
s64 start, len;
|
||||
|
||||
dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
|
||||
if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
|
||||
return NULL;
|
||||
*p++ = resp->status;
|
||||
/* exclusive */
|
||||
if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
|
||||
return false;
|
||||
if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
|
||||
return false;
|
||||
if (!svcxdr_encode_owner(xdr, &lock->oh))
|
||||
return false;
|
||||
start = loff_t_to_s64(fl->fl_start);
|
||||
if (fl->fl_end == OFFSET_MAX)
|
||||
len = 0;
|
||||
else
|
||||
len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
|
||||
if (xdr_stream_encode_u64(xdr, start) < 0)
|
||||
return false;
|
||||
if (xdr_stream_encode_u64(xdr, len) < 0)
|
||||
return false;
|
||||
|
||||
if (resp->status == nlm_lck_denied) {
|
||||
struct file_lock *fl = &resp->lock.fl;
|
||||
return true;
|
||||
}
|
||||
|
||||
*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
|
||||
*p++ = htonl(resp->lock.svid);
|
||||
|
||||
/* Encode owner handle. */
|
||||
if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
|
||||
return NULL;
|
||||
|
||||
start = loff_t_to_s64(fl->fl_start);
|
||||
if (fl->fl_end == OFFSET_MAX)
|
||||
len = 0;
|
||||
else
|
||||
len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
|
||||
|
||||
p = xdr_encode_hyper(p, start);
|
||||
p = xdr_encode_hyper(p, len);
|
||||
dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n",
|
||||
resp->status, (int)resp->lock.svid, fl->fl_type,
|
||||
(long long)fl->fl_start, (long long)fl->fl_end);
|
||||
static bool
|
||||
svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
|
||||
{
|
||||
if (!svcxdr_encode_stats(xdr, resp->status))
|
||||
return false;
|
||||
switch (resp->status) {
|
||||
case nlm_lck_denied:
|
||||
if (!svcxdr_encode_holder(xdr, &resp->lock))
|
||||
return false;
|
||||
}
|
||||
|
||||
dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
|
||||
return p;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* First, the server side XDR functions
|
||||
* Decode Call arguments
|
||||
*/
|
||||
|
||||
int
|
||||
nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
u32 exclusive;
|
||||
u32 exclusive;
|
||||
|
||||
if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
|
||||
exclusive = ntohl(*p++);
|
||||
if (!(p = nlm4_decode_lock(p, &argp->lock)))
|
||||
if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
|
||||
return 0;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return 0;
|
||||
if (exclusive)
|
||||
argp->lock.fl.fl_type = F_WRLCK;
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
if (!(p = nlm4_encode_testres(p, resp)))
|
||||
return 0;
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
u32 exclusive;
|
||||
u32 exclusive;
|
||||
|
||||
if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
argp->block = ntohl(*p++);
|
||||
exclusive = ntohl(*p++);
|
||||
if (!(p = nlm4_decode_lock(p, &argp->lock)))
|
||||
if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
|
||||
return 0;
|
||||
if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
|
||||
return 0;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return 0;
|
||||
if (exclusive)
|
||||
argp->lock.fl.fl_type = F_WRLCK;
|
||||
argp->reclaim = ntohl(*p++);
|
||||
argp->state = ntohl(*p++);
|
||||
if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
|
||||
return 0;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
|
||||
return 0;
|
||||
argp->monitor = 1; /* monitor client by default */
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
u32 exclusive;
|
||||
u32 exclusive;
|
||||
|
||||
if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
argp->block = ntohl(*p++);
|
||||
exclusive = ntohl(*p++);
|
||||
if (!(p = nlm4_decode_lock(p, &argp->lock)))
|
||||
if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
|
||||
return 0;
|
||||
if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
|
||||
return 0;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return 0;
|
||||
if (exclusive)
|
||||
argp->lock.fl.fl_type = F_WRLCK;
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
|
||||
if (!(p = nlm4_decode_cookie(p, &argp->cookie))
|
||||
|| !(p = nlm4_decode_lock(p, &argp->lock)))
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return 0;
|
||||
argp->lock.fl.fl_type = F_UNLCK;
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
memset(lock, 0, sizeof(*lock));
|
||||
locks_init_lock(&lock->fl);
|
||||
lock->svid = ~(u32) 0;
|
||||
|
||||
if (!(p = nlm4_decode_cookie(p, &argp->cookie))
|
||||
|| !(p = xdr_decode_string_inplace(p, &lock->caller,
|
||||
&lock->len, NLM_MAXSTRLEN))
|
||||
|| !(p = nlm4_decode_fh(p, &lock->fh))
|
||||
|| !(p = nlm4_decode_oh(p, &lock->oh)))
|
||||
return 0;
|
||||
argp->fsm_mode = ntohl(*p++);
|
||||
argp->fsm_access = ntohl(*p++);
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
|
||||
return 0;
|
||||
*p++ = resp->status;
|
||||
*p++ = xdr_zero; /* sequence argument */
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
|
||||
return 0;
|
||||
*p++ = resp->status;
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
if (!(p = xdr_decode_string_inplace(p, &lock->caller,
|
||||
&lock->len, NLM_MAXSTRLEN)))
|
||||
return 0;
|
||||
argp->state = ntohl(*p++);
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nlm_reboot *argp = rqstp->rq_argp;
|
||||
|
||||
if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
|
||||
return 0;
|
||||
argp->state = ntohl(*p++);
|
||||
memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
|
||||
p += XDR_QUADLEN(SM_PRIV_SIZE);
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_res *resp = rqstp->rq_argp;
|
||||
|
||||
if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
|
||||
if (!svcxdr_decode_cookie(xdr, &resp->cookie))
|
||||
return 0;
|
||||
resp->status = *p++;
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
if (!svcxdr_decode_stats(xdr, &resp->status))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p)
|
||||
nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_reboot *argp = rqstp->rq_argp;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return 0;
|
||||
if (len > SM_MAXSTRLEN)
|
||||
return 0;
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return 0;
|
||||
argp->len = len;
|
||||
argp->mon = (char *)p;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
|
||||
return 0;
|
||||
p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
|
||||
if (!p)
|
||||
return 0;
|
||||
memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
memset(lock, 0, sizeof(*lock));
|
||||
locks_init_lock(&lock->fl);
|
||||
lock->svid = ~(u32)0;
|
||||
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return 0;
|
||||
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
|
||||
return 0;
|
||||
if (!svcxdr_decode_fhandle(xdr, &lock->fh))
|
||||
return 0;
|
||||
if (!svcxdr_decode_owner(xdr, &lock->oh))
|
||||
return 0;
|
||||
/* XXX: Range checks are missing in the original code */
|
||||
if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
|
||||
return 0;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
|
||||
return 0;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encode Reply results
|
||||
*/
|
||||
|
||||
int
|
||||
nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_res_stream;
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
return svcxdr_encode_cookie(xdr, &resp->cookie) &&
|
||||
svcxdr_encode_testrply(xdr, resp);
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_res_stream;
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
return svcxdr_encode_cookie(xdr, &resp->cookie) &&
|
||||
svcxdr_encode_stats(xdr, resp->status);
|
||||
}
|
||||
|
||||
int
|
||||
nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct xdr_stream *xdr = &rqstp->rq_res_stream;
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
if (!svcxdr_encode_cookie(xdr, &resp->cookie))
|
||||
return 0;
|
||||
if (!svcxdr_encode_stats(xdr, resp->status))
|
||||
return 0;
|
||||
/* sequence */
|
||||
if (xdr_stream_encode_u32(xdr, 0) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ __state_in_grace(struct net *net, bool open)
|
||||
|
||||
/**
|
||||
* locks_in_grace
|
||||
* @net: network namespace
|
||||
*
|
||||
* Lock managers call this function to determine when it is OK for them
|
||||
* to answer ordinary lock requests, and when they should accept only
|
||||
|
@ -176,6 +176,12 @@ struct nfsd_net {
|
||||
unsigned int longest_chain_cachesize;
|
||||
|
||||
struct shrinker nfsd_reply_cache_shrinker;
|
||||
|
||||
/* tracking server-to-server copy mounts */
|
||||
spinlock_t nfsd_ssc_lock;
|
||||
struct list_head nfsd_ssc_mount_list;
|
||||
wait_queue_head_t nfsd_ssc_waitq;
|
||||
|
||||
/* utsname taken from the process that starts the server */
|
||||
char nfsd_name[UNX_MAXNODENAME+1];
|
||||
};
|
||||
|
@ -172,7 +172,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;
|
||||
struct kvec *head = rqstp->rq_res.head;
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct inode *inode;
|
||||
unsigned int base;
|
||||
int n;
|
||||
int w;
|
||||
@ -181,6 +181,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
|
||||
return 0;
|
||||
switch (resp->status) {
|
||||
case nfs_ok:
|
||||
inode = d_inode(dentry);
|
||||
if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
|
||||
return 0;
|
||||
if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
|
||||
|
@ -915,10 +915,8 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
|
||||
args.authflavor = clp->cl_cred.cr_flavor;
|
||||
clp->cl_cb_ident = conn->cb_ident;
|
||||
} else {
|
||||
if (!conn->cb_xprt) {
|
||||
trace_nfsd_cb_setup_err(clp, -EINVAL);
|
||||
if (!conn->cb_xprt)
|
||||
return -EINVAL;
|
||||
}
|
||||
clp->cl_cb_conn.cb_xprt = conn->cb_xprt;
|
||||
clp->cl_cb_session = ses;
|
||||
args.bc_xprt = conn->cb_xprt;
|
||||
@ -941,37 +939,43 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
|
||||
}
|
||||
clp->cl_cb_client = client;
|
||||
clp->cl_cb_cred = cred;
|
||||
trace_nfsd_cb_setup(clp);
|
||||
rcu_read_lock();
|
||||
trace_nfsd_cb_setup(clp, rpc_peeraddr2str(client, RPC_DISPLAY_NETID),
|
||||
args.authflavor);
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nfsd4_mark_cb_state(struct nfs4_client *clp, int newstate)
|
||||
{
|
||||
if (clp->cl_cb_state != newstate) {
|
||||
clp->cl_cb_state = newstate;
|
||||
trace_nfsd_cb_state(clp);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
|
||||
{
|
||||
if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags))
|
||||
return;
|
||||
clp->cl_cb_state = NFSD4_CB_DOWN;
|
||||
trace_nfsd_cb_state(clp);
|
||||
nfsd4_mark_cb_state(clp, NFSD4_CB_DOWN);
|
||||
}
|
||||
|
||||
static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason)
|
||||
{
|
||||
if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags))
|
||||
return;
|
||||
clp->cl_cb_state = NFSD4_CB_FAULT;
|
||||
trace_nfsd_cb_state(clp);
|
||||
nfsd4_mark_cb_state(clp, NFSD4_CB_FAULT);
|
||||
}
|
||||
|
||||
static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
|
||||
|
||||
trace_nfsd_cb_done(clp, task->tk_status);
|
||||
if (task->tk_status)
|
||||
nfsd4_mark_cb_down(clp, task->tk_status);
|
||||
else {
|
||||
clp->cl_cb_state = NFSD4_CB_UP;
|
||||
trace_nfsd_cb_state(clp);
|
||||
}
|
||||
else
|
||||
nfsd4_mark_cb_state(clp, NFSD4_CB_UP);
|
||||
}
|
||||
|
||||
static void nfsd4_cb_probe_release(void *calldata)
|
||||
@ -995,8 +999,8 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = {
|
||||
*/
|
||||
void nfsd4_probe_callback(struct nfs4_client *clp)
|
||||
{
|
||||
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
|
||||
trace_nfsd_cb_state(clp);
|
||||
trace_nfsd_cb_probe(clp);
|
||||
nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN);
|
||||
set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags);
|
||||
nfsd4_run_cb(&clp->cl_cb_null);
|
||||
}
|
||||
@ -1009,11 +1013,10 @@ void nfsd4_probe_callback_sync(struct nfs4_client *clp)
|
||||
|
||||
void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
|
||||
{
|
||||
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
|
||||
nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN);
|
||||
spin_lock(&clp->cl_lock);
|
||||
memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
|
||||
spin_unlock(&clp->cl_lock);
|
||||
trace_nfsd_cb_state(clp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1170,8 +1173,6 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
|
||||
struct nfsd4_callback *cb = calldata;
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
|
||||
trace_nfsd_cb_done(clp, task->tk_status);
|
||||
|
||||
if (!nfsd4_cb_sequence_done(task, cb))
|
||||
return;
|
||||
|
||||
@ -1231,6 +1232,9 @@ void nfsd4_destroy_callback_queue(void)
|
||||
/* must be called under the state lock */
|
||||
void nfsd4_shutdown_callback(struct nfs4_client *clp)
|
||||
{
|
||||
if (clp->cl_cb_state != NFSD4_CB_UNKNOWN)
|
||||
trace_nfsd_cb_shutdown(clp);
|
||||
|
||||
set_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags);
|
||||
/*
|
||||
* Note this won't actually result in a null callback;
|
||||
@ -1276,7 +1280,6 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
||||
* kill the old client:
|
||||
*/
|
||||
if (clp->cl_cb_client) {
|
||||
trace_nfsd_cb_shutdown(clp);
|
||||
rpc_shutdown_client(clp->cl_cb_client);
|
||||
clp->cl_cb_client = NULL;
|
||||
put_cred(clp->cl_cb_cred);
|
||||
@ -1322,8 +1325,6 @@ nfsd4_run_cb_work(struct work_struct *work)
|
||||
struct rpc_clnt *clnt;
|
||||
int flags;
|
||||
|
||||
trace_nfsd_cb_work(clp, cb->cb_msg.rpc_proc->p_name);
|
||||
|
||||
if (cb->cb_need_restart) {
|
||||
cb->cb_need_restart = false;
|
||||
} else {
|
||||
@ -1345,7 +1346,7 @@ nfsd4_run_cb_work(struct work_struct *work)
|
||||
* Don't send probe messages for 4.1 or later.
|
||||
*/
|
||||
if (!cb->cb_ops && clp->cl_minorversion) {
|
||||
clp->cl_cb_state = NFSD4_CB_UP;
|
||||
nfsd4_mark_cb_state(clp, NFSD4_CB_UP);
|
||||
nfsd41_destroy_cb(cb);
|
||||
return;
|
||||
}
|
||||
|
@ -55,6 +55,13 @@ module_param(inter_copy_offload_enable, bool, 0644);
|
||||
MODULE_PARM_DESC(inter_copy_offload_enable,
|
||||
"Enable inter server to server copy offload. Default: false");
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
||||
static int nfsd4_ssc_umount_timeout = 900000; /* default to 15 mins */
|
||||
module_param(nfsd4_ssc_umount_timeout, int, 0644);
|
||||
MODULE_PARM_DESC(nfsd4_ssc_umount_timeout,
|
||||
"idle msecs before unmount export from source server");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
#include <linux/security.h>
|
||||
|
||||
@ -1165,6 +1172,81 @@ extern void nfs_sb_deactive(struct super_block *sb);
|
||||
|
||||
#define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys"
|
||||
|
||||
/*
|
||||
* setup a work entry in the ssc delayed unmount list.
|
||||
*/
|
||||
static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr,
|
||||
struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt)
|
||||
{
|
||||
struct nfsd4_ssc_umount_item *ni = 0;
|
||||
struct nfsd4_ssc_umount_item *work = NULL;
|
||||
struct nfsd4_ssc_umount_item *tmp;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
*ss_mnt = NULL;
|
||||
*retwork = NULL;
|
||||
work = kzalloc(sizeof(*work), GFP_KERNEL);
|
||||
try_again:
|
||||
spin_lock(&nn->nfsd_ssc_lock);
|
||||
list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) {
|
||||
if (strncmp(ni->nsui_ipaddr, ipaddr, sizeof(ni->nsui_ipaddr)))
|
||||
continue;
|
||||
/* found a match */
|
||||
if (ni->nsui_busy) {
|
||||
/* wait - and try again */
|
||||
prepare_to_wait(&nn->nfsd_ssc_waitq, &wait,
|
||||
TASK_INTERRUPTIBLE);
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
|
||||
/* allow 20secs for mount/unmount for now - revisit */
|
||||
if (signal_pending(current) ||
|
||||
(schedule_timeout(20*HZ) == 0)) {
|
||||
kfree(work);
|
||||
return nfserr_eagain;
|
||||
}
|
||||
finish_wait(&nn->nfsd_ssc_waitq, &wait);
|
||||
goto try_again;
|
||||
}
|
||||
*ss_mnt = ni->nsui_vfsmount;
|
||||
refcount_inc(&ni->nsui_refcnt);
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
kfree(work);
|
||||
|
||||
/* return vfsmount in ss_mnt */
|
||||
return 0;
|
||||
}
|
||||
if (work) {
|
||||
strncpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr));
|
||||
refcount_set(&work->nsui_refcnt, 2);
|
||||
work->nsui_busy = true;
|
||||
list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list);
|
||||
*retwork = work;
|
||||
}
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nfsd4_ssc_update_dul_work(struct nfsd_net *nn,
|
||||
struct nfsd4_ssc_umount_item *work, struct vfsmount *ss_mnt)
|
||||
{
|
||||
/* set nsui_vfsmount, clear busy flag and wakeup waiters */
|
||||
spin_lock(&nn->nfsd_ssc_lock);
|
||||
work->nsui_vfsmount = ss_mnt;
|
||||
work->nsui_busy = false;
|
||||
wake_up_all(&nn->nfsd_ssc_waitq);
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
}
|
||||
|
||||
static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn,
|
||||
struct nfsd4_ssc_umount_item *work)
|
||||
{
|
||||
spin_lock(&nn->nfsd_ssc_lock);
|
||||
list_del(&work->nsui_list);
|
||||
wake_up_all(&nn->nfsd_ssc_waitq);
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
kfree(work);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support one copy source server for now.
|
||||
*/
|
||||
@ -1181,6 +1263,8 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
|
||||
char *ipaddr, *dev_name, *raw_data;
|
||||
int len, raw_len;
|
||||
__be32 status = nfserr_inval;
|
||||
struct nfsd4_ssc_umount_item *work = NULL;
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
|
||||
naddr = &nss->u.nl4_addr;
|
||||
tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->addr,
|
||||
@ -1229,12 +1313,24 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
|
||||
goto out_free_rawdata;
|
||||
snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep);
|
||||
|
||||
status = nfsd4_ssc_setup_dul(nn, ipaddr, &work, &ss_mnt);
|
||||
if (status)
|
||||
goto out_free_devname;
|
||||
if (ss_mnt)
|
||||
goto out_done;
|
||||
|
||||
/* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
|
||||
ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data);
|
||||
module_put(type->owner);
|
||||
if (IS_ERR(ss_mnt))
|
||||
if (IS_ERR(ss_mnt)) {
|
||||
status = nfserr_nodev;
|
||||
if (work)
|
||||
nfsd4_ssc_cancel_dul_work(nn, work);
|
||||
goto out_free_devname;
|
||||
|
||||
}
|
||||
if (work)
|
||||
nfsd4_ssc_update_dul_work(nn, work, ss_mnt);
|
||||
out_done:
|
||||
status = 0;
|
||||
*mount = ss_mnt;
|
||||
|
||||
@ -1301,10 +1397,42 @@ static void
|
||||
nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
|
||||
struct nfsd_file *dst)
|
||||
{
|
||||
bool found = false;
|
||||
long timeout;
|
||||
struct nfsd4_ssc_umount_item *tmp;
|
||||
struct nfsd4_ssc_umount_item *ni = NULL;
|
||||
struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id);
|
||||
|
||||
nfs42_ssc_close(src->nf_file);
|
||||
fput(src->nf_file);
|
||||
nfsd_file_put(dst);
|
||||
mntput(ss_mnt);
|
||||
fput(src->nf_file);
|
||||
|
||||
if (!nn) {
|
||||
mntput(ss_mnt);
|
||||
return;
|
||||
}
|
||||
spin_lock(&nn->nfsd_ssc_lock);
|
||||
timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout);
|
||||
list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) {
|
||||
if (ni->nsui_vfsmount->mnt_sb == ss_mnt->mnt_sb) {
|
||||
list_del(&ni->nsui_list);
|
||||
/*
|
||||
* vfsmount can be shared by multiple exports,
|
||||
* decrement refcnt. If the count drops to 1 it
|
||||
* will be unmounted when nsui_expire expires.
|
||||
*/
|
||||
refcount_dec(&ni->nsui_refcnt);
|
||||
ni->nsui_expire = jiffies + timeout;
|
||||
list_add_tail(&ni->nsui_list, &nn->nfsd_ssc_mount_list);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
if (!found) {
|
||||
mntput(ss_mnt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* CONFIG_NFSD_V4_2_INTER_SSC */
|
||||
@ -1375,7 +1503,8 @@ static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = {
|
||||
|
||||
static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync)
|
||||
{
|
||||
copy->cp_res.wr_stable_how = NFS_UNSTABLE;
|
||||
copy->cp_res.wr_stable_how =
|
||||
copy->committed ? NFS_FILE_SYNC : NFS_UNSTABLE;
|
||||
copy->cp_synchronous = sync;
|
||||
gen_boot_verifier(©->cp_res.wr_verifier, copy->cp_clp->net);
|
||||
}
|
||||
@ -1386,6 +1515,7 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
|
||||
u64 bytes_total = copy->cp_count;
|
||||
u64 src_pos = copy->cp_src_pos;
|
||||
u64 dst_pos = copy->cp_dst_pos;
|
||||
__be32 status;
|
||||
|
||||
/* See RFC 7862 p.67: */
|
||||
if (bytes_total == 0)
|
||||
@ -1403,6 +1533,16 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
|
||||
src_pos += bytes_copied;
|
||||
dst_pos += bytes_copied;
|
||||
} while (bytes_total > 0 && !copy->cp_synchronous);
|
||||
/* for a non-zero asynchronous copy do a commit of data */
|
||||
if (!copy->cp_synchronous && copy->cp_res.wr_bytes_written > 0) {
|
||||
down_write(©->nf_dst->nf_rwsem);
|
||||
status = vfs_fsync_range(copy->nf_dst->nf_file,
|
||||
copy->cp_dst_pos,
|
||||
copy->cp_res.wr_bytes_written, 0);
|
||||
up_write(©->nf_dst->nf_rwsem);
|
||||
if (!status)
|
||||
copy->committed = true;
|
||||
}
|
||||
return bytes_copied;
|
||||
}
|
||||
|
||||
@ -1497,6 +1637,8 @@ do_callback:
|
||||
memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh));
|
||||
nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp,
|
||||
&nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD);
|
||||
trace_nfsd_cb_offload(copy->cp_clp, ©->cp_res.cb_stateid,
|
||||
©->fh, copy->cp_count, copy->nfserr);
|
||||
nfsd4_run_cb(&cb_copy->cp_cb);
|
||||
out:
|
||||
if (!copy->cp_intra)
|
||||
@ -3232,7 +3374,7 @@ bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd4_compoundres *resp = rqstp->rq_resp;
|
||||
struct nfsd4_compoundargs *argp = rqstp->rq_argp;
|
||||
struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
|
||||
struct nfsd4_op *this;
|
||||
struct nfsd4_compound_state *cstate = &resp->cstate;
|
||||
struct nfs4_op_map *allow = &cstate->clp->cl_spo_must_allow;
|
||||
u32 opiter;
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/nfs_ssc.h>
|
||||
#include "xdr4.h"
|
||||
#include "xdr4cb.h"
|
||||
#include "vfs.h"
|
||||
@ -1745,6 +1746,8 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u)
|
||||
struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
|
||||
struct nfs4_client *clp = c->cn_session->se_client;
|
||||
|
||||
trace_nfsd_cb_lost(clp);
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (!list_empty(&c->cn_persession)) {
|
||||
list_del(&c->cn_persession);
|
||||
@ -2355,6 +2358,21 @@ static void seq_quote_mem(struct seq_file *m, char *data, int len)
|
||||
seq_printf(m, "\"");
|
||||
}
|
||||
|
||||
static const char *cb_state2str(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case NFSD4_CB_UP:
|
||||
return "UP";
|
||||
case NFSD4_CB_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case NFSD4_CB_DOWN:
|
||||
return "DOWN";
|
||||
case NFSD4_CB_FAULT:
|
||||
return "FAULT";
|
||||
}
|
||||
return "UNDEFINED";
|
||||
}
|
||||
|
||||
static int client_info_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct inode *inode = m->private;
|
||||
@ -2383,6 +2401,8 @@ static int client_info_show(struct seq_file *m, void *v)
|
||||
seq_printf(m, "\nImplementation time: [%lld, %ld]\n",
|
||||
clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec);
|
||||
}
|
||||
seq_printf(m, "callback state: %s\n", cb_state2str(clp->cl_cb_state));
|
||||
seq_printf(m, "callback address: %pISpc\n", &clp->cl_cb_conn.cb_addr);
|
||||
drop_client(clp);
|
||||
|
||||
return 0;
|
||||
@ -2665,6 +2685,8 @@ static void force_expire_client(struct nfs4_client *clp)
|
||||
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
|
||||
bool already_expired;
|
||||
|
||||
trace_nfsd_clid_admin_expired(&clp->cl_clientid);
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
clp->cl_time = 0;
|
||||
spin_unlock(&clp->cl_lock);
|
||||
@ -2816,14 +2838,11 @@ move_to_confirmed(struct nfs4_client *clp)
|
||||
|
||||
lockdep_assert_held(&nn->client_lock);
|
||||
|
||||
dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
|
||||
list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
|
||||
rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
|
||||
add_clp_to_name_tree(clp, &nn->conf_name_tree);
|
||||
if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags) &&
|
||||
clp->cl_nfsd_dentry &&
|
||||
clp->cl_nfsd_info_dentry)
|
||||
fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY);
|
||||
set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
|
||||
trace_nfsd_clid_confirmed(&clp->cl_clientid);
|
||||
renew_client_locked(clp);
|
||||
}
|
||||
|
||||
@ -3176,20 +3195,24 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
}
|
||||
/* case 6 */
|
||||
exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
|
||||
trace_nfsd_clid_confirmed_r(conf);
|
||||
goto out_copy;
|
||||
}
|
||||
if (!creds_match) { /* case 3 */
|
||||
if (client_has_state(conf)) {
|
||||
status = nfserr_clid_inuse;
|
||||
trace_nfsd_clid_cred_mismatch(conf, rqstp);
|
||||
goto out;
|
||||
}
|
||||
goto out_new;
|
||||
}
|
||||
if (verfs_match) { /* case 2 */
|
||||
conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
|
||||
trace_nfsd_clid_confirmed_r(conf);
|
||||
goto out_copy;
|
||||
}
|
||||
/* case 5, client reboot */
|
||||
trace_nfsd_clid_verf_mismatch(conf, rqstp, &verf);
|
||||
conf = NULL;
|
||||
goto out_new;
|
||||
}
|
||||
@ -3199,16 +3222,19 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
goto out;
|
||||
}
|
||||
|
||||
unconf = find_unconfirmed_client_by_name(&exid->clname, nn);
|
||||
unconf = find_unconfirmed_client_by_name(&exid->clname, nn);
|
||||
if (unconf) /* case 4, possible retry or client restart */
|
||||
unhash_client_locked(unconf);
|
||||
|
||||
/* case 1 (normal case) */
|
||||
/* case 1, new owner ID */
|
||||
trace_nfsd_clid_fresh(new);
|
||||
|
||||
out_new:
|
||||
if (conf) {
|
||||
status = mark_client_expired_locked(conf);
|
||||
if (status)
|
||||
goto out;
|
||||
trace_nfsd_clid_replaced(&conf->cl_clientid);
|
||||
}
|
||||
new->cl_minorversion = cstate->minorversion;
|
||||
new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0];
|
||||
@ -3232,8 +3258,10 @@ out:
|
||||
out_nolock:
|
||||
if (new)
|
||||
expire_client(new);
|
||||
if (unconf)
|
||||
if (unconf) {
|
||||
trace_nfsd_clid_expire_unconf(&unconf->cl_clientid);
|
||||
expire_client(unconf);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -3425,9 +3453,10 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
goto out_free_conn;
|
||||
}
|
||||
} else if (unconf) {
|
||||
status = nfserr_clid_inuse;
|
||||
if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
|
||||
!rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
|
||||
status = nfserr_clid_inuse;
|
||||
trace_nfsd_clid_cred_mismatch(unconf, rqstp);
|
||||
goto out_free_conn;
|
||||
}
|
||||
status = nfserr_wrong_cred;
|
||||
@ -3447,6 +3476,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
old = NULL;
|
||||
goto out_free_conn;
|
||||
}
|
||||
trace_nfsd_clid_replaced(&old->cl_clientid);
|
||||
}
|
||||
move_to_confirmed(unconf);
|
||||
conf = unconf;
|
||||
@ -3471,6 +3501,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
/* cache solo and embedded create sessions under the client_lock */
|
||||
nfsd4_cache_create_session(cr_ses, cs_slot, status);
|
||||
spin_unlock(&nn->client_lock);
|
||||
if (conf == unconf)
|
||||
fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY);
|
||||
/* init connection and backchannel */
|
||||
nfsd4_init_conn(rqstp, conn, new);
|
||||
nfsd4_put_session(new);
|
||||
@ -3904,6 +3936,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp,
|
||||
status = nfserr_wrong_cred;
|
||||
goto out;
|
||||
}
|
||||
trace_nfsd_clid_destroyed(&clp->cl_clientid);
|
||||
unhash_client_locked(clp);
|
||||
out:
|
||||
spin_unlock(&nn->client_lock);
|
||||
@ -3946,6 +3979,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp,
|
||||
goto out;
|
||||
|
||||
status = nfs_ok;
|
||||
trace_nfsd_clid_reclaim_complete(&clp->cl_clientid);
|
||||
nfsd4_client_record_create(clp);
|
||||
inc_reclaim_complete(clp);
|
||||
out:
|
||||
@ -3967,27 +4001,29 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
new = create_client(clname, rqstp, &clverifier);
|
||||
if (new == NULL)
|
||||
return nfserr_jukebox;
|
||||
/* Cases below refer to rfc 3530 section 14.2.33: */
|
||||
spin_lock(&nn->client_lock);
|
||||
conf = find_confirmed_client_by_name(&clname, nn);
|
||||
if (conf && client_has_state(conf)) {
|
||||
/* case 0: */
|
||||
status = nfserr_clid_inuse;
|
||||
if (clp_used_exchangeid(conf))
|
||||
goto out;
|
||||
if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
|
||||
trace_nfsd_clid_inuse_err(conf);
|
||||
trace_nfsd_clid_cred_mismatch(conf, rqstp);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
unconf = find_unconfirmed_client_by_name(&clname, nn);
|
||||
if (unconf)
|
||||
unhash_client_locked(unconf);
|
||||
/* We need to handle only case 1: probable callback update */
|
||||
if (conf && same_verf(&conf->cl_verifier, &clverifier)) {
|
||||
copy_clid(new, conf);
|
||||
gen_confirm(new, nn);
|
||||
}
|
||||
if (conf) {
|
||||
if (same_verf(&conf->cl_verifier, &clverifier)) {
|
||||
copy_clid(new, conf);
|
||||
gen_confirm(new, nn);
|
||||
} else
|
||||
trace_nfsd_clid_verf_mismatch(conf, rqstp,
|
||||
&clverifier);
|
||||
} else
|
||||
trace_nfsd_clid_fresh(new);
|
||||
new->cl_minorversion = 0;
|
||||
gen_callback(new, setclid, rqstp);
|
||||
add_to_unconfirmed(new);
|
||||
@ -4000,12 +4036,13 @@ out:
|
||||
spin_unlock(&nn->client_lock);
|
||||
if (new)
|
||||
free_client(new);
|
||||
if (unconf)
|
||||
if (unconf) {
|
||||
trace_nfsd_clid_expire_unconf(&unconf->cl_clientid);
|
||||
expire_client(unconf);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
__be32
|
||||
nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
||||
struct nfsd4_compound_state *cstate,
|
||||
@ -4034,25 +4071,27 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
||||
* Nevertheless, RFC 7530 recommends INUSE for this case:
|
||||
*/
|
||||
status = nfserr_clid_inuse;
|
||||
if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred))
|
||||
if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
|
||||
trace_nfsd_clid_cred_mismatch(unconf, rqstp);
|
||||
goto out;
|
||||
if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred))
|
||||
}
|
||||
if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
|
||||
trace_nfsd_clid_cred_mismatch(conf, rqstp);
|
||||
goto out;
|
||||
/* cases below refer to rfc 3530 section 14.2.34: */
|
||||
}
|
||||
if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) {
|
||||
if (conf && same_verf(&confirm, &conf->cl_confirm)) {
|
||||
/* case 2: probable retransmit */
|
||||
status = nfs_ok;
|
||||
} else /* case 4: client hasn't noticed we rebooted yet? */
|
||||
} else
|
||||
status = nfserr_stale_clientid;
|
||||
goto out;
|
||||
}
|
||||
status = nfs_ok;
|
||||
if (conf) { /* case 1: callback update */
|
||||
if (conf) {
|
||||
old = unconf;
|
||||
unhash_client_locked(old);
|
||||
nfsd4_change_callback(conf, &unconf->cl_cb_conn);
|
||||
} else { /* case 3: normal case; new or rebooted client */
|
||||
} else {
|
||||
old = find_confirmed_client_by_name(&unconf->cl_name, nn);
|
||||
if (old) {
|
||||
status = nfserr_clid_inuse;
|
||||
@ -4065,12 +4104,15 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
||||
old = NULL;
|
||||
goto out;
|
||||
}
|
||||
trace_nfsd_clid_replaced(&old->cl_clientid);
|
||||
}
|
||||
move_to_confirmed(unconf);
|
||||
conf = unconf;
|
||||
}
|
||||
get_client_locked(conf);
|
||||
spin_unlock(&nn->client_lock);
|
||||
if (conf == unconf)
|
||||
fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY);
|
||||
nfsd4_probe_callback(conf);
|
||||
spin_lock(&nn->client_lock);
|
||||
put_client_renew_locked(conf);
|
||||
@ -4618,7 +4660,7 @@ nfsd_break_deleg_cb(struct file_lock *fl)
|
||||
struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
|
||||
struct nfs4_file *fp = dp->dl_stid.sc_file;
|
||||
|
||||
trace_nfsd_deleg_break(&dp->dl_stid.sc_stateid);
|
||||
trace_nfsd_cb_recall(&dp->dl_stid);
|
||||
|
||||
/*
|
||||
* We don't want the locks code to timeout the lease for us;
|
||||
@ -5457,6 +5499,69 @@ static bool state_expired(struct laundry_time *lt, time64_t last_refresh)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
||||
void nfsd4_ssc_init_umount_work(struct nfsd_net *nn)
|
||||
{
|
||||
spin_lock_init(&nn->nfsd_ssc_lock);
|
||||
INIT_LIST_HEAD(&nn->nfsd_ssc_mount_list);
|
||||
init_waitqueue_head(&nn->nfsd_ssc_waitq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfsd4_ssc_init_umount_work);
|
||||
|
||||
/*
|
||||
* This is called when nfsd is being shutdown, after all inter_ssc
|
||||
* cleanup were done, to destroy the ssc delayed unmount list.
|
||||
*/
|
||||
static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn)
|
||||
{
|
||||
struct nfsd4_ssc_umount_item *ni = NULL;
|
||||
struct nfsd4_ssc_umount_item *tmp;
|
||||
|
||||
spin_lock(&nn->nfsd_ssc_lock);
|
||||
list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) {
|
||||
list_del(&ni->nsui_list);
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
mntput(ni->nsui_vfsmount);
|
||||
kfree(ni);
|
||||
spin_lock(&nn->nfsd_ssc_lock);
|
||||
}
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
}
|
||||
|
||||
static void nfsd4_ssc_expire_umount(struct nfsd_net *nn)
|
||||
{
|
||||
bool do_wakeup = false;
|
||||
struct nfsd4_ssc_umount_item *ni = 0;
|
||||
struct nfsd4_ssc_umount_item *tmp;
|
||||
|
||||
spin_lock(&nn->nfsd_ssc_lock);
|
||||
list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) {
|
||||
if (time_after(jiffies, ni->nsui_expire)) {
|
||||
if (refcount_read(&ni->nsui_refcnt) > 1)
|
||||
continue;
|
||||
|
||||
/* mark being unmount */
|
||||
ni->nsui_busy = true;
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
mntput(ni->nsui_vfsmount);
|
||||
spin_lock(&nn->nfsd_ssc_lock);
|
||||
|
||||
/* waiters need to start from begin of list */
|
||||
list_del(&ni->nsui_list);
|
||||
kfree(ni);
|
||||
|
||||
/* wakeup ssc_connect waiters */
|
||||
do_wakeup = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (do_wakeup)
|
||||
wake_up_all(&nn->nfsd_ssc_waitq);
|
||||
spin_unlock(&nn->nfsd_ssc_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
static time64_t
|
||||
nfs4_laundromat(struct nfsd_net *nn)
|
||||
{
|
||||
@ -5495,10 +5600,8 @@ nfs4_laundromat(struct nfsd_net *nn)
|
||||
clp = list_entry(pos, struct nfs4_client, cl_lru);
|
||||
if (!state_expired(<, clp->cl_time))
|
||||
break;
|
||||
if (mark_client_expired_locked(clp)) {
|
||||
trace_nfsd_clid_expired(&clp->cl_clientid);
|
||||
if (mark_client_expired_locked(clp))
|
||||
continue;
|
||||
}
|
||||
list_add(&clp->cl_lru, &reaplist);
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
@ -5568,6 +5671,10 @@ nfs4_laundromat(struct nfsd_net *nn)
|
||||
list_del_init(&nbl->nbl_lru);
|
||||
free_blocked_lock(nbl);
|
||||
}
|
||||
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
||||
/* service the server-to-server copy delayed unmount list */
|
||||
nfsd4_ssc_expire_umount(nn);
|
||||
#endif
|
||||
out:
|
||||
return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT);
|
||||
}
|
||||
@ -6430,8 +6537,10 @@ nfsd4_lm_notify(struct file_lock *fl)
|
||||
}
|
||||
spin_unlock(&nn->blocked_locks_lock);
|
||||
|
||||
if (queue)
|
||||
if (queue) {
|
||||
trace_nfsd_cb_notify_lock(lo, nbl);
|
||||
nfsd4_run_cb(&nbl->nbl_cb);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct lock_manager_operations nfsd_posix_mng_ops = {
|
||||
@ -7229,7 +7338,6 @@ nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash,
|
||||
unsigned int strhashval;
|
||||
struct nfs4_client_reclaim *crp;
|
||||
|
||||
trace_nfsd_clid_reclaim(nn, name.len, name.data);
|
||||
crp = alloc_reclaim();
|
||||
if (crp) {
|
||||
strhashval = clientstr_hashval(name);
|
||||
@ -7279,8 +7387,6 @@ nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn)
|
||||
unsigned int strhashval;
|
||||
struct nfs4_client_reclaim *crp = NULL;
|
||||
|
||||
trace_nfsd_clid_find(nn, name.len, name.data);
|
||||
|
||||
strhashval = clientstr_hashval(name);
|
||||
list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
|
||||
if (compare_blob(&crp->cr_name, &name) == 0) {
|
||||
@ -7486,6 +7592,9 @@ nfs4_state_shutdown_net(struct net *net)
|
||||
|
||||
nfsd4_client_tracking_exit(net);
|
||||
nfs4_state_destroy_net(net);
|
||||
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
||||
nfsd4_ssc_shutdown_umount(nn);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -484,6 +484,10 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval)
|
||||
extern int nfsd4_is_junction(struct dentry *dentry);
|
||||
extern int register_cld_notifier(void);
|
||||
extern void unregister_cld_notifier(void);
|
||||
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
||||
extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn);
|
||||
#endif
|
||||
|
||||
#else /* CONFIG_NFSD_V4 */
|
||||
static inline int nfsd4_is_junction(struct dentry *dentry)
|
||||
{
|
||||
|
@ -225,15 +225,12 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
|
||||
* returns a crc32 hash for the filehandle that is compatible with
|
||||
* the one displayed by "wireshark".
|
||||
*/
|
||||
|
||||
static inline u32
|
||||
knfsd_fh_hash(struct knfsd_fh *fh)
|
||||
static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh)
|
||||
{
|
||||
return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size);
|
||||
}
|
||||
#else
|
||||
static inline u32
|
||||
knfsd_fh_hash(struct knfsd_fh *fh)
|
||||
static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -403,6 +403,9 @@ static int nfsd_startup_net(struct net *net, const struct cred *cred)
|
||||
if (ret)
|
||||
goto out_filecache;
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
||||
nfsd4_ssc_init_umount_work(nn);
|
||||
#endif
|
||||
nn->nfsd_net_up = true;
|
||||
return 0;
|
||||
|
||||
|
256
fs/nfsd/trace.h
256
fs/nfsd/trace.h
@ -408,7 +408,6 @@ TRACE_EVENT(nfsd_dirent,
|
||||
__entry->ino = ino;
|
||||
__entry->len = namlen;
|
||||
memcpy(__get_str(name), name, namlen);
|
||||
__assign_str(name, name);
|
||||
),
|
||||
TP_printk("fh_hash=0x%08x ino=%llu name=%.*s",
|
||||
__entry->fh_hash, __entry->ino,
|
||||
@ -459,7 +458,6 @@ DEFINE_STATEID_EVENT(layout_recall_release);
|
||||
|
||||
DEFINE_STATEID_EVENT(open);
|
||||
DEFINE_STATEID_EVENT(deleg_read);
|
||||
DEFINE_STATEID_EVENT(deleg_break);
|
||||
DEFINE_STATEID_EVENT(deleg_recall);
|
||||
|
||||
DECLARE_EVENT_CLASS(nfsd_stateseqid_class,
|
||||
@ -511,7 +509,12 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \
|
||||
TP_PROTO(const clientid_t *clid), \
|
||||
TP_ARGS(clid))
|
||||
|
||||
DEFINE_CLIENTID_EVENT(expired);
|
||||
DEFINE_CLIENTID_EVENT(expire_unconf);
|
||||
DEFINE_CLIENTID_EVENT(reclaim_complete);
|
||||
DEFINE_CLIENTID_EVENT(confirmed);
|
||||
DEFINE_CLIENTID_EVENT(destroyed);
|
||||
DEFINE_CLIENTID_EVENT(admin_expired);
|
||||
DEFINE_CLIENTID_EVENT(replaced);
|
||||
DEFINE_CLIENTID_EVENT(purged);
|
||||
DEFINE_CLIENTID_EVENT(renew);
|
||||
DEFINE_CLIENTID_EVENT(stale);
|
||||
@ -536,58 +539,102 @@ DEFINE_EVENT(nfsd_net_class, nfsd_##name, \
|
||||
DEFINE_NET_EVENT(grace_start);
|
||||
DEFINE_NET_EVENT(grace_complete);
|
||||
|
||||
DECLARE_EVENT_CLASS(nfsd_clid_class,
|
||||
TP_PROTO(const struct nfsd_net *nn,
|
||||
unsigned int namelen,
|
||||
const unsigned char *namedata),
|
||||
TP_ARGS(nn, namelen, namedata),
|
||||
TRACE_EVENT(nfsd_clid_cred_mismatch,
|
||||
TP_PROTO(
|
||||
const struct nfs4_client *clp,
|
||||
const struct svc_rqst *rqstp
|
||||
),
|
||||
TP_ARGS(clp, rqstp),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned long long, boot_time)
|
||||
__field(unsigned int, namelen)
|
||||
__dynamic_array(unsigned char, name, namelen)
|
||||
__field(u32, cl_boot)
|
||||
__field(u32, cl_id)
|
||||
__field(unsigned long, cl_flavor)
|
||||
__field(unsigned long, new_flavor)
|
||||
__array(unsigned char, addr, sizeof(struct sockaddr_in6))
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->boot_time = nn->boot_time;
|
||||
__entry->namelen = namelen;
|
||||
memcpy(__get_dynamic_array(name), namedata, namelen);
|
||||
__entry->cl_boot = clp->cl_clientid.cl_boot;
|
||||
__entry->cl_id = clp->cl_clientid.cl_id;
|
||||
__entry->cl_flavor = clp->cl_cred.cr_flavor;
|
||||
__entry->new_flavor = rqstp->rq_cred.cr_flavor;
|
||||
memcpy(__entry->addr, &rqstp->rq_xprt->xpt_remote,
|
||||
sizeof(struct sockaddr_in6));
|
||||
),
|
||||
TP_printk("boot_time=%16llx nfs4_clientid=%.*s",
|
||||
__entry->boot_time, __entry->namelen, __get_str(name))
|
||||
TP_printk("client %08x:%08x flavor=%s, conflict=%s from addr=%pISpc",
|
||||
__entry->cl_boot, __entry->cl_id,
|
||||
show_nfsd_authflavor(__entry->cl_flavor),
|
||||
show_nfsd_authflavor(__entry->new_flavor), __entry->addr
|
||||
)
|
||||
)
|
||||
|
||||
#define DEFINE_CLID_EVENT(name) \
|
||||
DEFINE_EVENT(nfsd_clid_class, nfsd_clid_##name, \
|
||||
TP_PROTO(const struct nfsd_net *nn, \
|
||||
unsigned int namelen, \
|
||||
const unsigned char *namedata), \
|
||||
TP_ARGS(nn, namelen, namedata))
|
||||
TRACE_EVENT(nfsd_clid_verf_mismatch,
|
||||
TP_PROTO(
|
||||
const struct nfs4_client *clp,
|
||||
const struct svc_rqst *rqstp,
|
||||
const nfs4_verifier *verf
|
||||
),
|
||||
TP_ARGS(clp, rqstp, verf),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, cl_boot)
|
||||
__field(u32, cl_id)
|
||||
__array(unsigned char, cl_verifier, NFS4_VERIFIER_SIZE)
|
||||
__array(unsigned char, new_verifier, NFS4_VERIFIER_SIZE)
|
||||
__array(unsigned char, addr, sizeof(struct sockaddr_in6))
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->cl_boot = clp->cl_clientid.cl_boot;
|
||||
__entry->cl_id = clp->cl_clientid.cl_id;
|
||||
memcpy(__entry->cl_verifier, (void *)&clp->cl_verifier,
|
||||
NFS4_VERIFIER_SIZE);
|
||||
memcpy(__entry->new_verifier, (void *)verf,
|
||||
NFS4_VERIFIER_SIZE);
|
||||
memcpy(__entry->addr, &rqstp->rq_xprt->xpt_remote,
|
||||
sizeof(struct sockaddr_in6));
|
||||
),
|
||||
TP_printk("client %08x:%08x verf=0x%s, updated=0x%s from addr=%pISpc",
|
||||
__entry->cl_boot, __entry->cl_id,
|
||||
__print_hex_str(__entry->cl_verifier, NFS4_VERIFIER_SIZE),
|
||||
__print_hex_str(__entry->new_verifier, NFS4_VERIFIER_SIZE),
|
||||
__entry->addr
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_CLID_EVENT(find);
|
||||
DEFINE_CLID_EVENT(reclaim);
|
||||
|
||||
TRACE_EVENT(nfsd_clid_inuse_err,
|
||||
DECLARE_EVENT_CLASS(nfsd_clid_class,
|
||||
TP_PROTO(const struct nfs4_client *clp),
|
||||
TP_ARGS(clp),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, cl_boot)
|
||||
__field(u32, cl_id)
|
||||
__array(unsigned char, addr, sizeof(struct sockaddr_in6))
|
||||
__field(unsigned int, namelen)
|
||||
__dynamic_array(unsigned char, name, clp->cl_name.len)
|
||||
__field(unsigned long, flavor)
|
||||
__array(unsigned char, verifier, NFS4_VERIFIER_SIZE)
|
||||
__dynamic_array(char, name, clp->cl_name.len + 1)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->cl_boot = clp->cl_clientid.cl_boot;
|
||||
__entry->cl_id = clp->cl_clientid.cl_id;
|
||||
memcpy(__entry->addr, &clp->cl_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
__entry->namelen = clp->cl_name.len;
|
||||
memcpy(__get_dynamic_array(name), clp->cl_name.data,
|
||||
clp->cl_name.len);
|
||||
__entry->flavor = clp->cl_cred.cr_flavor;
|
||||
memcpy(__entry->verifier, (void *)&clp->cl_verifier,
|
||||
NFS4_VERIFIER_SIZE);
|
||||
memcpy(__get_str(name), clp->cl_name.data, clp->cl_name.len);
|
||||
__get_str(name)[clp->cl_name.len] = '\0';
|
||||
),
|
||||
TP_printk("nfs4_clientid %.*s already in use by %pISpc, client %08x:%08x",
|
||||
__entry->namelen, __get_str(name), __entry->addr,
|
||||
TP_printk("addr=%pISpc name='%s' verifier=0x%s flavor=%s client=%08x:%08x",
|
||||
__entry->addr, __get_str(name),
|
||||
__print_hex_str(__entry->verifier, NFS4_VERIFIER_SIZE),
|
||||
show_nfsd_authflavor(__entry->flavor),
|
||||
__entry->cl_boot, __entry->cl_id)
|
||||
)
|
||||
);
|
||||
|
||||
#define DEFINE_CLID_EVENT(name) \
|
||||
DEFINE_EVENT(nfsd_clid_class, nfsd_clid_##name, \
|
||||
TP_PROTO(const struct nfs4_client *clp), \
|
||||
TP_ARGS(clp))
|
||||
|
||||
DEFINE_CLID_EVENT(fresh);
|
||||
DEFINE_CLID_EVENT(confirmed_r);
|
||||
|
||||
/*
|
||||
* from fs/nfsd/filecache.h
|
||||
@ -809,9 +856,9 @@ TRACE_EVENT(nfsd_cb_args,
|
||||
memcpy(__entry->addr, &conn->cb_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
),
|
||||
TP_printk("client %08x:%08x callback addr=%pISpc prog=%u ident=%u",
|
||||
__entry->cl_boot, __entry->cl_id,
|
||||
__entry->addr, __entry->prog, __entry->ident)
|
||||
TP_printk("addr=%pISpc client %08x:%08x prog=%u ident=%u",
|
||||
__entry->addr, __entry->cl_boot, __entry->cl_id,
|
||||
__entry->prog, __entry->ident)
|
||||
);
|
||||
|
||||
TRACE_EVENT(nfsd_cb_nodelegs,
|
||||
@ -828,11 +875,6 @@ TRACE_EVENT(nfsd_cb_nodelegs,
|
||||
TP_printk("client %08x:%08x", __entry->cl_boot, __entry->cl_id)
|
||||
)
|
||||
|
||||
TRACE_DEFINE_ENUM(NFSD4_CB_UP);
|
||||
TRACE_DEFINE_ENUM(NFSD4_CB_UNKNOWN);
|
||||
TRACE_DEFINE_ENUM(NFSD4_CB_DOWN);
|
||||
TRACE_DEFINE_ENUM(NFSD4_CB_FAULT);
|
||||
|
||||
#define show_cb_state(val) \
|
||||
__print_symbolic(val, \
|
||||
{ NFSD4_CB_UP, "UP" }, \
|
||||
@ -866,10 +908,53 @@ DEFINE_EVENT(nfsd_cb_class, nfsd_cb_##name, \
|
||||
TP_PROTO(const struct nfs4_client *clp), \
|
||||
TP_ARGS(clp))
|
||||
|
||||
DEFINE_NFSD_CB_EVENT(setup);
|
||||
DEFINE_NFSD_CB_EVENT(state);
|
||||
DEFINE_NFSD_CB_EVENT(probe);
|
||||
DEFINE_NFSD_CB_EVENT(lost);
|
||||
DEFINE_NFSD_CB_EVENT(shutdown);
|
||||
|
||||
TRACE_DEFINE_ENUM(RPC_AUTH_NULL);
|
||||
TRACE_DEFINE_ENUM(RPC_AUTH_UNIX);
|
||||
TRACE_DEFINE_ENUM(RPC_AUTH_GSS);
|
||||
TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5);
|
||||
TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5I);
|
||||
TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5P);
|
||||
|
||||
#define show_nfsd_authflavor(val) \
|
||||
__print_symbolic(val, \
|
||||
{ RPC_AUTH_NULL, "none" }, \
|
||||
{ RPC_AUTH_UNIX, "sys" }, \
|
||||
{ RPC_AUTH_GSS, "gss" }, \
|
||||
{ RPC_AUTH_GSS_KRB5, "krb5" }, \
|
||||
{ RPC_AUTH_GSS_KRB5I, "krb5i" }, \
|
||||
{ RPC_AUTH_GSS_KRB5P, "krb5p" })
|
||||
|
||||
TRACE_EVENT(nfsd_cb_setup,
|
||||
TP_PROTO(const struct nfs4_client *clp,
|
||||
const char *netid,
|
||||
rpc_authflavor_t authflavor
|
||||
),
|
||||
TP_ARGS(clp, netid, authflavor),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, cl_boot)
|
||||
__field(u32, cl_id)
|
||||
__field(unsigned long, authflavor)
|
||||
__array(unsigned char, addr, sizeof(struct sockaddr_in6))
|
||||
__array(unsigned char, netid, 8)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->cl_boot = clp->cl_clientid.cl_boot;
|
||||
__entry->cl_id = clp->cl_clientid.cl_id;
|
||||
strlcpy(__entry->netid, netid, sizeof(__entry->netid));
|
||||
__entry->authflavor = authflavor;
|
||||
memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
),
|
||||
TP_printk("addr=%pISpc client %08x:%08x proto=%s flavor=%s",
|
||||
__entry->addr, __entry->cl_boot, __entry->cl_id,
|
||||
__entry->netid, show_nfsd_authflavor(__entry->authflavor))
|
||||
);
|
||||
|
||||
TRACE_EVENT(nfsd_cb_setup_err,
|
||||
TP_PROTO(
|
||||
const struct nfs4_client *clp,
|
||||
@ -893,52 +978,97 @@ TRACE_EVENT(nfsd_cb_setup_err,
|
||||
__entry->addr, __entry->cl_boot, __entry->cl_id, __entry->error)
|
||||
);
|
||||
|
||||
TRACE_EVENT(nfsd_cb_work,
|
||||
TRACE_EVENT(nfsd_cb_recall,
|
||||
TP_PROTO(
|
||||
const struct nfs4_client *clp,
|
||||
const char *procedure
|
||||
const struct nfs4_stid *stid
|
||||
),
|
||||
TP_ARGS(clp, procedure),
|
||||
TP_ARGS(stid),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, cl_boot)
|
||||
__field(u32, cl_id)
|
||||
__string(procedure, procedure)
|
||||
__field(u32, si_id)
|
||||
__field(u32, si_generation)
|
||||
__array(unsigned char, addr, sizeof(struct sockaddr_in6))
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->cl_boot = clp->cl_clientid.cl_boot;
|
||||
__entry->cl_id = clp->cl_clientid.cl_id;
|
||||
__assign_str(procedure, procedure)
|
||||
memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
const stateid_t *stp = &stid->sc_stateid;
|
||||
const struct nfs4_client *clp = stid->sc_client;
|
||||
|
||||
__entry->cl_boot = stp->si_opaque.so_clid.cl_boot;
|
||||
__entry->cl_id = stp->si_opaque.so_clid.cl_id;
|
||||
__entry->si_id = stp->si_opaque.so_id;
|
||||
__entry->si_generation = stp->si_generation;
|
||||
if (clp)
|
||||
memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
else
|
||||
memset(__entry->addr, 0, sizeof(struct sockaddr_in6));
|
||||
),
|
||||
TP_printk("addr=%pISpc client %08x:%08x procedure=%s",
|
||||
TP_printk("addr=%pISpc client %08x:%08x stateid %08x:%08x",
|
||||
__entry->addr, __entry->cl_boot, __entry->cl_id,
|
||||
__get_str(procedure))
|
||||
__entry->si_id, __entry->si_generation)
|
||||
);
|
||||
|
||||
TRACE_EVENT(nfsd_cb_done,
|
||||
TRACE_EVENT(nfsd_cb_notify_lock,
|
||||
TP_PROTO(
|
||||
const struct nfs4_client *clp,
|
||||
int status
|
||||
const struct nfs4_lockowner *lo,
|
||||
const struct nfsd4_blocked_lock *nbl
|
||||
),
|
||||
TP_ARGS(clp, status),
|
||||
TP_ARGS(lo, nbl),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, cl_boot)
|
||||
__field(u32, cl_id)
|
||||
__field(int, status)
|
||||
__field(u32, fh_hash)
|
||||
__array(unsigned char, addr, sizeof(struct sockaddr_in6))
|
||||
),
|
||||
TP_fast_assign(
|
||||
const struct nfs4_client *clp = lo->lo_owner.so_client;
|
||||
|
||||
__entry->cl_boot = clp->cl_clientid.cl_boot;
|
||||
__entry->cl_id = clp->cl_clientid.cl_id;
|
||||
__entry->status = status;
|
||||
__entry->fh_hash = knfsd_fh_hash(&nbl->nbl_fh);
|
||||
memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
),
|
||||
TP_printk("addr=%pISpc client %08x:%08x status=%d",
|
||||
TP_printk("addr=%pISpc client %08x:%08x fh_hash=0x%08x",
|
||||
__entry->addr, __entry->cl_boot, __entry->cl_id,
|
||||
__entry->status)
|
||||
__entry->fh_hash)
|
||||
);
|
||||
|
||||
TRACE_EVENT(nfsd_cb_offload,
|
||||
TP_PROTO(
|
||||
const struct nfs4_client *clp,
|
||||
const stateid_t *stp,
|
||||
const struct knfsd_fh *fh,
|
||||
u64 count,
|
||||
__be32 status
|
||||
),
|
||||
TP_ARGS(clp, stp, fh, count, status),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, cl_boot)
|
||||
__field(u32, cl_id)
|
||||
__field(u32, si_id)
|
||||
__field(u32, si_generation)
|
||||
__field(u32, fh_hash)
|
||||
__field(int, status)
|
||||
__field(u64, count)
|
||||
__array(unsigned char, addr, sizeof(struct sockaddr_in6))
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->cl_boot = stp->si_opaque.so_clid.cl_boot;
|
||||
__entry->cl_id = stp->si_opaque.so_clid.cl_id;
|
||||
__entry->si_id = stp->si_opaque.so_id;
|
||||
__entry->si_generation = stp->si_generation;
|
||||
__entry->fh_hash = knfsd_fh_hash(fh);
|
||||
__entry->status = be32_to_cpu(status);
|
||||
__entry->count = count;
|
||||
memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
),
|
||||
TP_printk("addr=%pISpc client %08x:%08x stateid %08x:%08x fh_hash=0x%08x count=%llu status=%d",
|
||||
__entry->addr, __entry->cl_boot, __entry->cl_id,
|
||||
__entry->si_id, __entry->si_generation,
|
||||
__entry->fh_hash, __entry->count, __entry->status)
|
||||
);
|
||||
|
||||
#endif /* _NFSD_TRACE_H */
|
||||
|
@ -1123,6 +1123,19 @@ out:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V3
|
||||
static int
|
||||
nfsd_filemap_write_and_wait_range(struct nfsd_file *nf, loff_t offset,
|
||||
loff_t end)
|
||||
{
|
||||
struct address_space *mapping = nf->nf_file->f_mapping;
|
||||
int ret = filemap_fdatawrite_range(mapping, offset, end);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
filemap_fdatawait_range_keep_errors(mapping, offset, end);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Commit all pending writes to stable storage.
|
||||
*
|
||||
@ -1153,10 +1166,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
if (err)
|
||||
goto out;
|
||||
if (EX_ISSYNC(fhp->fh_export)) {
|
||||
int err2;
|
||||
int err2 = nfsd_filemap_write_and_wait_range(nf, offset, end);
|
||||
|
||||
down_write(&nf->nf_rwsem);
|
||||
err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
|
||||
if (!err2)
|
||||
err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
|
||||
switch (err2) {
|
||||
case 0:
|
||||
nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net,
|
||||
@ -1613,9 +1627,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
|
||||
host_err = vfs_symlink(&init_user_ns, d_inode(dentry), dnew, path);
|
||||
err = nfserrno(host_err);
|
||||
fh_unlock(fhp);
|
||||
if (!err)
|
||||
err = nfserrno(commit_metadata(fhp));
|
||||
fh_unlock(fhp);
|
||||
|
||||
fh_drop_write(fhp);
|
||||
|
||||
@ -1680,6 +1694,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
|
||||
if (d_really_is_negative(dold))
|
||||
goto out_dput;
|
||||
host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL);
|
||||
fh_unlock(ffhp);
|
||||
if (!host_err) {
|
||||
err = nfserrno(commit_metadata(ffhp));
|
||||
if (!err)
|
||||
@ -1859,6 +1874,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
||||
{
|
||||
struct dentry *dentry, *rdentry;
|
||||
struct inode *dirp;
|
||||
struct inode *rinode;
|
||||
__be32 err;
|
||||
int host_err;
|
||||
|
||||
@ -1887,6 +1903,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
||||
host_err = -ENOENT;
|
||||
goto out_drop_write;
|
||||
}
|
||||
rinode = d_inode(rdentry);
|
||||
ihold(rinode);
|
||||
|
||||
if (!type)
|
||||
type = d_inode(rdentry)->i_mode & S_IFMT;
|
||||
@ -1899,9 +1917,11 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
||||
host_err = vfs_rmdir(&init_user_ns, dirp, rdentry);
|
||||
}
|
||||
|
||||
fh_unlock(fhp);
|
||||
if (!host_err)
|
||||
host_err = commit_metadata(fhp);
|
||||
dput(rdentry);
|
||||
iput(rinode); /* truncate the inode here */
|
||||
|
||||
out_drop_write:
|
||||
fh_drop_write(fhp);
|
||||
|
@ -567,6 +567,7 @@ struct nfsd4_copy {
|
||||
struct vfsmount *ss_mnt;
|
||||
struct nfs_fh c_fh;
|
||||
nfs4_stateid stateid;
|
||||
bool committed;
|
||||
};
|
||||
|
||||
struct nfsd4_seek {
|
||||
|
@ -109,11 +109,5 @@ int nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *);
|
||||
int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *);
|
||||
int nlmsvc_decode_notify(struct svc_rqst *, __be32 *);
|
||||
int nlmsvc_decode_reboot(struct svc_rqst *, __be32 *);
|
||||
/*
|
||||
int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
|
||||
int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
|
||||
int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *);
|
||||
int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
|
||||
*/
|
||||
|
||||
#endif /* LOCKD_XDR_H */
|
||||
|
@ -37,12 +37,7 @@ int nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *);
|
||||
int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *);
|
||||
int nlm4svc_decode_notify(struct svc_rqst *, __be32 *);
|
||||
int nlm4svc_decode_reboot(struct svc_rqst *, __be32 *);
|
||||
/*
|
||||
int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
|
||||
int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
|
||||
int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *);
|
||||
int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
|
||||
*/
|
||||
|
||||
extern const struct rpc_version nlm_version4;
|
||||
|
||||
#endif /* LOCKD_XDR4_H */
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/sunrpc/svc.h>
|
||||
|
||||
extern struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl;
|
||||
|
||||
@ -52,6 +53,19 @@ 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);
|
||||
}
|
||||
|
||||
struct nfsd4_ssc_umount_item {
|
||||
struct list_head nsui_list;
|
||||
bool nsui_busy;
|
||||
/*
|
||||
* nsui_refcnt inited to 2, 1 on list and 1 for consumer. Entry
|
||||
* is removed when refcnt drops to 1 and nsui_expire expires.
|
||||
*/
|
||||
refcount_t nsui_refcnt;
|
||||
unsigned long nsui_expire;
|
||||
struct vfsmount *nsui_vfsmount;
|
||||
char nsui_ipaddr[RPC_MAX_ADDRBUFLEN];
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -1275,7 +1275,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
|
||||
long long ctxh;
|
||||
struct gss_api_mech *gm = NULL;
|
||||
time64_t expiry;
|
||||
int status = -EINVAL;
|
||||
int status;
|
||||
|
||||
memset(&rsci, 0, sizeof(rsci));
|
||||
/* context handle */
|
||||
|
@ -483,7 +483,7 @@ out_overflow:
|
||||
* @iov: kvec to write
|
||||
*
|
||||
* Returns:
|
||||
* On succes, returns zero
|
||||
* On success, returns zero
|
||||
* %-E2BIG if the client-provided Write chunk is too small
|
||||
* %-ENOMEM if a resource has been exhausted
|
||||
* %-EIO if an rdma-rw error occurred
|
||||
@ -504,7 +504,7 @@ static int svc_rdma_iov_write(struct svc_rdma_write_info *info,
|
||||
* @length: number of bytes to write
|
||||
*
|
||||
* Returns:
|
||||
* On succes, returns zero
|
||||
* On success, returns zero
|
||||
* %-E2BIG if the client-provided Write chunk is too small
|
||||
* %-ENOMEM if a resource has been exhausted
|
||||
* %-EIO if an rdma-rw error occurred
|
||||
@ -526,7 +526,7 @@ static int svc_rdma_pages_write(struct svc_rdma_write_info *info,
|
||||
* @data: pointer to write arguments
|
||||
*
|
||||
* Returns:
|
||||
* On succes, returns zero
|
||||
* On success, returns zero
|
||||
* %-E2BIG if the client-provided Write chunk is too small
|
||||
* %-ENOMEM if a resource has been exhausted
|
||||
* %-EIO if an rdma-rw error occurred
|
||||
|
Loading…
Reference in New Issue
Block a user