[PATCH] r/o bind mounts: elevate write count for rmdir and unlink.
Elevate the write count during the vfs_rmdir() and vfs_unlink(). [AV: merged rmdir and unlink parts, added missing pieces in nfsd] Acked-by: Serge Hallyn <serue@us.ibm.com> Acked-by: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Dave Hansen <haveblue@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
49e0d02cf0
commit
0622753b80
@ -2190,7 +2190,12 @@ static long do_rmdir(int dfd, const char __user *pathname)
|
||||
error = PTR_ERR(dentry);
|
||||
if (IS_ERR(dentry))
|
||||
goto exit2;
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto exit3;
|
||||
error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
exit3:
|
||||
dput(dentry);
|
||||
exit2:
|
||||
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
||||
@ -2271,7 +2276,11 @@ static long do_unlinkat(int dfd, const char __user *pathname)
|
||||
inode = dentry->d_inode;
|
||||
if (inode)
|
||||
atomic_inc(&inode->i_count);
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto exit2;
|
||||
error = vfs_unlink(nd.path.dentry->d_inode, dentry);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
exit2:
|
||||
dput(dentry);
|
||||
}
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mount.h>
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
@ -313,12 +314,17 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
|
||||
if (!rec_dir_init || !clp->cl_firststate)
|
||||
return;
|
||||
|
||||
status = mnt_want_write(rec_dir.path.mnt);
|
||||
if (status)
|
||||
goto out;
|
||||
clp->cl_firststate = 0;
|
||||
nfs4_save_user(&uid, &gid);
|
||||
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
|
||||
nfs4_reset_user(uid, gid);
|
||||
if (status == 0)
|
||||
nfsd4_sync_rec_dir();
|
||||
mnt_drop_write(rec_dir.path.mnt);
|
||||
out:
|
||||
if (status)
|
||||
printk("NFSD: Failed to remove expired client state directory"
|
||||
" %.*s\n", HEXDIR_LEN, clp->cl_recdir);
|
||||
@ -347,13 +353,17 @@ nfsd4_recdir_purge_old(void) {
|
||||
|
||||
if (!rec_dir_init)
|
||||
return;
|
||||
status = mnt_want_write(rec_dir.path.mnt);
|
||||
if (status)
|
||||
goto out;
|
||||
status = nfsd4_list_rec_dir(rec_dir.path.dentry, purge_old);
|
||||
if (status == 0)
|
||||
nfsd4_sync_rec_dir();
|
||||
mnt_drop_write(rec_dir.path.mnt);
|
||||
out:
|
||||
if (status)
|
||||
printk("nfsd4: failed to purge old clients from recovery"
|
||||
" directory %s\n", rec_dir.path.dentry->d_name.name);
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1750,6 +1750,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
||||
if (!type)
|
||||
type = rdentry->d_inode->i_mode & S_IFMT;
|
||||
|
||||
host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
|
||||
if (type != S_IFDIR) { /* It's UNLINK */
|
||||
#ifdef MSNFS
|
||||
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
|
||||
@ -1765,10 +1769,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
||||
dput(rdentry);
|
||||
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
goto out_drop;
|
||||
if (EX_ISSYNC(fhp->fh_export))
|
||||
host_err = nfsd_sync_dir(dentry);
|
||||
|
||||
out_drop:
|
||||
mnt_drop_write(fhp->fh_export->ex_path.mnt);
|
||||
out_nfserr:
|
||||
err = nfserrno(host_err);
|
||||
out:
|
||||
|
@ -742,8 +742,11 @@ asmlinkage long sys_mq_unlink(const char __user *u_name)
|
||||
inode = dentry->d_inode;
|
||||
if (inode)
|
||||
atomic_inc(&inode->i_count);
|
||||
|
||||
err = mnt_want_write(mqueue_mnt);
|
||||
if (err)
|
||||
goto out_err;
|
||||
err = vfs_unlink(dentry->d_parent->d_inode, dentry);
|
||||
mnt_drop_write(mqueue_mnt);
|
||||
out_err:
|
||||
dput(dentry);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user