[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: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
NeilBrown 2005-06-23 22:03:13 -07:00 committed by Linus Torvalds
parent 46be925fa6
commit 7e06b7f9e9

View file

@ -45,6 +45,7 @@
#include <linux/param.h> #include <linux/param.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/file.h>
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.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) nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
{ {
int status; int status;
struct file *filp = NULL;
/* no need to check permission - this will be done in nfsd_read() */ /* no need to check permission - this will be done in nfsd_read() */
read->rd_filp = NULL;
if (read->rd_offset >= OFFSET_MAX) if (read->rd_offset >= OFFSET_MAX)
return nfserr_inval; return nfserr_inval;
nfs4_lock_state(); nfs4_lock_state();
/* check stateid */ /* check stateid */
if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_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"); dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
goto out; goto out;
} }
if (read->rd_filp)
get_file(read->rd_filp);
status = nfs_ok; status = nfs_ok;
out: out:
nfs4_unlock_state(); nfs4_unlock_state();
read->rd_rqstp = rqstp; read->rd_rqstp = rqstp;
read->rd_fhp = current_fh; read->rd_fhp = current_fh;
read->rd_filp = filp;
return status; 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"); dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
goto out; goto out;
} }
if (filp)
get_file(filp);
nfs4_unlock_state(); nfs4_unlock_state();
write->wr_bytes_written = write->wr_buflen; 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, status = nfsd_write(rqstp, current_fh, filp, write->wr_offset,
write->wr_vec, write->wr_vlen, write->wr_buflen, write->wr_vec, write->wr_vlen, write->wr_buflen,
&write->wr_how_written); &write->wr_how_written);
if (filp)
fput(filp);
if (status == nfserr_symlink) if (status == nfserr_symlink)
status = nfserr_inval; status = nfserr_inval;
@ -932,6 +938,9 @@ encode_op:
nfs4_put_stateowner(replay_owner); nfs4_put_stateowner(replay_owner);
replay_owner = NULL; 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: out: