mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-10 07:50:04 +00:00
nfsd: reorganize nfsd_create
There's some odd logic in nfsd_create() that allows it to be called with the parent directory either locked or unlocked. The only already-locked caller is NFSv2's nfsd_proc_create(). It's less confusing to split out the unlocked case into a separate function which the NFSv2 code can call directly. Also fix some comments while we're here. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
e75b23f9e3
commit
b44061d0b9
@ -359,8 +359,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
|
|||||||
nfserr = 0;
|
nfserr = 0;
|
||||||
if (!inode) {
|
if (!inode) {
|
||||||
/* File doesn't exist. Create it and set attrs */
|
/* File doesn't exist. Create it and set attrs */
|
||||||
nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
|
nfserr = nfsd_create_locked(rqstp, dirfhp, argp->name,
|
||||||
attr, type, rdev, newfhp);
|
argp->len, attr, type, rdev, newfhp);
|
||||||
} else if (type == S_IFREG) {
|
} else if (type == S_IFREG) {
|
||||||
dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
|
dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
|
||||||
argp->name, attr->ia_valid, (long) attr->ia_size);
|
argp->name, attr->ia_valid, (long) attr->ia_size);
|
||||||
|
109
fs/nfsd/vfs.c
109
fs/nfsd/vfs.c
@ -1135,16 +1135,9 @@ nfsd_check_ignore_resizing(struct iattr *iap)
|
|||||||
iap->ia_valid &= ~ATTR_SIZE;
|
iap->ia_valid &= ~ATTR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* The parent directory should already be locked: */
|
||||||
* Create a file (regular, directory, device, fifo); UNIX sockets
|
|
||||||
* not yet implemented.
|
|
||||||
* If the response fh has been verified, the parent directory should
|
|
||||||
* already be locked. Note that the parent directory is left locked.
|
|
||||||
*
|
|
||||||
* N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
|
|
||||||
*/
|
|
||||||
__be32
|
__be32
|
||||||
nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
char *fname, int flen, struct iattr *iap,
|
char *fname, int flen, struct iattr *iap,
|
||||||
int type, dev_t rdev, struct svc_fh *resfhp)
|
int type, dev_t rdev, struct svc_fh *resfhp)
|
||||||
{
|
{
|
||||||
@ -1154,50 +1147,15 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
__be32 err2;
|
__be32 err2;
|
||||||
int host_err;
|
int host_err;
|
||||||
|
|
||||||
err = nfserr_exist;
|
|
||||||
if (isdotent(fname, flen))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Even though it is a create, first let's see if we are even allowed
|
|
||||||
* to peek inside the parent
|
|
||||||
*/
|
|
||||||
err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
dentry = fhp->fh_dentry;
|
dentry = fhp->fh_dentry;
|
||||||
dirp = d_inode(dentry);
|
dirp = d_inode(dentry);
|
||||||
|
|
||||||
/*
|
dchild = dget(resfhp->fh_dentry);
|
||||||
* Check whether the response file handle has been verified yet.
|
if (!fhp->fh_locked) {
|
||||||
* If it has, the parent directory should already be locked.
|
WARN_ONCE(1, "nfsd_create: parent %pd2 not locked!\n",
|
||||||
*/
|
|
||||||
if (!resfhp->fh_dentry) {
|
|
||||||
host_err = fh_want_write(fhp);
|
|
||||||
if (host_err)
|
|
||||||
goto out_nfserr;
|
|
||||||
|
|
||||||
/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
|
|
||||||
fh_lock_nested(fhp, I_MUTEX_PARENT);
|
|
||||||
dchild = lookup_one_len(fname, dentry, flen);
|
|
||||||
host_err = PTR_ERR(dchild);
|
|
||||||
if (IS_ERR(dchild))
|
|
||||||
goto out_nfserr;
|
|
||||||
err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
} else {
|
|
||||||
/* called from nfsd_proc_create */
|
|
||||||
dchild = dget(resfhp->fh_dentry);
|
|
||||||
if (!fhp->fh_locked) {
|
|
||||||
/* not actually possible */
|
|
||||||
printk(KERN_ERR
|
|
||||||
"nfsd_create: parent %pd2 not locked!\n",
|
|
||||||
dentry);
|
dentry);
|
||||||
err = nfserr_io;
|
err = nfserr_io;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Make sure the child dentry is still negative ...
|
* Make sure the child dentry is still negative ...
|
||||||
@ -1225,9 +1183,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the dir op function pointer.
|
|
||||||
*/
|
|
||||||
err = 0;
|
err = 0;
|
||||||
host_err = 0;
|
host_err = 0;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -1254,7 +1209,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
/*
|
/*
|
||||||
* nfsd_create_setattr already committed the child. Transactional
|
* nfsd_create_setattr already committed the child. Transactional
|
||||||
* filesystems had a chance to commit changes for both parent and
|
* filesystems had a chance to commit changes for both parent and
|
||||||
* child * simultaneously making the following commit_metadata a
|
* child simultaneously making the following commit_metadata a
|
||||||
* noop.
|
* noop.
|
||||||
*/
|
*/
|
||||||
err2 = nfserrno(commit_metadata(fhp));
|
err2 = nfserrno(commit_metadata(fhp));
|
||||||
@ -1275,6 +1230,54 @@ out_nfserr:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a filesystem object (regular, directory, special).
|
||||||
|
* Note that the parent directory is left locked.
|
||||||
|
*
|
||||||
|
* N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
|
||||||
|
*/
|
||||||
|
__be32
|
||||||
|
nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
|
char *fname, int flen, struct iattr *iap,
|
||||||
|
int type, dev_t rdev, struct svc_fh *resfhp)
|
||||||
|
{
|
||||||
|
struct dentry *dentry, *dchild = NULL;
|
||||||
|
struct inode *dirp;
|
||||||
|
__be32 err;
|
||||||
|
int host_err;
|
||||||
|
|
||||||
|
if (isdotent(fname, flen))
|
||||||
|
return nfserr_exist;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Even though it is a create, first let's see if we are even allowed
|
||||||
|
* to peek inside the parent
|
||||||
|
*/
|
||||||
|
err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
dentry = fhp->fh_dentry;
|
||||||
|
dirp = d_inode(dentry);
|
||||||
|
|
||||||
|
host_err = fh_want_write(fhp);
|
||||||
|
if (host_err)
|
||||||
|
return nfserrno(host_err);
|
||||||
|
|
||||||
|
fh_lock_nested(fhp, I_MUTEX_PARENT);
|
||||||
|
dchild = lookup_one_len(fname, dentry, flen);
|
||||||
|
host_err = PTR_ERR(dchild);
|
||||||
|
if (IS_ERR(dchild))
|
||||||
|
return nfserrno(host_err);
|
||||||
|
err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
|
||||||
|
if (err) {
|
||||||
|
dput(dchild);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return nfsd_create_locked(rqstp, fhp, fname, flen, iap, type,
|
||||||
|
rdev, resfhp);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_NFSD_V3
|
#ifdef CONFIG_NFSD_V3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -59,6 +59,9 @@ __be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
|
|||||||
__be32 nfsd4_clone_file_range(struct file *, u64, struct file *,
|
__be32 nfsd4_clone_file_range(struct file *, u64, struct file *,
|
||||||
u64, u64);
|
u64, u64);
|
||||||
#endif /* CONFIG_NFSD_V4 */
|
#endif /* CONFIG_NFSD_V4 */
|
||||||
|
__be32 nfsd_create_locked(struct svc_rqst *, struct svc_fh *,
|
||||||
|
char *name, int len, struct iattr *attrs,
|
||||||
|
int type, dev_t rdev, struct svc_fh *res);
|
||||||
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
|
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
|
||||||
char *name, int len, struct iattr *attrs,
|
char *name, int len, struct iattr *attrs,
|
||||||
int type, dev_t rdev, struct svc_fh *res);
|
int type, dev_t rdev, struct svc_fh *res);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user