Commit 0622753b authored by Dave Hansen's avatar Dave Hansen Committed by Al Viro

[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: default avatarSerge Hallyn <serue@us.ibm.com>
Acked-by: default avatarAl Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDave Hansen <haveblue@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 49e0d02c
...@@ -2190,7 +2190,12 @@ static long do_rmdir(int dfd, const char __user *pathname) ...@@ -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) ...@@ -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);
} }
......
...@@ -46,6 +46,7 @@ ...@@ -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) ...@@ -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) { ...@@ -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
......
...@@ -1750,6 +1750,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, ...@@ -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, ...@@ -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:
......
...@@ -742,8 +742,11 @@ asmlinkage long sys_mq_unlink(const char __user *u_name) ...@@ -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);
......
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