Commit 94a6d753 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust

NFS: Use cached page as buffer for NFS symlink requests

Now that we have a copy of the symlink path in the page cache, we can pass
a struct page down to the XDR routines instead of a string buffer.

Test plan:
Connectathon, all NFS versions.
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 873101b3
...@@ -1464,10 +1464,6 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym ...@@ -1464,10 +1464,6 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
char *kaddr; char *kaddr;
struct iattr attr; struct iattr attr;
unsigned int pathlen = strlen(symname); unsigned int pathlen = strlen(symname);
struct qstr qsymname = {
.name = symname,
.len = pathlen,
};
int error; int error;
dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id, dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,
...@@ -1493,10 +1489,8 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym ...@@ -1493,10 +1489,8 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen); memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
kunmap_atomic(kaddr, KM_USER0); kunmap_atomic(kaddr, KM_USER0);
/* XXX: eventually this will pass in {page, pathlen},
* instead of qsymname; need XDR changes for that */
nfs_begin_data_update(dir); nfs_begin_data_update(dir);
error = NFS_PROTO(dir)->symlink(dir, dentry, &qsymname, &attr); error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
nfs_end_data_update(dir); nfs_end_data_update(dir);
if (error != 0) { if (error != 0) {
dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n", dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
#define NFS_symlinkargs_sz (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz) #define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
#define NFS_readdirargs_sz (NFS_fhandle_sz+2) #define NFS_readdirargs_sz (NFS_fhandle_sz+2)
#define NFS_attrstat_sz (1+NFS_fattr_sz) #define NFS_attrstat_sz (1+NFS_fattr_sz)
...@@ -351,11 +351,26 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args) ...@@ -351,11 +351,26 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
static int static int
nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
{ {
struct xdr_buf *sndbuf = &req->rq_snd_buf;
size_t pad;
p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_array(p, args->fromname, args->fromlen); p = xdr_encode_array(p, args->fromname, args->fromlen);
p = xdr_encode_array(p, args->topath, args->tolen); *p++ = htonl(args->pathlen);
sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
/*
* xdr_encode_pages may have added a few bytes to ensure the
* pathname ends on a 4-byte boundary. Start encoding the
* attributes after the pad bytes.
*/
pad = sndbuf->tail->iov_len;
if (pad > 0)
p++;
p = xdr_encode_sattr(p, args->sattr); p = xdr_encode_sattr(p, args->sattr);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
return 0; return 0;
} }
......
...@@ -544,8 +544,8 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) ...@@ -544,8 +544,8 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
} }
static int static int
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path, nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
struct iattr *sattr) unsigned int len, struct iattr *sattr)
{ {
struct nfs_fh fhandle; struct nfs_fh fhandle;
struct nfs_fattr fattr, dir_attr; struct nfs_fattr fattr, dir_attr;
...@@ -553,8 +553,8 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path, ...@@ -553,8 +553,8 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
.fromfh = NFS_FH(dir), .fromfh = NFS_FH(dir),
.fromname = dentry->d_name.name, .fromname = dentry->d_name.name,
.fromlen = dentry->d_name.len, .fromlen = dentry->d_name.len,
.topath = path->name, .pages = &page,
.tolen = path->len, .pathlen = len,
.sattr = sattr .sattr = sattr
}; };
struct nfs3_diropres res = { struct nfs3_diropres res = {
...@@ -569,11 +569,11 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path, ...@@ -569,11 +569,11 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
}; };
int status; int status;
if (path->len > NFS3_MAXPATHLEN) if (len > NFS3_MAXPATHLEN)
return -ENAMETOOLONG; return -ENAMETOOLONG;
dprintk("NFS call symlink %s -> %s\n", dentry->d_name.name, dprintk("NFS call symlink %s\n", dentry->d_name.name);
path->name);
nfs_fattr_init(&dir_attr); nfs_fattr_init(&dir_attr);
nfs_fattr_init(&fattr); nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
#define NFS3_writeargs_sz (NFS3_fh_sz+5) #define NFS3_writeargs_sz (NFS3_fh_sz+5)
#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz) #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
...@@ -398,8 +398,11 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args ...@@ -398,8 +398,11 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args
p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_array(p, args->fromname, args->fromlen); p = xdr_encode_array(p, args->fromname, args->fromlen);
p = xdr_encode_sattr(p, args->sattr); p = xdr_encode_sattr(p, args->sattr);
p = xdr_encode_array(p, args->topath, args->tolen); *p++ = htonl(args->pathlen);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
/* Copy the page */
xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
return 0; return 0;
} }
......
...@@ -2085,7 +2085,7 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n ...@@ -2085,7 +2085,7 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n
} }
static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct qstr *path, struct iattr *sattr) struct page *page, unsigned int len, struct iattr *sattr)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
struct nfs_fh fhandle; struct nfs_fh fhandle;
...@@ -2111,10 +2111,11 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, ...@@ -2111,10 +2111,11 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
}; };
int status; int status;
if (path->len > NFS4_MAXPATHLEN) if (len > NFS4_MAXPATHLEN)
return -ENAMETOOLONG; return -ENAMETOOLONG;
arg.u.symlink = path; arg.u.symlink.pages = &page;
arg.u.symlink.len = len;
nfs_fattr_init(&fattr); nfs_fattr_init(&fattr);
nfs_fattr_init(&dir_fattr); nfs_fattr_init(&dir_fattr);
...@@ -2128,13 +2129,14 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, ...@@ -2128,13 +2129,14 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
} }
static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct qstr *path, struct iattr *sattr) struct page *page, unsigned int len, struct iattr *sattr)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = { };
int err; int err;
do { do {
err = nfs4_handle_exception(NFS_SERVER(dir), err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_symlink(dir, dentry, path, sattr), _nfs4_proc_symlink(dir, dentry, page,
len, sattr),
&exception); &exception);
} while (exception.retry); } while (exception.retry);
return err; return err;
......
...@@ -128,7 +128,7 @@ static int nfs4_stat_to_errno(int); ...@@ -128,7 +128,7 @@ static int nfs4_stat_to_errno(int);
#define decode_link_maxsz (op_decode_hdr_maxsz + 5) #define decode_link_maxsz (op_decode_hdr_maxsz + 5)
#define encode_symlink_maxsz (op_encode_hdr_maxsz + \ #define encode_symlink_maxsz (op_encode_hdr_maxsz + \
1 + nfs4_name_maxsz + \ 1 + nfs4_name_maxsz + \
nfs4_path_maxsz + \ 1 + \
nfs4_fattr_maxsz) nfs4_fattr_maxsz)
#define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8)
#define encode_create_maxsz (op_encode_hdr_maxsz + \ #define encode_create_maxsz (op_encode_hdr_maxsz + \
...@@ -673,9 +673,9 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c ...@@ -673,9 +673,9 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
switch (create->ftype) { switch (create->ftype) {
case NF4LNK: case NF4LNK:
RESERVE_SPACE(4 + create->u.symlink->len); RESERVE_SPACE(4);
WRITE32(create->u.symlink->len); WRITE32(create->u.symlink.len);
WRITEMEM(create->u.symlink->name, create->u.symlink->len); xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
break; break;
case NF4BLK: case NF4CHR: case NF4BLK: case NF4CHR:
......
...@@ -425,8 +425,8 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) ...@@ -425,8 +425,8 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
} }
static int static int
nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path, nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
struct iattr *sattr) unsigned int len, struct iattr *sattr)
{ {
struct nfs_fh fhandle; struct nfs_fh fhandle;
struct nfs_fattr fattr; struct nfs_fattr fattr;
...@@ -434,8 +434,8 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path, ...@@ -434,8 +434,8 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
.fromfh = NFS_FH(dir), .fromfh = NFS_FH(dir),
.fromname = dentry->d_name.name, .fromname = dentry->d_name.name,
.fromlen = dentry->d_name.len, .fromlen = dentry->d_name.len,
.topath = path->name, .pages = &page,
.tolen = path->len, .pathlen = len,
.sattr = sattr .sattr = sattr
}; };
struct rpc_message msg = { struct rpc_message msg = {
...@@ -444,11 +444,11 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path, ...@@ -444,11 +444,11 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
}; };
int status; int status;
if (path->len > NFS2_MAXPATHLEN) if (len > NFS2_MAXPATHLEN)
return -ENAMETOOLONG; return -ENAMETOOLONG;
dprintk("NFS call symlink %s -> %s\n", dentry->d_name.name, dprintk("NFS call symlink %s\n", dentry->d_name.name);
path->name);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_mark_for_revalidate(dir); nfs_mark_for_revalidate(dir);
......
...@@ -358,8 +358,8 @@ struct nfs_symlinkargs { ...@@ -358,8 +358,8 @@ struct nfs_symlinkargs {
struct nfs_fh * fromfh; struct nfs_fh * fromfh;
const char * fromname; const char * fromname;
unsigned int fromlen; unsigned int fromlen;
const char * topath; struct page ** pages;
unsigned int tolen; unsigned int pathlen;
struct iattr * sattr; struct iattr * sattr;
}; };
...@@ -434,8 +434,8 @@ struct nfs3_symlinkargs { ...@@ -434,8 +434,8 @@ struct nfs3_symlinkargs {
struct nfs_fh * fromfh; struct nfs_fh * fromfh;
const char * fromname; const char * fromname;
unsigned int fromlen; unsigned int fromlen;
const char * topath; struct page ** pages;
unsigned int tolen; unsigned int pathlen;
struct iattr * sattr; struct iattr * sattr;
}; };
...@@ -533,7 +533,10 @@ struct nfs4_accessres { ...@@ -533,7 +533,10 @@ struct nfs4_accessres {
struct nfs4_create_arg { struct nfs4_create_arg {
u32 ftype; u32 ftype;
union { union {
struct qstr * symlink; /* NF4LNK */ struct {
struct page ** pages;
unsigned int len;
} symlink; /* NF4LNK */
struct { struct {
u32 specdata1; u32 specdata1;
u32 specdata2; u32 specdata2;
...@@ -793,8 +796,8 @@ struct nfs_rpc_ops { ...@@ -793,8 +796,8 @@ struct nfs_rpc_ops {
int (*rename) (struct inode *, struct qstr *, int (*rename) (struct inode *, struct qstr *,
struct inode *, struct qstr *); struct inode *, struct qstr *);
int (*link) (struct inode *, struct inode *, struct qstr *); int (*link) (struct inode *, struct inode *, struct qstr *);
int (*symlink) (struct inode *, struct dentry *, struct qstr *, int (*symlink) (struct inode *, struct dentry *, struct page *,
struct iattr *); unsigned int, struct iattr *);
int (*mkdir) (struct inode *, struct dentry *, struct iattr *); int (*mkdir) (struct inode *, struct dentry *, struct iattr *);
int (*rmdir) (struct inode *, struct qstr *); int (*rmdir) (struct inode *, struct qstr *);
int (*readdir) (struct dentry *, struct rpc_cred *, int (*readdir) (struct dentry *, struct rpc_cred *,
......
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