From: NeilBrown Use the struct file * obtained in nfsd4_open for nfsd_read and nfsd_write when available. To do this we add a struct file * argument to nfsd_read and nfsd_write. If a struct file is passed in, nfsd_read and nfsd_write will use it, doing just an access check instead of an open and close. If the new argument is NULL, they will fall back on the old behaviour. Signed-off-by: Andy Adamson Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton --- 25-akpm/fs/nfsd/nfs3proc.c | 4 - 25-akpm/fs/nfsd/nfs4proc.c | 18 +++--- 25-akpm/fs/nfsd/nfs4state.c | 8 ++ 25-akpm/fs/nfsd/nfs4xdr.c | 8 +- 25-akpm/fs/nfsd/nfsproc.c | 4 - 25-akpm/fs/nfsd/vfs.c | 103 +++++++++++++++++++++++++------------ 25-akpm/include/linux/nfsd/nfsd.h | 6 +- 25-akpm/include/linux/nfsd/state.h | 2 25-akpm/include/linux/nfsd/xdr4.h | 1 9 files changed, 100 insertions(+), 54 deletions(-) diff -puN fs/nfsd/nfs3proc.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write fs/nfsd/nfs3proc.c --- 25/fs/nfsd/nfs3proc.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write 2005-03-07 23:55:21.000000000 -0800 +++ 25-akpm/fs/nfsd/nfs3proc.c 2005-03-07 23:55:21.000000000 -0800 @@ -171,7 +171,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); fh_copy(&resp->fh, &argp->fh); - nfserr = nfsd_read(rqstp, &resp->fh, + nfserr = nfsd_read(rqstp, &resp->fh, NULL, argp->offset, argp->vec, argp->vlen, &resp->count); @@ -201,7 +201,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp, fh_copy(&resp->fh, &argp->fh); resp->committed = argp->stable; - nfserr = nfsd_write(rqstp, &resp->fh, + nfserr = nfsd_write(rqstp, &resp->fh, NULL, argp->offset, argp->vec, argp->vlen, argp->len, diff -puN fs/nfsd/nfs4proc.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write fs/nfsd/nfs4proc.c --- 25/fs/nfsd/nfs4proc.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write 2005-03-07 23:55:21.000000000 -0800 +++ 25-akpm/fs/nfsd/nfs4proc.c 2005-03-07 23:55:21.000000000 -0800 @@ -464,6 +464,7 @@ 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() */ @@ -472,8 +473,8 @@ nfsd4_read(struct svc_rqst *rqstp, struc nfs4_lock_state(); /* check stateid */ - if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, - CHECK_FH | RD_STATE))) { + if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, + CHECK_FH | RD_STATE, &filp))) { dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); goto out; } @@ -482,6 +483,7 @@ out: nfs4_unlock_state(); read->rd_rqstp = rqstp; read->rd_fhp = current_fh; + read->rd_filp = filp; return status; } @@ -574,7 +576,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, st nfs4_lock_state(); if ((status = nfs4_preprocess_stateid_op(current_fh, &setattr->sa_stateid, - CHECK_FH | WR_STATE))) { + CHECK_FH | WR_STATE, NULL))) { dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); goto out_unlock; } @@ -598,6 +600,7 @@ static inline int nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write) { stateid_t *stateid = &write->wr_stateid; + struct file *filp = NULL; u32 *p; int status = nfs_ok; @@ -608,7 +611,7 @@ nfsd4_write(struct svc_rqst *rqstp, stru nfs4_lock_state(); if ((status = nfs4_preprocess_stateid_op(current_fh, stateid, - CHECK_FH | WR_STATE))) { + CHECK_FH | WR_STATE, &filp))) { dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); goto out; } @@ -620,9 +623,10 @@ nfsd4_write(struct svc_rqst *rqstp, stru *p++ = nfssvc_boot.tv_sec; *p++ = nfssvc_boot.tv_usec; - status = nfsd_write(rqstp, current_fh, write->wr_offset, - write->wr_vec, write->wr_vlen, write->wr_buflen, - &write->wr_how_written); + status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, + write->wr_vec, write->wr_vlen, write->wr_buflen, + &write->wr_how_written); + if (status == nfserr_symlink) status = nfserr_inval; return status; diff -puN fs/nfsd/nfs4state.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write fs/nfsd/nfs4state.c --- 25/fs/nfsd/nfs4state.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write 2005-03-07 23:55:21.000000000 -0800 +++ 25-akpm/fs/nfsd/nfs4state.c 2005-03-07 23:55:21.000000000 -0800 @@ -2042,7 +2042,7 @@ io_during_grace_disallowed(struct inode * Checks for stateid operations */ int -nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags) +nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp) { struct nfs4_stateid *stp = NULL; struct nfs4_delegation *dp = NULL; @@ -2053,6 +2053,8 @@ nfs4_preprocess_stateid_op(struct svc_fh dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n", stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); + if (filpp) + *filpp = NULL; if (io_during_grace_disallowed(ino, flags)) return nfserr_grace; @@ -2099,6 +2101,8 @@ nfs4_preprocess_stateid_op(struct svc_fh if ((status = nfs4_check_openmode(stp,flags))) goto out; renew_client(stp->st_stateowner->so_client); + if (filpp) + *filpp = stp->st_vfs_file; } else if (dp) { if ((status = nfs4_check_delegmode(dp, flags))) goto out; @@ -2405,7 +2409,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp goto out; nfs4_lock_state(); - status = nfs4_preprocess_stateid_op(current_fh, &dr->dr_stateid, DELEG_RET); + status = nfs4_preprocess_stateid_op(current_fh, &dr->dr_stateid, DELEG_RET, NULL); nfs4_unlock_state(); out: return status; diff -puN fs/nfsd/nfs4xdr.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write fs/nfsd/nfs4xdr.c --- 25/fs/nfsd/nfs4xdr.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write 2005-03-07 23:55:21.000000000 -0800 +++ 25-akpm/fs/nfsd/nfs4xdr.c 2005-03-07 23:55:21.000000000 -0800 @@ -2068,10 +2068,10 @@ nfsd4_encode_read(struct nfsd4_compoundr } read->rd_vlen = v; - nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, - read->rd_offset, - read->rd_iov, read->rd_vlen, - &maxcount); + nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp, + read->rd_offset, read->rd_iov, read->rd_vlen, + &maxcount); + if (nfserr == nfserr_symlink) nfserr = nfserr_inval; if (nfserr) diff -puN fs/nfsd/nfsproc.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write fs/nfsd/nfsproc.c --- 25/fs/nfsd/nfsproc.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write 2005-03-07 23:55:21.000000000 -0800 +++ 25-akpm/fs/nfsd/nfsproc.c 2005-03-07 23:55:21.000000000 -0800 @@ -137,7 +137,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, s svc_reserve(rqstp, (19<<2) + argp->count + 4); resp->count = argp->count; - nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), + nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, argp->offset, argp->vec, argp->vlen, &resp->count); @@ -160,7 +160,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, SVCFH_fmt(&argp->fh), argp->len, argp->offset); - nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), + nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, argp->offset, argp->vec, argp->vlen, argp->len, diff -puN fs/nfsd/vfs.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write fs/nfsd/vfs.c --- 25/fs/nfsd/vfs.c~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write 2005-03-07 23:55:21.000000000 -0800 +++ 25-akpm/fs/nfsd/vfs.c 2005-03-07 23:55:21.000000000 -0800 @@ -810,30 +810,21 @@ nfsd_read_actor(read_descriptor_t *desc, return size; } -/* - * Read data from a file. count must contain the requested read count - * on entry. On return, *count contains the number of bytes actually read. - * N.B. After this call fhp needs an fh_put - */ -int -nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, - struct kvec *vec, int vlen, unsigned long *count) +static inline int +nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, + loff_t offset, struct kvec *vec, int vlen, unsigned long *count) { + struct inode *inode; struct raparms *ra; mm_segment_t oldfs; int err; - struct file *file; - struct inode *inode; - err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file); - if (err) - goto out; err = nfserr_perm; inode = file->f_dentry->d_inode; #ifdef MSNFS if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && (!lock_may_read(inode, offset, *count))) - goto out_close; + goto out; #endif /* Get readahead parameters */ @@ -869,41 +860,28 @@ nfsd_read(struct svc_rqst *rqstp, struct dnotify_parent(file->f_dentry, DN_ACCESS); } else err = nfserrno(err); -out_close: - nfsd_close(file); out: return err; } -/* - * Write data to a file. - * The stable flag requests synchronous writes. - * N.B. After this call fhp needs an fh_put - */ -int -nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, - struct kvec *vec, int vlen, +static inline int +nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, + loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, int *stablep) { struct svc_export *exp; - struct file *file; struct dentry *dentry; struct inode *inode; mm_segment_t oldfs; int err = 0; int stable = *stablep; - err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file); - if (err) - goto out; - if (!cnt) - goto out_close; err = nfserr_perm; #ifdef MSNFS if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && (!lock_may_write(file->f_dentry->d_inode, offset, cnt))) - goto out_close; + goto out; #endif dentry = file->f_dentry; @@ -990,12 +968,71 @@ nfsd_write(struct svc_rqst *rqstp, struc err = 0; else err = nfserrno(err); -out_close: - nfsd_close(file); out: return err; } +/* + * Read data from a file. count must contain the requested read count + * on entry. On return, *count contains the number of bytes actually read. + * N.B. After this call fhp needs an fh_put + */ +int +nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, + loff_t offset, struct kvec *vec, int vlen, + unsigned long *count) +{ + int err; + + if (file) { + err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, + MAY_READ|MAY_OWNER_OVERRIDE); + if (err) + goto out; + err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); + } else { + err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file); + if (err) + goto out; + err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); + nfsd_close(file); + } +out: + return err; +} + +/* + * Write data to a file. + * The stable flag requests synchronous writes. + * N.B. After this call fhp needs an fh_put + */ +int +nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, + loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, + int *stablep) +{ + int err = 0; + + if (file) { + err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, + MAY_WRITE|MAY_OWNER_OVERRIDE); + if (err) + goto out; + err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt, + stablep); + } else { + err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file); + if (err) + goto out; + + if (cnt) + err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, + cnt, stablep); + nfsd_close(file); + } +out: + return err; +} #ifdef CONFIG_NFSD_V3 /* diff -puN include/linux/nfsd/nfsd.h~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write include/linux/nfsd/nfsd.h --- 25/include/linux/nfsd/nfsd.h~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write 2005-03-07 23:55:21.000000000 -0800 +++ 25-akpm/include/linux/nfsd/nfsd.h 2005-03-07 23:55:21.000000000 -0800 @@ -96,9 +96,9 @@ int nfsd_commit(struct svc_rqst *, stru int nfsd_open(struct svc_rqst *, struct svc_fh *, int, int, struct file **); void nfsd_close(struct file *); -int nfsd_read(struct svc_rqst *, struct svc_fh *, - loff_t, struct kvec *,int, unsigned long *); -int nfsd_write(struct svc_rqst *, struct svc_fh *, +int nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *, + loff_t, struct kvec *, int, unsigned long *); +int nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, loff_t, struct kvec *,int, unsigned long, int *); int nfsd_readlink(struct svc_rqst *, struct svc_fh *, char *, int *); diff -puN include/linux/nfsd/state.h~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write include/linux/nfsd/state.h --- 25/include/linux/nfsd/state.h~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write 2005-03-07 23:55:21.000000000 -0800 +++ 25-akpm/include/linux/nfsd/state.h 2005-03-07 23:55:21.000000000 -0800 @@ -279,7 +279,7 @@ struct nfs4_stateid { extern time_t nfs4_laundromat(void); extern int nfsd4_renew(clientid_t *clid); extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh, - stateid_t *stateid, int flags); + stateid_t *stateid, int flags, struct file **filp); extern int nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type); extern void nfs4_lock_state(void); diff -puN include/linux/nfsd/xdr4.h~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write include/linux/nfsd/xdr4.h --- 25/include/linux/nfsd/xdr4.h~nfsd4-use-existing-open-instead-of-reopening-on-read-and-write 2005-03-07 23:55:21.000000000 -0800 +++ 25-akpm/include/linux/nfsd/xdr4.h 2005-03-07 23:55:21.000000000 -0800 @@ -241,6 +241,7 @@ struct nfsd4_read { u32 rd_length; /* request */ struct kvec rd_iov[RPCSVC_MAXPAGES]; int rd_vlen; + struct file *rd_filp; struct svc_rqst *rd_rqstp; /* response */ struct svc_fh * rd_fhp; /* response */ _