diff options
author | Dave Hansen <haveblue@us.ibm.com> | 2008-02-15 17:37:34 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-19 00:25:33 -0400 |
commit | 0622753b800e4cc6cb9319b36b27658c72dd7cdc (patch) | |
tree | 5a32b65a087ff7fd5effa8d3f6f1f9717d4391aa | |
parent | 49e0d02cf018d4edf24bfc8531a816a26367e4ce (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.c | 9 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 12 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 8 | ||||
-rw-r--r-- | ipc/mqueue.c | 5 |
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); | ||
2198 | exit3: | ||
2194 | dput(dentry); | 2199 | dput(dentry); |
2195 | exit2: | 2200 | exit2: |
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); | ||
327 | out: | ||
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); | ||
363 | out: | ||
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 | ||
359 | static int | 369 | static 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 | ||
1776 | out_drop: | ||
1777 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
1772 | out_nfserr: | 1778 | out_nfserr: |
1773 | err = nfserrno(host_err); | 1779 | err = nfserrno(host_err); |
1774 | out: | 1780 | out: |
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); | ||
747 | out_err: | 750 | out_err: |
748 | dput(dentry); | 751 | dput(dentry); |
749 | 752 | ||