Skip to content

Commit

Permalink
[PATCH] knfsd: Replace two page lists in struct svc_rqst with one
Browse files Browse the repository at this point in the history
We are planning to increase RPCSVC_MAXPAGES from about 8 to about 256.  This
means we need to be a bit careful about arrays of size RPCSVC_MAXPAGES.

struct svc_rqst contains two such arrays.  However the there are never more
that RPCSVC_MAXPAGES pages in the two arrays together, so only one array is
needed.

The two arrays are for the pages holding the request, and the pages holding
the reply.  Instead of two arrays, we can simply keep an index into where the
first reply page is.

This patch also removes a number of small inline functions that probably
server to obscure what is going on rather than clarify it, and opencode the
needed functionality.

Also remove the 'rq_restailpage' variable as it is *always* 0.  i.e.  if the
response 'xdr' structure has a non-empty tail it is always in the same pages
as the head.

 check counters are initilised and incr properly
 check for consistant usage of ++ etc
 maybe extra some inlines for common approach
 general review

Signed-off-by: Neil Brown <[email protected]>
Cc: Magnus Maatta <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
neilbrown authored and Linus Torvalds committed Oct 4, 2006
1 parent 5680c44 commit 4452435
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 141 deletions.
2 changes: 1 addition & 1 deletion fs/nfsd/nfs2acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,

rqstp->rq_res.page_len = w;
while (w > 0) {
if (!svc_take_res_page(rqstp))
if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
w -= PAGE_SIZE;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/nfsd/nfs3acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,

rqstp->rq_res.page_len = w;
while (w > 0) {
if (!svc_take_res_page(rqstp))
if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
w -= PAGE_SIZE;
}
Expand Down
23 changes: 9 additions & 14 deletions fs/nfsd/nfs3xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
/* set up the kvec */
v=0;
while (len > 0) {
pn = rqstp->rq_resused;
svc_take_page(rqstp);
pn = rqstp->rq_resused++;
args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
len -= args->vec[v].iov_len;
Expand Down Expand Up @@ -382,7 +381,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
while (len > args->vec[v].iov_len) {
len -= args->vec[v].iov_len;
v++;
args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
args->vec[v].iov_base = page_address(rqstp->rq_pages[v]);
args->vec[v].iov_len = PAGE_SIZE;
}
args->vec[v].iov_len = len;
Expand Down Expand Up @@ -446,11 +445,11 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
* This page appears in the rq_res.pages list, but as pages_len is always
* 0, it won't get in the way
*/
svc_take_page(rqstp);
len = ntohl(*p++);
if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
return 0;
args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
args->tname = new =
page_address(rqstp->rq_respages[rqstp->rq_resused++]);
args->tlen = len;
/* first copy and check from the first page */
old = (char*)p;
Expand Down Expand Up @@ -522,8 +521,8 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p,
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
svc_take_page(rqstp);
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
args->buffer =
page_address(rqstp->rq_respages[rqstp->rq_resused++]);

return xdr_argsize_check(rqstp, p);
}
Expand Down Expand Up @@ -554,8 +553,8 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
if (args->count > PAGE_SIZE)
args->count = PAGE_SIZE;

svc_take_page(rqstp);
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
args->buffer =
page_address(rqstp->rq_respages[rqstp->rq_resused++]);

return xdr_argsize_check(rqstp, p);
}
Expand All @@ -578,8 +577,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
args->count = len;

