aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Hansen <haveblue@us.ibm.com>2008-02-15 17:37:34 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2008-04-19 00:25:33 -0400
commit0622753b800e4cc6cb9319b36b27658c72dd7cdc (patch)
tree5a32b65a087ff7fd5effa8d3f6f1f9717d4391aa
parent49e0d02cf018d4edf24bfc8531a816a26367e4ce (diff)
[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>
-rw-r--r--fs/namei.c9
-rw-r--r--fs/nfsd/nfs4recover.c12
-rw-r--r--fs/nfsd/vfs.c8
-rw-r--r--ipc/mqueue.c5
4 files changed, 31 insertions, 3 deletions
diff --git a/fs/namei.c b/fs/namei.c
index a1f8bbbd58e5..89ef3178eaaa 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2190,7 +2190,12 @@ static long do_rmdir(int dfd, const char __user *pathname)
2190 error = PTR_ERR(dentry); 2190 error = PTR_ERR(dentry);
2191 if (IS_ERR(dentry)) 2191 if (IS_ERR(dentry))
2192 goto exit2; 2192 goto exit2;
2193 error = mnt_want_write(nd.path.mnt);
2194 if (error)
2195 goto exit3;
2193 error = vfs_rmdir(nd.path.dentry->d_inode, dentry); 2196 error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
2197 mnt_drop_write(nd.path.mnt);
2198exit3:
2194 dput(dentry); 2199 dput(dentry);
2195exit2: 2200exit2:
2196 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2201 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
@@ -2271,7 +2276,11 @@ static long do_unlinkat(int dfd, const char __user *pathname)
2271 inode = dentry->d_inode; 2276 inode = dentry->d_inode;
2272 if (inode) 2277 if (inode)
2273 atomic_inc(&inode->i_count); 2278 atomic_inc(&inode->i_count);
2279 error = mnt_want_write(nd.path.mnt);
2280 if (error)
2281 goto exit2;
2274 error = vfs_unlink(nd.path.dentry->d_inode, dentry); 2282 error = vfs_unlink(nd.path.dentry->d_inode, dentry);
2283 mnt_drop_write(nd.path.mnt);
2275 exit2: 2284 exit2:
2276 dput(dentry); 2285 dput(dentry);
2277 } 2286 }
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 1ff90625860f..4e77a1a3bd73 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -46,6 +46,7 @@
46#include <linux/scatterlist.h> 46#include <linux/scatterlist.h>
47#include <linux/crypto.h> 47#include <linux/crypto.h>
48#include <linux/sched.h> 48#include <linux/sched.h>
49#include <linux/mount.h>
49 50
50#define NFSDDBG_FACILITY NFSDDBG_PROC 51#define NFSDDBG_FACILITY NFSDDBG_PROC
51 52
@@ -313,12 +314,17 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
313 if (!rec_dir_init || !clp->cl_firststate) 314 if (!rec_dir_init || !clp->cl_firststate)
314 return; 315 return;
315 316
317 status = mnt_want_write(rec_dir.path.mnt);
318 if (status)
319 goto out;
316 clp->cl_firststate = 0; 320 clp->cl_firststate = 0;
317 nfs4_save_user(&uid, &gid); 321 nfs4_save_user(&uid, &gid);
318 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); 322 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
319 nfs4_reset_user(uid, gid); 323 nfs4_reset_user(uid, gid);
320 if (status == 0) 324 if (status == 0)
321 nfsd4_sync_rec_dir(); 325 nfsd4_sync_rec_dir();
326 mnt_drop_write(rec_dir.path.mnt);
327out:
322 if (status) 328 if (status)
323 printk("NFSD: Failed to remove expired client state directory" 329 printk("NFSD: Failed to remove expired client state directory"
324 " %.*s\n", HEXDIR_LEN, clp->cl_recdir); 330 " %.*s\n", HEXDIR_LEN, clp->cl_recdir);
@@ -347,13 +353,17 @@ nfsd4_recdir_purge_old(void) {
347 353
348 if (!rec_dir_init) 354 if (!rec_dir_init)
349 return; 355 return;
356 status = mnt_want_write(rec_dir.path.mnt);
357 if (status)
358 goto out;
350 status = nfsd4_list_rec_dir(rec_dir.path.dentry, purge_old); 359 status = nfsd4_list_rec_dir(rec_dir.path.dentry, purge_old);
351 if (status == 0) 360 if (status == 0)
352 nfsd4_sync_rec_dir(); 361 nfsd4_sync_rec_dir();
362 mnt_drop_write(rec_dir.path.mnt);
363out:
353 if (status) 364 if (status)
354 printk("nfsd4: failed to purge old clients from recovery" 365 printk("nfsd4: failed to purge old clients from recovery"
355 " directory %s\n", rec_dir.path.dentry->d_name.name); 366 " directory %s\n", rec_dir.path.dentry->d_name.name);
356 return;
357} 367}
358 368
359static int 369static int
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 46f59d5365a0..efff58a5818c 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1750,6 +1750,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
1750 if (!type) 1750 if (!type)
1751 type = rdentry->d_inode->i_mode & S_IFMT; 1751 type = rdentry->d_inode->i_mode & S_IFMT;
1752 1752
1753 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1754 if (host_err)
1755 goto out_nfserr;
1756
1753 if (type != S_IFDIR) { /* It's UNLINK */ 1757 if (type != S_IFDIR) { /* It's UNLINK */
1754#ifdef MSNFS 1758#ifdef MSNFS
1755 if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && 1759 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 dput(rdentry); 1769 dput(rdentry);
1766 1770
1767 if (host_err) 1771 if (host_err)
1768 goto out_nfserr; 1772 goto out_drop;
1769 if (EX_ISSYNC(fhp->fh_export)) 1773 if (EX_ISSYNC(fhp->fh_export))
1770 host_err = nfsd_sync_dir(dentry); 1774 host_err = nfsd_sync_dir(dentry);
1771 1775
1776out_drop:
1777 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1772out_nfserr: 1778out_nfserr:
1773 err = nfserrno(host_err); 1779 err = nfserrno(host_err);
1774out: 1780out:
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 60f7a27f7a9e..34262c11f480 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -742,8 +742,11 @@ asmlinkage long sys_mq_unlink(const char __user *u_name)
742 inode = dentry->d_inode; 742 inode = dentry->d_inode;
743 if (inode) 743 if (inode)
744 atomic_inc(&inode->i_count); 744 atomic_inc(&inode->i_count);
745 745 err = mnt_want_write(mqueue_mnt);
746 if (err)
747 goto out_err;
746 err = vfs_unlink(dentry->d_parent->d_inode, dentry); 748 err = vfs_unlink(dentry->d_parent->d_inode, dentry);
749 mnt_drop_write(mqueue_mnt);
747out_err: 750out_err:
748 dput(dentry); 751 dput(dentry);
749 752