NFS: Reduce the stack usage in NFSv3 create operations
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
57dc9a5747
commit
0b4aae7aad
1 changed files with 143 additions and 130 deletions
|
@ -248,6 +248,53 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nfs3_createdata {
|
||||||
|
struct rpc_message msg;
|
||||||
|
union {
|
||||||
|
struct nfs3_createargs create;
|
||||||
|
struct nfs3_mkdirargs mkdir;
|
||||||
|
struct nfs3_symlinkargs symlink;
|
||||||
|
struct nfs3_mknodargs mknod;
|
||||||
|
} arg;
|
||||||
|
struct nfs3_diropres res;
|
||||||
|
struct nfs_fh fh;
|
||||||
|
struct nfs_fattr fattr;
|
||||||
|
struct nfs_fattr dir_attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nfs3_createdata *nfs3_alloc_createdata(void)
|
||||||
|
{
|
||||||
|
struct nfs3_createdata *data;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||||
|
if (data != NULL) {
|
||||||
|
data->msg.rpc_argp = &data->arg;
|
||||||
|
data->msg.rpc_resp = &data->res;
|
||||||
|
data->res.fh = &data->fh;
|
||||||
|
data->res.fattr = &data->fattr;
|
||||||
|
data->res.dir_attr = &data->dir_attr;
|
||||||
|
nfs_fattr_init(data->res.fattr);
|
||||||
|
nfs_fattr_init(data->res.dir_attr);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_createdata *data)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
|
||||||
|
nfs_post_op_update_inode(dir, data->res.dir_attr);
|
||||||
|
if (status == 0)
|
||||||
|
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs3_free_createdata(struct nfs3_createdata *data)
|
||||||
|
{
|
||||||
|
kfree(data);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a regular file.
|
* Create a regular file.
|
||||||
* For now, we don't implement O_EXCL.
|
* For now, we don't implement O_EXCL.
|
||||||
|
@ -256,70 +303,60 @@ static int
|
||||||
nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
||||||
int flags, struct nameidata *nd)
|
int flags, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
struct nfs_fh fhandle;
|
struct nfs3_createdata *data;
|
||||||
struct nfs_fattr fattr;
|
|
||||||
struct nfs_fattr dir_attr;
|
|
||||||
struct nfs3_createargs arg = {
|
|
||||||
.fh = NFS_FH(dir),
|
|
||||||
.name = dentry->d_name.name,
|
|
||||||
.len = dentry->d_name.len,
|
|
||||||
.sattr = sattr,
|
|
||||||
};
|
|
||||||
struct nfs3_diropres res = {
|
|
||||||
.dir_attr = &dir_attr,
|
|
||||||
.fh = &fhandle,
|
|
||||||
.fattr = &fattr
|
|
||||||
};
|
|
||||||
struct rpc_message msg = {
|
|
||||||
.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE],
|
|
||||||
.rpc_argp = &arg,
|
|
||||||
.rpc_resp = &res,
|
|
||||||
};
|
|
||||||
mode_t mode = sattr->ia_mode;
|
mode_t mode = sattr->ia_mode;
|
||||||
int status;
|
int status = -ENOMEM;
|
||||||
|
|
||||||
dprintk("NFS call create %s\n", dentry->d_name.name);
|
dprintk("NFS call create %s\n", dentry->d_name.name);
|
||||||
arg.createmode = NFS3_CREATE_UNCHECKED;
|
|
||||||
|
data = nfs3_alloc_createdata();
|
||||||
|
if (data == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE];
|
||||||
|
data->arg.create.fh = NFS_FH(dir);
|
||||||
|
data->arg.create.name = dentry->d_name.name;
|
||||||
|
data->arg.create.len = dentry->d_name.len;
|
||||||
|
data->arg.create.sattr = sattr;
|
||||||
|
|
||||||
|
data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
|
||||||
if (flags & O_EXCL) {
|
if (flags & O_EXCL) {
|
||||||
arg.createmode = NFS3_CREATE_EXCLUSIVE;
|
data->arg.create.createmode = NFS3_CREATE_EXCLUSIVE;
|
||||||
arg.verifier[0] = jiffies;
|
data->arg.create.verifier[0] = jiffies;
|
||||||
arg.verifier[1] = current->pid;
|
data->arg.create.verifier[1] = current->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
sattr->ia_mode &= ~current->fs->umask;
|
sattr->ia_mode &= ~current->fs->umask;
|
||||||
|
|
||||||
again:
|
for (;;) {
|
||||||
nfs_fattr_init(&dir_attr);
|
status = nfs3_do_create(dir, dentry, data);
|
||||||
nfs_fattr_init(&fattr);
|
|
||||||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
|
||||||
nfs_refresh_inode(dir, &dir_attr);
|
|
||||||
|
|
||||||
/* If the server doesn't support the exclusive creation semantics,
|
if (status != -ENOTSUPP)
|
||||||
* try again with simple 'guarded' mode. */
|
break;
|
||||||
if (status == -ENOTSUPP) {
|
/* If the server doesn't support the exclusive creation
|
||||||
switch (arg.createmode) {
|
* semantics, try again with simple 'guarded' mode. */
|
||||||
|
switch (data->arg.create.createmode) {
|
||||||
case NFS3_CREATE_EXCLUSIVE:
|
case NFS3_CREATE_EXCLUSIVE:
|
||||||
arg.createmode = NFS3_CREATE_GUARDED;
|
data->arg.create.createmode = NFS3_CREATE_GUARDED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NFS3_CREATE_GUARDED:
|
case NFS3_CREATE_GUARDED:
|
||||||
arg.createmode = NFS3_CREATE_UNCHECKED;
|
data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NFS3_CREATE_UNCHECKED:
|
case NFS3_CREATE_UNCHECKED:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
goto again;
|
nfs_fattr_init(data->res.dir_attr);
|
||||||
|
nfs_fattr_init(data->res.fattr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == 0)
|
|
||||||
status = nfs_instantiate(dentry, &fhandle, &fattr);
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* When we created the file with exclusive semantics, make
|
/* When we created the file with exclusive semantics, make
|
||||||
* sure we set the attributes afterwards. */
|
* sure we set the attributes afterwards. */
|
||||||
if (arg.createmode == NFS3_CREATE_EXCLUSIVE) {
|
if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) {
|
||||||
dprintk("NFS call setattr (post-create)\n");
|
dprintk("NFS call setattr (post-create)\n");
|
||||||
|
|
||||||
if (!(sattr->ia_valid & ATTR_ATIME_SET))
|
if (!(sattr->ia_valid & ATTR_ATIME_SET))
|
||||||
|
@ -330,14 +367,15 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
||||||
/* Note: we could use a guarded setattr here, but I'm
|
/* Note: we could use a guarded setattr here, but I'm
|
||||||
* not sure this buys us anything (and I'd have
|
* not sure this buys us anything (and I'd have
|
||||||
* to revamp the NFSv3 XDR code) */
|
* to revamp the NFSv3 XDR code) */
|
||||||
status = nfs3_proc_setattr(dentry, &fattr, sattr);
|
status = nfs3_proc_setattr(dentry, data->res.fattr, sattr);
|
||||||
nfs_post_op_update_inode(dentry->d_inode, &fattr);
|
nfs_post_op_update_inode(dentry->d_inode, data->res.fattr);
|
||||||
dprintk("NFS reply setattr (post-create): %d\n", status);
|
dprintk("NFS reply setattr (post-create): %d\n", status);
|
||||||
|
if (status != 0)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
if (status != 0)
|
|
||||||
goto out;
|
|
||||||
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
|
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
|
||||||
out:
|
out:
|
||||||
|
nfs3_free_createdata(data);
|
||||||
dprintk("NFS reply create: %d\n", status);
|
dprintk("NFS reply create: %d\n", status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -452,40 +490,28 @@ static int
|
||||||
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
|
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
|
||||||
unsigned int len, struct iattr *sattr)
|
unsigned int len, struct iattr *sattr)
|
||||||
{
|
{
|
||||||
struct nfs_fh fhandle;
|
struct nfs3_createdata *data;
|
||||||
struct nfs_fattr fattr, dir_attr;
|
int status = -ENOMEM;
|
||||||
struct nfs3_symlinkargs arg = {
|
|
||||||
.fromfh = NFS_FH(dir),
|
|
||||||
.fromname = dentry->d_name.name,
|
|
||||||
.fromlen = dentry->d_name.len,
|
|
||||||
.pages = &page,
|
|
||||||
.pathlen = len,
|
|
||||||
.sattr = sattr
|
|
||||||
};
|
|
||||||
struct nfs3_diropres res = {
|
|
||||||
.dir_attr = &dir_attr,
|
|
||||||
.fh = &fhandle,
|
|
||||||
.fattr = &fattr
|
|
||||||
};
|
|
||||||
struct rpc_message msg = {
|
|
||||||
.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK],
|
|
||||||
.rpc_argp = &arg,
|
|
||||||
.rpc_resp = &res,
|
|
||||||
};
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if (len > NFS3_MAXPATHLEN)
|
if (len > NFS3_MAXPATHLEN)
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
|
|
||||||
dprintk("NFS call symlink %s\n", dentry->d_name.name);
|
dprintk("NFS call symlink %s\n", dentry->d_name.name);
|
||||||
|
|
||||||
nfs_fattr_init(&dir_attr);
|
data = nfs3_alloc_createdata();
|
||||||
nfs_fattr_init(&fattr);
|
if (data == NULL)
|
||||||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
|
||||||
nfs_post_op_update_inode(dir, &dir_attr);
|
|
||||||
if (status != 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
status = nfs_instantiate(dentry, &fhandle, &fattr);
|
data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK];
|
||||||
|
data->arg.symlink.fromfh = NFS_FH(dir);
|
||||||
|
data->arg.symlink.fromname = dentry->d_name.name;
|
||||||
|
data->arg.symlink.fromlen = dentry->d_name.len;
|
||||||
|
data->arg.symlink.pages = &page;
|
||||||
|
data->arg.symlink.pathlen = len;
|
||||||
|
data->arg.symlink.sattr = sattr;
|
||||||
|
|
||||||
|
status = nfs3_do_create(dir, dentry, data);
|
||||||
|
|
||||||
|
nfs3_free_createdata(data);
|
||||||
out:
|
out:
|
||||||
dprintk("NFS reply symlink: %d\n", status);
|
dprintk("NFS reply symlink: %d\n", status);
|
||||||
return status;
|
return status;
|
||||||
|
@ -494,42 +520,31 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
|
||||||
static int
|
static int
|
||||||
nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
|
nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
|
||||||
{
|
{
|
||||||
struct nfs_fh fhandle;
|
struct nfs3_createdata *data;
|
||||||
struct nfs_fattr fattr, dir_attr;
|
|
||||||
struct nfs3_mkdirargs arg = {
|
|
||||||
.fh = NFS_FH(dir),
|
|
||||||
.name = dentry->d_name.name,
|
|
||||||
.len = dentry->d_name.len,
|
|
||||||
.sattr = sattr
|
|
||||||
};
|
|
||||||
struct nfs3_diropres res = {
|
|
||||||
.dir_attr = &dir_attr,
|
|
||||||
.fh = &fhandle,
|
|
||||||
.fattr = &fattr
|
|
||||||
};
|
|
||||||
struct rpc_message msg = {
|
|
||||||
.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR],
|
|
||||||
.rpc_argp = &arg,
|
|
||||||
.rpc_resp = &res,
|
|
||||||
};
|
|
||||||
int mode = sattr->ia_mode;
|
int mode = sattr->ia_mode;
|
||||||
int status;
|
int status = -ENOMEM;
|
||||||
|
|
||||||
dprintk("NFS call mkdir %s\n", dentry->d_name.name);
|
dprintk("NFS call mkdir %s\n", dentry->d_name.name);
|
||||||
|
|
||||||
sattr->ia_mode &= ~current->fs->umask;
|
sattr->ia_mode &= ~current->fs->umask;
|
||||||
|
|
||||||
nfs_fattr_init(&dir_attr);
|
data = nfs3_alloc_createdata();
|
||||||
nfs_fattr_init(&fattr);
|
if (data == NULL)
|
||||||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
goto out;
|
||||||
nfs_post_op_update_inode(dir, &dir_attr);
|
|
||||||
if (status != 0)
|
data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR];
|
||||||
goto out;
|
data->arg.mkdir.fh = NFS_FH(dir);
|
||||||
status = nfs_instantiate(dentry, &fhandle, &fattr);
|
data->arg.mkdir.name = dentry->d_name.name;
|
||||||
|
data->arg.mkdir.len = dentry->d_name.len;
|
||||||
|
data->arg.mkdir.sattr = sattr;
|
||||||
|
|
||||||
|
status = nfs3_do_create(dir, dentry, data);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
|
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
|
||||||
out:
|
out:
|
||||||
|
nfs3_free_createdata(data);
|
||||||
dprintk("NFS reply mkdir: %d\n", status);
|
dprintk("NFS reply mkdir: %d\n", status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -615,52 +630,50 @@ static int
|
||||||
nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
||||||
dev_t rdev)
|
dev_t rdev)
|
||||||
{
|
{
|
||||||
struct nfs_fh fh;
|
struct nfs3_createdata *data;
|
||||||
struct nfs_fattr fattr, dir_attr;
|
|
||||||
struct nfs3_mknodargs arg = {
|
|
||||||
.fh = NFS_FH(dir),
|
|
||||||
.name = dentry->d_name.name,
|
|
||||||
.len = dentry->d_name.len,
|
|
||||||
.sattr = sattr,
|
|
||||||
.rdev = rdev
|
|
||||||
};
|
|
||||||
struct nfs3_diropres res = {
|
|
||||||
.dir_attr = &dir_attr,
|
|
||||||
.fh = &fh,
|
|
||||||
.fattr = &fattr
|
|
||||||
};
|
|
||||||
struct rpc_message msg = {
|
|
||||||
.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD],
|
|
||||||
.rpc_argp = &arg,
|
|
||||||
.rpc_resp = &res,
|
|
||||||
};
|
|
||||||
mode_t mode = sattr->ia_mode;
|
mode_t mode = sattr->ia_mode;
|
||||||
int status;
|
int status = -ENOMEM;
|
||||||
|
|
||||||
switch (sattr->ia_mode & S_IFMT) {
|
|
||||||
case S_IFBLK: arg.type = NF3BLK; break;
|
|
||||||
case S_IFCHR: arg.type = NF3CHR; break;
|
|
||||||
case S_IFIFO: arg.type = NF3FIFO; break;
|
|
||||||
case S_IFSOCK: arg.type = NF3SOCK; break;
|
|
||||||
default: return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name,
|
dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name,
|
||||||
MAJOR(rdev), MINOR(rdev));
|
MAJOR(rdev), MINOR(rdev));
|
||||||
|
|
||||||
sattr->ia_mode &= ~current->fs->umask;
|
sattr->ia_mode &= ~current->fs->umask;
|
||||||
|
|
||||||
nfs_fattr_init(&dir_attr);
|
data = nfs3_alloc_createdata();
|
||||||
nfs_fattr_init(&fattr);
|
if (data == NULL)
|
||||||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
|
||||||
nfs_post_op_update_inode(dir, &dir_attr);
|
|
||||||
if (status != 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
status = nfs_instantiate(dentry, &fh, &fattr);
|
|
||||||
|
data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD];
|
||||||
|
data->arg.mknod.fh = NFS_FH(dir);
|
||||||
|
data->arg.mknod.name = dentry->d_name.name;
|
||||||
|
data->arg.mknod.len = dentry->d_name.len;
|
||||||
|
data->arg.mknod.sattr = sattr;
|
||||||
|
data->arg.mknod.rdev = rdev;
|
||||||
|
|
||||||
|
switch (sattr->ia_mode & S_IFMT) {
|
||||||
|
case S_IFBLK:
|
||||||
|
data->arg.mknod.type = NF3BLK;
|
||||||
|
break;
|
||||||
|
case S_IFCHR:
|
||||||
|
data->arg.mknod.type = NF3CHR;
|
||||||
|
break;
|
||||||
|
case S_IFIFO:
|
||||||
|
data->arg.mknod.type = NF3FIFO;
|
||||||
|
break;
|
||||||
|
case S_IFSOCK:
|
||||||
|
data->arg.mknod.type = NF3SOCK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
status = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = nfs3_do_create(dir, dentry, data);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
goto out;
|
goto out;
|
||||||
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
|
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
|
||||||
out:
|
out:
|
||||||
|
nfs3_free_createdata(data);
|
||||||
dprintk("NFS reply mknod: %d\n", status);
|
dprintk("NFS reply mknod: %d\n", status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue