aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2014-03-18 17:01:51 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-05-30 17:32:09 -0400
commitdc97618ddda9a23e5211e800f0614e9612178200 (patch)
treee4167f2ff3e8edf0bb5f331d58bc308476180744 /fs/nfsd
parent02fe4707740e7c8a3d0ec34ffbf4630d7d41ca68 (diff)
nfsd4: separate splice and readv cases
The splice and readv cases are actually quite different--for example the former case ignores the array of vectors we build up for the latter. It is probably clearer to separate the two cases entirely. There's some code duplication between the split out encoders, but this is only temporary and will be fixed by a later patch. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4xdr.c173
-rw-r--r--fs/nfsd/vfs.c121
-rw-r--r--fs/nfsd/vfs.h8
3 files changed, 214 insertions, 88 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index f6a5cb722697..bad762b6cf10 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3069,41 +3069,84 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc
3069 return nfserr; 3069 return nfserr;
3070} 3070}
3071 3071
3072static __be32 3072static __be32 nfsd4_encode_splice_read(
3073nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, 3073 struct nfsd4_compoundres *resp,
3074 struct nfsd4_read *read) 3074 struct nfsd4_read *read,
3075 struct file *file, unsigned long maxcount)
3075{ 3076{
3076 u32 eof;
3077 int v;
3078 struct page *page;
3079 unsigned long maxcount;
3080 struct xdr_stream *xdr = &resp->xdr; 3077 struct xdr_stream *xdr = &resp->xdr;
3081 int starting_len = xdr->buf->len; 3078 u32 eof;
3079 int starting_len = xdr->buf->len - 8;
3082 int space_left; 3080 int space_left;
3083 long len; 3081 __be32 nfserr;
3082 __be32 tmp;
3084 __be32 *p; 3083 __be32 *p;
3085 3084
3086 if (nfserr) 3085 /*
3087 return nfserr; 3086 * Don't inline pages unless we know there's room for eof,
3088 3087 * count, and possible padding:
3089 p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */ 3088 */
3090 if (!p) { 3089 if (xdr->end - xdr->p < 3)
3091 WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
3092 return nfserr_resource; 3090 return nfserr_resource;
3091
3092 nfserr = nfsd_splice_read(read->rd_rqstp, file,
3093 read->rd_offset, &maxcount);
3094 if (nfserr) {
3095 /*
3096 * nfsd_splice_actor may have already messed with the
3097 * page length; reset it so as not to confuse
3098 * xdr_truncate_encode:
3099 */
3100 xdr->buf->page_len = 0;
3101 return nfserr;
3093 } 3102 }
3094 3103
3095 /* Make sure there will be room for padding if needed: */ 3104 eof = (read->rd_offset + maxcount >=
3096 if (xdr->end - xdr->p < 1) 3105 read->rd_fhp->fh_dentry->d_inode->i_size);
3097 return nfserr_resource;
3098 3106
3099 if (resp->xdr.buf->page_len) { 3107 tmp = htonl(eof);
3100 WARN_ON_ONCE(resp->rqstp->rq_splice_ok); 3108 write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
3101 return nfserr_resource; 3109 tmp = htonl(maxcount);
3110 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
3111
3112 resp->xdr.buf->page_len = maxcount;
3113 xdr->buf->len += maxcount;
3114 xdr->page_ptr += (maxcount + PAGE_SIZE - 1) / PAGE_SIZE;
3115 xdr->iov = xdr->buf->tail;
3116
3117 /* Use rest of head for padding and remaining ops: */
3118 resp->xdr.buf->tail[0].iov_base = xdr->p;
3119 resp->xdr.buf->tail[0].iov_len = 0;
3120 if (maxcount&3) {
3121 p = xdr_reserve_space(xdr, 4);
3122 WRITE32(0);
3123 resp->xdr.buf->tail[0].iov_base += maxcount&3;
3124 resp->xdr.buf->tail[0].iov_len = 4 - (maxcount&3);
3125 xdr->buf->len -= (maxcount&3);
3102 } 3126 }
3103 3127
3104 maxcount = svc_max_payload(resp->rqstp); 3128 space_left = min_t(int, (void *)xdr->end - (void *)xdr->p,
3105 if (maxcount > read->rd_length) 3129 xdr->buf->buflen - xdr->buf->len);
3106 maxcount = read->rd_length; 3130 xdr->buf->buflen = xdr->buf->len + space_left;
3131 xdr->end = (__be32 *)((void *)xdr->end + space_left);
3132
3133 return 0;
3134}
3135
3136static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
3137 struct nfsd4_read *read,
3138 struct file *file, unsigned long maxcount)
3139{
3140 struct xdr_stream *xdr = &resp->xdr;
3141 u32 eof;
3142 int v;
3143 struct page *page;
3144 int starting_len = xdr->buf->len - 8;
3145 int space_left;
3146 long len;
3147 __be32 nfserr;
3148 __be32 tmp;
3149 __be32 *p;
3107 3150
3108 len = maxcount; 3151 len = maxcount;
3109 v = 0; 3152 v = 0;
@@ -3124,34 +3167,26 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
3124 } 3167 }
3125 read->rd_vlen = v; 3168 read->rd_vlen = v;
3126 3169
3127 nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp, 3170 nfserr = nfsd_readv(file, read->rd_offset, resp->rqstp->rq_vec,
3128 read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, 3171 read->rd_vlen, &maxcount);
3129 &maxcount); 3172 if (nfserr)
3130
3131 if (nfserr) {
3132 /*
3133 * nfsd_splice_actor may have already messed with the
3134 * page length; reset it so as not to confuse
3135 * xdr_truncate_encode:
3136 */
3137 xdr->buf->page_len = 0;
3138 xdr_truncate_encode(xdr, starting_len);
3139 return nfserr; 3173 return nfserr;
3140 } 3174
3141 eof = (read->rd_offset + maxcount >= 3175 eof = (read->rd_offset + maxcount >=
3142 read->rd_fhp->fh_dentry->d_inode->i_size); 3176 read->rd_fhp->fh_dentry->d_inode->i_size);
3143 3177
3144 WRITE32(eof); 3178 tmp = htonl(eof);
3145 WRITE32(maxcount); 3179 write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
3146 WARN_ON_ONCE(resp->xdr.buf->head[0].iov_len != (char *)p 3180 tmp = htonl(maxcount);
3147 - (char *)resp->xdr.buf->head[0].iov_base); 3181 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
3182
3148 resp->xdr.buf->page_len = maxcount; 3183 resp->xdr.buf->page_len = maxcount;
3149 xdr->buf->len += maxcount; 3184 xdr->buf->len += maxcount;
3150 xdr->page_ptr += v; 3185 xdr->page_ptr += v;
3151 xdr->iov = xdr->buf->tail; 3186 xdr->iov = xdr->buf->tail;
3152 3187
3153 /* Use rest of head for padding and remaining ops: */ 3188 /* Use rest of head for padding and remaining ops: */
3154 resp->xdr.buf->tail[0].iov_base = p; 3189 resp->xdr.buf->tail[0].iov_base = xdr->p;
3155 resp->xdr.buf->tail[0].iov_len = 0; 3190 resp->xdr.buf->tail[0].iov_len = 0;
3156 if (maxcount&3) { 3191 if (maxcount&3) {
3157 p = xdr_reserve_space(xdr, 4); 3192 p = xdr_reserve_space(xdr, 4);
@@ -3167,6 +3202,60 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
3167 xdr->end = (__be32 *)((void *)xdr->end + space_left); 3202 xdr->end = (__be32 *)((void *)xdr->end + space_left);
3168 3203
3169 return 0; 3204 return 0;
3205
3206}
3207
3208static __be32
3209nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
3210 struct nfsd4_read *read)
3211{
3212 unsigned long maxcount;
3213 struct xdr_stream *xdr = &resp->xdr;
3214 struct file *file = read->rd_filp;
3215 int starting_len = xdr->buf->len;
3216 struct raparms *ra;
3217 __be32 *p;
3218 __be32 err;
3219
3220 if (nfserr)
3221 return nfserr;
3222
3223 p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
3224 if (!p) {
3225 WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
3226 return nfserr_resource;
3227 }
3228
3229 if (resp->xdr.buf->page_len) {
3230 WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
3231 return nfserr_resource;
3232 }
3233
3234 xdr_commit_encode(xdr);
3235
3236 maxcount = svc_max_payload(resp->rqstp);
3237 if (maxcount > read->rd_length)
3238 maxcount = read->rd_length;
3239
3240 if (!read->rd_filp) {
3241 err = nfsd_get_tmp_read_open(resp->rqstp, read->rd_fhp,
3242 &file, &ra);
3243 if (err)
3244 goto err_truncate;
3245 }
3246
3247 if (file->f_op->splice_read && resp->rqstp->rq_splice_ok)
3248 err = nfsd4_encode_splice_read(resp, read, file, maxcount);
3249 else
3250 err = nfsd4_encode_readv(resp, read, file, maxcount);
3251
3252 if (!read->rd_filp)
3253 nfsd_put_tmp_read_open(file, ra);
3254
3255err_truncate:
3256 if (err)
3257 xdr_truncate_encode(xdr, starting_len);
3258 return err;
3170} 3259}
3171 3260
3172static __be32 3261static __be32
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index f3a0f6cc4298..b7d35a4afefb 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -820,41 +820,54 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
820 return __splice_from_pipe(pipe, sd, nfsd_splice_actor); 820 return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
821} 821}
822 822
823static __be32 823__be32 nfsd_finish_read(struct file *file, unsigned long *count, int host_err)
824nfsd_vfs_read(struct svc_rqst *rqstp, struct file *file,
825 loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
826{ 824{
827 mm_segment_t oldfs;
828 __be32 err;
829 int host_err;
830
831 err = nfserr_perm;
832
833 if (file->f_op->splice_read && rqstp->rq_splice_ok) {
834 struct splice_desc sd = {
835 .len = 0,
836 .total_len = *count,
837 .pos = offset,
838 .u.data = rqstp,
839 };
840
841 rqstp->rq_next_page = rqstp->rq_respages + 1;
842 host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
843 } else {
844 oldfs = get_fs();
845 set_fs(KERNEL_DS);
846 host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
847 set_fs(oldfs);
848 }
849
850 if (host_err >= 0) { 825 if (host_err >= 0) {
851 nfsdstats.io_read += host_err; 826 nfsdstats.io_read += host_err;
852 *count = host_err; 827 *count = host_err;
853 err = 0;
854 fsnotify_access(file); 828 fsnotify_access(file);
829 return 0;
855 } else 830 } else
856 err = nfserrno(host_err); 831 return nfserrno(host_err);
857 return err; 832}
833
834int nfsd_splice_read(struct svc_rqst *rqstp,
835 struct file *file, loff_t offset, unsigned long *count)
836{
837 struct splice_desc sd = {
838 .len = 0,
839 .total_len = *count,
840 .pos = offset,
841 .u.data = rqstp,
842 };
843 int host_err;
844
845 rqstp->rq_next_page = rqstp->rq_respages + 1;
846 host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
847 return nfsd_finish_read(file, count, host_err);
848}
849
850int nfsd_readv(struct file *file, loff_t offset, struct kvec *vec, int vlen,
851 unsigned long *count)
852{
853 mm_segment_t oldfs;
854 int host_err;
855
856 oldfs = get_fs();
857 set_fs(KERNEL_DS);
858 host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
859 set_fs(oldfs);
860 return nfsd_finish_read(file, count, host_err);
861}
862
863static __be32
864nfsd_vfs_read(struct svc_rqst *rqstp, struct file *file,
865 loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
866{
867 if (file->f_op->splice_read && rqstp->rq_splice_ok)
868 return nfsd_splice_read(rqstp, file, offset, count);
869 else
870 return nfsd_readv(file, offset, vec, vlen, count);
858} 871}
859 872
860/* 873/*
@@ -956,33 +969,28 @@ out_nfserr:
956 return err; 969 return err;
957} 970}
958 971
959/* 972__be32 nfsd_get_tmp_read_open(struct svc_rqst *rqstp, struct svc_fh *fhp,
960 * Read data from a file. count must contain the requested read count 973 struct file **file, struct raparms **ra)
961 * on entry. On return, *count contains the number of bytes actually read.
962 * N.B. After this call fhp needs an fh_put
963 */
964__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
965 loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
966{ 974{
967 struct file *file;
968 struct inode *inode; 975 struct inode *inode;
969 struct raparms *ra;
970 __be32 err; 976 __be32 err;
971 977
972 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); 978 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, file);
973 if (err) 979 if (err)
974 return err; 980 return err;
975 981
976 inode = file_inode(file); 982 inode = file_inode(*file);
977 983
978 /* Get readahead parameters */ 984 /* Get readahead parameters */
979 ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino); 985 *ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
980
981 if (ra && ra->p_set)
982 file->f_ra = ra->p_ra;
983 986
984 err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count); 987 if (*ra && (*ra)->p_set)
988 (*file)->f_ra = (*ra)->p_ra;
989 return nfs_ok;
990}
985 991
992void nfsd_put_tmp_read_open(struct file *file, struct raparms *ra)
993{
986 /* Write back readahead params */ 994 /* Write back readahead params */
987 if (ra) { 995 if (ra) {
988 struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; 996 struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
@@ -992,8 +1000,29 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
992 ra->p_count--; 1000 ra->p_count--;
993 spin_unlock(&rab->pb_lock); 1001 spin_unlock(&rab->pb_lock);
994 } 1002 }
995
996 nfsd_close(file); 1003 nfsd_close(file);
1004}
1005
1006/*
1007 * Read data from a file. count must contain the requested read count
1008 * on entry. On return, *count contains the number of bytes actually read.
1009 * N.B. After this call fhp needs an fh_put
1010 */
1011__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
1012 loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
1013{
1014 struct file *file;
1015 struct raparms *ra;
1016 __be32 err;
1017
1018 err = nfsd_get_tmp_read_open(rqstp, fhp, &file, &ra);
1019 if (err)
1020 return err;
1021
1022 err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count);
1023
1024 nfsd_put_tmp_read_open(file, ra);
1025
997 return err; 1026 return err;
998} 1027}
999 1028
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index fbe90bdb2214..7441e9655eb7 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -70,6 +70,14 @@ __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
70__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t, 70__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t,
71 int, struct file **); 71 int, struct file **);
72void nfsd_close(struct file *); 72void nfsd_close(struct file *);
73struct raparms;
74__be32 nfsd_get_tmp_read_open(struct svc_rqst *, struct svc_fh *,
75 struct file **, struct raparms **);
76void nfsd_put_tmp_read_open(struct file *, struct raparms *);
77int nfsd_splice_read(struct svc_rqst *,
78 struct file *, loff_t, unsigned long *);
79int nfsd_readv(struct file *, loff_t, struct kvec *, int,
80 unsigned long *);
73__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, 81__be32 nfsd_read(struct svc_rqst *, struct svc_fh *,
74 loff_t, struct kvec *, int, unsigned long *); 82 loff_t, struct kvec *, int, unsigned long *);
75__be32 nfsd_read_file(struct svc_rqst *, struct svc_fh *, struct file *, 83__be32 nfsd_read_file(struct svc_rqst *, struct svc_fh *, struct file *,