]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/fs/nfs/nfs2xdr.c | |
3 | * | |
4 | * XDR functions to encode/decode NFS RPC arguments and results. | |
5 | * | |
6 | * Copyright (C) 1992, 1993, 1994 Rick Sladkey | |
7 | * Copyright (C) 1996 Olaf Kirch | |
8 | * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu> | |
9 | * FIFO's need special handling in NFSv2 | |
10 | */ | |
11 | ||
12 | #include <linux/param.h> | |
13 | #include <linux/time.h> | |
14 | #include <linux/mm.h> | |
1da177e4 LT |
15 | #include <linux/errno.h> |
16 | #include <linux/string.h> | |
17 | #include <linux/in.h> | |
18 | #include <linux/pagemap.h> | |
19 | #include <linux/proc_fs.h> | |
20 | #include <linux/sunrpc/clnt.h> | |
21 | #include <linux/nfs.h> | |
22 | #include <linux/nfs2.h> | |
23 | #include <linux/nfs_fs.h> | |
816724e6 | 24 | #include "internal.h" |
1da177e4 LT |
25 | |
26 | #define NFSDBG_FACILITY NFSDBG_XDR | |
1da177e4 | 27 | |
1da177e4 LT |
28 | /* Mapping from NFS error code to "errno" error code. */ |
29 | #define errno_NFSERR_IO EIO | |
30 | ||
31 | /* | |
32 | * Declare the space requirements for NFS arguments and replies as | |
33 | * number of 32bit-words | |
34 | */ | |
35 | #define NFS_fhandle_sz (8) | |
36 | #define NFS_sattr_sz (8) | |
37 | #define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2)) | |
38 | #define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2)) | |
39 | #define NFS_fattr_sz (17) | |
40 | #define NFS_info_sz (5) | |
41 | #define NFS_entry_sz (NFS_filename_sz+3) | |
42 | ||
43 | #define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz) | |
4fdc17b2 | 44 | #define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz) |
1da177e4 LT |
45 | #define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz) |
46 | #define NFS_readlinkargs_sz (NFS_fhandle_sz) | |
47 | #define NFS_readargs_sz (NFS_fhandle_sz+3) | |
48 | #define NFS_writeargs_sz (NFS_fhandle_sz+4) | |
49 | #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) | |
50 | #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) | |
51 | #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) | |
94a6d753 | 52 | #define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz) |
1da177e4 LT |
53 | #define NFS_readdirargs_sz (NFS_fhandle_sz+2) |
54 | ||
55 | #define NFS_attrstat_sz (1+NFS_fattr_sz) | |
56 | #define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz) | |
57 | #define NFS_readlinkres_sz (2) | |
58 | #define NFS_readres_sz (1+NFS_fattr_sz+1) | |
59 | #define NFS_writeres_sz (NFS_attrstat_sz) | |
60 | #define NFS_stat_sz (1) | |
61 | #define NFS_readdirres_sz (1) | |
62 | #define NFS_statfsres_sz (1+NFS_info_sz) | |
63 | ||
25a0866c CL |
64 | |
65 | /* | |
66 | * While encoding arguments, set up the reply buffer in advance to | |
67 | * receive reply data directly into the page cache. | |
68 | */ | |
69 | static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages, | |
70 | unsigned int base, unsigned int len, | |
71 | unsigned int bufsize) | |
72 | { | |
73 | struct rpc_auth *auth = req->rq_cred->cr_auth; | |
74 | unsigned int replen; | |
75 | ||
76 | replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize; | |
77 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len); | |
78 | } | |
79 | ||
f796f8b3 CL |
80 | /* |
81 | * Handle decode buffer overflows out-of-line. | |
82 | */ | |
83 | static 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 | ||
25a0866c | 90 | |
1da177e4 LT |
91 | /* |
92 | * Common NFS XDR functions as inlines | |
93 | */ | |
9d787a75 AV |
94 | static inline __be32* |
95 | xdr_decode_time(__be32 *p, struct timespec *timep) | |
1da177e4 LT |
96 | { |
97 | timep->tv_sec = ntohl(*p++); | |
98 | /* Convert microseconds into nanoseconds */ | |
99 | timep->tv_nsec = ntohl(*p++) * 1000; | |
100 | return p; | |
101 | } | |
102 | ||
9d787a75 AV |
103 | static __be32 * |
104 | xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) | |
1da177e4 | 105 | { |
bca79478 TM |
106 | u32 rdev, type; |
107 | type = ntohl(*p++); | |
1da177e4 LT |
108 | fattr->mode = ntohl(*p++); |
109 | fattr->nlink = ntohl(*p++); | |
110 | fattr->uid = ntohl(*p++); | |
111 | fattr->gid = ntohl(*p++); | |
112 | fattr->size = ntohl(*p++); | |
113 | fattr->du.nfs2.blocksize = ntohl(*p++); | |
114 | rdev = ntohl(*p++); | |
115 | fattr->du.nfs2.blocks = ntohl(*p++); | |
8b4bdcf8 TM |
116 | fattr->fsid.major = ntohl(*p++); |
117 | fattr->fsid.minor = 0; | |
1da177e4 LT |
118 | fattr->fileid = ntohl(*p++); |
119 | p = xdr_decode_time(p, &fattr->atime); | |
120 | p = xdr_decode_time(p, &fattr->mtime); | |
121 | p = xdr_decode_time(p, &fattr->ctime); | |
9e6e70f8 | 122 | fattr->valid |= NFS_ATTR_FATTR_V2; |
1da177e4 | 123 | fattr->rdev = new_decode_dev(rdev); |
bca79478 | 124 | if (type == NFCHR && rdev == NFS2_FIFO_DEV) { |
1da177e4 LT |
125 | fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; |
126 | fattr->rdev = 0; | |
127 | } | |
1da177e4 LT |
128 | return p; |
129 | } | |
130 | ||
25a0866c CL |
131 | /* |
132 | * Encode/decode NFSv2 basic data types | |
133 | * | |
134 | * Basic NFSv2 data types are defined in section 2.3 of RFC 1094: | |
135 | * "NFS: Network File System Protocol Specification". | |
136 | * | |
137 | * Not all basic data types have their own encoding and decoding | |
138 | * functions. For run-time efficiency, some data types are encoded | |
139 | * or decoded inline. | |
140 | */ | |
141 | ||
f796f8b3 CL |
142 | /* |
143 | * typedef opaque nfsdata<>; | |
144 | */ | |
145 | static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result) | |
146 | { | |
147 | u32 recvd, count; | |
148 | size_t hdrlen; | |
149 | __be32 *p; | |
150 | ||
151 | p = xdr_inline_decode(xdr, 4); | |
152 | if (unlikely(p == NULL)) | |
153 | goto out_overflow; | |
154 | count = be32_to_cpup(p); | |
155 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | |
156 | recvd = xdr->buf->len - hdrlen; | |
157 | if (unlikely(count > recvd)) | |
158 | goto out_cheating; | |
159 | out: | |
160 | xdr_read_pages(xdr, count); | |
161 | result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */ | |
162 | result->count = count; | |
163 | return count; | |
164 | out_cheating: | |
165 | dprintk("NFS: server cheating in read result: " | |
166 | "count %u > recvd %u\n", count, recvd); | |
167 | count = recvd; | |
168 | goto out; | |
169 | out_overflow: | |
170 | print_overflow_msg(__func__, xdr); | |
171 | return -EIO; | |
172 | } | |
173 | ||
174 | /* | |
175 | * enum stat { | |
176 | * NFS_OK = 0, | |
177 | * NFSERR_PERM = 1, | |
178 | * NFSERR_NOENT = 2, | |
179 | * NFSERR_IO = 5, | |
180 | * NFSERR_NXIO = 6, | |
181 | * NFSERR_ACCES = 13, | |
182 | * NFSERR_EXIST = 17, | |
183 | * NFSERR_NODEV = 19, | |
184 | * NFSERR_NOTDIR = 20, | |
185 | * NFSERR_ISDIR = 21, | |
186 | * NFSERR_FBIG = 27, | |
187 | * NFSERR_NOSPC = 28, | |
188 | * NFSERR_ROFS = 30, | |
189 | * NFSERR_NAMETOOLONG = 63, | |
190 | * NFSERR_NOTEMPTY = 66, | |
191 | * NFSERR_DQUOT = 69, | |
192 | * NFSERR_STALE = 70, | |
193 | * NFSERR_WFLUSH = 99 | |
194 | * }; | |
195 | */ | |
196 | static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status) | |
197 | { | |
198 | __be32 *p; | |
199 | ||
200 | p = xdr_inline_decode(xdr, 4); | |
201 | if (unlikely(p == NULL)) | |
202 | goto out_overflow; | |
203 | *status = be32_to_cpup(p); | |
204 | return 0; | |
205 | out_overflow: | |
206 | print_overflow_msg(__func__, xdr); | |
207 | return -EIO; | |
208 | } | |
209 | ||
25a0866c CL |
210 | /* |
211 | * 2.3.3. fhandle | |
212 | * | |
213 | * typedef opaque fhandle[FHSIZE]; | |
214 | */ | |
215 | static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh) | |
216 | { | |
217 | __be32 *p; | |
218 | ||
219 | BUG_ON(fh->size != NFS2_FHSIZE); | |
220 | p = xdr_reserve_space(xdr, NFS2_FHSIZE); | |
221 | memcpy(p, fh->data, NFS2_FHSIZE); | |
222 | } | |
223 | ||
f796f8b3 CL |
224 | static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) |
225 | { | |
226 | __be32 *p; | |
227 | ||
228 | p = xdr_inline_decode(xdr, NFS2_FHSIZE); | |
229 | if (unlikely(p == NULL)) | |
230 | goto out_overflow; | |
231 | fh->size = NFS2_FHSIZE; | |
232 | memcpy(fh->data, p, NFS2_FHSIZE); | |
233 | return 0; | |
234 | out_overflow: | |
235 | print_overflow_msg(__func__, xdr); | |
236 | return -EIO; | |
237 | } | |
238 | ||
282ac2a5 CL |
239 | /* |
240 | * 2.3.4. timeval | |
241 | * | |
242 | * struct timeval { | |
243 | * unsigned int seconds; | |
244 | * unsigned int useconds; | |
245 | * }; | |
246 | */ | |
247 | static __be32 *xdr_encode_time(__be32 *p, const struct timespec *timep) | |
248 | { | |
249 | *p++ = cpu_to_be32(timep->tv_sec); | |
250 | if (timep->tv_nsec != 0) | |
251 | *p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC); | |
252 | else | |
253 | *p++ = cpu_to_be32(0); | |
254 | return p; | |
255 | } | |
256 | ||
257 | /* | |
258 | * Passing the invalid value useconds=1000000 is a Sun convention for | |
259 | * "set to current server time". It's needed to make permissions checks | |
260 | * for the "touch" program across v2 mounts to Solaris and Irix servers | |
261 | * work correctly. See description of sattr in section 6.1 of "NFS | |
262 | * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5. | |
263 | */ | |
264 | static __be32 *xdr_encode_current_server_time(__be32 *p, | |
265 | const struct timespec *timep) | |
266 | { | |
267 | *p++ = cpu_to_be32(timep->tv_sec); | |
268 | *p++ = cpu_to_be32(1000000); | |
269 | return p; | |
270 | } | |
271 | ||
f796f8b3 CL |
272 | /* |
273 | * 2.3.5. fattr | |
274 | * | |
275 | * struct fattr { | |
276 | * ftype type; | |
277 | * unsigned int mode; | |
278 | * unsigned int nlink; | |
279 | * unsigned int uid; | |
280 | * unsigned int gid; | |
281 | * unsigned int size; | |
282 | * unsigned int blocksize; | |
283 | * unsigned int rdev; | |
284 | * unsigned int blocks; | |
285 | * unsigned int fsid; | |
286 | * unsigned int fileid; | |
287 | * timeval atime; | |
288 | * timeval mtime; | |
289 | * timeval ctime; | |
290 | * }; | |
291 | * | |
292 | */ | |
293 | static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr) | |
294 | { | |
295 | __be32 *p; | |
296 | ||
297 | p = xdr_inline_decode(xdr, NFS_fattr_sz << 2); | |
298 | if (unlikely(p == NULL)) | |
299 | goto out_overflow; | |
300 | xdr_decode_fattr(p, fattr); | |
301 | return 0; | |
302 | out_overflow: | |
303 | print_overflow_msg(__func__, xdr); | |
304 | return -EIO; | |
305 | } | |
306 | ||
25a0866c CL |
307 | /* |
308 | * 2.3.6. sattr | |
309 | * | |
310 | * struct sattr { | |
311 | * unsigned int mode; | |
312 | * unsigned int uid; | |
313 | * unsigned int gid; | |
314 | * unsigned int size; | |
315 | * timeval atime; | |
316 | * timeval mtime; | |
317 | * }; | |
318 | */ | |
319 | ||
320 | #define NFS2_SATTR_NOT_SET (0xffffffff) | |
321 | ||
322 | static __be32 *xdr_time_not_set(__be32 *p) | |
323 | { | |
324 | *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); | |
325 | *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); | |
326 | return p; | |
327 | } | |
328 | ||
329 | static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr) | |
330 | { | |
331 | __be32 *p; | |
332 | ||
333 | p = xdr_reserve_space(xdr, NFS_sattr_sz << 2); | |
334 | ||
335 | if (attr->ia_valid & ATTR_MODE) | |
336 | *p++ = cpu_to_be32(attr->ia_mode); | |
337 | else | |
338 | *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); | |
339 | if (attr->ia_valid & ATTR_UID) | |
340 | *p++ = cpu_to_be32(attr->ia_uid); | |
341 | else | |
342 | *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); | |
343 | if (attr->ia_valid & ATTR_GID) | |
344 | *p++ = cpu_to_be32(attr->ia_gid); | |
345 | else | |
346 | *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); | |
347 | if (attr->ia_valid & ATTR_SIZE) | |
348 | *p++ = cpu_to_be32((u32)attr->ia_size); | |
349 | else | |
350 | *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET); | |
351 | ||
352 | if (attr->ia_valid & ATTR_ATIME_SET) | |
353 | p = xdr_encode_time(p, &attr->ia_atime); | |
354 | else if (attr->ia_valid & ATTR_ATIME) | |
355 | p = xdr_encode_current_server_time(p, &attr->ia_atime); | |
356 | else | |
357 | p = xdr_time_not_set(p); | |
358 | if (attr->ia_valid & ATTR_MTIME_SET) | |
359 | xdr_encode_time(p, &attr->ia_mtime); | |
360 | else if (attr->ia_valid & ATTR_MTIME) | |
361 | xdr_encode_current_server_time(p, &attr->ia_mtime); | |
362 | else | |
363 | xdr_time_not_set(p); | |
364 | } | |
365 | ||
366 | /* | |
367 | * 2.3.7. filename | |
368 | * | |
369 | * typedef string filename<MAXNAMLEN>; | |
370 | */ | |
371 | static void encode_filename(struct xdr_stream *xdr, | |
372 | const char *name, u32 length) | |
373 | { | |
374 | __be32 *p; | |
375 | ||
376 | BUG_ON(length > NFS2_MAXNAMLEN); | |
377 | p = xdr_reserve_space(xdr, 4 + length); | |
378 | xdr_encode_opaque(p, name, length); | |
379 | } | |
380 | ||
f796f8b3 CL |
381 | static int decode_filename_inline(struct xdr_stream *xdr, |
382 | const char **name, u32 *length) | |
383 | { | |
384 | __be32 *p; | |
385 | u32 count; | |
386 | ||
387 | p = xdr_inline_decode(xdr, 4); | |
388 | if (unlikely(p == NULL)) | |
389 | goto out_overflow; | |
390 | count = be32_to_cpup(p); | |
391 | if (count > NFS3_MAXNAMLEN) | |
392 | goto out_nametoolong; | |
393 | p = xdr_inline_decode(xdr, count); | |
394 | if (unlikely(p == NULL)) | |
395 | goto out_overflow; | |
396 | *name = (const char *)p; | |
397 | *length = count; | |
398 | return 0; | |
399 | out_nametoolong: | |
400 | dprintk("NFS: returned filename too long: %u\n", count); | |
401 | return -ENAMETOOLONG; | |
402 | out_overflow: | |
403 | print_overflow_msg(__func__, xdr); | |
404 | return -EIO; | |
405 | } | |
406 | ||
25a0866c CL |
407 | /* |
408 | * 2.3.8. path | |
409 | * | |
410 | * typedef string path<MAXPATHLEN>; | |
411 | */ | |
412 | static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length) | |
413 | { | |
414 | __be32 *p; | |
415 | ||
416 | BUG_ON(length > NFS2_MAXPATHLEN); | |
417 | p = xdr_reserve_space(xdr, 4); | |
418 | *p = cpu_to_be32(length); | |
419 | xdr_write_pages(xdr, pages, 0, length); | |
420 | } | |
421 | ||
f796f8b3 CL |
422 | static int decode_path(struct xdr_stream *xdr) |
423 | { | |
424 | u32 length, recvd; | |
425 | size_t hdrlen; | |
426 | __be32 *p; | |
427 | ||
428 | p = xdr_inline_decode(xdr, 4); | |
429 | if (unlikely(p == NULL)) | |
430 | goto out_overflow; | |
431 | length = be32_to_cpup(p); | |
432 | if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN)) | |
433 | goto out_size; | |
434 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | |
435 | recvd = xdr->buf->len - hdrlen; | |
436 | if (unlikely(length > recvd)) | |
437 | goto out_cheating; | |
438 | ||
439 | xdr_read_pages(xdr, length); | |
440 | xdr_terminate_string(xdr->buf, length); | |
441 | return 0; | |
442 | out_size: | |
443 | dprintk("NFS: returned pathname too long: %u\n", length); | |
444 | return -ENAMETOOLONG; | |
445 | out_cheating: | |
446 | dprintk("NFS: server cheating in pathname result: " | |
447 | "length %u > received %u\n", length, recvd); | |
448 | return -EIO; | |
449 | out_overflow: | |
450 | print_overflow_msg(__func__, xdr); | |
451 | return -EIO; | |
452 | } | |
453 | ||
454 | /* | |
455 | * 2.3.9. attrstat | |
456 | * | |
457 | * union attrstat switch (stat status) { | |
458 | * case NFS_OK: | |
459 | * fattr attributes; | |
460 | * default: | |
461 | * void; | |
462 | * }; | |
463 | */ | |
464 | static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result) | |
465 | { | |
466 | enum nfs_stat status; | |
467 | int error; | |
468 | ||
469 | error = decode_stat(xdr, &status); | |
470 | if (unlikely(error)) | |
471 | goto out; | |
472 | if (status != NFS_OK) | |
473 | goto out_default; | |
474 | error = decode_fattr(xdr, result); | |
475 | out: | |
476 | return error; | |
477 | out_default: | |
478 | return nfs_stat_to_errno(status); | |
479 | } | |
480 | ||
25a0866c CL |
481 | /* |
482 | * 2.3.10. diropargs | |
483 | * | |
484 | * struct diropargs { | |
485 | * fhandle dir; | |
486 | * filename name; | |
487 | * }; | |
488 | */ | |
489 | static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh, | |
490 | const char *name, u32 length) | |
491 | { | |
492 | encode_fhandle(xdr, fh); | |
493 | encode_filename(xdr, name, length); | |
494 | } | |
495 | ||
f796f8b3 CL |
496 | /* |
497 | * 2.3.11. diropres | |
498 | * | |
499 | * union diropres switch (stat status) { | |
500 | * case NFS_OK: | |
501 | * struct { | |
502 | * fhandle file; | |
503 | * fattr attributes; | |
504 | * } diropok; | |
505 | * default: | |
506 | * void; | |
507 | * }; | |
508 | */ | |
509 | static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result) | |
510 | { | |
511 | int error; | |
512 | ||
513 | error = decode_fhandle(xdr, result->fh); | |
514 | if (unlikely(error)) | |
515 | goto out; | |
516 | error = decode_fattr(xdr, result->fattr); | |
517 | out: | |
518 | return error; | |
519 | } | |
520 | ||
521 | static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result) | |
522 | { | |
523 | enum nfs_stat status; | |
524 | int error; | |
525 | ||
526 | error = decode_stat(xdr, &status); | |
527 | if (unlikely(error)) | |
528 | goto out; | |
529 | if (status != NFS_OK) | |
530 | goto out_default; | |
531 | error = decode_diropok(xdr, result); | |
532 | out: | |
533 | return error; | |
534 | out_default: | |
535 | return nfs_stat_to_errno(status); | |
536 | } | |
537 | ||
25a0866c | 538 | |
1da177e4 | 539 | /* |
2d70f533 CL |
540 | * NFSv2 XDR encode functions |
541 | * | |
542 | * NFSv2 argument types are defined in section 2.2 of RFC 1094: | |
543 | * "NFS: Network File System Protocol Specification". | |
1da177e4 | 544 | */ |
1da177e4 | 545 | |
25a0866c CL |
546 | static int nfs2_xdr_enc_fhandle(struct rpc_rqst *req, __be32 *p, |
547 | const struct nfs_fh *fh) | |
548 | { | |
549 | struct xdr_stream xdr; | |
550 | ||
551 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
552 | encode_fhandle(&xdr, fh); | |
553 | return 0; | |
554 | } | |
555 | ||
25a0866c CL |
556 | /* |
557 | * 2.2.3. sattrargs | |
558 | * | |
559 | * struct sattrargs { | |
560 | * fhandle file; | |
561 | * sattr attributes; | |
562 | * }; | |
563 | */ | |
564 | static int nfs2_xdr_enc_sattrargs(struct rpc_rqst *req, __be32 *p, | |
565 | const struct nfs_sattrargs *args) | |
566 | { | |
567 | struct xdr_stream xdr; | |
568 | ||
569 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
570 | encode_fhandle(&xdr, args->fh); | |
571 | encode_sattr(&xdr, args->sattr); | |
572 | return 0; | |
573 | } | |
574 | ||
25a0866c CL |
575 | static int nfs2_xdr_enc_diropargs(struct rpc_rqst *req, __be32 *p, |
576 | const struct nfs_diropargs *args) | |
577 | { | |
578 | struct xdr_stream xdr; | |
579 | ||
580 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
581 | encode_diropargs(&xdr, args->fh, args->name, args->len); | |
582 | return 0; | |
583 | } | |
584 | ||
25a0866c CL |
585 | static int nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, __be32 *p, |
586 | const struct nfs_readlinkargs *args) | |
587 | { | |
588 | struct xdr_stream xdr; | |
589 | ||
590 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
591 | encode_fhandle(&xdr, args->fh); | |
592 | prepare_reply_buffer(req, args->pages, args->pgbase, | |
593 | args->pglen, NFS_readlinkres_sz); | |
594 | return 0; | |
595 | } | |
596 | ||
25a0866c CL |
597 | /* |
598 | * 2.2.7. readargs | |
599 | * | |
600 | * struct readargs { | |
601 | * fhandle file; | |
602 | * unsigned offset; | |
603 | * unsigned count; | |
604 | * unsigned totalcount; | |
605 | * }; | |
606 | */ | |
607 | static void encode_readargs(struct xdr_stream *xdr, | |
608 | const struct nfs_readargs *args) | |
609 | { | |
610 | u32 offset = args->offset; | |
611 | u32 count = args->count; | |
612 | __be32 *p; | |
613 | ||
614 | encode_fhandle(xdr, args->fh); | |
615 | ||
616 | p = xdr_reserve_space(xdr, 4 + 4 + 4); | |
617 | *p++ = cpu_to_be32(offset); | |
618 | *p++ = cpu_to_be32(count); | |
619 | *p = cpu_to_be32(count); | |
620 | } | |
621 | ||
622 | static int nfs2_xdr_enc_readargs(struct rpc_rqst *req, __be32 *p, | |
623 | const struct nfs_readargs *args) | |
624 | { | |
625 | struct xdr_stream xdr; | |
626 | ||
627 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
628 | encode_readargs(&xdr, args); | |
629 | prepare_reply_buffer(req, args->pages, args->pgbase, | |
630 | args->count, NFS_readres_sz); | |
631 | req->rq_rcv_buf.flags |= XDRBUF_READ; | |
632 | return 0; | |
633 | } | |
634 | ||
25a0866c CL |
635 | /* |
636 | * 2.2.9. writeargs | |
637 | * | |
638 | * struct writeargs { | |
639 | * fhandle file; | |
640 | * unsigned beginoffset; | |
641 | * unsigned offset; | |
642 | * unsigned totalcount; | |
643 | * nfsdata data; | |
644 | * }; | |
645 | */ | |
646 | static void encode_writeargs(struct xdr_stream *xdr, | |
647 | const struct nfs_writeargs *args) | |
648 | { | |
649 | u32 offset = args->offset; | |
650 | u32 count = args->count; | |
651 | __be32 *p; | |
652 | ||
653 | encode_fhandle(xdr, args->fh); | |
654 | ||
655 | p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4); | |
656 | *p++ = cpu_to_be32(offset); | |
657 | *p++ = cpu_to_be32(offset); | |
658 | *p++ = cpu_to_be32(count); | |
659 | ||
660 | /* nfsdata */ | |
661 | *p = cpu_to_be32(count); | |
662 | xdr_write_pages(xdr, args->pages, args->pgbase, count); | |
663 | } | |
664 | ||
665 | static int nfs2_xdr_enc_writeargs(struct rpc_rqst *req, __be32 *p, | |
666 | const struct nfs_writeargs *args) | |
667 | { | |
668 | struct xdr_stream xdr; | |
669 | ||
670 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
671 | encode_writeargs(&xdr, args); | |
672 | xdr.buf->flags |= XDRBUF_WRITE; | |
673 | return 0; | |
674 | } | |
675 | ||
25a0866c CL |
676 | /* |
677 | * 2.2.10. createargs | |
678 | * | |
679 | * struct createargs { | |
680 | * diropargs where; | |
681 | * sattr attributes; | |
682 | * }; | |
683 | */ | |
684 | static int nfs2_xdr_enc_createargs(struct rpc_rqst *req, __be32 *p, | |
685 | const struct nfs_createargs *args) | |
686 | { | |
687 | struct xdr_stream xdr; | |
688 | ||
689 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
690 | encode_diropargs(&xdr, args->fh, args->name, args->len); | |
691 | encode_sattr(&xdr, args->sattr); | |
692 | return 0; | |
693 | } | |
694 | ||
695 | static int nfs2_xdr_enc_removeargs(struct rpc_rqst *req, __be32 *p, | |
696 | const struct nfs_removeargs *args) | |
697 | { | |
698 | struct xdr_stream xdr; | |
699 | ||
700 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
701 | encode_diropargs(&xdr, args->fh, args->name.name, args->name.len); | |
702 | return 0; | |
703 | } | |
704 | ||
25a0866c CL |
705 | /* |
706 | * 2.2.12. renameargs | |
707 | * | |
708 | * struct renameargs { | |
709 | * diropargs from; | |
710 | * diropargs to; | |
711 | * }; | |
712 | */ | |
713 | static int nfs2_xdr_enc_renameargs(struct rpc_rqst *req, __be32 *p, | |
714 | const struct nfs_renameargs *args) | |
715 | { | |
716 | const struct qstr *old = args->old_name; | |
717 | const struct qstr *new = args->new_name; | |
718 | struct xdr_stream xdr; | |
719 | ||
720 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
721 | encode_diropargs(&xdr, args->old_dir, old->name, old->len); | |
722 | encode_diropargs(&xdr, args->new_dir, new->name, new->len); | |
723 | return 0; | |
724 | } | |
725 | ||
25a0866c CL |
726 | /* |
727 | * 2.2.13. linkargs | |
728 | * | |
729 | * struct linkargs { | |
730 | * fhandle from; | |
731 | * diropargs to; | |
732 | * }; | |
733 | */ | |
734 | static int nfs2_xdr_enc_linkargs(struct rpc_rqst *req, __be32 *p, | |
735 | const struct nfs_linkargs *args) | |
736 | { | |
737 | struct xdr_stream xdr; | |
738 | ||
739 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
740 | encode_fhandle(&xdr, args->fromfh); | |
741 | encode_diropargs(&xdr, args->tofh, args->toname, args->tolen); | |
742 | return 0; | |
743 | } | |
744 | ||
25a0866c CL |
745 | /* |
746 | * 2.2.14. symlinkargs | |
747 | * | |
748 | * struct symlinkargs { | |
749 | * diropargs from; | |
750 | * path to; | |
751 | * sattr attributes; | |
752 | * }; | |
753 | */ | |
754 | static int nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req, __be32 *p, | |
755 | const struct nfs_symlinkargs *args) | |
756 | { | |
757 | struct xdr_stream xdr; | |
758 | ||
759 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
760 | encode_diropargs(&xdr, args->fromfh, args->fromname, args->fromlen); | |
761 | encode_path(&xdr, args->pages, args->pathlen); | |
762 | encode_sattr(&xdr, args->sattr); | |
763 | return 0; | |
764 | } | |
765 | ||
25a0866c CL |
766 | /* |
767 | * 2.2.17. readdirargs | |
768 | * | |
769 | * struct readdirargs { | |
770 | * fhandle dir; | |
771 | * nfscookie cookie; | |
772 | * unsigned count; | |
773 | * }; | |
774 | */ | |
775 | static void encode_readdirargs(struct xdr_stream *xdr, | |
776 | const struct nfs_readdirargs *args) | |
777 | { | |
778 | __be32 *p; | |
779 | ||
780 | encode_fhandle(xdr, args->fh); | |
781 | ||
782 | p = xdr_reserve_space(xdr, 4 + 4); | |
783 | *p++ = cpu_to_be32(args->cookie); | |
784 | *p = cpu_to_be32(args->count); | |
785 | } | |
786 | ||
787 | static int nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, __be32 *p, | |
788 | const struct nfs_readdirargs *args) | |
789 | { | |
790 | struct xdr_stream xdr; | |
791 | ||
792 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | |
793 | encode_readdirargs(&xdr, args); | |
794 | prepare_reply_buffer(req, args->pages, 0, | |
795 | args->count, NFS_readdirres_sz); | |
796 | return 0; | |
797 | } | |
798 | ||
1da177e4 | 799 | /* |
661ad423 CL |
800 | * NFSv2 XDR decode functions |
801 | * | |
802 | * NFSv2 result types are defined in section 2.2 of RFC 1094: | |
803 | * "NFS: Network File System Protocol Specification". | |
1da177e4 | 804 | */ |
1da177e4 | 805 | |
f796f8b3 CL |
806 | static int nfs2_xdr_dec_stat(struct rpc_rqst *req, __be32 *p, |
807 | void *__unused) | |
808 | { | |
809 | struct xdr_stream xdr; | |
810 | enum nfs_stat status; | |
811 | int error; | |
812 | ||
813 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | |
814 | error = decode_stat(&xdr, &status); | |
815 | if (unlikely(error)) | |
816 | goto out; | |
817 | if (status != NFS_OK) | |
818 | goto out_default; | |
819 | out: | |
820 | return error; | |
821 | out_default: | |
822 | return nfs_stat_to_errno(status); | |
823 | } | |
824 | ||
f796f8b3 CL |
825 | static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, __be32 *p, |
826 | struct nfs_fattr *result) | |
827 | { | |
828 | struct xdr_stream xdr; | |
829 | ||
830 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | |
831 | return decode_attrstat(&xdr, result); | |
832 | } | |
833 | ||
f796f8b3 CL |
834 | static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, __be32 *p, |
835 | struct nfs_diropok *result) | |
836 | { | |
837 | struct xdr_stream xdr; | |
838 | ||
839 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | |
840 | return decode_diropres(&xdr, result); | |
841 | } | |
842 | ||
f796f8b3 CL |
843 | /* |
844 | * 2.2.6. readlinkres | |
845 | * | |
846 | * union readlinkres switch (stat status) { | |
847 | * case NFS_OK: | |
848 | * path data; | |
849 | * default: | |
850 | * void; | |
851 | * }; | |
852 | */ | |
853 | static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req, __be32 *p, | |
854 | void *__unused) | |
855 | { | |
856 | struct xdr_stream xdr; | |
857 | enum nfs_stat status; | |
858 | int error; | |
859 | ||
860 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | |
861 | error = decode_stat(&xdr, &status); | |
862 | if (unlikely(error)) | |
863 | goto out; | |
864 | if (status != NFS_OK) | |
865 | goto out_default; | |
866 | error = decode_path(&xdr); | |
867 | out: | |
868 | return error; | |
869 | out_default: | |
870 | return nfs_stat_to_errno(status); | |
871 | } | |
872 | ||
873 | /* | |
874 | * 2.2.7. readres | |
875 | * | |
876 | * union readres switch (stat status) { | |
877 | * case NFS_OK: | |
878 | * fattr attributes; | |
879 | * nfsdata data; | |
880 | * default: | |
881 | * void; | |
882 | * }; | |
883 | */ | |
884 | static int nfs2_xdr_dec_readres(struct rpc_rqst *req, __be32 *p, | |
885 | struct nfs_readres *result) | |
886 | { | |
887 | struct xdr_stream xdr; | |
888 | enum nfs_stat status; | |
889 | int error; | |
890 | ||
891 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | |
892 | error = decode_stat(&xdr, &status); | |
893 | if (unlikely(error)) | |
894 | goto out; | |
895 | if (status != NFS_OK) | |
896 | goto out_default; | |
897 | error = decode_fattr(&xdr, result->fattr); | |
898 | if (unlikely(error)) | |
899 | goto out; | |
900 | error = decode_nfsdata(&xdr, result); | |
901 | out: | |
902 | return error; | |
903 | out_default: | |
904 | return nfs_stat_to_errno(status); | |
905 | } | |
906 | ||
f796f8b3 CL |
907 | static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, __be32 *p, |
908 | struct nfs_writeres *result) | |
909 | { | |
910 | struct xdr_stream xdr; | |
911 | ||
912 | /* All NFSv2 writes are "file sync" writes */ | |
913 | result->verf->committed = NFS_FILE_SYNC; | |
914 | ||
915 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | |
916 | return decode_attrstat(&xdr, result->fattr); | |
917 | } | |
918 | ||
919 | /** | |
920 | * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in | |
921 | * the local page cache. | |
922 | * @xdr: XDR stream where entry resides | |
923 | * @entry: buffer to fill in with entry data | |
924 | * @server: nfs_server data for this directory | |
925 | * @plus: boolean indicating whether this should be a readdirplus entry | |
926 | * | |
927 | * Returns the position of the next item in the buffer, or an ERR_PTR. | |
928 | * | |
929 | * This function is not invoked during READDIR reply decoding, but | |
930 | * rather whenever an application invokes the getdents(2) system call | |
931 | * on a directory already in our cache. | |
932 | * | |
933 | * 2.2.17. entry | |
934 | * | |
935 | * struct entry { | |
936 | * unsigned fileid; | |
937 | * filename name; | |
938 | * nfscookie cookie; | |
939 | * entry *nextentry; | |
940 | * }; | |
941 | */ | |
942 | __be32 *nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |
943 | struct nfs_server *server, int plus) | |
944 | { | |
945 | __be32 *p; | |
946 | int error; | |
947 | ||
948 | p = xdr_inline_decode(xdr, 4); | |
949 | if (unlikely(p == NULL)) | |
950 | goto out_overflow; | |
951 | if (*p++ == xdr_zero) { | |
952 | p = xdr_inline_decode(xdr, 4); | |
953 | if (unlikely(p == NULL)) | |
954 | goto out_overflow; | |
955 | if (*p++ == xdr_zero) | |
956 | return ERR_PTR(-EAGAIN); | |
957 | entry->eof = 1; | |
958 | return ERR_PTR(-EBADCOOKIE); | |
959 | } | |
960 | ||
961 | p = xdr_inline_decode(xdr, 4); | |
962 | if (unlikely(p == NULL)) | |
963 | goto out_overflow; | |
964 | entry->ino = be32_to_cpup(p); | |
965 | ||
966 | error = decode_filename_inline(xdr, &entry->name, &entry->len); | |
967 | if (unlikely(error)) | |
968 | return ERR_PTR(error); | |
969 | ||
970 | /* | |
971 | * The type (size and byte order) of nfscookie isn't defined in | |
972 | * RFC 1094. This implementation assumes that it's an XDR uint32. | |
973 | */ | |
974 | entry->prev_cookie = entry->cookie; | |
975 | p = xdr_inline_decode(xdr, 4); | |
976 | if (unlikely(p == NULL)) | |
977 | goto out_overflow; | |
978 | entry->cookie = be32_to_cpup(p); | |
979 | ||
980 | entry->d_type = DT_UNKNOWN; | |
981 | ||
982 | /* Peek at the next entry to see if we're at EOD */ | |
983 | p = xdr_inline_peek(xdr, 4 + 4); | |
984 | entry->eof = 0; | |
985 | if (p != NULL) | |
986 | entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero); | |
987 | return p; | |
988 | ||
989 | out_overflow: | |
990 | print_overflow_msg(__func__, xdr); | |
991 | return ERR_PTR(-EAGAIN); | |
992 | } | |
993 | ||
994 | /* | |
995 | * 2.2.17. readdirres | |
996 | * | |
997 | * union readdirres switch (stat status) { | |
998 | * case NFS_OK: | |
999 | * struct { | |
1000 | * entry *entries; | |
1001 | * bool eof; | |
1002 | * } readdirok; | |
1003 | * default: | |
1004 | * void; | |
1005 | * }; | |
1006 | * | |
1007 | * Read the directory contents into the page cache, but don't | |
1008 | * touch them. The actual decoding is done by nfs2_decode_dirent() | |
1009 | * during subsequent nfs_readdir() calls. | |
1010 | */ | |
1011 | static int decode_readdirok(struct xdr_stream *xdr) | |
1012 | { | |
1013 | u32 recvd, pglen; | |
1014 | size_t hdrlen; | |
1015 | ||
1016 | pglen = xdr->buf->page_len; | |
1017 | hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; | |
1018 | recvd = xdr->buf->len - hdrlen; | |
1019 | if (unlikely(pglen > recvd)) | |
1020 | goto out_cheating; | |
1021 | out: | |
1022 | xdr_read_pages(xdr, pglen); | |
1023 | return pglen; | |
1024 | out_cheating: | |
1025 | dprintk("NFS: server cheating in readdir result: " | |
1026 | "pglen %u > recvd %u\n", pglen, recvd); | |
1027 | pglen = recvd; | |
1028 | goto out; | |
1029 | } | |
1030 | ||
1031 | static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, __be32 *p, | |
1032 | void *__unused) | |
1033 | { | |
1034 | struct xdr_stream xdr; | |
1035 | enum nfs_stat status; | |
1036 | int error; | |
1037 | ||
1038 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | |
1039 | error = decode_stat(&xdr, &status); | |
1040 | if (unlikely(error)) | |
1041 | goto out; | |
1042 | if (status != NFS_OK) | |
1043 | goto out_default; | |
1044 | error = decode_readdirok(&xdr); | |
1045 | out: | |
1046 | return error; | |
1047 | out_default: | |
1048 | return nfs_stat_to_errno(status); | |
1049 | } | |
1050 | ||
f796f8b3 CL |
1051 | /* |
1052 | * 2.2.18. statfsres | |
1053 | * | |
1054 | * union statfsres (stat status) { | |
1055 | * case NFS_OK: | |
1056 | * struct { | |
1057 | * unsigned tsize; | |
1058 | * unsigned bsize; | |
1059 | * unsigned blocks; | |
1060 | * unsigned bfree; | |
1061 | * unsigned bavail; | |
1062 | * } info; | |
1063 | * default: | |
1064 | * void; | |
1065 | * }; | |
1066 | */ | |
1067 | static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result) | |
1068 | { | |
1069 | __be32 *p; | |
1070 | ||
1071 | p = xdr_inline_decode(xdr, NFS_info_sz << 2); | |
1072 | if (unlikely(p == NULL)) | |
1073 | goto out_overflow; | |
1074 | result->tsize = be32_to_cpup(p++); | |
1075 | result->bsize = be32_to_cpup(p++); | |
1076 | result->blocks = be32_to_cpup(p++); | |
1077 | result->bfree = be32_to_cpup(p++); | |
1078 | result->bavail = be32_to_cpup(p); | |
1079 | return 0; | |
1080 | out_overflow: | |
1081 | print_overflow_msg(__func__, xdr); | |
1082 | return -EIO; | |
1083 | } | |
1084 | ||
1085 | static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, __be32 *p, | |
1086 | struct nfs2_fsstat *result) | |
1087 | { | |
1088 | struct xdr_stream xdr; | |
1089 | enum nfs_stat status; | |
1090 | int error; | |
1091 | ||
1092 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | |
1093 | error = decode_stat(&xdr, &status); | |
1094 | if (unlikely(error)) | |
1095 | goto out; | |
1096 | if (status != NFS_OK) | |
1097 | goto out_default; | |
1098 | error = decode_info(&xdr, result); | |
1099 | out: | |
1100 | return error; | |
1101 | out_default: | |
1102 | return nfs_stat_to_errno(status); | |
1103 | } | |
1104 | ||
1105 | ||
1da177e4 LT |
1106 | /* |
1107 | * We need to translate between nfs status return values and | |
1108 | * the local errno values which may not be the same. | |
1109 | */ | |
85828493 | 1110 | static const struct { |
1da177e4 LT |
1111 | int stat; |
1112 | int errno; | |
1113 | } nfs_errtbl[] = { | |
1114 | { NFS_OK, 0 }, | |
856dff3d BH |
1115 | { NFSERR_PERM, -EPERM }, |
1116 | { NFSERR_NOENT, -ENOENT }, | |
1117 | { NFSERR_IO, -errno_NFSERR_IO}, | |
1118 | { NFSERR_NXIO, -ENXIO }, | |
1119 | /* { NFSERR_EAGAIN, -EAGAIN }, */ | |
1120 | { NFSERR_ACCES, -EACCES }, | |
1121 | { NFSERR_EXIST, -EEXIST }, | |
1122 | { NFSERR_XDEV, -EXDEV }, | |
1123 | { NFSERR_NODEV, -ENODEV }, | |
1124 | { NFSERR_NOTDIR, -ENOTDIR }, | |
1125 | { NFSERR_ISDIR, -EISDIR }, | |
1126 | { NFSERR_INVAL, -EINVAL }, | |
1127 | { NFSERR_FBIG, -EFBIG }, | |
1128 | { NFSERR_NOSPC, -ENOSPC }, | |
1129 | { NFSERR_ROFS, -EROFS }, | |
1130 | { NFSERR_MLINK, -EMLINK }, | |
1131 | { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, | |
1132 | { NFSERR_NOTEMPTY, -ENOTEMPTY }, | |
1133 | { NFSERR_DQUOT, -EDQUOT }, | |
1134 | { NFSERR_STALE, -ESTALE }, | |
1135 | { NFSERR_REMOTE, -EREMOTE }, | |
1da177e4 | 1136 | #ifdef EWFLUSH |
856dff3d | 1137 | { NFSERR_WFLUSH, -EWFLUSH }, |
1da177e4 | 1138 | #endif |
856dff3d BH |
1139 | { NFSERR_BADHANDLE, -EBADHANDLE }, |
1140 | { NFSERR_NOT_SYNC, -ENOTSYNC }, | |
1141 | { NFSERR_BAD_COOKIE, -EBADCOOKIE }, | |
1142 | { NFSERR_NOTSUPP, -ENOTSUPP }, | |
1143 | { NFSERR_TOOSMALL, -ETOOSMALL }, | |
fdcb4577 | 1144 | { NFSERR_SERVERFAULT, -EREMOTEIO }, |
856dff3d BH |
1145 | { NFSERR_BADTYPE, -EBADTYPE }, |
1146 | { NFSERR_JUKEBOX, -EJUKEBOX }, | |
1147 | { -1, -EIO } | |
1da177e4 LT |
1148 | }; |
1149 | ||
85828493 CL |
1150 | /** |
1151 | * nfs_stat_to_errno - convert an NFS status code to a local errno | |
1152 | * @status: NFS status code to convert | |
1153 | * | |
1154 | * Returns a local errno value, or -EIO if the NFS status code is | |
1155 | * not recognized. This function is used jointly by NFSv2 and NFSv3. | |
1da177e4 | 1156 | */ |
85828493 | 1157 | int nfs_stat_to_errno(enum nfs_stat status) |
1da177e4 LT |
1158 | { |
1159 | int i; | |
1160 | ||
1161 | for (i = 0; nfs_errtbl[i].stat != -1; i++) { | |
85828493 | 1162 | if (nfs_errtbl[i].stat == (int)status) |
1da177e4 LT |
1163 | return nfs_errtbl[i].errno; |
1164 | } | |
85828493 | 1165 | dprintk("NFS: Unrecognized nfs status value: %u\n", status); |
1da177e4 LT |
1166 | return nfs_errtbl[i].errno; |
1167 | } | |
1168 | ||
1da177e4 LT |
1169 | #define PROC(proc, argtype, restype, timer) \ |
1170 | [NFSPROC_##proc] = { \ | |
1171 | .p_proc = NFSPROC_##proc, \ | |
25a0866c | 1172 | .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \ |
f796f8b3 | 1173 | .p_decode = (kxdrproc_t)nfs2_xdr_dec_##restype, \ |
2bea90d4 CL |
1174 | .p_arglen = NFS_##argtype##_sz, \ |
1175 | .p_replen = NFS_##restype##_sz, \ | |
cc0175c1 CL |
1176 | .p_timer = timer, \ |
1177 | .p_statidx = NFSPROC_##proc, \ | |
1178 | .p_name = #proc, \ | |
1da177e4 LT |
1179 | } |
1180 | struct rpc_procinfo nfs_procedures[] = { | |
1181 | PROC(GETATTR, fhandle, attrstat, 1), | |
1182 | PROC(SETATTR, sattrargs, attrstat, 0), | |
1183 | PROC(LOOKUP, diropargs, diropres, 2), | |
1184 | PROC(READLINK, readlinkargs, readlinkres, 3), | |
1185 | PROC(READ, readargs, readres, 3), | |
1186 | PROC(WRITE, writeargs, writeres, 4), | |
1187 | PROC(CREATE, createargs, diropres, 0), | |
4fdc17b2 | 1188 | PROC(REMOVE, removeargs, stat, 0), |
1da177e4 LT |
1189 | PROC(RENAME, renameargs, stat, 0), |
1190 | PROC(LINK, linkargs, stat, 0), | |
1191 | PROC(SYMLINK, symlinkargs, stat, 0), | |
1192 | PROC(MKDIR, createargs, diropres, 0), | |
1193 | PROC(RMDIR, diropargs, stat, 0), | |
1194 | PROC(READDIR, readdirargs, readdirres, 3), | |
1195 | PROC(STATFS, fhandle, statfsres, 0), | |
1196 | }; | |
1197 | ||
1198 | struct rpc_version nfs_version2 = { | |
1199 | .number = 2, | |
e8c96f8c | 1200 | .nrprocs = ARRAY_SIZE(nfs_procedures), |
1da177e4 LT |
1201 | .procs = nfs_procedures |
1202 | }; |