diff options
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 173 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 121 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 8 |
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 | ||
3072 | static __be32 | 3072 | static __be32 nfsd4_encode_splice_read( |
3073 | nfsd4_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 | |||
3136 | static __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 | |||
3208 | static __be32 | ||
3209 | nfsd4_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 | |||
3255 | err_truncate: | ||
3256 | if (err) | ||
3257 | xdr_truncate_encode(xdr, starting_len); | ||
3258 | return err; | ||
3170 | } | 3259 | } |
3171 | 3260 | ||
3172 | static __be32 | 3261 | static __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 | ||
823 | static __be32 | 823 | __be32 nfsd_finish_read(struct file *file, unsigned long *count, int host_err) |
824 | nfsd_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 | |||
834 | int 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 | |||
850 | int 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 | |||
863 | static __be32 | ||
864 | nfsd_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 | ||
992 | void 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 **); |
72 | void nfsd_close(struct file *); | 72 | void nfsd_close(struct file *); |
73 | struct raparms; | ||
74 | __be32 nfsd_get_tmp_read_open(struct svc_rqst *, struct svc_fh *, | ||
75 | struct file **, struct raparms **); | ||
76 | void nfsd_put_tmp_read_open(struct file *, struct raparms *); | ||
77 | int nfsd_splice_read(struct svc_rqst *, | ||
78 | struct file *, loff_t, unsigned long *); | ||
79 | int 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 *, |