Commit 7e06b7f9 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds
Browse files

[PATCH] knfsd: nfs4: hold filp while reading or writing



We're trying to read and write from a struct file that we may not hold a
reference to any more (since a close could be processed as soon as we drop the
state lock).

Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: default avatarNeil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 46be925f
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include <linux/param.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/file.h>

#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
@@ -477,26 +478,27 @@ static inline int
nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
{
	int status;
	struct file *filp = NULL;

	/* no need to check permission - this will be done in nfsd_read() */

	read->rd_filp = NULL;
	if (read->rd_offset >= OFFSET_MAX)
		return nfserr_inval;

	nfs4_lock_state();
	/* check stateid */
	if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid,
					CHECK_FH | RD_STATE, &filp))) {
				CHECK_FH | RD_STATE, &read->rd_filp))) {
		dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
		goto out;
	}
	if (read->rd_filp)
		get_file(read->rd_filp);
	status = nfs_ok;
out:
	nfs4_unlock_state();
	read->rd_rqstp = rqstp;
	read->rd_fhp = current_fh;
	read->rd_filp = filp;
	return status;
}

@@ -633,6 +635,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
		dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
		goto out;
	}
	if (filp)
		get_file(filp);
	nfs4_unlock_state();

	write->wr_bytes_written = write->wr_buflen;
@@ -644,6 +648,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
	status =  nfsd_write(rqstp, current_fh, filp, write->wr_offset,
			write->wr_vec, write->wr_vlen, write->wr_buflen,
			&write->wr_how_written);
	if (filp)
		fput(filp);

	if (status == nfserr_symlink)
		status = nfserr_inval;
@@ -932,6 +938,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
			nfs4_put_stateowner(replay_owner);
			replay_owner = NULL;
		}
		/* XXX Ugh, we need to get rid of this kind of special case: */
		if (op->opnum == OP_READ && op->u.read.rd_filp)
			fput(op->u.read.rd_filp);
	}

out: