aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2010-12-14 09:55:10 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-12-16 12:37:21 -0500
commitf796f8b3ae292abb9cb2931e8db6fc1d69bba09d (patch)
tree80d62906e65bda8fb82b3b9c76a56a2071e99a7e
parent858284932462cec260f3d1d7426aeb03f5dbc2ad (diff)
NFS: Introduce new-style XDR decoding functions for NFSv2
We'd like to prevent local buffer overflows caused by malicious or broken servers. New xdr_stream style decoders can do that. For efficiency, we also eventually want to be able to pass xdr_streams from call_decode() to all XDR decoding functions, rather than building an xdr_stream in every XDR decoding function in the kernel. nfs_decode_dirent() is renamed to follow the naming convention of the other two dirent decoders. Static helper functions are left without the "inline" directive. This allows the compiler to choose automatically how to optimize these for size or speed. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Tested-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/internal.h2
-rw-r--r--fs/nfs/nfs2xdr.c564
-rw-r--r--fs/nfs/proc.c2
3 files changed, 558 insertions, 10 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 8c2d9d83771e..6c6a9955bae9 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -187,7 +187,7 @@ extern void nfs_destroy_directcache(void);
187/* nfs2xdr.c */ 187/* nfs2xdr.c */
188extern int nfs_stat_to_errno(enum nfs_stat); 188extern int nfs_stat_to_errno(enum nfs_stat);
189extern struct rpc_procinfo nfs_procedures[]; 189extern struct rpc_procinfo nfs_procedures[];
190extern __be32 *nfs_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); 190extern __be32 *nfs2_decode_dirent(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
191 191
192/* nfs3xdr.c */ 192/* nfs3xdr.c */
193extern struct rpc_procinfo nfs3_procedures[]; 193extern struct rpc_procinfo nfs3_procedures[];
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 2da9824d432a..827d1b8ad55b 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -77,6 +77,16 @@ static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
77 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len); 77 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
78} 78}
79 79
80/*
81 * Handle decode buffer overflows out-of-line.
82 */
83static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
84{
85 dprintk("NFS: %s prematurely hit the end of our receive buffer. "
86 "Remaining buffer length is %tu words.\n",
87 func, xdr->end - xdr->p);
88}
89
80 90
81/* 91/*
82 * Common NFS XDR functions as inlines 92 * Common NFS XDR functions as inlines
@@ -139,6 +149,74 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
139 */ 149 */
140 150
141/* 151/*
152 * typedef opaque nfsdata<>;
153 */
154static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result)
155{
156 u32 recvd, count;
157 size_t hdrlen;
158 __be32 *p;
159
160 p = xdr_inline_decode(xdr, 4);
161 if (unlikely(p == NULL))
162 goto out_overflow;
163 count = be32_to_cpup(p);
164 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
165 recvd = xdr->buf->len - hdrlen;
166 if (unlikely(count > recvd))
167 goto out_cheating;
168out:
169 xdr_read_pages(xdr, count);
170 result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */
171 result->count = count;
172 return count;
173out_cheating:
174 dprintk("NFS: server cheating in read result: "
175 "count %u > recvd %u\n", count, recvd);
176 count = recvd;
177 goto out;
178out_overflow:
179 print_overflow_msg(__func__, xdr);
180 return -EIO;
181}
182
183/*
184 * enum stat {
185 * NFS_OK = 0,
186 * NFSERR_PERM = 1,
187 * NFSERR_NOENT = 2,
188 * NFSERR_IO = 5,
189 * NFSERR_NXIO = 6,
190 * NFSERR_ACCES = 13,
191 * NFSERR_EXIST = 17,
192 * NFSERR_NODEV = 19,
193 * NFSERR_NOTDIR = 20,
194 * NFSERR_ISDIR = 21,
195 * NFSERR_FBIG = 27,
196 * NFSERR_NOSPC = 28,
197 * NFSERR_ROFS = 30,
198 * NFSERR_NAMETOOLONG = 63,
199 * NFSERR_NOTEMPTY = 66,
200 * NFSERR_DQUOT = 69,
201 * NFSERR_STALE = 70,
202 * NFSERR_WFLUSH = 99
203 * };
204 */
205static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
206{
207 __be32 *p;
208
209 p = xdr_inline_decode(xdr, 4);
210 if (unlikely(p == NULL))
211 goto out_overflow;
212 *status = be32_to_cpup(p);
213 return 0;
214out_overflow:
215 print_overflow_msg(__func__, xdr);
216 return -EIO;
217}
218
219/*
142 * 2.3.3. fhandle 220 * 2.3.3. fhandle
143 * 221 *
144 * typedef opaque fhandle[FHSIZE]; 222 * typedef opaque fhandle[FHSIZE];
@@ -152,6 +230,21 @@ static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
152 memcpy(p, fh->data, NFS2_FHSIZE); 230 memcpy(p, fh->data, NFS2_FHSIZE);
153} 231}
154 232
233static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
234{
235 __be32 *p;
236
237 p = xdr_inline_decode(xdr, NFS2_FHSIZE);
238 if (unlikely(p == NULL))
239 goto out_overflow;
240 fh->size = NFS2_FHSIZE;
241 memcpy(fh->data, p, NFS2_FHSIZE);
242 return 0;
243out_overflow:
244 print_overflow_msg(__func__, xdr);
245 return -EIO;
246}
247
155/* 248/*
156 * 2.3.4. timeval 249 * 2.3.4. timeval
157 * 250 *
@@ -186,6 +279,41 @@ static __be32 *xdr_encode_current_server_time(__be32 *p,
186} 279}
187 280
188/* 281/*
282 * 2.3.5. fattr
283 *
284 * struct fattr {
285 * ftype type;
286 * unsigned int mode;
287 * unsigned int nlink;
288 * unsigned int uid;
289 * unsigned int gid;
290 * unsigned int size;
291 * unsigned int blocksize;
292 * unsigned int rdev;
293 * unsigned int blocks;
294 * unsigned int fsid;
295 * unsigned int fileid;
296 * timeval atime;
297 * timeval mtime;
298 * timeval ctime;
299 * };
300 *
301 */
302static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
303{
304 __be32 *p;
305
306 p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
307 if (unlikely(p == NULL))
308 goto out_overflow;
309 xdr_decode_fattr(p, fattr);
310 return 0;
311out_overflow:
312 print_overflow_msg(__func__, xdr);
313 return -EIO;
314}
315
316/*
189 * 2.3.6. sattr 317 * 2.3.6. sattr
190 * 318 *
191 * struct sattr { 319 * struct sattr {
@@ -259,6 +387,32 @@ static void encode_filename(struct xdr_stream *xdr,
259 xdr_encode_opaque(p, name, length); 387 xdr_encode_opaque(p, name, length);
260} 388}
261 389
390static int decode_filename_inline(struct xdr_stream *xdr,
391 const char **name, u32 *length)
392{
393 __be32 *p;
394 u32 count;
395
396 p = xdr_inline_decode(xdr, 4);
397 if (unlikely(p == NULL))
398 goto out_overflow;
399 count = be32_to_cpup(p);
400 if (count > NFS3_MAXNAMLEN)
401 goto out_nametoolong;
402 p = xdr_inline_decode(xdr, count);
403 if (unlikely(p == NULL))
404 goto out_overflow;
405 *name = (const char *)p;
406 *length = count;
407 return 0;
408out_nametoolong:
409 dprintk("NFS: returned filename too long: %u\n", count);
410 return -ENAMETOOLONG;
411out_overflow:
412 print_overflow_msg(__func__, xdr);
413 return -EIO;
414}
415
262/* 416/*
263 * 2.3.8. path 417 * 2.3.8. path
264 * 418 *
@@ -274,6 +428,65 @@ static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
274 xdr_write_pages(xdr, pages, 0, length); 428 xdr_write_pages(xdr, pages, 0, length);
275} 429}
276 430
431static int decode_path(struct xdr_stream *xdr)
432{
433 u32 length, recvd;
434 size_t hdrlen;
435 __be32 *p;
436
437 p = xdr_inline_decode(xdr, 4);
438 if (unlikely(p == NULL))
439 goto out_overflow;
440 length = be32_to_cpup(p);
441 if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
442 goto out_size;
443 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
444 recvd = xdr->buf->len - hdrlen;
445 if (unlikely(length > recvd))
446 goto out_cheating;
447
448 xdr_read_pages(xdr, length);
449 xdr_terminate_string(xdr->buf, length);
450 return 0;
451out_size:
452 dprintk("NFS: returned pathname too long: %u\n", length);
453 return -ENAMETOOLONG;
454out_cheating:
455 dprintk("NFS: server cheating in pathname result: "
456 "length %u > received %u\n", length, recvd);
457 return -EIO;
458out_overflow:
459 print_overflow_msg(__func__, xdr);
460 return -EIO;
461}
462
463/*
464 * 2.3.9. attrstat
465 *
466 * union attrstat switch (stat status) {
467 * case NFS_OK:
468 * fattr attributes;
469 * default:
470 * void;
471 * };
472 */
473static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result)
474{
475 enum nfs_stat status;
476 int error;
477
478 error = decode_stat(xdr, &status);
479 if (unlikely(error))
480 goto out;
481 if (status != NFS_OK)
482 goto out_default;
483 error = decode_fattr(xdr, result);
484out:
485 return error;
486out_default:
487 return nfs_stat_to_errno(status);
488}
489
277/* 490/*
278 * 2.3.10. diropargs 491 * 2.3.10. diropargs
279 * 492 *
@@ -289,6 +502,48 @@ static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
289 encode_filename(xdr, name, length); 502 encode_filename(xdr, name, length);
290} 503}
291 504
505/*
506 * 2.3.11. diropres
507 *
508 * union diropres switch (stat status) {
509 * case NFS_OK:
510 * struct {
511 * fhandle file;
512 * fattr attributes;
513 * } diropok;
514 * default:
515 * void;
516 * };
517 */
518static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result)
519{
520 int error;
521
522 error = decode_fhandle(xdr, result->fh);
523 if (unlikely(error))
524 goto out;
525 error = decode_fattr(xdr, result->fattr);
526out:
527 return error;
528}
529
530static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result)
531{
532 enum nfs_stat status;
533 int error;
534
535 error = decode_stat(xdr, &status);
536 if (unlikely(error))
537 goto out;
538 if (status != NFS_OK)
539 goto out_default;
540 error = decode_diropok(xdr, result);
541out:
542 return error;
543out_default:
544 return nfs_stat_to_errno(status);
545}
546
292 547
293/* 548/*
294 * NFSv2 XDR encode functions 549 * NFSv2 XDR encode functions
@@ -630,13 +885,6 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
630 return pglen; 885 return pglen;
631} 886}
632 887
633static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
634{
635 dprintk("nfs: %s: prematurely hit end of receive buffer. "
636 "Remaining buffer length is %tu words.\n",
637 func, xdr->end - xdr->p);
638}
639
640__be32 * 888__be32 *
641nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus) 889nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
642{ 890{
@@ -700,6 +948,25 @@ nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
700 return status; 948 return status;
701} 949}
702 950
951static int nfs2_xdr_dec_stat(struct rpc_rqst *req, __be32 *p,
952 void *__unused)
953{
954 struct xdr_stream xdr;
955 enum nfs_stat status;
956 int error;
957
958 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
959 error = decode_stat(&xdr, &status);
960 if (unlikely(error))
961 goto out;
962 if (status != NFS_OK)
963 goto out_default;
964out:
965 return error;
966out_default:
967 return nfs_stat_to_errno(status);
968}
969
703/* 970/*
704 * Decode attrstat reply 971 * Decode attrstat reply
705 * GETATTR, SETATTR, WRITE 972 * GETATTR, SETATTR, WRITE
@@ -715,6 +982,15 @@ nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
715 return 0; 982 return 0;
716} 983}
717 984
985static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, __be32 *p,
986 struct nfs_fattr *result)
987{
988 struct xdr_stream xdr;
989
990 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
991 return decode_attrstat(&xdr, result);
992}
993
718/* 994/*
719 * Decode diropres reply 995 * Decode diropres reply
720 * LOOKUP, CREATE, MKDIR 996 * LOOKUP, CREATE, MKDIR
@@ -731,6 +1007,15 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
731 return 0; 1007 return 0;
732} 1008}
733 1009
1010static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, __be32 *p,
1011 struct nfs_diropok *result)
1012{
1013 struct xdr_stream xdr;
1014
1015 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1016 return decode_diropres(&xdr, result);
1017}
1018
734/* 1019/*
735 * Decode READLINK reply 1020 * Decode READLINK reply
736 */ 1021 */
@@ -772,6 +1057,70 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
772} 1057}
773 1058
774/* 1059/*
1060 * 2.2.6. readlinkres
1061 *
1062 * union readlinkres switch (stat status) {
1063 * case NFS_OK:
1064 * path data;
1065 * default:
1066 * void;
1067 * };
1068 */
1069static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req, __be32 *p,
1070 void *__unused)
1071{
1072 struct xdr_stream xdr;
1073 enum nfs_stat status;
1074 int error;
1075
1076 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1077 error = decode_stat(&xdr, &status);
1078 if (unlikely(error))
1079 goto out;
1080 if (status != NFS_OK)
1081 goto out_default;
1082 error = decode_path(&xdr);
1083out:
1084 return error;
1085out_default:
1086 return nfs_stat_to_errno(status);
1087}
1088
1089/*
1090 * 2.2.7. readres
1091 *
1092 * union readres switch (stat status) {
1093 * case NFS_OK:
1094 * fattr attributes;
1095 * nfsdata data;
1096 * default:
1097 * void;
1098 * };
1099 */
1100static int nfs2_xdr_dec_readres(struct rpc_rqst *req, __be32 *p,
1101 struct nfs_readres *result)
1102{
1103 struct xdr_stream xdr;
1104 enum nfs_stat status;
1105 int error;
1106
1107 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1108 error = decode_stat(&xdr, &status);
1109 if (unlikely(error))
1110 goto out;
1111 if (status != NFS_OK)
1112 goto out_default;
1113 error = decode_fattr(&xdr, result->fattr);
1114 if (unlikely(error))
1115 goto out;
1116 error = decode_nfsdata(&xdr, result);
1117out:
1118 return error;
1119out_default:
1120 return nfs_stat_to_errno(status);
1121}
1122
1123/*
775 * Decode WRITE reply 1124 * Decode WRITE reply
776 */ 1125 */
777static int 1126static int
@@ -781,6 +1130,150 @@ nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
781 return nfs_xdr_attrstat(req, p, res->fattr); 1130 return nfs_xdr_attrstat(req, p, res->fattr);
782} 1131}
783 1132
1133static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, __be32 *p,
1134 struct nfs_writeres *result)
1135{
1136 struct xdr_stream xdr;
1137
1138 /* All NFSv2 writes are "file sync" writes */
1139 result->verf->committed = NFS_FILE_SYNC;
1140
1141 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1142 return decode_attrstat(&xdr, result->fattr);
1143}
1144
1145/**
1146 * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
1147 * the local page cache.
1148 * @xdr: XDR stream where entry resides
1149 * @entry: buffer to fill in with entry data
1150 * @server: nfs_server data for this directory
1151 * @plus: boolean indicating whether this should be a readdirplus entry
1152 *
1153 * Returns the position of the next item in the buffer, or an ERR_PTR.
1154 *
1155 * This function is not invoked during READDIR reply decoding, but
1156 * rather whenever an application invokes the getdents(2) system call
1157 * on a directory already in our cache.
1158 *
1159 * 2.2.17. entry
1160 *
1161 * struct entry {
1162 * unsigned fileid;
1163 * filename name;
1164 * nfscookie cookie;
1165 * entry *nextentry;
1166 * };
1167 */
1168__be32 *nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
1169 struct nfs_server *server, int plus)
1170{
1171 __be32 *p;
1172 int error;
1173
1174 p = xdr_inline_decode(xdr, 4);
1175 if (unlikely(p == NULL))
1176 goto out_overflow;
1177 if (*p++ == xdr_zero) {
1178 p = xdr_inline_decode(xdr, 4);
1179 if (unlikely(p == NULL))
1180 goto out_overflow;
1181 if (*p++ == xdr_zero)
1182 return ERR_PTR(-EAGAIN);
1183 entry->eof = 1;
1184 return ERR_PTR(-EBADCOOKIE);
1185 }
1186
1187 p = xdr_inline_decode(xdr, 4);
1188 if (unlikely(p == NULL))
1189 goto out_overflow;
1190 entry->ino = be32_to_cpup(p);
1191
1192 error = decode_filename_inline(xdr, &entry->name, &entry->len);
1193 if (unlikely(error))
1194 return ERR_PTR(error);
1195
1196 /*
1197 * The type (size and byte order) of nfscookie isn't defined in
1198 * RFC 1094. This implementation assumes that it's an XDR uint32.
1199 */
1200 entry->prev_cookie = entry->cookie;
1201 p = xdr_inline_decode(xdr, 4);
1202 if (unlikely(p == NULL))
1203 goto out_overflow;
1204 entry->cookie = be32_to_cpup(p);
1205
1206 entry->d_type = DT_UNKNOWN;
1207
1208 /* Peek at the next entry to see if we're at EOD */
1209 p = xdr_inline_peek(xdr, 4 + 4);
1210 entry->eof = 0;
1211 if (p != NULL)
1212 entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
1213 return p;
1214
1215out_overflow:
1216 print_overflow_msg(__func__, xdr);
1217 return ERR_PTR(-EAGAIN);
1218}
1219
1220/*
1221 * 2.2.17. readdirres
1222 *
1223 * union readdirres switch (stat status) {
1224 * case NFS_OK:
1225 * struct {
1226 * entry *entries;
1227 * bool eof;
1228 * } readdirok;
1229 * default:
1230 * void;
1231 * };
1232 *
1233 * Read the directory contents into the page cache, but don't
1234 * touch them. The actual decoding is done by nfs2_decode_dirent()
1235 * during subsequent nfs_readdir() calls.
1236 */
1237static int decode_readdirok(struct xdr_stream *xdr)
1238{
1239 u32 recvd, pglen;
1240 size_t hdrlen;
1241
1242 pglen = xdr->buf->page_len;
1243 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
1244 recvd = xdr->buf->len - hdrlen;
1245 if (unlikely(pglen > recvd))
1246 goto out_cheating;
1247out:
1248 xdr_read_pages(xdr, pglen);
1249 return pglen;
1250out_cheating:
1251 dprintk("NFS: server cheating in readdir result: "
1252 "pglen %u > recvd %u\n", pglen, recvd);
1253 pglen = recvd;
1254 goto out;
1255}
1256
1257static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, __be32 *p,
1258 void *__unused)
1259{
1260 struct xdr_stream xdr;
1261 enum nfs_stat status;
1262 int error;
1263
1264 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1265 error = decode_stat(&xdr, &status);
1266 if (unlikely(error))
1267 goto out;
1268 if (status != NFS_OK)
1269 goto out_default;
1270 error = decode_readdirok(&xdr);
1271out:
1272 return error;
1273out_default:
1274 return nfs_stat_to_errno(status);
1275}
1276
784/* 1277/*
785 * Decode STATFS reply 1278 * Decode STATFS reply
786 */ 1279 */
@@ -801,6 +1294,61 @@ nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
801} 1294}
802 1295
803/* 1296/*
1297 * 2.2.18. statfsres
1298 *
1299 * union statfsres (stat status) {
1300 * case NFS_OK:
1301 * struct {
1302 * unsigned tsize;
1303 * unsigned bsize;
1304 * unsigned blocks;
1305 * unsigned bfree;
1306 * unsigned bavail;
1307 * } info;
1308 * default:
1309 * void;
1310 * };
1311 */
1312static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
1313{
1314 __be32 *p;
1315
1316 p = xdr_inline_decode(xdr, NFS_info_sz << 2);
1317 if (unlikely(p == NULL))
1318 goto out_overflow;
1319 result->tsize = be32_to_cpup(p++);
1320 result->bsize = be32_to_cpup(p++);
1321 result->blocks = be32_to_cpup(p++);
1322 result->bfree = be32_to_cpup(p++);
1323 result->bavail = be32_to_cpup(p);
1324 return 0;
1325out_overflow:
1326 print_overflow_msg(__func__, xdr);
1327 return -EIO;
1328}
1329
1330static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, __be32 *p,
1331 struct nfs2_fsstat *result)
1332{
1333 struct xdr_stream xdr;
1334 enum nfs_stat status;
1335 int error;
1336
1337 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1338 error = decode_stat(&xdr, &status);
1339 if (unlikely(error))
1340 goto out;
1341 if (status != NFS_OK)
1342 goto out_default;
1343 error = decode_info(&xdr, result);
1344out:
1345 return error;
1346out_default:
1347 return nfs_stat_to_errno(status);
1348}
1349
1350
1351/*
804 * We need to translate between nfs status return values and 1352 * We need to translate between nfs status return values and
805 * the local errno values which may not be the same. 1353 * the local errno values which may not be the same.
806 */ 1354 */
@@ -867,7 +1415,7 @@ int nfs_stat_to_errno(enum nfs_stat status)
867[NFSPROC_##proc] = { \ 1415[NFSPROC_##proc] = { \
868 .p_proc = NFSPROC_##proc, \ 1416 .p_proc = NFSPROC_##proc, \
869 .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \ 1417 .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \
870 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \ 1418 .p_decode = (kxdrproc_t)nfs2_xdr_dec_##restype, \
871 .p_arglen = NFS_##argtype##_sz, \ 1419 .p_arglen = NFS_##argtype##_sz, \
872 .p_replen = NFS_##restype##_sz, \ 1420 .p_replen = NFS_##restype##_sz, \
873 .p_timer = timer, \ 1421 .p_timer = timer, \
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 58e7f84fc1fd..00df60523aac 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -731,7 +731,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
731 .statfs = nfs_proc_statfs, 731 .statfs = nfs_proc_statfs,
732 .fsinfo = nfs_proc_fsinfo, 732 .fsinfo = nfs_proc_fsinfo,
733 .pathconf = nfs_proc_pathconf, 733 .pathconf = nfs_proc_pathconf,
734 .decode_dirent = nfs_decode_dirent, 734 .decode_dirent = nfs2_decode_dirent,
735 .read_setup = nfs_proc_read_setup, 735 .read_setup = nfs_proc_read_setup,
736 .read_done = nfs_read_done, 736 .read_done = nfs_read_done,
737 .write_setup = nfs_proc_write_setup, 737 .write_setup = nfs_proc_write_setup,