while (len > 0) {
pn = rqstp->rq_resused;
svc_take_page(rqstp);
pn = rqstp->rq_resused++;
if (!args->buffer)
args->buffer = page_address(rqstp->rq_respages[pn]);
len -= PAGE_SIZE;
Expand Down Expand Up @@ -668,7 +666,6 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = resp->len;
if (resp->len & 3) {
/* need to pad the tail */
rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
Expand All @@ -693,7 +690,6 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = resp->count;
if (resp->count & 3) {
/* need to pad the tail */
rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
Expand Down Expand Up @@ -768,7 +764,6 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = (resp->count) << 2;

/* add the 'tail' to the end of the 'head' page - page 0. */
rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p++ = 0; /* no more entries */
*p++ = htonl(resp->common.err == nfserr_eof);
Expand Down
27 changes: 13 additions & 14 deletions fs/nfsd/nfs4xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2039,7 +2039,8 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct n
}

static int
nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read)
nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr,
struct nfsd4_read *read)
{
u32 eof;
int v, pn;
Expand All @@ -2061,10 +2062,11 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
len = maxcount;
v = 0;
while (len > 0) {
pn = resp->rqstp->rq_resused;
svc_take_page(resp->rqstp);
read->rd_iov[v].iov_base = page_address(resp->rqstp->rq_respages[pn]);
read->rd_iov[v].iov_len = len < PAGE_SIZE ? len : PAGE_SIZE;
pn = resp->rqstp->rq_resused++;
read->rd_iov[v].iov_base =
page_address(resp->rqstp->rq_respages[pn]);
read->rd_iov[v].iov_len =
len < PAGE_SIZE ? len : PAGE_SIZE;
v++;
len -= PAGE_SIZE;
}
Expand All @@ -2078,7 +2080,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
nfserr = nfserr_inval;
if (nfserr)
return nfserr;
eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size);
eof = (read->rd_offset + maxcount >=
read->rd_fhp->fh_dentry->d_inode->i_size);

WRITE32(eof);
WRITE32(maxcount);
Expand All @@ -2088,7 +2091,6 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
resp->xbuf->page_len = maxcount;

/* Use rest of head for padding and remaining ops: */
resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = p;
resp->xbuf->tail[0].iov_len = 0;
if (maxcount&3) {
Expand All @@ -2113,8 +2115,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r
if (resp->xbuf->page_len)
return nfserr_resource;

svc_take_page(resp->rqstp);
page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);

maxcount = PAGE_SIZE;
RESERVE_SPACE(4);
Expand All @@ -2138,7 +2139,6 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r
resp->xbuf->page_len = maxcount;

/* Use rest of head for padding and remaining ops: */
resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = p;
resp->xbuf->tail[0].iov_len = 0;
if (maxcount&3) {
Expand Down Expand Up @@ -2189,8 +2189,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
goto err_no_verf;
}

svc_take_page(resp->rqstp);
page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
readdir->common.err = 0;
readdir->buflen = maxcount;
readdir->buffer = page;
Expand All @@ -2215,10 +2214,10 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
p = readdir->buffer;
*p++ = 0; /* no more entries */
*p++ = htonl(readdir->common.err == nfserr_eof);
resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
resp->xbuf->page_len = ((char*)p) - (char*)page_address(
resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);

/* Use rest of head for padding and remaining ops: */
resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = tailbase;
resp->xbuf->tail[0].iov_len = 0;
resp->p = resp->xbuf->tail[0].iov_base;
Expand Down
13 changes: 4 additions & 9 deletions fs/nfsd/nfsxdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
*/
v=0;
while (len > 0) {
pn=rqstp->rq_resused;
svc_take_page(rqstp);
pn = rqstp->rq_resused++;
args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
len -= args->vec[v].iov_len;
Expand Down Expand Up @@ -295,7 +294,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
while (len > args->vec[v].iov_len) {
len -= args->vec[v].iov_len;
v++;
args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
args->vec[v].iov_base = page_address(rqstp->rq_pages[v]);
args->vec[v].iov_len = PAGE_SIZE;
}
args->vec[v].iov_len = len;
Expand Down Expand Up @@ -333,8 +332,7 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinka
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
svc_take_page(rqstp);
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);

return xdr_argsize_check(rqstp, p);
}
Expand Down Expand Up @@ -375,8 +373,7 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
if (args->count > PAGE_SIZE)
args->count = PAGE_SIZE;

svc_take_page(rqstp);
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);

