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: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Родитель
873101b337
Коммит
94a6d75320
|
@ -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
|
||||||
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 @@
|
||||||
#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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
.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,
|
||||||
};
|
};
|
||||||
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 @@
|
||||||
#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
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
};
|
};
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
#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
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
.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,
|
||||||
};
|
};
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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 *,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче