You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'nfsd-4.17' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields: "Chuck Lever did a bunch of work on nfsd tracepoints, on RDMA, and on server xdr decoding (with an eye towards eliminating a data copy in the RDMA case). I did some refactoring of the delegation code in preparation for eliminating some delegation self-conflicts and implementing write delegations" * tag 'nfsd-4.17' of git://linux-nfs.org/~bfields/linux: (40 commits) nfsd: fix incorrect umasks sunrpc: remove incorrect HMAC request initialization NFSD: Clean up legacy NFS SYMLINK argument XDR decoders NFSD: Clean up legacy NFS WRITE argument XDR decoders nfsd: Trace NFSv4 COMPOUND execution nfsd: Add I/O trace points in the NFSv4 read proc nfsd: Add I/O trace points in the NFSv4 write path nfsd: Add "nfsd_" to trace point names nfsd: Record request byte count, not count of vectors nfsd: Fix NFSD trace points svc: Report xprt dequeue latency sunrpc: Report per-RPC execution stats sunrpc: Re-purpose trace_svc_process sunrpc: Save remote presentation address in svc_xprt for trace events sunrpc: Simplify trace_svc_recv sunrpc: Simplify do_enqueue tracing sunrpc: Move trace_svc_xprt_dequeue() sunrpc: Update show_svc_xprt_flags() to include recently added flags svc: Simplify ->xpo_secure_port sunrpc: Remove unneeded pointer dereference ...
This commit is contained in:
+2
-2
@@ -57,8 +57,8 @@ static struct task_struct *nlmsvc_task;
|
||||
static struct svc_rqst *nlmsvc_rqst;
|
||||
unsigned long nlmsvc_timeout;
|
||||
|
||||
atomic_t nlm_ntf_refcnt = ATOMIC_INIT(0);
|
||||
DECLARE_WAIT_QUEUE_HEAD(nlm_ntf_wq);
|
||||
static atomic_t nlm_ntf_refcnt = ATOMIC_INIT(0);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(nlm_ntf_wq);
|
||||
|
||||
unsigned int lockd_net_id;
|
||||
|
||||
|
||||
+16
-2
@@ -192,6 +192,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
|
||||
struct nfsd3_writeres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
unsigned long cnt = argp->len;
|
||||
unsigned int nvecs;
|
||||
|
||||
dprintk("nfsd: WRITE(3) %s %d bytes at %Lu%s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -201,9 +202,12 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
resp->committed = argp->stable;
|
||||
nvecs = svc_fill_write_vector(rqstp, &argp->first, cnt);
|
||||
if (!nvecs)
|
||||
RETURN_STATUS(nfserr_io);
|
||||
nfserr = nfsd_write(rqstp, &resp->fh, argp->offset,
|
||||
rqstp->rq_vec, argp->vlen,
|
||||
&cnt, resp->committed);
|
||||
rqstp->rq_vec, nvecs, &cnt,
|
||||
resp->committed);
|
||||
resp->count = cnt;
|
||||
RETURN_STATUS(nfserr);
|
||||
}
|
||||
@@ -279,6 +283,16 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
if (argp->tlen == 0)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
if (argp->tlen > NFS3_MAXPATHLEN)
|
||||
RETURN_STATUS(nfserr_nametoolong);
|
||||
|
||||
argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
|
||||
argp->tlen);
|
||||
if (IS_ERR(argp->tname))
|
||||
RETURN_STATUS(nfserrno(PTR_ERR(argp->tname)));
|
||||
|
||||
dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n",
|
||||
SVCFH_fmt(&argp->ffh),
|
||||
argp->flen, argp->fname,
|
||||
|
||||
+16
-51
@@ -391,7 +391,7 @@ int
|
||||
nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_writeargs *args = rqstp->rq_argp;
|
||||
unsigned int len, v, hdr, dlen;
|
||||
unsigned int len, hdr, dlen;
|
||||
u32 max_blocksize = svc_max_payload(rqstp);
|
||||
struct kvec *head = rqstp->rq_arg.head;
|
||||
struct kvec *tail = rqstp->rq_arg.tail;
|
||||
@@ -433,17 +433,9 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
args->count = max_blocksize;
|
||||
len = args->len = max_blocksize;
|
||||
}
|
||||
rqstp->rq_vec[0].iov_base = (void*)p;
|
||||
rqstp->rq_vec[0].iov_len = head->iov_len - hdr;
|
||||
v = 0;
|
||||
while (len > rqstp->rq_vec[v].iov_len) {
|
||||
len -= rqstp->rq_vec[v].iov_len;
|
||||
v++;
|
||||
rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
|
||||
rqstp->rq_vec[v].iov_len = PAGE_SIZE;
|
||||
}
|
||||
rqstp->rq_vec[v].iov_len = len;
|
||||
args->vlen = v + 1;
|
||||
|
||||
args->first.iov_base = (void *)p;
|
||||
args->first.iov_len = head->iov_len - hdr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -489,51 +481,24 @@ int
|
||||
nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_symlinkargs *args = rqstp->rq_argp;
|
||||
unsigned int len, avail;
|
||||
char *old, *new;
|
||||
struct kvec *vec;
|
||||
char *base = (char *)p;
|
||||
size_t dlen;
|
||||
|
||||
if (!(p = decode_fh(p, &args->ffh)) ||
|
||||
!(p = decode_filename(p, &args->fname, &args->flen))
|
||||
)
|
||||
!(p = decode_filename(p, &args->fname, &args->flen)))
|
||||
return 0;
|
||||
p = decode_sattr3(p, &args->attrs);
|
||||
|
||||
/* now decode the pathname, which might be larger than the first page.
|
||||
* As we have to check for nul's anyway, we copy it into a new page
|
||||
* This page appears in the rq_res.pages list, but as pages_len is always
|
||||
* 0, it won't get in the way
|
||||
*/
|
||||
len = ntohl(*p++);
|
||||
if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
|
||||
return 0;
|
||||
args->tname = new = page_address(*(rqstp->rq_next_page++));
|
||||
args->tlen = len;
|
||||
/* first copy and check from the first page */
|
||||
old = (char*)p;
|
||||
vec = &rqstp->rq_arg.head[0];
|
||||
if ((void *)old > vec->iov_base + vec->iov_len)
|
||||
return 0;
|
||||
avail = vec->iov_len - (old - (char*)vec->iov_base);
|
||||
while (len && avail && *old) {
|
||||
*new++ = *old++;
|
||||
len--;
|
||||
avail--;
|
||||
}
|
||||
/* now copy next page if there is one */
|
||||
if (len && !avail && rqstp->rq_arg.page_len) {
|
||||
avail = min_t(unsigned int, rqstp->rq_arg.page_len, PAGE_SIZE);
|
||||
old = page_address(rqstp->rq_arg.pages[0]);
|
||||
}
|
||||
while (len && avail && *old) {
|
||||
*new++ = *old++;
|
||||
len--;
|
||||
avail--;
|
||||
}
|
||||
*new = '\0';
|
||||
if (len)
|
||||
return 0;
|
||||
args->tlen = ntohl(*p++);
|
||||
|
||||
args->first.iov_base = p;
|
||||
args->first.iov_len = rqstp->rq_arg.head[0].iov_len;
|
||||
args->first.iov_len -= (char *)p - base;
|
||||
|
||||
dlen = args->first.iov_len + rqstp->rq_arg.page_len +
|
||||
rqstp->rq_arg.tail[0].iov_len;
|
||||
if (dlen < XDR_QUADLEN(args->tlen) << 2)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -223,8 +223,8 @@ static int nfs_cb_stat_to_errno(int status)
|
||||
return -status;
|
||||
}
|
||||
|
||||
static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected,
|
||||
int *status)
|
||||
static int decode_cb_op_status(struct xdr_stream *xdr,
|
||||
enum nfs_cb_opnum4 expected, int *status)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 op;
|
||||
|
||||
@@ -165,7 +165,7 @@ nfsd4_free_layout_stateid(struct nfs4_stid *stid)
|
||||
struct nfs4_client *clp = ls->ls_stid.sc_client;
|
||||
struct nfs4_file *fp = ls->ls_stid.sc_file;
|
||||
|
||||
trace_layoutstate_free(&ls->ls_stid.sc_stateid);
|
||||
trace_nfsd_layoutstate_free(&ls->ls_stid.sc_stateid);
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_del_init(&ls->ls_perclnt);
|
||||
@@ -264,7 +264,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
|
||||
list_add(&ls->ls_perfile, &fp->fi_lo_states);
|
||||
spin_unlock(&fp->fi_lock);
|
||||
|
||||
trace_layoutstate_alloc(&ls->ls_stid.sc_stateid);
|
||||
trace_nfsd_layoutstate_alloc(&ls->ls_stid.sc_stateid);
|
||||
return ls;
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ nfsd4_recall_file_layout(struct nfs4_layout_stateid *ls)
|
||||
if (list_empty(&ls->ls_layouts))
|
||||
goto out_unlock;
|
||||
|
||||
trace_layout_recall(&ls->ls_stid.sc_stateid);
|
||||
trace_nfsd_layout_recall(&ls->ls_stid.sc_stateid);
|
||||
|
||||
refcount_inc(&ls->ls_stid.sc_count);
|
||||
nfsd4_run_cb(&ls->ls_recall);
|
||||
@@ -507,7 +507,7 @@ nfsd4_return_file_layouts(struct svc_rqst *rqstp,
|
||||
false, lrp->lr_layout_type,
|
||||
&ls);
|
||||
if (nfserr) {
|
||||
trace_layout_return_lookup_fail(&lrp->lr_sid);
|
||||
trace_nfsd_layout_return_lookup_fail(&lrp->lr_sid);
|
||||
return nfserr;
|
||||
}
|
||||
|
||||
@@ -523,7 +523,7 @@ nfsd4_return_file_layouts(struct svc_rqst *rqstp,
|
||||
nfs4_inc_and_copy_stateid(&lrp->lr_sid, &ls->ls_stid);
|
||||
lrp->lrs_present = 1;
|
||||
} else {
|
||||
trace_layoutstate_unhash(&ls->ls_stid.sc_stateid);
|
||||
trace_nfsd_layoutstate_unhash(&ls->ls_stid.sc_stateid);
|
||||
nfs4_unhash_stid(&ls->ls_stid);
|
||||
lrp->lrs_present = 0;
|
||||
}
|
||||
@@ -694,7 +694,7 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
|
||||
/*
|
||||
* Unknown error or non-responding client, we'll need to fence.
|
||||
*/
|
||||
trace_layout_recall_fail(&ls->ls_stid.sc_stateid);
|
||||
trace_nfsd_layout_recall_fail(&ls->ls_stid.sc_stateid);
|
||||
|
||||
ops = nfsd4_layout_ops[ls->ls_layout_type];
|
||||
if (ops->fence_client)
|
||||
@@ -703,7 +703,7 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
|
||||
nfsd4_cb_layout_fail(ls);
|
||||
return -1;
|
||||
case -NFS4ERR_NOMATCHING_LAYOUT:
|
||||
trace_layout_recall_done(&ls->ls_stid.sc_stateid);
|
||||
trace_nfsd_layout_recall_done(&ls->ls_stid.sc_stateid);
|
||||
task->tk_status = 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -716,7 +716,7 @@ nfsd4_cb_layout_release(struct nfsd4_callback *cb)
|
||||
container_of(cb, struct nfs4_layout_stateid, ls_recall);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
trace_layout_recall_release(&ls->ls_stid.sc_stateid);
|
||||
trace_nfsd_layout_recall_release(&ls->ls_stid.sc_stateid);
|
||||
|
||||
nfsd4_return_all_layouts(ls, &reaplist);
|
||||
nfsd4_free_layouts(&reaplist);
|
||||
|
||||
+25
-13
@@ -32,6 +32,7 @@
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <linux/fs_struct.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -252,11 +253,13 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
|
||||
* Note: create modes (UNCHECKED,GUARDED...) are the same
|
||||
* in NFSv4 as in v3 except EXCLUSIVE4_1.
|
||||
*/
|
||||
current->fs->umask = open->op_umask;
|
||||
status = do_nfsd_create(rqstp, current_fh, open->op_fname.data,
|
||||
open->op_fname.len, &open->op_iattr,
|
||||
*resfh, open->op_createmode,
|
||||
(u32 *)open->op_verf.data,
|
||||
&open->op_truncate, &open->op_created);
|
||||
current->fs->umask = 0;
|
||||
|
||||
if (!status && open->op_label.len)
|
||||
nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval);
|
||||
@@ -603,6 +606,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
current->fs->umask = create->cr_umask;
|
||||
switch (create->cr_type) {
|
||||
case NF4LNK:
|
||||
status = nfsd_symlink(rqstp, &cstate->current_fh,
|
||||
@@ -611,20 +615,22 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
break;
|
||||
|
||||
case NF4BLK:
|
||||
status = nfserr_inval;
|
||||
rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
|
||||
if (MAJOR(rdev) != create->cr_specdata1 ||
|
||||
MINOR(rdev) != create->cr_specdata2)
|
||||
return nfserr_inval;
|
||||
goto out_umask;
|
||||
status = nfsd_create(rqstp, &cstate->current_fh,
|
||||
create->cr_name, create->cr_namelen,
|
||||
&create->cr_iattr, S_IFBLK, rdev, &resfh);
|
||||
break;
|
||||
|
||||
case NF4CHR:
|
||||
status = nfserr_inval;
|
||||
rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
|
||||
if (MAJOR(rdev) != create->cr_specdata1 ||
|
||||
MINOR(rdev) != create->cr_specdata2)
|
||||
return nfserr_inval;
|
||||
goto out_umask;
|
||||
status = nfsd_create(rqstp, &cstate->current_fh,
|
||||
create->cr_name, create->cr_namelen,
|
||||
&create->cr_iattr,S_IFCHR, rdev, &resfh);
|
||||
@@ -668,6 +674,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
fh_dup2(&cstate->current_fh, &resfh);
|
||||
out:
|
||||
fh_put(&resfh);
|
||||
out_umask:
|
||||
current->fs->umask = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -751,6 +759,9 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (read->rd_offset >= OFFSET_MAX)
|
||||
return nfserr_inval;
|
||||
|
||||
trace_nfsd_read_start(rqstp, &cstate->current_fh,
|
||||
read->rd_offset, read->rd_length);
|
||||
|
||||
/*
|
||||
* If we do a zero copy read, then a client will see read data
|
||||
* that reflects the state of the file *after* performing the
|
||||
@@ -783,6 +794,8 @@ nfsd4_read_release(union nfsd4_op_u *u)
|
||||
{
|
||||
if (u->read.rd_filp)
|
||||
fput(u->read.rd_filp);
|
||||
trace_nfsd_read_done(u->read.rd_rqstp, u->read.rd_fhp,
|
||||
u->read.rd_offset, u->read.rd_length);
|
||||
}
|
||||
|
||||
static __be32
|
||||
@@ -1001,6 +1014,9 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (write->wr_offset >= OFFSET_MAX)
|
||||
return nfserr_inval;
|
||||
|
||||
cnt = write->wr_buflen;
|
||||
trace_nfsd_write_start(rqstp, &cstate->current_fh,
|
||||
write->wr_offset, cnt);
|
||||
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
|
||||
stateid, WR_STATE, &filp, NULL);
|
||||
if (status) {
|
||||
@@ -1008,7 +1024,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
return status;
|
||||
}
|
||||
|
||||
cnt = write->wr_buflen;
|
||||
write->wr_how_written = write->wr_stable_how;
|
||||
gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp));
|
||||
|
||||
@@ -1021,7 +1036,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
fput(filp);
|
||||
|
||||
write->wr_bytes_written = cnt;
|
||||
|
||||
trace_nfsd_write_done(rqstp, &cstate->current_fh,
|
||||
write->wr_offset, cnt);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1106,7 +1122,6 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
else {
|
||||
copy->cp_res.wr_bytes_written = bytes;
|
||||
copy->cp_res.wr_stable_how = NFS_UNSTABLE;
|
||||
copy->cp_consecutive = 1;
|
||||
copy->cp_synchronous = 1;
|
||||
gen_boot_verifier(©->cp_res.wr_verifier, SVC_NET(rqstp));
|
||||
status = nfs_ok;
|
||||
@@ -1412,7 +1427,7 @@ nfsd4_layoutget(struct svc_rqst *rqstp,
|
||||
nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lgp->lg_sid,
|
||||
true, lgp->lg_layout_type, &ls);
|
||||
if (nfserr) {
|
||||
trace_layout_get_lookup_fail(&lgp->lg_sid);
|
||||
trace_nfsd_layout_get_lookup_fail(&lgp->lg_sid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1481,7 +1496,7 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp,
|
||||
false, lcp->lc_layout_type,
|
||||
&ls);
|
||||
if (nfserr) {
|
||||
trace_layout_commit_lookup_fail(&lcp->lc_sid);
|
||||
trace_nfsd_layout_commit_lookup_fail(&lcp->lc_sid);
|
||||
/* fixup error code as per RFC5661 */
|
||||
if (nfserr == nfserr_bad_stateid)
|
||||
nfserr = nfserr_badlayout;
|
||||
@@ -1714,12 +1729,10 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
|
||||
goto encode_op;
|
||||
}
|
||||
|
||||
trace_nfsd_compound(rqstp, args->opcnt);
|
||||
while (!status && resp->opcnt < args->opcnt) {
|
||||
op = &args->ops[resp->opcnt++];
|
||||
|
||||
dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
|
||||
resp->opcnt, args->opcnt, op->opnum,
|
||||
nfsd4_op_name(op->opnum));
|
||||
/*
|
||||
* The XDR decode routines may have pre-set op->status;
|
||||
* for example, if there is a miscellaneous XDR error
|
||||
@@ -1793,9 +1806,8 @@ encode_op:
|
||||
status = op->status;
|
||||
}
|
||||
|
||||
dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n",
|
||||
args->ops, args->opcnt, resp->opcnt, op->opnum,
|
||||
be32_to_cpu(status));
|
||||
trace_nfsd_compound_status(args->opcnt, resp->opcnt, status,
|
||||
nfsd4_op_name(op->opnum));
|
||||
|
||||
nfsd4_cstate_clear_replay(cstate);
|
||||
nfsd4_increment_op_stats(op->opnum);
|
||||
|
||||
+136
-166
@@ -98,6 +98,7 @@ enum nfsd4_st_mutex_lock_subclass {
|
||||
*/
|
||||
static DECLARE_WAIT_QUEUE_HEAD(close_wq);
|
||||
|
||||
static struct kmem_cache *client_slab;
|
||||
static struct kmem_cache *openowner_slab;
|
||||
static struct kmem_cache *lockowner_slab;
|
||||
static struct kmem_cache *file_slab;
|
||||
@@ -806,7 +807,8 @@ static void block_delegations(struct knfsd_fh *fh)
|
||||
}
|
||||
|
||||
static struct nfs4_delegation *
|
||||
alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
|
||||
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
|
||||
struct svc_fh *current_fh,
|
||||
struct nfs4_clnt_odstate *odstate)
|
||||
{
|
||||
struct nfs4_delegation *dp;
|
||||
@@ -837,6 +839,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
|
||||
dp->dl_retries = 1;
|
||||
nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client,
|
||||
&nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL);
|
||||
get_nfs4_file(fp);
|
||||
dp->dl_stid.sc_file = fp;
|
||||
return dp;
|
||||
out_dec:
|
||||
atomic_long_dec(&num_delegations);
|
||||
@@ -874,19 +878,35 @@ nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid)
|
||||
spin_unlock(&stid->sc_lock);
|
||||
}
|
||||
|
||||
static void nfs4_put_deleg_lease(struct nfs4_file *fp)
|
||||
static void put_deleg_file(struct nfs4_file *fp)
|
||||
{
|
||||
struct file *filp = NULL;
|
||||
|
||||
spin_lock(&fp->fi_lock);
|
||||
if (fp->fi_deleg_file && --fp->fi_delegees == 0)
|
||||
if (--fp->fi_delegees == 0)
|
||||
swap(filp, fp->fi_deleg_file);
|
||||
spin_unlock(&fp->fi_lock);
|
||||
|
||||
if (filp) {
|
||||
vfs_setlease(filp, F_UNLCK, NULL, (void **)&fp);
|
||||
if (filp)
|
||||
fput(filp);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp)
|
||||
{
|
||||
struct nfs4_file *fp = dp->dl_stid.sc_file;
|
||||
struct file *filp = fp->fi_deleg_file;
|
||||
|
||||
WARN_ON_ONCE(!fp->fi_delegees);
|
||||
|
||||
vfs_setlease(filp, F_UNLCK, NULL, (void **)&dp);
|
||||
put_deleg_file(fp);
|
||||
}
|
||||
|
||||
static void destroy_unhashed_deleg(struct nfs4_delegation *dp)
|
||||
{
|
||||
put_clnt_odstate(dp->dl_clnt_odstate);
|
||||
nfs4_unlock_deleg_lease(dp);
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
}
|
||||
|
||||
void nfs4_unhash_stid(struct nfs4_stid *s)
|
||||
@@ -895,20 +915,16 @@ void nfs4_unhash_stid(struct nfs4_stid *s)
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs4_get_existing_delegation - Discover if this delegation already exists
|
||||
* nfs4_delegation_exists - Discover if this delegation already exists
|
||||
* @clp: a pointer to the nfs4_client we're granting a delegation to
|
||||
* @fp: a pointer to the nfs4_file we're granting a delegation on
|
||||
*
|
||||
* Return:
|
||||
* On success: NULL if an existing delegation was not found.
|
||||
*
|
||||
* On error: -EAGAIN if one was previously granted to this nfs4_client
|
||||
* for this nfs4_file.
|
||||
*
|
||||
* On success: true iff an existing delegation is found
|
||||
*/
|
||||
|
||||
static int
|
||||
nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp)
|
||||
static bool
|
||||
nfs4_delegation_exists(struct nfs4_client *clp, struct nfs4_file *fp)
|
||||
{
|
||||
struct nfs4_delegation *searchdp = NULL;
|
||||
struct nfs4_client *searchclp = NULL;
|
||||
@@ -919,10 +935,10 @@ nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp)
|
||||
list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) {
|
||||
searchclp = searchdp->dl_stid.sc_client;
|
||||
if (clp == searchclp) {
|
||||
return -EAGAIN;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -941,16 +957,13 @@ nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp)
|
||||
static int
|
||||
hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
|
||||
{
|
||||
int status;
|
||||
struct nfs4_client *clp = dp->dl_stid.sc_client;
|
||||
|
||||
lockdep_assert_held(&state_lock);
|
||||
lockdep_assert_held(&fp->fi_lock);
|
||||
|
||||
status = nfs4_get_existing_delegation(clp, fp);
|
||||
if (status)
|
||||
return status;
|
||||
++fp->fi_delegees;
|
||||
if (nfs4_delegation_exists(clp, fp))
|
||||
return -EAGAIN;
|
||||
refcount_inc(&dp->dl_stid.sc_count);
|
||||
dp->dl_stid.sc_type = NFS4_DELEG_STID;
|
||||
list_add(&dp->dl_perfile, &fp->fi_delegations);
|
||||
@@ -986,11 +999,8 @@ static void destroy_delegation(struct nfs4_delegation *dp)
|
||||
spin_lock(&state_lock);
|
||||
unhashed = unhash_delegation_locked(dp);
|
||||
spin_unlock(&state_lock);
|
||||
if (unhashed) {
|
||||
put_clnt_odstate(dp->dl_clnt_odstate);
|
||||
nfs4_put_deleg_lease(dp->dl_stid.sc_file);
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
}
|
||||
if (unhashed)
|
||||
destroy_unhashed_deleg(dp);
|
||||
}
|
||||
|
||||
static void revoke_delegation(struct nfs4_delegation *dp)
|
||||
@@ -999,17 +1009,14 @@ static void revoke_delegation(struct nfs4_delegation *dp)
|
||||
|
||||
WARN_ON(!list_empty(&dp->dl_recall_lru));
|
||||
|
||||
put_clnt_odstate(dp->dl_clnt_odstate);
|
||||
nfs4_put_deleg_lease(dp->dl_stid.sc_file);
|
||||
|
||||
if (clp->cl_minorversion == 0)
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
else {
|
||||
if (clp->cl_minorversion) {
|
||||
dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
|
||||
refcount_inc(&dp->dl_stid.sc_count);
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_add(&dp->dl_recall_lru, &clp->cl_revoked);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
destroy_unhashed_deleg(dp);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1794,7 +1801,7 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
|
||||
struct nfs4_client *clp;
|
||||
int i;
|
||||
|
||||
clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
|
||||
clp = kmem_cache_zalloc(client_slab, GFP_KERNEL);
|
||||
if (clp == NULL)
|
||||
return NULL;
|
||||
clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
|
||||
@@ -1825,7 +1832,7 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
|
||||
err_no_hashtbl:
|
||||
kfree(clp->cl_name.data);
|
||||
err_no_name:
|
||||
kfree(clp);
|
||||
kmem_cache_free(client_slab, clp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1845,7 +1852,7 @@ free_client(struct nfs4_client *clp)
|
||||
kfree(clp->cl_ownerstr_hashtbl);
|
||||
kfree(clp->cl_name.data);
|
||||
idr_destroy(&clp->cl_stateids);
|
||||
kfree(clp);
|
||||
kmem_cache_free(client_slab, clp);
|
||||
}
|
||||
|
||||
/* must be called under the client_lock */
|
||||
@@ -1911,9 +1918,7 @@ __destroy_client(struct nfs4_client *clp)
|
||||
while (!list_empty(&reaplist)) {
|
||||
dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
|
||||
list_del_init(&dp->dl_recall_lru);
|
||||
put_clnt_odstate(dp->dl_clnt_odstate);
|
||||
nfs4_put_deleg_lease(dp->dl_stid.sc_file);
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
destroy_unhashed_deleg(dp);
|
||||
}
|
||||
while (!list_empty(&clp->cl_revoked)) {
|
||||
dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru);
|
||||
@@ -2953,7 +2958,7 @@ out_no_session:
|
||||
static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
|
||||
{
|
||||
if (!session)
|
||||
return 0;
|
||||
return false;
|
||||
return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
|
||||
}
|
||||
|
||||
@@ -3471,21 +3476,26 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval,
|
||||
void
|
||||
nfsd4_free_slabs(void)
|
||||
{
|
||||
kmem_cache_destroy(odstate_slab);
|
||||
kmem_cache_destroy(client_slab);
|
||||
kmem_cache_destroy(openowner_slab);
|
||||
kmem_cache_destroy(lockowner_slab);
|
||||
kmem_cache_destroy(file_slab);
|
||||
kmem_cache_destroy(stateid_slab);
|
||||
kmem_cache_destroy(deleg_slab);
|
||||
kmem_cache_destroy(odstate_slab);
|
||||
}
|
||||
|
||||
int
|
||||
nfsd4_init_slabs(void)
|
||||
{
|
||||
client_slab = kmem_cache_create("nfsd4_clients",
|
||||
sizeof(struct nfs4_client), 0, 0, NULL);
|
||||
if (client_slab == NULL)
|
||||
goto out;
|
||||
openowner_slab = kmem_cache_create("nfsd4_openowners",
|
||||
sizeof(struct nfs4_openowner), 0, 0, NULL);
|
||||
if (openowner_slab == NULL)
|
||||
goto out;
|
||||
goto out_free_client_slab;
|
||||
lockowner_slab = kmem_cache_create("nfsd4_lockowners",
|
||||
sizeof(struct nfs4_lockowner), 0, 0, NULL);
|
||||
if (lockowner_slab == NULL)
|
||||
@@ -3518,6 +3528,8 @@ out_free_lockowner_slab:
|
||||
kmem_cache_destroy(lockowner_slab);
|
||||
out_free_openowner_slab:
|
||||
kmem_cache_destroy(openowner_slab);
|
||||
out_free_client_slab:
|
||||
kmem_cache_destroy(client_slab);
|
||||
out:
|
||||
dprintk("nfsd4: out of memory while initializing nfsv4\n");
|
||||
return -ENOMEM;
|
||||
@@ -3945,17 +3957,9 @@ static bool
|
||||
nfsd_break_deleg_cb(struct file_lock *fl)
|
||||
{
|
||||
bool ret = false;
|
||||
struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
|
||||
struct nfs4_delegation *dp;
|
||||
struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
|
||||
struct nfs4_file *fp = dp->dl_stid.sc_file;
|
||||
|
||||
if (!fp) {
|
||||
WARN(1, "(%p)->fl_owner NULL\n", fl);
|
||||
return ret;
|
||||
}
|
||||
if (fp->fi_had_conflict) {
|
||||
WARN(1, "duplicate break on %p\n", fp);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* We don't want the locks code to timeout the lease for us;
|
||||
* we'll remove it ourself if a delegation isn't returned
|
||||
@@ -3965,15 +3969,7 @@ nfsd_break_deleg_cb(struct file_lock *fl)
|
||||
|
||||
spin_lock(&fp->fi_lock);
|
||||
fp->fi_had_conflict = true;
|
||||
/*
|
||||
* If there are no delegations on the list, then return true
|
||||
* so that the lease code will go ahead and delete it.
|
||||
*/
|
||||
if (list_empty(&fp->fi_delegations))
|
||||
ret = true;
|
||||
else
|
||||
list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
|
||||
nfsd_break_one_deleg(dp);
|
||||
nfsd_break_one_deleg(dp);
|
||||
spin_unlock(&fp->fi_lock);
|
||||
return ret;
|
||||
}
|
||||
@@ -4297,7 +4293,8 @@ static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
|
||||
return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
|
||||
}
|
||||
|
||||
static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
|
||||
static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp,
|
||||
int flag)
|
||||
{
|
||||
struct file_lock *fl;
|
||||
|
||||
@@ -4308,124 +4305,88 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
|
||||
fl->fl_flags = FL_DELEG;
|
||||
fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
|
||||
fl->fl_end = OFFSET_MAX;
|
||||
fl->fl_owner = (fl_owner_t)fp;
|
||||
fl->fl_owner = (fl_owner_t)dp;
|
||||
fl->fl_pid = current->tgid;
|
||||
fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file;
|
||||
return fl;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs4_setlease - Obtain a delegation by requesting lease from vfs layer
|
||||
* @dp: a pointer to the nfs4_delegation we're adding.
|
||||
*
|
||||
* Return:
|
||||
* On success: Return code will be 0 on success.
|
||||
*
|
||||
* On error: -EAGAIN if there was an existing delegation.
|
||||
* nonzero if there is an error in other cases.
|
||||
*
|
||||
*/
|
||||
|
||||
static int nfs4_setlease(struct nfs4_delegation *dp)
|
||||
{
|
||||
struct nfs4_file *fp = dp->dl_stid.sc_file;
|
||||
struct file_lock *fl;
|
||||
struct file *filp;
|
||||
int status = 0;
|
||||
|
||||
fl = nfs4_alloc_init_lease(fp, NFS4_OPEN_DELEGATE_READ);
|
||||
if (!fl)
|
||||
return -ENOMEM;
|
||||
filp = find_readable_file(fp);
|
||||
if (!filp) {
|
||||
/* We should always have a readable file here */
|
||||
WARN_ON_ONCE(1);
|
||||
locks_free_lock(fl);
|
||||
return -EBADF;
|
||||
}
|
||||
fl->fl_file = filp;
|
||||
status = vfs_setlease(filp, fl->fl_type, &fl, NULL);
|
||||
if (fl)
|
||||
locks_free_lock(fl);
|
||||
if (status)
|
||||
goto out_fput;
|
||||
spin_lock(&state_lock);
|
||||
spin_lock(&fp->fi_lock);
|
||||
/* Did the lease get broken before we took the lock? */
|
||||
status = -EAGAIN;
|
||||
if (fp->fi_had_conflict)
|
||||
goto out_unlock;
|
||||
/* Race breaker */
|
||||
if (fp->fi_deleg_file) {
|
||||
status = hash_delegation_locked(dp, fp);
|
||||
goto out_unlock;
|
||||
}
|
||||
fp->fi_deleg_file = filp;
|
||||
fp->fi_delegees = 0;
|
||||
status = hash_delegation_locked(dp, fp);
|
||||
spin_unlock(&fp->fi_lock);
|
||||
spin_unlock(&state_lock);
|
||||
if (status) {
|
||||
/* Should never happen, this is a new fi_deleg_file */
|
||||
WARN_ON_ONCE(1);
|
||||
goto out_fput;
|
||||
}
|
||||
return 0;
|
||||
out_unlock:
|
||||
spin_unlock(&fp->fi_lock);
|
||||
spin_unlock(&state_lock);
|
||||
out_fput:
|
||||
fput(filp);
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct nfs4_delegation *
|
||||
nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
|
||||
struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
|
||||
{
|
||||
int status;
|
||||
int status = 0;
|
||||
struct nfs4_delegation *dp;
|
||||
struct file *filp;
|
||||
struct file_lock *fl;
|
||||
|
||||
/*
|
||||
* The fi_had_conflict and nfs_get_existing_delegation checks
|
||||
* here are just optimizations; we'll need to recheck them at
|
||||
* the end:
|
||||
*/
|
||||
if (fp->fi_had_conflict)
|
||||
return ERR_PTR(-EAGAIN);
|
||||
|
||||
filp = find_readable_file(fp);
|
||||
if (!filp) {
|
||||
/* We should always have a readable file here */
|
||||
WARN_ON_ONCE(1);
|
||||
return ERR_PTR(-EBADF);
|
||||
}
|
||||
spin_lock(&state_lock);
|
||||
spin_lock(&fp->fi_lock);
|
||||
status = nfs4_get_existing_delegation(clp, fp);
|
||||
if (nfs4_delegation_exists(clp, fp))
|
||||
status = -EAGAIN;
|
||||
else if (!fp->fi_deleg_file) {
|
||||
fp->fi_deleg_file = filp;
|
||||
/* increment early to prevent fi_deleg_file from being
|
||||
* cleared */
|
||||
fp->fi_delegees = 1;
|
||||
filp = NULL;
|
||||
} else
|
||||
fp->fi_delegees++;
|
||||
spin_unlock(&fp->fi_lock);
|
||||
spin_unlock(&state_lock);
|
||||
if (filp)
|
||||
fput(filp);
|
||||
if (status)
|
||||
return ERR_PTR(status);
|
||||
|
||||
status = -ENOMEM;
|
||||
dp = alloc_init_deleg(clp, fp, fh, odstate);
|
||||
if (!dp)
|
||||
goto out_delegees;
|
||||
|
||||
fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ);
|
||||
if (!fl)
|
||||
goto out_stid;
|
||||
|
||||
status = vfs_setlease(fp->fi_deleg_file, fl->fl_type, &fl, NULL);
|
||||
if (fl)
|
||||
locks_free_lock(fl);
|
||||
if (status)
|
||||
goto out_clnt_odstate;
|
||||
|
||||
spin_lock(&state_lock);
|
||||
spin_lock(&fp->fi_lock);
|
||||
if (fp->fi_had_conflict)
|
||||
status = -EAGAIN;
|
||||
else
|
||||
status = hash_delegation_locked(dp, fp);
|
||||
spin_unlock(&fp->fi_lock);
|
||||
spin_unlock(&state_lock);
|
||||
|
||||
if (status)
|
||||
return ERR_PTR(status);
|
||||
|
||||
dp = alloc_init_deleg(clp, fh, odstate);
|
||||
if (!dp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
get_nfs4_file(fp);
|
||||
spin_lock(&state_lock);
|
||||
spin_lock(&fp->fi_lock);
|
||||
dp->dl_stid.sc_file = fp;
|
||||
if (!fp->fi_deleg_file) {
|
||||
spin_unlock(&fp->fi_lock);
|
||||
spin_unlock(&state_lock);
|
||||
status = nfs4_setlease(dp);
|
||||
goto out;
|
||||
}
|
||||
if (fp->fi_had_conflict) {
|
||||
status = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
status = hash_delegation_locked(dp, fp);
|
||||
out_unlock:
|
||||
spin_unlock(&fp->fi_lock);
|
||||
spin_unlock(&state_lock);
|
||||
out:
|
||||
if (status) {
|
||||
put_clnt_odstate(dp->dl_clnt_odstate);
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
return ERR_PTR(status);
|
||||
}
|
||||
destroy_unhashed_deleg(dp);
|
||||
return dp;
|
||||
out_clnt_odstate:
|
||||
put_clnt_odstate(dp->dl_clnt_odstate);
|
||||
out_stid:
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
out_delegees:
|
||||
put_deleg_file(fp);
|
||||
return ERR_PTR(status);
|
||||
}
|
||||
|
||||
static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
|
||||
@@ -5521,15 +5482,26 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
goto out;
|
||||
|
||||
stp->st_stid.sc_type = NFS4_CLOSED_STID;
|
||||
|
||||
/*
|
||||
* Technically we don't _really_ have to increment or copy it, since
|
||||
* it should just be gone after this operation and we clobber the
|
||||
* copied value below, but we continue to do so here just to ensure
|
||||
* that racing ops see that there was a state change.
|
||||
*/
|
||||
nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid);
|
||||
|
||||
nfsd4_close_open_stateid(stp);
|
||||
mutex_unlock(&stp->st_mutex);
|
||||
|
||||
/* See RFC5661 sectionm 18.2.4 */
|
||||
if (stp->st_stid.sc_client->cl_minorversion)
|
||||
memcpy(&close->cl_stateid, &close_stateid,
|
||||
sizeof(close->cl_stateid));
|
||||
/* v4.1+ suggests that we send a special stateid in here, since the
|
||||
* clients should just ignore this anyway. Since this is not useful
|
||||
* for v4.0 clients either, we set it to the special close_stateid
|
||||
* universally.
|
||||
*
|
||||
* See RFC5661 section 18.2.4, and RFC7530 section 16.2.5
|
||||
*/
|
||||
memcpy(&close->cl_stateid, &close_stateid, sizeof(close->cl_stateid));
|
||||
|
||||
/* put reference from nfs4_preprocess_seqid_op */
|
||||
nfs4_put_stid(&stp->st_stid);
|
||||
@@ -7264,9 +7236,7 @@ nfs4_state_shutdown_net(struct net *net)
|
||||
list_for_each_safe(pos, next, &reaplist) {
|
||||
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
|
||||
list_del_init(&dp->dl_recall_lru);
|
||||
put_clnt_odstate(dp->dl_clnt_odstate);
|
||||
nfs4_put_deleg_lease(dp->dl_stid.sc_file);
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
destroy_unhashed_deleg(dp);
|
||||
}
|
||||
|
||||
nfsd4_client_tracking_exit(net);
|
||||
|
||||
+11
-11
@@ -33,7 +33,6 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/fs_struct.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/namei.h>
|
||||
@@ -682,7 +681,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
|
||||
|
||||
status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
|
||||
&create->cr_acl, &create->cr_label,
|
||||
¤t->fs->umask);
|
||||
&create->cr_umask);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
@@ -927,7 +926,6 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
|
||||
case NFS4_OPEN_NOCREATE:
|
||||
break;
|
||||
case NFS4_OPEN_CREATE:
|
||||
current->fs->umask = 0;
|
||||
READ_BUF(4);
|
||||
open->op_createmode = be32_to_cpup(p++);
|
||||
switch (open->op_createmode) {
|
||||
@@ -935,7 +933,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
|
||||
case NFS4_CREATE_GUARDED:
|
||||
status = nfsd4_decode_fattr(argp, open->op_bmval,
|
||||
&open->op_iattr, &open->op_acl, &open->op_label,
|
||||
¤t->fs->umask);
|
||||
&open->op_umask);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
@@ -950,7 +948,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
|
||||
COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
|
||||
status = nfsd4_decode_fattr(argp, open->op_bmval,
|
||||
&open->op_iattr, &open->op_acl, &open->op_label,
|
||||
¤t->fs->umask);
|
||||
&open->op_umask);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
@@ -1759,7 +1757,7 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
|
||||
p = xdr_decode_hyper(p, ©->cp_src_pos);
|
||||
p = xdr_decode_hyper(p, ©->cp_dst_pos);
|
||||
p = xdr_decode_hyper(p, ©->cp_count);
|
||||
copy->cp_consecutive = be32_to_cpup(p++);
|
||||
p++; /* ca_consecutive: we always do consecutive copies */
|
||||
copy->cp_synchronous = be32_to_cpup(p++);
|
||||
tmp = be32_to_cpup(p); /* Source server list not supported */
|
||||
|
||||
@@ -3427,8 +3425,9 @@ static __be32 nfsd4_encode_splice_read(
|
||||
return nfserr_resource;
|
||||
|
||||
len = maxcount;
|
||||
nfserr = nfsd_splice_read(read->rd_rqstp, file,
|
||||
read->rd_offset, &maxcount);
|
||||
nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
|
||||
file, read->rd_offset, &maxcount);
|
||||
read->rd_length = maxcount;
|
||||
if (nfserr) {
|
||||
/*
|
||||
* nfsd_splice_actor may have already messed with the
|
||||
@@ -3511,8 +3510,9 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
|
||||
read->rd_vlen = v;
|
||||
|
||||
len = maxcount;
|
||||
nfserr = nfsd_readv(file, read->rd_offset, resp->rqstp->rq_vec,
|
||||
read->rd_vlen, &maxcount);
|
||||
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
|
||||
resp->rqstp->rq_vec, read->rd_vlen, &maxcount);
|
||||
read->rd_length = maxcount;
|
||||
if (nfserr)
|
||||
return nfserr;
|
||||
xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
|
||||
@@ -4214,7 +4214,7 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
return nfserr;
|
||||
|
||||
p = xdr_reserve_space(&resp->xdr, 4 + 4);
|
||||
*p++ = cpu_to_be32(copy->cp_consecutive);
|
||||
*p++ = xdr_one; /* cr_consecutive */
|
||||
*p++ = cpu_to_be32(copy->cp_synchronous);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+11
-1
@@ -87,13 +87,23 @@ nfsd_mode_check(struct svc_rqst *rqstp, struct dentry *dentry,
|
||||
return nfserr_inval;
|
||||
}
|
||||
|
||||
static bool nfsd_originating_port_ok(struct svc_rqst *rqstp, int flags)
|
||||
{
|
||||
if (flags & NFSEXP_INSECURE_PORT)
|
||||
return true;
|
||||
/* We don't require gss requests to use low ports: */
|
||||
if (rqstp->rq_cred.cr_flavor >= RPC_AUTH_GSS)
|
||||
return true;
|
||||
return test_bit(RQ_SECURE, &rqstp->rq_flags);
|
||||
}
|
||||
|
||||
static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
|
||||
struct svc_export *exp)
|
||||
{
|
||||
int flags = nfsexp_flags(rqstp, exp);
|
||||
|
||||
/* Check if the request originated from a secure port. */
|
||||
if (!test_bit(RQ_SECURE, &rqstp->rq_flags) && !(flags & NFSEXP_INSECURE_PORT)) {
|
||||
if (!nfsd_originating_port_ok(rqstp, flags)) {
|
||||
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
|
||||
dprintk("nfsd: request from insecure port %s!\n",
|
||||
svc_print_addr(rqstp, buf, sizeof(buf)));
|
||||
|
||||
+15
-8
@@ -212,13 +212,18 @@ nfsd_proc_write(struct svc_rqst *rqstp)
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
unsigned long cnt = argp->len;
|
||||
unsigned int nvecs;
|
||||
|
||||
dprintk("nfsd: WRITE %s %d bytes at %d\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
argp->len, argp->offset);
|
||||
|
||||
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), argp->offset,
|
||||
rqstp->rq_vec, argp->vlen, &cnt, NFS_DATA_SYNC);
|
||||
nvecs = svc_fill_write_vector(rqstp, &argp->first, cnt);
|
||||
if (!nvecs)
|
||||
return nfserr_io;
|
||||
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset, rqstp->rq_vec, nvecs,
|
||||
&cnt, NFS_DATA_SYNC);
|
||||
return nfsd_return_attrs(nfserr, resp);
|
||||
}
|
||||
|
||||
@@ -444,17 +449,19 @@ nfsd_proc_symlink(struct svc_rqst *rqstp)
|
||||
struct svc_fh newfh;
|
||||
__be32 nfserr;
|
||||
|
||||
if (argp->tlen > NFS_MAXPATHLEN)
|
||||
return nfserr_nametoolong;
|
||||
|
||||
argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
|
||||
argp->tlen);
|
||||
if (IS_ERR(argp->tname))
|
||||
return nfserrno(PTR_ERR(argp->tname));
|
||||
|
||||
dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
|
||||
SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
|
||||
argp->tlen, argp->tname);
|
||||
|
||||
fh_init(&newfh, NFS_FHSIZE);
|
||||
/*
|
||||
* Crazy hack: the request fits in a page, and already-decoded
|
||||
* attributes follow argp->tname, so it's safe to just write a
|
||||
* null to ensure it's null-terminated:
|
||||
*/
|
||||
argp->tname[argp->tlen] = '\0';
|
||||
nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
|
||||
argp->tname, &newfh);
|
||||
|
||||
|
||||
+31
-32
@@ -70,22 +70,6 @@ decode_filename(__be32 *p, char **namp, unsigned int *lenp)
|
||||
return p;
|
||||
}
|
||||
|
||||
static __be32 *
|
||||
decode_pathname(__be32 *p, char **namp, unsigned int *lenp)
|
||||
{
|
||||
char *name;
|
||||
unsigned int i;
|
||||
|
||||
if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
|
||||
for (i = 0, name = *namp; i < *lenp; i++, name++) {
|
||||
if (*name == '\0')
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static __be32 *
|
||||
decode_sattr(__be32 *p, struct iattr *iap)
|
||||
{
|
||||
@@ -287,7 +271,6 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
struct nfsd_writeargs *args = rqstp->rq_argp;
|
||||
unsigned int len, hdr, dlen;
|
||||
struct kvec *head = rqstp->rq_arg.head;
|
||||
int v;
|
||||
|
||||
p = decode_fh(p, &args->fh);
|
||||
if (!p)
|
||||
@@ -323,17 +306,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
if (dlen < XDR_QUADLEN(len)*4)
|
||||
return 0;
|
||||
|
||||
rqstp->rq_vec[0].iov_base = (void*)p;
|
||||
rqstp->rq_vec[0].iov_len = head->iov_len - hdr;
|
||||
v = 0;
|
||||
while (len > rqstp->rq_vec[v].iov_len) {
|
||||
len -= rqstp->rq_vec[v].iov_len;
|
||||
v++;
|
||||
rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
|
||||
rqstp->rq_vec[v].iov_len = PAGE_SIZE;
|
||||
}
|
||||
rqstp->rq_vec[v].iov_len = len;
|
||||
args->vlen = v + 1;
|
||||
args->first.iov_base = (void *)p;
|
||||
args->first.iov_len = head->iov_len - hdr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -394,14 +368,39 @@ int
|
||||
nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd_symlinkargs *args = rqstp->rq_argp;
|
||||
char *base = (char *)p;
|
||||
size_t xdrlen;
|
||||
|
||||
if ( !(p = decode_fh(p, &args->ffh))
|
||||
|| !(p = decode_filename(p, &args->fname, &args->flen))
|
||||
|| !(p = decode_pathname(p, &args->tname, &args->tlen)))
|
||||
|| !(p = decode_filename(p, &args->fname, &args->flen)))
|
||||
return 0;
|
||||
p = decode_sattr(p, &args->attrs);
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
args->tlen = ntohl(*p++);
|
||||
if (args->tlen == 0)
|
||||
return 0;
|
||||
|
||||
args->first.iov_base = p;
|
||||
args->first.iov_len = rqstp->rq_arg.head[0].iov_len;
|
||||
args->first.iov_len -= (char *)p - base;
|
||||
|
||||
/* This request is never larger than a page. Therefore,
|
||||
* transport will deliver either:
|
||||
* 1. pathname in the pagelist -> sattr is in the tail.
|
||||
* 2. everything in the head buffer -> sattr is in the head.
|
||||
*/
|
||||
if (rqstp->rq_arg.page_len) {
|
||||
if (args->tlen != rqstp->rq_arg.page_len)
|
||||
return 0;
|
||||
p = rqstp->rq_arg.tail[0].iov_base;
|
||||
} else {
|
||||
xdrlen = XDR_QUADLEN(args->tlen);
|
||||
if (xdrlen > args->first.iov_len - (8 * sizeof(__be32)))
|
||||
return 0;
|
||||
p += xdrlen;
|
||||
}
|
||||
decode_sattr(p, &args->attrs);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
+86
-12
@@ -11,39 +11,79 @@
|
||||
#include <linux/tracepoint.h>
|
||||
#include "nfsfh.h"
|
||||
|
||||
TRACE_EVENT(nfsd_compound,
|
||||
TP_PROTO(const struct svc_rqst *rqst,
|
||||
u32 args_opcnt),
|
||||
TP_ARGS(rqst, args_opcnt),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, xid)
|
||||
__field(u32, args_opcnt)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = be32_to_cpu(rqst->rq_xid);
|
||||
__entry->args_opcnt = args_opcnt;
|
||||
),
|
||||
TP_printk("xid=0x%08x opcnt=%u",
|
||||
__entry->xid, __entry->args_opcnt)
|
||||
)
|
||||
|
||||
TRACE_EVENT(nfsd_compound_status,
|
||||
TP_PROTO(u32 args_opcnt,
|
||||
u32 resp_opcnt,
|
||||
__be32 status,
|
||||
const char *name),
|
||||
TP_ARGS(args_opcnt, resp_opcnt, status, name),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, args_opcnt)
|
||||
__field(u32, resp_opcnt)
|
||||
__field(int, status)
|
||||
__string(name, name)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->args_opcnt = args_opcnt;
|
||||
__entry->resp_opcnt = resp_opcnt;
|
||||
__entry->status = be32_to_cpu(status);
|
||||
__assign_str(name, name);
|
||||
),
|
||||
TP_printk("op=%u/%u %s status=%d",
|
||||
__entry->resp_opcnt, __entry->args_opcnt,
|
||||
__get_str(name), __entry->status)
|
||||
)
|
||||
|
||||
DECLARE_EVENT_CLASS(nfsd_io_class,
|
||||
TP_PROTO(struct svc_rqst *rqstp,
|
||||
struct svc_fh *fhp,
|
||||
loff_t offset,
|
||||
int len),
|
||||
unsigned long len),
|
||||
TP_ARGS(rqstp, fhp, offset, len),
|
||||
TP_STRUCT__entry(
|
||||
__field(__be32, xid)
|
||||
__field_struct(struct knfsd_fh, fh)
|
||||
__field(u32, xid)
|
||||
__field(u32, fh_hash)
|
||||
__field(loff_t, offset)
|
||||
__field(int, len)
|
||||
__field(unsigned long, len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = rqstp->rq_xid,
|
||||
fh_copy_shallow(&__entry->fh, &fhp->fh_handle);
|
||||
__entry->xid = be32_to_cpu(rqstp->rq_xid);
|
||||
__entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle);
|
||||
__entry->offset = offset;
|
||||
__entry->len = len;
|
||||
),
|
||||
TP_printk("xid=0x%x fh=0x%x offset=%lld len=%d",
|
||||
__be32_to_cpu(__entry->xid), knfsd_fh_hash(&__entry->fh),
|
||||
TP_printk("xid=0x%08x fh_hash=0x%08x offset=%lld len=%lu",
|
||||
__entry->xid, __entry->fh_hash,
|
||||
__entry->offset, __entry->len)
|
||||
)
|
||||
|
||||
#define DEFINE_NFSD_IO_EVENT(name) \
|
||||
DEFINE_EVENT(nfsd_io_class, name, \
|
||||
DEFINE_EVENT(nfsd_io_class, nfsd_##name, \
|
||||
TP_PROTO(struct svc_rqst *rqstp, \
|
||||
struct svc_fh *fhp, \
|
||||
loff_t offset, \
|
||||
int len), \
|
||||
unsigned long len), \
|
||||
TP_ARGS(rqstp, fhp, offset, len))
|
||||
|
||||
DEFINE_NFSD_IO_EVENT(read_start);
|
||||
DEFINE_NFSD_IO_EVENT(read_opened);
|
||||
DEFINE_NFSD_IO_EVENT(read_splice);
|
||||
DEFINE_NFSD_IO_EVENT(read_vector);
|
||||
DEFINE_NFSD_IO_EVENT(read_io_done);
|
||||
DEFINE_NFSD_IO_EVENT(read_done);
|
||||
DEFINE_NFSD_IO_EVENT(write_start);
|
||||
@@ -51,6 +91,40 @@ DEFINE_NFSD_IO_EVENT(write_opened);
|
||||
DEFINE_NFSD_IO_EVENT(write_io_done);
|
||||
DEFINE_NFSD_IO_EVENT(write_done);
|
||||
|
||||
DECLARE_EVENT_CLASS(nfsd_err_class,
|
||||
TP_PROTO(struct svc_rqst *rqstp,
|
||||
struct svc_fh *fhp,
|
||||
loff_t offset,
|
||||
int status),
|
||||
TP_ARGS(rqstp, fhp, offset, status),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, xid)
|
||||
__field(u32, fh_hash)
|
||||
__field(loff_t, offset)
|
||||
__field(int, status)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->xid = be32_to_cpu(rqstp->rq_xid);
|
||||
__entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle);
|
||||
__entry->offset = offset;
|
||||
__entry->status = status;
|
||||
),
|
||||
TP_printk("xid=0x%08x fh_hash=0x%08x offset=%lld status=%d",
|
||||
__entry->xid, __entry->fh_hash,
|
||||
__entry->offset, __entry->status)
|
||||
)
|
||||
|
||||
#define DEFINE_NFSD_ERR_EVENT(name) \
|
||||
DEFINE_EVENT(nfsd_err_class, nfsd_##name, \
|
||||
TP_PROTO(struct svc_rqst *rqstp, \
|
||||
struct svc_fh *fhp, \
|
||||
loff_t offset, \
|
||||
int len), \
|
||||
TP_ARGS(rqstp, fhp, offset, len))
|
||||
|
||||
DEFINE_NFSD_ERR_EVENT(read_err);
|
||||
DEFINE_NFSD_ERR_EVENT(write_err);
|
||||
|
||||
#include "state.h"
|
||||
|
||||
DECLARE_EVENT_CLASS(nfsd_stateid_class,
|
||||
@@ -76,7 +150,7 @@ DECLARE_EVENT_CLASS(nfsd_stateid_class,
|
||||
)
|
||||
|
||||
#define DEFINE_STATEID_EVENT(name) \
|
||||
DEFINE_EVENT(nfsd_stateid_class, name, \
|
||||
DEFINE_EVENT(nfsd_stateid_class, nfsd_##name, \
|
||||
TP_PROTO(stateid_t *stp), \
|
||||
TP_ARGS(stp))
|
||||
DEFINE_STATEID_EVENT(layoutstate_alloc);
|
||||
|
||||
+34
-31
@@ -881,20 +881,24 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
|
||||
return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_finish_read(struct file *file, unsigned long *count, int host_err)
|
||||
static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct file *file, loff_t offset,
|
||||
unsigned long *count, int host_err)
|
||||
{
|
||||
if (host_err >= 0) {
|
||||
nfsdstats.io_read += host_err;
|
||||
*count = host_err;
|
||||
fsnotify_access(file);
|
||||
trace_nfsd_read_io_done(rqstp, fhp, offset, *count);
|
||||
return 0;
|
||||
} else
|
||||
} else {
|
||||
trace_nfsd_read_err(rqstp, fhp, offset, host_err);
|
||||
return nfserrno(host_err);
|
||||
}
|
||||
}
|
||||
|
||||
__be32 nfsd_splice_read(struct svc_rqst *rqstp,
|
||||
struct file *file, loff_t offset, unsigned long *count)
|
||||
__be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct file *file, loff_t offset, unsigned long *count)
|
||||
{
|
||||
struct splice_desc sd = {
|
||||
.len = 0,
|
||||
@@ -904,21 +908,23 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp,
|
||||
};
|
||||
int host_err;
|
||||
|
||||
trace_nfsd_read_splice(rqstp, fhp, offset, *count);
|
||||
rqstp->rq_next_page = rqstp->rq_respages + 1;
|
||||
host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
|
||||
return nfsd_finish_read(file, count, host_err);
|
||||
return nfsd_finish_read(rqstp, fhp, file, offset, count, host_err);
|
||||
}
|
||||
|
||||
__be32 nfsd_readv(struct file *file, loff_t offset, struct kvec *vec, int vlen,
|
||||
unsigned long *count)
|
||||
__be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct file *file, loff_t offset,
|
||||
struct kvec *vec, int vlen, unsigned long *count)
|
||||
{
|
||||
struct iov_iter iter;
|
||||
int host_err;
|
||||
|
||||
trace_nfsd_read_vector(rqstp, fhp, offset, *count);
|
||||
iov_iter_kvec(&iter, READ | ITER_KVEC, vec, vlen, *count);
|
||||
host_err = vfs_iter_read(file, &iter, &offset, 0);
|
||||
|
||||
return nfsd_finish_read(file, count, host_err);
|
||||
return nfsd_finish_read(rqstp, fhp, file, offset, count, host_err);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -965,13 +971,15 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
||||
{
|
||||
struct svc_export *exp;
|
||||
struct iov_iter iter;
|
||||
__be32 err = 0;
|
||||
__be32 nfserr;
|
||||
int host_err;
|
||||
int use_wgather;
|
||||
loff_t pos = offset;
|
||||
unsigned int pflags = current->flags;
|
||||
rwf_t flags = 0;
|
||||
|
||||
trace_nfsd_write_opened(rqstp, fhp, offset, *cnt);
|
||||
|
||||
if (test_bit(RQ_LOCAL, &rqstp->rq_flags))
|
||||
/*
|
||||
* We want less throttling in balance_dirty_pages()
|
||||
@@ -994,22 +1002,23 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
||||
host_err = vfs_iter_write(file, &iter, &pos, flags);
|
||||
if (host_err < 0)
|
||||
goto out_nfserr;
|
||||
*cnt = host_err;
|
||||
nfsdstats.io_write += host_err;
|
||||
nfsdstats.io_write += *cnt;
|
||||
fsnotify_modify(file);
|
||||
|
||||
if (stable && use_wgather)
|
||||
host_err = wait_for_concurrent_writes(file);
|
||||
|
||||
out_nfserr:
|
||||
dprintk("nfsd: write complete host_err=%d\n", host_err);
|
||||
if (host_err >= 0)
|
||||
err = 0;
|
||||
else
|
||||
err = nfserrno(host_err);
|
||||
if (host_err >= 0) {
|
||||
trace_nfsd_write_io_done(rqstp, fhp, offset, *cnt);
|
||||
nfserr = nfs_ok;
|
||||
} else {
|
||||
trace_nfsd_write_err(rqstp, fhp, offset, host_err);
|
||||
nfserr = nfserrno(host_err);
|
||||
}
|
||||
if (test_bit(RQ_LOCAL, &rqstp->rq_flags))
|
||||
current_restore_flags(pflags, PF_LESS_THROTTLE);
|
||||
return err;
|
||||
return nfserr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1024,27 +1033,23 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct raparms *ra;
|
||||
__be32 err;
|
||||
|
||||
trace_read_start(rqstp, fhp, offset, vlen);
|
||||
trace_nfsd_read_start(rqstp, fhp, offset, *count);
|
||||
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ra = nfsd_init_raparms(file);
|
||||
|
||||
trace_read_opened(rqstp, fhp, offset, vlen);
|
||||
|
||||
if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags))
|
||||
err = nfsd_splice_read(rqstp, file, offset, count);
|
||||
err = nfsd_splice_read(rqstp, fhp, file, offset, count);
|
||||
else
|
||||
err = nfsd_readv(file, offset, vec, vlen, count);
|
||||
|
||||
trace_read_io_done(rqstp, fhp, offset, vlen);
|
||||
err = nfsd_readv(rqstp, fhp, file, offset, vec, vlen, count);
|
||||
|
||||
if (ra)
|
||||
nfsd_put_raparams(file, ra);
|
||||
fput(file);
|
||||
|
||||
trace_read_done(rqstp, fhp, offset, vlen);
|
||||
trace_nfsd_read_done(rqstp, fhp, offset, *count);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1061,18 +1066,16 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
|
||||
struct file *file = NULL;
|
||||
__be32 err = 0;
|
||||
|
||||
trace_write_start(rqstp, fhp, offset, vlen);
|
||||
trace_nfsd_write_start(rqstp, fhp, offset, *cnt);
|
||||
|
||||
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
trace_write_opened(rqstp, fhp, offset, vlen);
|
||||
err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt, stable);
|
||||
trace_write_io_done(rqstp, fhp, offset, vlen);
|
||||
fput(file);
|
||||
out:
|
||||
trace_write_done(rqstp, fhp, offset, vlen);
|
||||
trace_nfsd_write_done(rqstp, fhp, offset, *cnt);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
+7
-4
@@ -78,10 +78,13 @@ __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
|
||||
__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t,
|
||||
int, struct file **);
|
||||
struct raparms;
|
||||
__be32 nfsd_splice_read(struct svc_rqst *,
|
||||
struct file *, loff_t, unsigned long *);
|
||||
__be32 nfsd_readv(struct file *, loff_t, struct kvec *, int,
|
||||
unsigned long *);
|
||||
__be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct file *file, loff_t offset,
|
||||
unsigned long *count);
|
||||
__be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct file *file, loff_t offset,
|
||||
struct kvec *vec, int vlen,
|
||||
unsigned long *count);
|
||||
__be32 nfsd_read(struct svc_rqst *, struct svc_fh *,
|
||||
loff_t, struct kvec *, int, unsigned long *);
|
||||
__be32 nfsd_write(struct svc_rqst *, struct svc_fh *, loff_t,
|
||||
|
||||
+2
-1
@@ -34,7 +34,7 @@ struct nfsd_writeargs {
|
||||
svc_fh fh;
|
||||
__u32 offset;
|
||||
int len;
|
||||
int vlen;
|
||||
struct kvec first;
|
||||
};
|
||||
|
||||
struct nfsd_createargs {
|
||||
@@ -72,6 +72,7 @@ struct nfsd_symlinkargs {
|
||||
char * tname;
|
||||
unsigned int tlen;
|
||||
struct iattr attrs;
|
||||
struct kvec first;
|
||||
};
|
||||
|
||||
struct nfsd_readdirargs {
|
||||
|
||||
+2
-1
@@ -41,7 +41,7 @@ struct nfsd3_writeargs {
|
||||
__u32 count;
|
||||
int stable;
|
||||
__u32 len;
|
||||
int vlen;
|
||||
struct kvec first;
|
||||
};
|
||||
|
||||
struct nfsd3_createargs {
|
||||
@@ -90,6 +90,7 @@ struct nfsd3_symlinkargs {
|
||||
char * tname;
|
||||
unsigned int tlen;
|
||||
struct iattr attrs;
|
||||
struct kvec first;
|
||||
};
|
||||
|
||||
struct nfsd3_readdirargs {
|
||||
|
||||
+4
-1
@@ -110,6 +110,7 @@ struct nfsd4_create {
|
||||
struct {
|
||||
u32 datalen;
|
||||
char *data;
|
||||
struct kvec first;
|
||||
} link; /* NF4LNK */
|
||||
struct {
|
||||
u32 specdata1;
|
||||
@@ -118,12 +119,14 @@ struct nfsd4_create {
|
||||
} u;
|
||||
u32 cr_bmval[3]; /* request */
|
||||
struct iattr cr_iattr; /* request */
|
||||
int cr_umask; /* request */
|
||||
struct nfsd4_change_info cr_cinfo; /* response */
|
||||
struct nfs4_acl *cr_acl;
|
||||
struct xdr_netobj cr_label;
|
||||
};
|
||||
#define cr_datalen u.link.datalen
|
||||
#define cr_data u.link.data
|
||||
#define cr_first u.link.first
|
||||
#define cr_specdata1 u.dev.specdata1
|
||||
#define cr_specdata2 u.dev.specdata2
|
||||
|
||||
@@ -228,6 +231,7 @@ struct nfsd4_open {
|
||||
u32 op_why_no_deleg; /* response - DELEG_NONE_EXT only */
|
||||
u32 op_create; /* request */
|
||||
u32 op_createmode; /* request */
|
||||
int op_umask; /* request */
|
||||
u32 op_bmval[3]; /* request */
|
||||
struct iattr op_iattr; /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */
|
||||
nfs4_verifier op_verf __attribute__((aligned(32)));
|
||||
@@ -518,7 +522,6 @@ struct nfsd4_copy {
|
||||
u64 cp_count;
|
||||
|
||||
/* both */
|
||||
bool cp_consecutive;
|
||||
bool cp_synchronous;
|
||||
|
||||
/* response */
|
||||
|
||||
@@ -272,6 +272,7 @@ struct svc_rqst {
|
||||
#define RQ_BUSY (6) /* request is busy */
|
||||
#define RQ_DATA (7) /* request has data */
|
||||
unsigned long rq_flags; /* flags field */
|
||||
ktime_t rq_qtime; /* enqueue time */
|
||||
|
||||
void * rq_argp; /* decoded arguments */
|
||||
void * rq_resp; /* xdr'd results */
|
||||
@@ -283,6 +284,7 @@ struct svc_rqst {
|
||||
int rq_reserved; /* space on socket outq
|
||||
* reserved for this request
|
||||
*/
|
||||
ktime_t rq_stime; /* start time */
|
||||
|
||||
struct cache_req rq_chandle; /* handle passed to caches for
|
||||
* request delaying
|
||||
@@ -493,6 +495,10 @@ void svc_wake_up(struct svc_serv *);
|
||||
void svc_reserve(struct svc_rqst *rqstp, int space);
|
||||
struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
|
||||
char * svc_print_addr(struct svc_rqst *, char *, size_t);
|
||||
unsigned int svc_fill_write_vector(struct svc_rqst *rqstp,
|
||||
struct kvec *first, size_t total);
|
||||
char *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
|
||||
struct kvec *first, size_t total);
|
||||
|
||||
#define RPC_MAX_ADDRBUFLEN (63U)
|
||||
|
||||
|
||||
@@ -132,9 +132,6 @@ struct svcxprt_rdma {
|
||||
#define RDMAXPRT_CONN_PENDING 3
|
||||
|
||||
#define RPCRDMA_LISTEN_BACKLOG 10
|
||||
/* The default ORD value is based on two outstanding full-size writes with a
|
||||
* page size of 4k, or 32k * 2 ops / 4k = 16 outstanding RDMA_READ. */
|
||||
#define RPCRDMA_ORD (64/4)
|
||||
#define RPCRDMA_MAX_REQUESTS 32
|
||||
|
||||
/* Typical ULP usage of BC requests is NFSv4.1 backchannel. Our
|
||||
|
||||
@@ -25,7 +25,7 @@ struct svc_xprt_ops {
|
||||
void (*xpo_release_rqst)(struct svc_rqst *);
|
||||
void (*xpo_detach)(struct svc_xprt *);
|
||||
void (*xpo_free)(struct svc_xprt *);
|
||||
int (*xpo_secure_port)(struct svc_rqst *);
|
||||
void (*xpo_secure_port)(struct svc_rqst *rqstp);
|
||||
void (*xpo_kill_temp_xprt)(struct svc_xprt *);
|
||||
};
|
||||
|
||||
@@ -83,6 +83,7 @@ struct svc_xprt {
|
||||
size_t xpt_locallen; /* length of address */
|
||||
struct sockaddr_storage xpt_remote; /* remote peer's address */
|
||||
size_t xpt_remotelen; /* length of address */
|
||||
char xpt_remotebuf[INET6_ADDRSTRLEN + 10];
|
||||
struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */
|
||||
struct list_head xpt_users; /* callbacks on free */
|
||||
|
||||
@@ -152,7 +153,10 @@ static inline void svc_xprt_set_remote(struct svc_xprt *xprt,
|
||||
{
|
||||
memcpy(&xprt->xpt_remote, sa, salen);
|
||||
xprt->xpt_remotelen = salen;
|
||||
snprintf(xprt->xpt_remotebuf, sizeof(xprt->xpt_remotebuf) - 1,
|
||||
"%pISpc", sa);
|
||||
}
|
||||
|
||||
static inline unsigned short svc_addr_port(const struct sockaddr *sa)
|
||||
{
|
||||
const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user