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

[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
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -2190,7 +2190,12 @@ static long do_rmdir(int dfd, const char __user *pathname)
	error = PTR_ERR(dentry);
	if (IS_ERR(dentry))
		goto exit2;
	error = mnt_want_write(nd.path.mnt);
	if (error)
		goto exit3;
	error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
	mnt_drop_write(nd.path.mnt);
exit3:
	dput(dentry);
exit2:
	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;
		if (inode)
			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);
		mnt_drop_write(nd.path.mnt);
	exit2:
		dput(dentry);
	}
+11 −1
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@
#include <linux/scatterlist.h>
#include <linux/crypto.h>
#include <linux/sched.h>
#include <linux/mount.h>

#define NFSDDBG_FACILITY                NFSDDBG_PROC

@@ -313,12 +314,17 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
	if (!rec_dir_init || !clp->cl_firststate)
		return;

	status = mnt_want_write(rec_dir.path.mnt);
	if (status)
		goto out;
	clp->cl_firststate = 0;
	nfs4_save_user(&uid, &gid);
	status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
	nfs4_reset_user(uid, gid);
	if (status == 0)
		nfsd4_sync_rec_dir();
	mnt_drop_write(rec_dir.path.mnt);
out:
	if (status)
		printk("NFSD: Failed to remove expired client state directory"
				" %.*s\n", HEXDIR_LEN, clp->cl_recdir);
@@ -347,13 +353,17 @@ nfsd4_recdir_purge_old(void) {

	if (!rec_dir_init)
		return;
	status = mnt_want_write(rec_dir.path.mnt);
	if (status)
		goto out;
	status = nfsd4_list_rec_dir(rec_dir.path.dentry, purge_old);
	if (status == 0)
		nfsd4_sync_rec_dir();
	mnt_drop_write(rec_dir.path.mnt);
out:
	if (status)
		printk("nfsd4: failed to purge old clients from recovery"
			" directory %s\n", rec_dir.path.dentry->d_name.name);
	return;
}

static int
+7 −1
Original line number Diff line number Diff line
@@ -1750,6 +1750,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
	if (!type)
		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 */
#ifdef 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);

	if (host_err)
		goto out_nfserr;
		goto out_drop;
	if (EX_ISSYNC(fhp->fh_export))
		host_err = nfsd_sync_dir(dentry);

out_drop:
	mnt_drop_write(fhp->fh_export->ex_path.mnt);
out_nfserr:
	err = nfserrno(host_err);
out:
+4 −1
Original line number Diff line number Diff line
@@ -742,8 +742,11 @@ asmlinkage long sys_mq_unlink(const char __user *u_name)
	inode = dentry->d_inode;
	if (inode)
		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);
	mnt_drop_write(mqueue_mnt);
out_err:
	dput(dentry);