return xdr_argsize_check(rqstp, p);
}
Expand Down Expand Up @@ -416,7 +413,6 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = resp->len;
if (resp->len & 3) {
/* need to pad the tail */
rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
Expand All @@ -436,7 +432,6 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = resp->count;
if (resp->count & 3) {
/* need to pad the tail */
rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
Expand Down
16 changes: 10 additions & 6 deletions fs/nfsd/vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,22 +791,26 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset
{
unsigned long count = desc->count;
struct svc_rqst *rqstp = desc->arg.data;
struct page **pp = rqstp->rq_respages + rqstp->rq_resused;

if (size > count)
size = count;

if (rqstp->rq_res.page_len == 0) {
get_page(page);
rqstp->rq_respages[rqstp->rq_resused++] = page;
put_page(*pp);
*pp = page;
rqstp->rq_resused++;
rqstp->rq_res.page_base = offset;
rqstp->rq_res.page_len = size;
} else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) {
} else if (page != pp[-1]) {
get_page(page);
rqstp->rq_respages[rqstp->rq_resused++] = page;
put_page(*pp);
*pp = page;
rqstp->rq_resused++;
rqstp->rq_res.page_len += size;
} else {
} else
rqstp->rq_res.page_len += size;
}

desc->count = count - size;
desc->written += size;
Expand Down Expand Up @@ -837,7 +841,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
file->f_ra = ra->p_ra;

if (file->f_op->sendfile && rqstp->rq_sendfile_ok) {
svc_pushback_unused_pages(rqstp);
rqstp->rq_resused = 1;
err = file->f_op->sendfile(file, &offset, *count,
nfsd_read_actor, rqstp);
} else {
Expand Down
69 changes: 10 additions & 59 deletions include/linux/sunrpc/svc.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ static inline void svc_putu32(struct kvec *iov, __be32 val)
/*
* The context of a single thread, including the request currently being
* processed.
* NOTE: First two items must be prev/next.
*/
struct svc_rqst {
struct list_head rq_list; /* idle list */
Expand All @@ -189,12 +188,9 @@ struct svc_rqst {

struct xdr_buf rq_arg;
struct xdr_buf rq_res;
struct page * rq_argpages[RPCSVC_MAXPAGES];
struct page * rq_respages[RPCSVC_MAXPAGES];
int rq_restailpage;
short rq_argused; /* pages used for argument */
short rq_arghi; /* pages available in argument page list */
short rq_resused; /* pages used for result */
struct page * rq_pages[RPCSVC_MAXPAGES];
struct page * *rq_respages; /* points into rq_pages */
int rq_resused; /* number of pages used for result */

__be32 rq_xid; /* transmission id */
u32 rq_prog; /* program number */
Expand Down Expand Up @@ -255,63 +251,18 @@ xdr_ressize_check(struct svc_rqst *rqstp, __be32 *p)
return vec->iov_len <= PAGE_SIZE;
}

static inline struct page *
svc_take_res_page(struct svc_rqst *rqstp)
static inline void svc_free_res_pages(struct svc_rqst *rqstp)
{
if (rqstp->rq_arghi <= rqstp->rq_argused)
return NULL;
rqstp->rq_arghi--;
rqstp->rq_respages[rqstp->rq_resused] =
rqstp->rq_argpages[rqstp->rq_arghi];
return rqstp->rq_respages[rqstp->rq_resused++];
}

static inline void svc_take_page(struct svc_rqst *rqstp)
{
if (rqstp->rq_arghi <= rqstp->rq_argused) {
WARN_ON(1);
return;
}
rqstp->rq_arghi--;
rqstp->rq_respages[rqstp->rq_resused] =
rqstp->rq_argpages[rqstp->rq_arghi];
rqstp->rq_resused++;
}

static inline void svc_pushback_allpages(struct svc_rqst *rqstp)
{
while (rqstp->rq_resused) {
if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
continue;
rqstp->rq_argpages[rqstp->rq_arghi++] =
rqstp->rq_respages[rqstp->rq_resused];
rqstp->rq_respages[rqstp->rq_resused] = NULL;
}
}

static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp)
{
while (rqstp->rq_resused &&
rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) {

if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) {
rqstp->rq_argpages[rqstp->rq_arghi++] =
rqstp->rq_respages[rqstp->rq_resused];
rqstp->rq_respages[rqstp->rq_resused] = NULL;
while (rqstp->rq_resused) {
struct page **pp = (rqstp->rq_respages +
--rqstp->rq_resused);
if (*pp) {
put_page(*pp);
*pp = NULL;
}
}
}

static inline void svc_free_allpages(struct svc_rqst *rqstp)
{
while (rqstp->rq_resused) {
if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
continue;
put_page(rqstp->rq_respages[rqstp->rq_resused]);
rqstp->rq_respages[rqstp->rq_resused] = NULL;
}
}

struct svc_deferred_req {
u32 prot; /* protocol (UDP or TCP) */
struct sockaddr_in addr;
Expand Down
Loading

0 comments on commit 4452435

Please sign in to comment.