diff options
author | NeilBrown <neilb@cse.unsw.edu.au> | 2005-06-23 22:03:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 00:06:30 -0700 |
commit | 7e06b7f9e9537cb826f3cff95816fc4384b67806 (patch) | |
tree | b6f41e8c458756da5ccf82e075c76b1be329959b /fs/nfsd | |
parent | 46be925fa6f4796e732e16a020fa0ef9d48ea7c8 (diff) | |
download | linux-stable-7e06b7f9e9537cb826f3cff95816fc4384b67806.tar.gz linux-stable-7e06b7f9e9537cb826f3cff95816fc4384b67806.tar.bz2 linux-stable-7e06b7f9e9537cb826f3cff95816fc4384b67806.zip |
[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>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index ac4878ac2213..d71f14517b9c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -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 @@ encode_op: 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: |