Commit 3a689637 authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] kNFSd: Convert readlink to use a separate page for returning symlink contents.

This allows NFSv3 to manage 4096byte symlinks.

Also remove now-unused svcbuf_reserver function.

This was used to reserve space in output buffer
for 'data', but now this is stored in separate page.
parent 65774d49
...@@ -682,10 +682,9 @@ static void compute_parity(struct stripe_head *sh, int method) ...@@ -682,10 +682,9 @@ static void compute_parity(struct stripe_head *sh, int method)
raid5_conf_t *conf = sh->raid_conf; raid5_conf_t *conf = sh->raid_conf;
int i, pd_idx = sh->pd_idx, disks = conf->raid_disks, count; int i, pd_idx = sh->pd_idx, disks = conf->raid_disks, count;
void *ptr[MAX_XOR_BLOCKS]; void *ptr[MAX_XOR_BLOCKS];
struct bio *chosen[MD_SB_DISKS]; struct bio *chosen;
PRINTK("compute_parity, stripe %llu, method %d\n", (unsigned long long)sh->sector, method); PRINTK("compute_parity, stripe %llu, method %d\n", (unsigned long long)sh->sector, method);
memset(chosen, 0, sizeof(chosen));
count = 1; count = 1;
ptr[0] = page_address(sh->dev[pd_idx].page); ptr[0] = page_address(sh->dev[pd_idx].page);
...@@ -699,10 +698,10 @@ static void compute_parity(struct stripe_head *sh, int method) ...@@ -699,10 +698,10 @@ static void compute_parity(struct stripe_head *sh, int method)
if (sh->dev[i].towrite && if (sh->dev[i].towrite &&
test_bit(R5_UPTODATE, &sh->dev[i].flags)) { test_bit(R5_UPTODATE, &sh->dev[i].flags)) {
ptr[count++] = page_address(sh->dev[i].page); ptr[count++] = page_address(sh->dev[i].page);
chosen[i] = sh->dev[i].towrite; chosen = sh->dev[i].towrite;
sh->dev[i].towrite = NULL; sh->dev[i].towrite = NULL;
if (sh->dev[i].written) BUG(); if (sh->dev[i].written) BUG();
sh->dev[i].written = chosen[i]; sh->dev[i].written = chosen;
check_xor(); check_xor();
} }
} }
...@@ -711,10 +710,10 @@ static void compute_parity(struct stripe_head *sh, int method) ...@@ -711,10 +710,10 @@ static void compute_parity(struct stripe_head *sh, int method)
memset(ptr[0], 0, STRIPE_SIZE); memset(ptr[0], 0, STRIPE_SIZE);
for (i= disks; i-- ;) for (i= disks; i-- ;)
if (i!=pd_idx && sh->dev[i].towrite) { if (i!=pd_idx && sh->dev[i].towrite) {
chosen[i] = sh->dev[i].towrite; chosen = sh->dev[i].towrite;
sh->dev[i].towrite = NULL; sh->dev[i].towrite = NULL;
if (sh->dev[i].written) BUG(); if (sh->dev[i].written) BUG();
sh->dev[i].written = chosen[i]; sh->dev[i].written = chosen;
} }
break; break;
case CHECK_PARITY: case CHECK_PARITY:
...@@ -726,9 +725,9 @@ static void compute_parity(struct stripe_head *sh, int method) ...@@ -726,9 +725,9 @@ static void compute_parity(struct stripe_head *sh, int method)
} }
for (i = disks; i--;) for (i = disks; i--;)
if (chosen[i]) { if (sh->dev[i].written) {
sector_t sector = sh->dev[i].sector; sector_t sector = sh->dev[i].sector;
copy_data(1, chosen[i], sh->dev[i].page, sector); copy_data(1, sh->dev[i].written, sh->dev[i].page, sector);
set_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(R5_UPTODATE, &sh->dev[i].flags); set_bit(R5_UPTODATE, &sh->dev[i].flags);
...@@ -745,7 +744,7 @@ static void compute_parity(struct stripe_head *sh, int method) ...@@ -745,7 +744,7 @@ static void compute_parity(struct stripe_head *sh, int method)
break; break;
case READ_MODIFY_WRITE: case READ_MODIFY_WRITE:
for (i = disks; i--;) for (i = disks; i--;)
if (chosen[i]) { if (sh->dev[i].written) {
ptr[count++] = page_address(sh->dev[i].page); ptr[count++] = page_address(sh->dev[i].page);
check_xor(); check_xor();
} }
......
...@@ -40,16 +40,6 @@ static int nfs3_ftypes[] = { ...@@ -40,16 +40,6 @@ static int nfs3_ftypes[] = {
S_IFIFO, /* NF3FIFO */ S_IFIFO, /* NF3FIFO */
}; };
/*
* Reserve room in the send buffer
*/
static inline void
svcbuf_reserve(struct xdr_buf *buf, u32 **ptr, int *len, int nr)
{
*ptr = (u32*)(buf->head[0].iov_base+buf->head[0].iov_len) + nr;
*len = ((PAGE_SIZE-buf->head[0].iov_len)>>2) - nr;
}
/* /*
* NULL call. * NULL call.
*/ */
...@@ -141,22 +131,17 @@ nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, ...@@ -141,22 +131,17 @@ nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
* Read a symlink. * Read a symlink.
*/ */
static int static int
nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
struct nfsd3_readlinkres *resp) struct nfsd3_readlinkres *resp)
{ {
u32 *path; int nfserr;
int dummy, nfserr;
dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
/* Reserve room for status, post_op_attr, and path length */
svcbuf_reserve(&rqstp->rq_res, &path, &dummy,
1 + NFS3_POST_OP_ATTR_WORDS + 1);
/* Read the symlink. */ /* Read the symlink. */
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
resp->len = NFS3_MAXPATHLEN; resp->len = NFS3_MAXPATHLEN;
nfserr = nfsd_readlink(rqstp, &resp->fh, (char *) path, &resp->len); nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
} }
...@@ -669,7 +654,7 @@ static struct svc_procedure nfsd_procedures3[22] = { ...@@ -669,7 +654,7 @@ static struct svc_procedure nfsd_procedures3[22] = {
PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF, ST+WC), PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF, ST+WC),
PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT), PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT),
PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1), PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1),
PROC(readlink, fhandle, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4), PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4),
PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE), PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE),
PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4), PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4),
PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
......
...@@ -275,9 +275,9 @@ encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) ...@@ -275,9 +275,9 @@ encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
* XDR decode functions * XDR decode functions
*/ */
int int
nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
{ {
if (!(p = decode_fh(p, fhp))) if (!(p = decode_fh(p, &args->fh)))
return 0; return 0;
return xdr_argsize_check(rqstp, p); return xdr_argsize_check(rqstp, p);
} }
...@@ -467,6 +467,18 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, ...@@ -467,6 +467,18 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
return xdr_argsize_check(rqstp, p); return xdr_argsize_check(rqstp, p);
} }
int
nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_readlinkargs *args)
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
svc_take_page(rqstp);
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
return xdr_argsize_check(rqstp, p);
}
int int
nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_linkargs *args) struct nfsd3_linkargs *args)
...@@ -592,8 +604,16 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, ...@@ -592,8 +604,16 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
p = encode_post_op_attr(rqstp, p, &resp->fh); p = encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0) { if (resp->status == 0) {
*p++ = htonl(resp->len); *p++ = htonl(resp->len);
p += XDR_QUADLEN(resp->len); xdr_ressize_check(rqstp, p);
rqstp->rq_res.page_len = resp->len;
if (resp->len & 3) {
/* need to pad the tail */
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
} }
return 1;
} else
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
} }
......
...@@ -30,13 +30,6 @@ typedef struct svc_buf svc_buf; ...@@ -30,13 +30,6 @@ typedef struct svc_buf svc_buf;
#define NFSDDBG_FACILITY NFSDDBG_PROC #define NFSDDBG_FACILITY NFSDDBG_PROC
static inline void
svcbuf_reserve(struct xdr_buf *buf, u32 **ptr, int *len, int nr)
{
*ptr = (u32*)(buf->head[0].iov_base+buf->head[0].iov_len) + nr;
*len = ((PAGE_SIZE-buf->head[0].iov_len)>>2) - nr;
}
static int static int
nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{ {
...@@ -100,20 +93,16 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, ...@@ -100,20 +93,16 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
* Read a symlink. * Read a symlink.
*/ */
static int static int
nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
struct nfsd_readlinkres *resp) struct nfsd_readlinkres *resp)
{ {
u32 *path; int nfserr;
int dummy, nfserr;
dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
/* Reserve room for status and path length */
svcbuf_reserve(&rqstp->rq_res, &path, &dummy, 2);
/* Read the symlink. */ /* Read the symlink. */
resp->len = NFS_MAXPATHLEN; resp->len = NFS_MAXPATHLEN;
nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len); nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
fh_put(&argp->fh); fh_put(&argp->fh);
return nfserr; return nfserr;
...@@ -545,7 +534,7 @@ static struct svc_procedure nfsd_procedures2[18] = { ...@@ -545,7 +534,7 @@ static struct svc_procedure nfsd_procedures2[18] = {
PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF, ST+AT),
PROC(none, void, void, none, RC_NOCACHE, ST), PROC(none, void, void, none, RC_NOCACHE, ST),
PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT), PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT),
PROC(readlink, fhandle, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4), PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE), PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE),
PROC(none, void, void, none, RC_NOCACHE, ST), PROC(none, void, void, none, RC_NOCACHE, ST),
PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT),
......
...@@ -188,9 +188,9 @@ nfssvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) ...@@ -188,9 +188,9 @@ nfssvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
} }
int int
nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
{ {
if (!(p = decode_fh(p, fhp))) if (!(p = decode_fh(p, &args->fh)))
return 0; return 0;
return xdr_argsize_check(rqstp, p); return xdr_argsize_check(rqstp, p);
} }
...@@ -304,6 +304,17 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, ...@@ -304,6 +304,17 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
return xdr_argsize_check(rqstp, p); return xdr_argsize_check(rqstp, p);
} }
int
nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinkargs *args)
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
svc_take_page(rqstp);
args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
return xdr_argsize_check(rqstp, p);
}
int int
nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
struct nfsd_linkargs *args) struct nfsd_linkargs *args)
...@@ -377,8 +388,15 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, ...@@ -377,8 +388,15 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
struct nfsd_readlinkres *resp) struct nfsd_readlinkres *resp)
{ {
*p++ = htonl(resp->len); *p++ = htonl(resp->len);
p += XDR_QUADLEN(resp->len); xdr_ressize_check(rqstp, p);
return xdr_ressize_check(rqstp, p); rqstp->rq_res.page_len = resp->len;
if (resp->len & 3) {
/* need to pad the tail */
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
}
return 1;
} }
int int
......
...@@ -57,6 +57,11 @@ struct nfsd_renameargs { ...@@ -57,6 +57,11 @@ struct nfsd_renameargs {
int tlen; int tlen;
}; };
struct nfsd_readlinkargs {
struct svc_fh fh;
char * buffer;
};
struct nfsd_linkargs { struct nfsd_linkargs {
struct svc_fh ffh; struct svc_fh ffh;
struct svc_fh tfh; struct svc_fh tfh;
...@@ -129,7 +134,7 @@ union nfsd_xdrstore { ...@@ -129,7 +134,7 @@ union nfsd_xdrstore {
int nfssvc_decode_void(struct svc_rqst *, u32 *, void *); int nfssvc_decode_void(struct svc_rqst *, u32 *, void *);
int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct svc_fh *); int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
int nfssvc_decode_sattrargs(struct svc_rqst *, u32 *, int nfssvc_decode_sattrargs(struct svc_rqst *, u32 *,
struct nfsd_sattrargs *); struct nfsd_sattrargs *);
int nfssvc_decode_diropargs(struct svc_rqst *, u32 *, int nfssvc_decode_diropargs(struct svc_rqst *, u32 *,
...@@ -142,6 +147,8 @@ int nfssvc_decode_createargs(struct svc_rqst *, u32 *, ...@@ -142,6 +147,8 @@ int nfssvc_decode_createargs(struct svc_rqst *, u32 *,
struct nfsd_createargs *); struct nfsd_createargs *);
int nfssvc_decode_renameargs(struct svc_rqst *, u32 *, int nfssvc_decode_renameargs(struct svc_rqst *, u32 *,
struct nfsd_renameargs *); struct nfsd_renameargs *);
int nfssvc_decode_readlinkargs(struct svc_rqst *, u32 *,
struct nfsd_readlinkargs *);
int nfssvc_decode_linkargs(struct svc_rqst *, u32 *, int nfssvc_decode_linkargs(struct svc_rqst *, u32 *,
struct nfsd_linkargs *); struct nfsd_linkargs *);
int nfssvc_decode_symlinkargs(struct svc_rqst *, u32 *, int nfssvc_decode_symlinkargs(struct svc_rqst *, u32 *,
......
...@@ -74,6 +74,11 @@ struct nfsd3_renameargs { ...@@ -74,6 +74,11 @@ struct nfsd3_renameargs {
int tlen; int tlen;
}; };
struct nfsd3_readlinkargs {
struct svc_fh fh;
char * buffer;
};
struct nfsd3_linkargs { struct nfsd3_linkargs {
struct svc_fh ffh; struct svc_fh ffh;
struct svc_fh tfh; struct svc_fh tfh;
...@@ -239,7 +244,7 @@ union nfsd3_xdrstore { ...@@ -239,7 +244,7 @@ union nfsd3_xdrstore {
#define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore)
int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct svc_fh *); int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *, int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *,
struct nfsd3_sattrargs *); struct nfsd3_sattrargs *);
int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *, int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *,
...@@ -258,6 +263,8 @@ int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *, ...@@ -258,6 +263,8 @@ int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *,
struct nfsd3_mknodargs *); struct nfsd3_mknodargs *);
int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *, int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *,
struct nfsd3_renameargs *); struct nfsd3_renameargs *);
int nfs3svc_decode_readlinkargs(struct svc_rqst *, u32 *,
struct nfsd3_readlinkargs *);
int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *, int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *,
struct nfsd3_linkargs *); struct nfsd3_linkargs *);
int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *, int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment