aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 *,