Commit 57dc9a57 authored by Trond Myklebust's avatar Trond Myklebust

NFS: Reduce the stack usage in NFSv4 create operations

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent f57e9168
...@@ -2079,47 +2079,81 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n ...@@ -2079,47 +2079,81 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n
return err; return err;
} }
struct nfs4_createdata {
struct rpc_message msg;
struct nfs4_create_arg arg;
struct nfs4_create_res res;
struct nfs_fh fh;
struct nfs_fattr fattr;
struct nfs_fattr dir_fattr;
};
static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
struct qstr *name, struct iattr *sattr, u32 ftype)
{
struct nfs4_createdata *data;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data != NULL) {
struct nfs_server *server = NFS_SERVER(dir);
data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
data->msg.rpc_argp = &data->arg;
data->msg.rpc_resp = &data->res;
data->arg.dir_fh = NFS_FH(dir);
data->arg.server = server;
data->arg.name = name;
data->arg.attrs = sattr;
data->arg.ftype = ftype;
data->arg.bitmask = server->attr_bitmask;
data->res.server = server;
data->res.fh = &data->fh;
data->res.fattr = &data->fattr;
data->res.dir_fattr = &data->dir_fattr;
nfs_fattr_init(data->res.fattr);
nfs_fattr_init(data->res.dir_fattr);
}
return data;
}
static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
{
int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
if (status == 0) {
update_changeattr(dir, &data->res.dir_cinfo);
nfs_post_op_update_inode(dir, data->res.dir_fattr);
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
}
return status;
}
static void nfs4_free_createdata(struct nfs4_createdata *data)
{
kfree(data);
}
static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct page *page, unsigned int len, struct iattr *sattr) struct page *page, unsigned int len, struct iattr *sattr)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs4_createdata *data;
struct nfs_fh fhandle; int status = -ENAMETOOLONG;
struct nfs_fattr fattr, dir_fattr;
struct nfs4_create_arg arg = {
.dir_fh = NFS_FH(dir),
.server = server,
.name = &dentry->d_name,
.attrs = sattr,
.ftype = NF4LNK,
.bitmask = server->attr_bitmask,
};
struct nfs4_create_res res = {
.server = server,
.fh = &fhandle,
.fattr = &fattr,
.dir_fattr = &dir_fattr,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK],
.rpc_argp = &arg,
.rpc_resp = &res,
};
int status;
if (len > NFS4_MAXPATHLEN) if (len > NFS4_MAXPATHLEN)
return -ENAMETOOLONG; goto out;
arg.u.symlink.pages = &page; status = -ENOMEM;
arg.u.symlink.len = len; data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4LNK);
nfs_fattr_init(&fattr); if (data == NULL)
nfs_fattr_init(&dir_fattr); goto out;
data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
data->arg.u.symlink.pages = &page;
data->arg.u.symlink.len = len;
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = nfs4_do_create(dir, dentry, data);
if (!status) {
update_changeattr(dir, &res.dir_cinfo); nfs4_free_createdata(data);
nfs_post_op_update_inode(dir, res.dir_fattr); out:
status = nfs_instantiate(dentry, &fhandle, &fattr);
}
return status; return status;
} }
...@@ -2140,39 +2174,17 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, ...@@ -2140,39 +2174,17 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
struct iattr *sattr) struct iattr *sattr)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs4_createdata *data;
struct nfs_fh fhandle; int status = -ENOMEM;
struct nfs_fattr fattr, dir_fattr;
struct nfs4_create_arg arg = {
.dir_fh = NFS_FH(dir),
.server = server,
.name = &dentry->d_name,
.attrs = sattr,
.ftype = NF4DIR,
.bitmask = server->attr_bitmask,
};
struct nfs4_create_res res = {
.server = server,
.fh = &fhandle,
.fattr = &fattr,
.dir_fattr = &dir_fattr,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
.rpc_argp = &arg,
.rpc_resp = &res,
};
int status;
nfs_fattr_init(&fattr); data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR);
nfs_fattr_init(&dir_fattr); if (data == NULL)
goto out;
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (!status) { status = nfs4_do_create(dir, dentry, data);
update_changeattr(dir, &res.dir_cinfo);
nfs_post_op_update_inode(dir, res.dir_fattr); nfs4_free_createdata(data);
status = nfs_instantiate(dentry, &fhandle, &fattr); out:
}
return status; return status;
} }
...@@ -2242,56 +2254,34 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, ...@@ -2242,56 +2254,34 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
struct iattr *sattr, dev_t rdev) struct iattr *sattr, dev_t rdev)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs4_createdata *data;
struct nfs_fh fh; int mode = sattr->ia_mode;
struct nfs_fattr fattr, dir_fattr; int status = -ENOMEM;
struct nfs4_create_arg arg = {
.dir_fh = NFS_FH(dir),
.server = server,
.name = &dentry->d_name,
.attrs = sattr,
.bitmask = server->attr_bitmask,
};
struct nfs4_create_res res = {
.server = server,
.fh = &fh,
.fattr = &fattr,
.dir_fattr = &dir_fattr,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
.rpc_argp = &arg,
.rpc_resp = &res,
};
int status;
int mode = sattr->ia_mode;
nfs_fattr_init(&fattr);
nfs_fattr_init(&dir_fattr);
BUG_ON(!(sattr->ia_valid & ATTR_MODE)); BUG_ON(!(sattr->ia_valid & ATTR_MODE));
BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK);
if (data == NULL)
goto out;
if (S_ISFIFO(mode)) if (S_ISFIFO(mode))
arg.ftype = NF4FIFO; data->arg.ftype = NF4FIFO;
else if (S_ISBLK(mode)) { else if (S_ISBLK(mode)) {
arg.ftype = NF4BLK; data->arg.ftype = NF4BLK;
arg.u.device.specdata1 = MAJOR(rdev); data->arg.u.device.specdata1 = MAJOR(rdev);
arg.u.device.specdata2 = MINOR(rdev); data->arg.u.device.specdata2 = MINOR(rdev);
} }
else if (S_ISCHR(mode)) { else if (S_ISCHR(mode)) {
arg.ftype = NF4CHR; data->arg.ftype = NF4CHR;
arg.u.device.specdata1 = MAJOR(rdev); data->arg.u.device.specdata1 = MAJOR(rdev);
arg.u.device.specdata2 = MINOR(rdev); data->arg.u.device.specdata2 = MINOR(rdev);
} }
else
arg.ftype = NF4SOCK;
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = nfs4_do_create(dir, dentry, data);
if (status == 0) {
update_changeattr(dir, &res.dir_cinfo); nfs4_free_createdata(data);
nfs_post_op_update_inode(dir, res.dir_fattr); out:
status = nfs_instantiate(dentry, &fh, &fattr);
}
return status; return status;
} }
......
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