NFSD: Refactor the generic write vector fill helper
fill_in_write_vector() is nearly the same logic as svc_fill_write_vector(), but there are a few differences so that the former can handle multiple WRITE payloads in a single COMPOUND. svc_fill_write_vector() can be adjusted so that it can be used in the NFSv4 WRITE code path too. Instead of assuming the pages are coming from rq_args.pages, have the caller pass in the page list. The immediate benefit is a reduction of code duplication. It also prevents the NFSv4 WRITE decoder from passing an empty vector element when the transport has provided the payload in the xdr_buf's page array. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
07d0ff3b0c
commit
3fd9557aec
5 changed files with 13 additions and 28 deletions
|
@ -202,7 +202,8 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
|
||||||
|
|
||||||
fh_copy(&resp->fh, &argp->fh);
|
fh_copy(&resp->fh, &argp->fh);
|
||||||
resp->committed = argp->stable;
|
resp->committed = argp->stable;
|
||||||
nvecs = svc_fill_write_vector(rqstp, &argp->first, cnt);
|
nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages,
|
||||||
|
&argp->first, cnt);
|
||||||
if (!nvecs)
|
if (!nvecs)
|
||||||
RETURN_STATUS(nfserr_io);
|
RETURN_STATUS(nfserr_io);
|
||||||
nfserr = nfsd_write(rqstp, &resp->fh, argp->offset,
|
nfserr = nfsd_write(rqstp, &resp->fh, argp->offset,
|
||||||
|
|
|
@ -986,24 +986,6 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
|
|
||||||
{
|
|
||||||
int i = 1;
|
|
||||||
int buflen = write->wr_buflen;
|
|
||||||
|
|
||||||
vec[0].iov_base = write->wr_head.iov_base;
|
|
||||||
vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len);
|
|
||||||
buflen -= vec[0].iov_len;
|
|
||||||
|
|
||||||
while (buflen) {
|
|
||||||
vec[i].iov_base = page_address(write->wr_pagelist[i - 1]);
|
|
||||||
vec[i].iov_len = min_t(int, PAGE_SIZE, buflen);
|
|
||||||
buflen -= vec[i].iov_len;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
union nfsd4_op_u *u)
|
union nfsd4_op_u *u)
|
||||||
|
@ -1031,7 +1013,10 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
write->wr_how_written = write->wr_stable_how;
|
write->wr_how_written = write->wr_stable_how;
|
||||||
gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp));
|
gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp));
|
||||||
|
|
||||||
nvecs = fill_in_write_vector(rqstp->rq_vec, write);
|
nvecs = svc_fill_write_vector(rqstp, write->wr_pagelist,
|
||||||
|
&write->wr_head, write->wr_buflen);
|
||||||
|
if (!nvecs)
|
||||||
|
return nfserr_io;
|
||||||
WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));
|
WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));
|
||||||
|
|
||||||
status = nfsd_vfs_write(rqstp, &cstate->current_fh, filp,
|
status = nfsd_vfs_write(rqstp, &cstate->current_fh, filp,
|
||||||
|
|
|
@ -218,7 +218,8 @@ nfsd_proc_write(struct svc_rqst *rqstp)
|
||||||
SVCFH_fmt(&argp->fh),
|
SVCFH_fmt(&argp->fh),
|
||||||
argp->len, argp->offset);
|
argp->len, argp->offset);
|
||||||
|
|
||||||
nvecs = svc_fill_write_vector(rqstp, &argp->first, cnt);
|
nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages,
|
||||||
|
&argp->first, cnt);
|
||||||
if (!nvecs)
|
if (!nvecs)
|
||||||
return nfserr_io;
|
return nfserr_io;
|
||||||
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
|
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||||
|
|
|
@ -496,6 +496,7 @@ void svc_reserve(struct svc_rqst *rqstp, int space);
|
||||||
struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
|
struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
|
||||||
char * svc_print_addr(struct svc_rqst *, char *, size_t);
|
char * svc_print_addr(struct svc_rqst *, char *, size_t);
|
||||||
unsigned int svc_fill_write_vector(struct svc_rqst *rqstp,
|
unsigned int svc_fill_write_vector(struct svc_rqst *rqstp,
|
||||||
|
struct page **pages,
|
||||||
struct kvec *first, size_t total);
|
struct kvec *first, size_t total);
|
||||||
char *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
|
char *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
|
||||||
struct kvec *first, size_t total);
|
struct kvec *first, size_t total);
|
||||||
|
|
|
@ -1537,16 +1537,16 @@ EXPORT_SYMBOL_GPL(svc_max_payload);
|
||||||
/**
|
/**
|
||||||
* svc_fill_write_vector - Construct data argument for VFS write call
|
* svc_fill_write_vector - Construct data argument for VFS write call
|
||||||
* @rqstp: svc_rqst to operate on
|
* @rqstp: svc_rqst to operate on
|
||||||
|
* @pages: list of pages containing data payload
|
||||||
* @first: buffer containing first section of write payload
|
* @first: buffer containing first section of write payload
|
||||||
* @total: total number of bytes of write payload
|
* @total: total number of bytes of write payload
|
||||||
*
|
*
|
||||||
* Returns the number of elements populated in the data argument array.
|
* Fills in rqstp::rq_vec, and returns the number of elements.
|
||||||
*/
|
*/
|
||||||
unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct kvec *first,
|
unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct page **pages,
|
||||||
size_t total)
|
struct kvec *first, size_t total)
|
||||||
{
|
{
|
||||||
struct kvec *vec = rqstp->rq_vec;
|
struct kvec *vec = rqstp->rq_vec;
|
||||||
struct page **pages;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* Some types of transport can present the write payload
|
/* Some types of transport can present the write payload
|
||||||
|
@ -1560,14 +1560,11 @@ unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct kvec *first,
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
WARN_ON_ONCE(rqstp->rq_arg.page_base != 0);
|
|
||||||
pages = rqstp->rq_arg.pages;
|
|
||||||
while (total) {
|
while (total) {
|
||||||
vec[i].iov_base = page_address(*pages);
|
vec[i].iov_base = page_address(*pages);
|
||||||
vec[i].iov_len = min_t(size_t, total, PAGE_SIZE);
|
vec[i].iov_len = min_t(size_t, total, PAGE_SIZE);
|
||||||
total -= vec[i].iov_len;
|
total -= vec[i].iov_len;
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
++pages;
|
++pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue