Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nfsd: take struct file setup fully into nfs4_preprocess_stateid_op

This patch changes nfs4_preprocess_stateid_op so it always returns
a valid struct file if it has been asked for that. For that we
now allocate a temporary struct file for special stateids, and check
permissions if we got the file structure from the stateid. This
ensures that all callers will get their handling of special stateids
right, and avoids code duplication.

There is a little wart in here because the read code needs to know
if we allocated a file structure so that it can copy around the
read-ahead parameters. In the long run we should probably aim to
cache full file structures used with special stateids instead.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>

authored by

Christoph Hellwig and committed by
J. Bruce Fields
af90f707 a0649b2d

+74 -62
+15 -24
fs/nfsd/nfs4proc.c
··· 760 760 { 761 761 __be32 status; 762 762 763 - /* no need to check permission - this will be done in nfsd_read() */ 764 - 765 763 read->rd_filp = NULL; 766 764 if (read->rd_offset >= OFFSET_MAX) 767 765 return nfserr_inval; ··· 776 778 clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); 777 779 778 780 /* check stateid */ 779 - if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), 780 - cstate, &read->rd_stateid, 781 - RD_STATE, &read->rd_filp))) { 781 + status = nfs4_preprocess_stateid_op(rqstp, cstate, &read->rd_stateid, 782 + RD_STATE, &read->rd_filp, &read->rd_tmp_file); 783 + if (status) { 782 784 dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); 783 785 goto out; 784 786 } ··· 922 924 int err; 923 925 924 926 if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { 925 - status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate, 926 - &setattr->sa_stateid, WR_STATE, NULL); 927 + status = nfs4_preprocess_stateid_op(rqstp, cstate, 928 + &setattr->sa_stateid, WR_STATE, NULL, NULL); 927 929 if (status) { 928 930 dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); 929 931 return status; ··· 984 986 unsigned long cnt; 985 987 int nvecs; 986 988 987 - /* no need to check permission - this will be done in nfsd_write() */ 988 - 989 989 if (write->wr_offset >= OFFSET_MAX) 990 990 return nfserr_inval; 991 991 992 - status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), 993 - cstate, stateid, WR_STATE, &filp); 992 + status = nfs4_preprocess_stateid_op(rqstp, cstate, stateid, WR_STATE, 993 + &filp, NULL); 994 994 if (status) { 995 995 dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); 996 996 return status; ··· 1001 1005 nvecs = fill_in_write_vector(rqstp->rq_vec, write); 1002 1006 WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); 1003 1007 1004 - status = nfsd_write(rqstp, &cstate->current_fh, filp, 1005 - write->wr_offset, rqstp->rq_vec, nvecs, 1006 - &cnt, &write->wr_how_written); 1007 - if (filp) 1008 - fput(filp); 1008 + status = nfsd_vfs_write(rqstp, &cstate->current_fh, filp, 1009 + write->wr_offset, rqstp->rq_vec, nvecs, &cnt, 1010 + &write->wr_how_written); 1011 + fput(filp); 1009 1012 1010 1013 write->wr_bytes_written = cnt; 1011 1014 ··· 1018 1023 __be32 status = nfserr_notsupp; 1019 1024 struct file *file; 1020 1025 1021 - status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate, 1026 + status = nfs4_preprocess_stateid_op(rqstp, cstate, 1022 1027 &fallocate->falloc_stateid, 1023 - WR_STATE, &file); 1028 + WR_STATE, &file, NULL); 1024 1029 if (status != nfs_ok) { 1025 1030 dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n"); 1026 1031 return status; 1027 1032 } 1028 - if (!file) 1029 - return nfserr_bad_stateid; 1030 1033 1031 1034 status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, file, 1032 1035 fallocate->falloc_offset, ··· 1057 1064 __be32 status; 1058 1065 struct file *file; 1059 1066 1060 - status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate, 1067 + status = nfs4_preprocess_stateid_op(rqstp, cstate, 1061 1068 &seek->seek_stateid, 1062 - RD_STATE, &file); 1069 + RD_STATE, &file, NULL); 1063 1070 if (status) { 1064 1071 dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n"); 1065 1072 return status; 1066 1073 } 1067 - if (!file) 1068 - return nfserr_bad_stateid; 1069 1074 1070 1075 switch (seek->seek_whence) { 1071 1076 case NFS4_CONTENT_DATA:
+49 -11
fs/nfsd/nfs4state.c
··· 4576 4576 static struct file * 4577 4577 nfs4_find_file(struct nfs4_stid *s, int flags) 4578 4578 { 4579 + if (!s) 4580 + return NULL; 4581 + 4579 4582 switch (s->sc_type) { 4580 4583 case NFS4_DELEG_STID: 4581 4584 if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) ··· 4610 4607 return nfs4_check_openmode(ols, flags); 4611 4608 } 4612 4609 4610 + static __be32 4611 + nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 4612 + struct file **filpp, bool *tmp_file, int flags) 4613 + { 4614 + int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 4615 + struct file *file; 4616 + __be32 status; 4617 + 4618 + file = nfs4_find_file(s, flags); 4619 + if (file) { 4620 + status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 4621 + acc | NFSD_MAY_OWNER_OVERRIDE); 4622 + if (status) { 4623 + fput(file); 4624 + return status; 4625 + } 4626 + 4627 + *filpp = file; 4628 + } else { 4629 + status = nfsd_open(rqstp, fhp, S_IFREG, acc, filpp); 4630 + if (status) 4631 + return status; 4632 + 4633 + if (tmp_file) 4634 + *tmp_file = true; 4635 + } 4636 + 4637 + return 0; 4638 + } 4639 + 4613 4640 /* 4614 4641 * Checks for stateid operations 4615 4642 */ 4616 4643 __be32 4617 - nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, 4618 - stateid_t *stateid, int flags, struct file **filpp) 4644 + nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 4645 + struct nfsd4_compound_state *cstate, stateid_t *stateid, 4646 + int flags, struct file **filpp, bool *tmp_file) 4619 4647 { 4620 4648 struct svc_fh *fhp = &cstate->current_fh; 4621 4649 struct inode *ino = d_inode(fhp->fh_dentry); 4650 + struct net *net = SVC_NET(rqstp); 4622 4651 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 4623 - struct nfs4_stid *s; 4652 + struct nfs4_stid *s = NULL; 4624 4653 __be32 status; 4625 4654 4626 4655 if (filpp) 4627 4656 *filpp = NULL; 4657 + if (tmp_file) 4658 + *tmp_file = false; 4628 4659 4629 4660 if (grace_disallows_io(net, ino)) 4630 4661 return nfserr_grace; 4631 4662 4632 - if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 4633 - return check_special_stateids(net, fhp, stateid, flags); 4663 + if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 4664 + status = check_special_stateids(net, fhp, stateid, flags); 4665 + goto done; 4666 + } 4634 4667 4635 4668 status = nfsd4_lookup_stateid(cstate, stateid, 4636 4669 NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, ··· 4691 4652 break; 4692 4653 } 4693 4654 4694 - if (!status && filpp) { 4695 - *filpp = nfs4_find_file(s, flags); 4696 - if (!*filpp) 4697 - status = nfserr_serverfault; 4698 - } 4655 + done: 4656 + if (!status && filpp) 4657 + status = nfs4_check_file(rqstp, fhp, s, filpp, tmp_file, flags); 4699 4658 out: 4700 - nfs4_put_stid(s); 4659 + if (s) 4660 + nfs4_put_stid(s); 4701 4661 return status; 4702 4662 } 4703 4663
+1 -18
fs/nfsd/nfs4xdr.c
··· 33 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 34 */ 35 35 36 - #include <linux/file.h> 37 36 #include <linux/slab.h> 38 37 #include <linux/namei.h> 39 38 #include <linux/statfs.h> ··· 3417 3418 unsigned long maxcount; 3418 3419 struct xdr_stream *xdr = &resp->xdr; 3419 3420 struct file *file = read->rd_filp; 3420 - struct svc_fh *fhp = read->rd_fhp; 3421 3421 int starting_len = xdr->buf->len; 3422 3422 struct raparms *ra = NULL; 3423 3423 __be32 *p; ··· 3440 3442 maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len)); 3441 3443 maxcount = min_t(unsigned long, maxcount, read->rd_length); 3442 3444 3443 - if (read->rd_filp) { 3444 - err = nfsd_permission(resp->rqstp, fhp->fh_export, 3445 - fhp->fh_dentry, 3446 - NFSD_MAY_READ|NFSD_MAY_OWNER_OVERRIDE); 3447 - if (err) 3448 - goto err_truncate; 3449 - } else { 3450 - err = nfsd_open(resp->rqstp, fhp, S_IFREG, NFSD_MAY_READ, 3451 - &file); 3452 - if (err) 3453 - goto err_truncate; 3454 - 3445 + if (read->rd_tmp_file) 3455 3446 ra = nfsd_init_raparms(file); 3456 - } 3457 3447 3458 3448 if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) 3459 3449 err = nfsd4_encode_splice_read(resp, read, file, maxcount); ··· 3450 3464 3451 3465 if (ra) 3452 3466 nfsd_put_raparams(file, ra); 3453 - if (!read->rd_filp) 3454 - fput(file); 3455 3467 3456 - err_truncate: 3457 3468 if (err) 3458 3469 xdr_truncate_encode(xdr, starting_len); 3459 3470 return err;
+3 -3
fs/nfsd/state.h
··· 583 583 struct nfsd4_compound_state; 584 584 struct nfsd_net; 585 585 586 - extern __be32 nfs4_preprocess_stateid_op(struct net *net, 587 - struct nfsd4_compound_state *cstate, 588 - stateid_t *stateid, int flags, struct file **filp); 586 + extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 587 + struct nfsd4_compound_state *cstate, stateid_t *stateid, 588 + int flags, struct file **filp, bool *tmp_file); 589 589 __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 590 590 stateid_t *stateid, unsigned char typemask, 591 591 struct nfs4_stid **s, struct nfsd_net *nn);
+1 -6
fs/nfsd/vfs.c
··· 502 502 struct file *file, loff_t offset, loff_t len, 503 503 int flags) 504 504 { 505 - __be32 err; 506 505 int error; 507 506 508 507 if (!S_ISREG(file_inode(file)->i_mode)) 509 508 return nfserr_inval; 510 - 511 - err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, NFSD_MAY_WRITE); 512 - if (err) 513 - return err; 514 509 515 510 error = vfs_fallocate(file, flags, offset, len); 516 511 if (!error) ··· 907 912 return err; 908 913 } 909 914 910 - static __be32 915 + __be32 911 916 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, 912 917 loff_t offset, struct kvec *vec, int vlen, 913 918 unsigned long *cnt, int *stablep)
+4
fs/nfsd/vfs.h
··· 80 80 loff_t, struct kvec *, int, unsigned long *); 81 81 __be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, 82 82 loff_t, struct kvec *,int, unsigned long *, int *); 83 + __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, 84 + struct file *file, loff_t offset, 85 + struct kvec *vec, int vlen, unsigned long *cnt, 86 + int *stablep); 83 87 __be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *, 84 88 char *, int *); 85 89 __be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
+1
fs/nfsd/xdr4.h
··· 273 273 u32 rd_length; /* request */ 274 274 int rd_vlen; 275 275 struct file *rd_filp; 276 + bool rd_tmp_file; 276 277 277 278 struct svc_rqst *rd_rqstp; /* response */ 278 279 struct svc_fh * rd_fhp; /* response */