mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-27 22:24:11 +08:00
[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);
|
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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user