[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:
Dave Hansen 2008-02-15 14:37:34 -08:00 committed by Al Viro
parent 49e0d02cf0
commit 0622753b80
4 changed files with 31 additions and 3 deletions

View File

@ -2190,7 +2190,12 @@ static long do_rmdir(int dfd, const char __user *pathname)
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
goto exit2; goto exit2;
error = mnt_want_write(nd.path.mnt);
if (error)
goto exit3;
error = vfs_rmdir(nd.path.dentry->d_inode, dentry); error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
mnt_drop_write(nd.path.mnt);
exit3:
dput(dentry); dput(dentry);
exit2: exit2:
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 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; inode = dentry->d_inode;
if (inode) if (inode)
atomic_inc(&inode->i_count); 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); error = vfs_unlink(nd.path.dentry->d_inode, dentry);
mnt_drop_write(nd.path.mnt);
exit2: exit2:
dput(dentry); dput(dentry);
} }

View File

@ -46,6 +46,7 @@
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/crypto.h> #include <linux/crypto.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mount.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC #define NFSDDBG_FACILITY NFSDDBG_PROC
@ -313,12 +314,17 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
if (!rec_dir_init || !clp->cl_firststate) if (!rec_dir_init || !clp->cl_firststate)
return; return;
status = mnt_want_write(rec_dir.path.mnt);
if (status)
goto out;
clp->cl_firststate = 0; clp->cl_firststate = 0;
nfs4_save_user(&uid, &gid); nfs4_save_user(&uid, &gid);
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
nfs4_reset_user(uid, gid); nfs4_reset_user(uid, gid);
if (status == 0) if (status == 0)
nfsd4_sync_rec_dir(); nfsd4_sync_rec_dir();
mnt_drop_write(rec_dir.path.mnt);
out:
if (status) if (status)
printk("NFSD: Failed to remove expired client state directory" printk("NFSD: Failed to remove expired client state directory"
" %.*s\n", HEXDIR_LEN, clp->cl_recdir); " %.*s\n", HEXDIR_LEN, clp->cl_recdir);
@ -347,13 +353,17 @@ nfsd4_recdir_purge_old(void) {
if (!rec_dir_init) if (!rec_dir_init)
return; return;
status = mnt_want_write(rec_dir.path.mnt);
if (status)
goto out;
status = nfsd4_list_rec_dir(rec_dir.path.dentry, purge_old); status = nfsd4_list_rec_dir(rec_dir.path.dentry, purge_old);
if (status == 0) if (status == 0)
nfsd4_sync_rec_dir(); nfsd4_sync_rec_dir();
mnt_drop_write(rec_dir.path.mnt);
out:
if (status) if (status)
printk("nfsd4: failed to purge old clients from recovery" printk("nfsd4: failed to purge old clients from recovery"
" directory %s\n", rec_dir.path.dentry->d_name.name); " directory %s\n", rec_dir.path.dentry->d_name.name);
return;
} }
static int static int

View File

@ -1750,6 +1750,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (!type) if (!type)
type = rdentry->d_inode->i_mode & S_IFMT; 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 */ if (type != S_IFDIR) { /* It's UNLINK */
#ifdef MSNFS #ifdef MSNFS
if ((fhp->fh_export->ex_flags & NFSEXP_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); dput(rdentry);
if (host_err) if (host_err)
goto out_nfserr; goto out_drop;
if (EX_ISSYNC(fhp->fh_export)) if (EX_ISSYNC(fhp->fh_export))
host_err = nfsd_sync_dir(dentry); host_err = nfsd_sync_dir(dentry);
out_drop:
mnt_drop_write(fhp->fh_export->ex_path.mnt);
out_nfserr: out_nfserr:
err = nfserrno(host_err); err = nfserrno(host_err);
out: out:

View File

@ -742,8 +742,11 @@ asmlinkage long sys_mq_unlink(const char __user *u_name)
inode = dentry->d_inode; inode = dentry->d_inode;
if (inode) if (inode)
atomic_inc(&inode->i_count); 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); err = vfs_unlink(dentry->d_parent->d_inode, dentry);
mnt_drop_write(mqueue_mnt);
out_err: out_err:
dput(dentry); dput(dentry);