nfs41: enable nfs_client only nfs4_async_handle_error
[linux-2.6-block.git] / fs / nfs / nfs2xdr.c
CommitLineData
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>
15#include <linux/slab.h>
16#include <linux/utsname.h>
17#include <linux/errno.h>
18#include <linux/string.h>
19#include <linux/in.h>
20#include <linux/pagemap.h>
21#include <linux/proc_fs.h>
22#include <linux/sunrpc/clnt.h>
23#include <linux/nfs.h>
24#include <linux/nfs2.h>
25#include <linux/nfs_fs.h>
816724e6 26#include "internal.h"
1da177e4
LT
27
28#define NFSDBG_FACILITY NFSDBG_XDR
1da177e4 29
1da177e4
LT
30/* Mapping from NFS error code to "errno" error code. */
31#define errno_NFSERR_IO EIO
32
33/*
34 * Declare the space requirements for NFS arguments and replies as
35 * number of 32bit-words
36 */
37#define NFS_fhandle_sz (8)
38#define NFS_sattr_sz (8)
39#define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2))
40#define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2))
41#define NFS_fattr_sz (17)
42#define NFS_info_sz (5)
43#define NFS_entry_sz (NFS_filename_sz+3)
44
45#define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
4fdc17b2 46#define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz)
1da177e4
LT
47#define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
48#define NFS_readlinkargs_sz (NFS_fhandle_sz)
49#define NFS_readargs_sz (NFS_fhandle_sz+3)
50#define NFS_writeargs_sz (NFS_fhandle_sz+4)
51#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
52#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
53#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
94a6d753 54#define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
1da177e4
LT
55#define NFS_readdirargs_sz (NFS_fhandle_sz+2)
56
57#define NFS_attrstat_sz (1+NFS_fattr_sz)
58#define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
59#define NFS_readlinkres_sz (2)
60#define NFS_readres_sz (1+NFS_fattr_sz+1)
61#define NFS_writeres_sz (NFS_attrstat_sz)
62#define NFS_stat_sz (1)
63#define NFS_readdirres_sz (1)
64#define NFS_statfsres_sz (1+NFS_info_sz)
65
66/*
67 * Common NFS XDR functions as inlines
68 */
9d787a75 69static inline __be32 *
4fdc17b2 70xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fhandle)
1da177e4
LT
71{
72 memcpy(p, fhandle->data, NFS2_FHSIZE);
73 return p + XDR_QUADLEN(NFS2_FHSIZE);
74}
75
9d787a75
AV
76static inline __be32 *
77xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
1da177e4
LT
78{
79 /* NFSv2 handles have a fixed length */
80 fhandle->size = NFS2_FHSIZE;
81 memcpy(fhandle->data, p, NFS2_FHSIZE);
82 return p + XDR_QUADLEN(NFS2_FHSIZE);
83}
84
9d787a75
AV
85static inline __be32*
86xdr_encode_time(__be32 *p, struct timespec *timep)
1da177e4
LT
87{
88 *p++ = htonl(timep->tv_sec);
89 /* Convert nanoseconds into microseconds */
90 *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
91 return p;
92}
93
9d787a75
AV
94static inline __be32*
95xdr_encode_current_server_time(__be32 *p, struct timespec *timep)
1da177e4
LT
96{
97 /*
98 * Passing the invalid value useconds=1000000 is a
99 * Sun convention for "set to current server time".
100 * It's needed to make permissions checks for the
101 * "touch" program across v2 mounts to Solaris and
102 * Irix boxes work correctly. See description of
103 * sattr in section 6.1 of "NFS Illustrated" by
104 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
105 */
106 *p++ = htonl(timep->tv_sec);
107 *p++ = htonl(1000000);
108 return p;
109}
110
9d787a75
AV
111static inline __be32*
112xdr_decode_time(__be32 *p, struct timespec *timep)
1da177e4
LT
113{
114 timep->tv_sec = ntohl(*p++);
115 /* Convert microseconds into nanoseconds */
116 timep->tv_nsec = ntohl(*p++) * 1000;
117 return p;
118}
119
9d787a75
AV
120static __be32 *
121xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
1da177e4 122{
bca79478
TM
123 u32 rdev, type;
124 type = ntohl(*p++);
1da177e4
LT
125 fattr->mode = ntohl(*p++);
126 fattr->nlink = ntohl(*p++);
127 fattr->uid = ntohl(*p++);
128 fattr->gid = ntohl(*p++);
129 fattr->size = ntohl(*p++);
130 fattr->du.nfs2.blocksize = ntohl(*p++);
131 rdev = ntohl(*p++);
132 fattr->du.nfs2.blocks = ntohl(*p++);
8b4bdcf8
TM
133 fattr->fsid.major = ntohl(*p++);
134 fattr->fsid.minor = 0;
1da177e4
LT
135 fattr->fileid = ntohl(*p++);
136 p = xdr_decode_time(p, &fattr->atime);
137 p = xdr_decode_time(p, &fattr->mtime);
138 p = xdr_decode_time(p, &fattr->ctime);
9e6e70f8 139 fattr->valid |= NFS_ATTR_FATTR_V2;
1da177e4 140 fattr->rdev = new_decode_dev(rdev);
bca79478 141 if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
1da177e4
LT
142 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
143 fattr->rdev = 0;
144 }
1da177e4
LT
145 return p;
146}
147
9d787a75
AV
148static inline __be32 *
149xdr_encode_sattr(__be32 *p, struct iattr *attr)
1da177e4 150{
9d787a75 151 const __be32 not_set = __constant_htonl(0xFFFFFFFF);
eadb8c14
TM
152
153 *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
154 *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
155 *p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set;
156 *p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set;
1da177e4
LT
157
158 if (attr->ia_valid & ATTR_ATIME_SET) {
159 p = xdr_encode_time(p, &attr->ia_atime);
160 } else if (attr->ia_valid & ATTR_ATIME) {
161 p = xdr_encode_current_server_time(p, &attr->ia_atime);
162 } else {
eadb8c14
TM
163 *p++ = not_set;
164 *p++ = not_set;
1da177e4
LT
165 }
166
167 if (attr->ia_valid & ATTR_MTIME_SET) {
168 p = xdr_encode_time(p, &attr->ia_mtime);
169 } else if (attr->ia_valid & ATTR_MTIME) {
170 p = xdr_encode_current_server_time(p, &attr->ia_mtime);
171 } else {
eadb8c14
TM
172 *p++ = not_set;
173 *p++ = not_set;
1da177e4
LT
174 }
175 return p;
176}
1da177e4
LT
177
178/*
179 * NFS encode functions
180 */
181/*
182 * Encode file handle argument
183 * GETATTR, READLINK, STATFS
184 */
185static int
9d787a75 186nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
1da177e4
LT
187{
188 p = xdr_encode_fhandle(p, fh);
189 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
190 return 0;
191}
192
193/*
194 * Encode SETATTR arguments
195 */
196static int
9d787a75 197nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
1da177e4
LT
198{
199 p = xdr_encode_fhandle(p, args->fh);
200 p = xdr_encode_sattr(p, args->sattr);
201 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
202 return 0;
203}
204
205/*
206 * Encode directory ops argument
4fdc17b2 207 * LOOKUP, RMDIR
1da177e4
LT
208 */
209static int
9d787a75 210nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
1da177e4
LT
211{
212 p = xdr_encode_fhandle(p, args->fh);
213 p = xdr_encode_array(p, args->name, args->len);
214 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
215 return 0;
216}
217
4fdc17b2
TM
218/*
219 * Encode REMOVE argument
220 */
221static int
222nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
223{
224 p = xdr_encode_fhandle(p, args->fh);
225 p = xdr_encode_array(p, args->name.name, args->name.len);
226 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
227 return 0;
228}
229
1da177e4
LT
230/*
231 * Arguments to a READ call. Since we read data directly into the page
232 * cache, we also set up the reply iovec here so that iov[1] points
233 * exactly to the page we want to fetch.
234 */
235static int
9d787a75 236nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
1da177e4 237{
1be27f36 238 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
239 unsigned int replen;
240 u32 offset = (u32)args->offset;
241 u32 count = args->count;
242
243 p = xdr_encode_fhandle(p, args->fh);
244 *p++ = htonl(offset);
245 *p++ = htonl(count);
246 *p++ = htonl(count);
247 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
248
249 /* Inline the page array */
250 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
251 xdr_inline_pages(&req->rq_rcv_buf, replen,
252 args->pages, args->pgbase, count);
4f22ccc3 253 req->rq_rcv_buf.flags |= XDRBUF_READ;
1da177e4
LT
254 return 0;
255}
256
257/*
258 * Decode READ reply
259 */
260static int
9d787a75 261nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
1da177e4
LT
262{
263 struct kvec *iov = req->rq_rcv_buf.head;
6232dbbc
CL
264 size_t hdrlen;
265 u32 count, recvd;
266 int status;
1da177e4
LT
267
268 if ((status = ntohl(*p++)))
856dff3d 269 return nfs_stat_to_errno(status);
1da177e4
LT
270 p = xdr_decode_fattr(p, res->fattr);
271
272 count = ntohl(*p++);
273 res->eof = 0;
274 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
275 if (iov->iov_len < hdrlen) {
fe82a183 276 dprintk("NFS: READ reply header overflowed:"
6232dbbc 277 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
278 return -errno_NFSERR_IO;
279 } else if (iov->iov_len != hdrlen) {
280 dprintk("NFS: READ header is short. iovec will be shifted.\n");
281 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
282 }
283
284 recvd = req->rq_rcv_buf.len - hdrlen;
285 if (count > recvd) {
fe82a183 286 dprintk("NFS: server cheating in read reply: "
6232dbbc 287 "count %u > recvd %u\n", count, recvd);
1da177e4
LT
288 count = recvd;
289 }
290
6232dbbc 291 dprintk("RPC: readres OK count %u\n", count);
1da177e4
LT
292 if (count < res->count)
293 res->count = count;
294
295 return count;
296}
297
298
299/*
300 * Write arguments. Splice the buffer to be written into the iovec.
301 */
302static int
9d787a75 303nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
1da177e4
LT
304{
305 struct xdr_buf *sndbuf = &req->rq_snd_buf;
306 u32 offset = (u32)args->offset;
307 u32 count = args->count;
308
309 p = xdr_encode_fhandle(p, args->fh);
310 *p++ = htonl(offset);
311 *p++ = htonl(offset);
312 *p++ = htonl(count);
313 *p++ = htonl(count);
314 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
315
316 /* Copy the page array */
317 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
4f22ccc3 318 sndbuf->flags |= XDRBUF_WRITE;
1da177e4
LT
319 return 0;
320}
321
322/*
323 * Encode create arguments
324 * CREATE, MKDIR
325 */
326static int
9d787a75 327nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
1da177e4
LT
328{
329 p = xdr_encode_fhandle(p, args->fh);
330 p = xdr_encode_array(p, args->name, args->len);
331 p = xdr_encode_sattr(p, args->sattr);
332 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
333 return 0;
334}
335
336/*
337 * Encode RENAME arguments
338 */
339static int
9d787a75 340nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
1da177e4
LT
341{
342 p = xdr_encode_fhandle(p, args->fromfh);
343 p = xdr_encode_array(p, args->fromname, args->fromlen);
344 p = xdr_encode_fhandle(p, args->tofh);
345 p = xdr_encode_array(p, args->toname, args->tolen);
346 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
347 return 0;
348}
349
350/*
351 * Encode LINK arguments
352 */
353static int
9d787a75 354nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
1da177e4
LT
355{
356 p = xdr_encode_fhandle(p, args->fromfh);
357 p = xdr_encode_fhandle(p, args->tofh);
358 p = xdr_encode_array(p, args->toname, args->tolen);
359 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
360 return 0;
361}
362
363/*
364 * Encode SYMLINK arguments
365 */
366static int
9d787a75 367nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
1da177e4 368{
94a6d753
CL
369 struct xdr_buf *sndbuf = &req->rq_snd_buf;
370 size_t pad;
371
1da177e4
LT
372 p = xdr_encode_fhandle(p, args->fromfh);
373 p = xdr_encode_array(p, args->fromname, args->fromlen);
94a6d753
CL
374 *p++ = htonl(args->pathlen);
375 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
376
377 xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
378
379 /*
380 * xdr_encode_pages may have added a few bytes to ensure the
381 * pathname ends on a 4-byte boundary. Start encoding the
382 * attributes after the pad bytes.
383 */
384 pad = sndbuf->tail->iov_len;
385 if (pad > 0)
386 p++;
1da177e4 387 p = xdr_encode_sattr(p, args->sattr);
94a6d753 388 sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
1da177e4
LT
389 return 0;
390}
391
392/*
393 * Encode arguments to readdir call
394 */
395static int
9d787a75 396nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
1da177e4
LT
397{
398 struct rpc_task *task = req->rq_task;
1be27f36 399 struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
400 unsigned int replen;
401 u32 count = args->count;
402
403 p = xdr_encode_fhandle(p, args->fh);
404 *p++ = htonl(args->cookie);
405 *p++ = htonl(count); /* see above */
406 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
407
408 /* Inline the page array */
409 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
410 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
411 return 0;
412}
413
414/*
415 * Decode the result of a readdir call.
416 * We're not really decoding anymore, we just leave the buffer untouched
417 * and only check that it is syntactically correct.
418 * The real decoding happens in nfs_decode_entry below, called directly
419 * from nfs_readdir for each entry.
420 */
421static int
9d787a75 422nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
1da177e4
LT
423{
424 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
425 struct kvec *iov = rcvbuf->head;
426 struct page **page;
6232dbbc
CL
427 size_t hdrlen;
428 unsigned int pglen, recvd;
429 u32 len;
caa02bd5 430 int status, nr = 0;
9d787a75 431 __be32 *end, *entry, *kaddr;
1da177e4
LT
432
433 if ((status = ntohl(*p++)))
856dff3d 434 return nfs_stat_to_errno(status);
1da177e4
LT
435
436 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
437 if (iov->iov_len < hdrlen) {
fe82a183 438 dprintk("NFS: READDIR reply header overflowed:"
6232dbbc 439 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
440 return -errno_NFSERR_IO;
441 } else if (iov->iov_len != hdrlen) {
442 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
443 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
444 }
445
446 pglen = rcvbuf->page_len;
447 recvd = rcvbuf->len - hdrlen;
448 if (pglen > recvd)
449 pglen = recvd;
450 page = rcvbuf->pages;
9d787a75
AV
451 kaddr = p = kmap_atomic(*page, KM_USER0);
452 end = (__be32 *)((char *)p + pglen);
1da177e4 453 entry = p;
caa02bd5
JL
454
455 /* Make sure the packet actually has a value_follows and EOF entry */
456 if ((entry + 1) > end)
457 goto short_pkt;
458
459 for (; *p++; nr++) {
1da177e4
LT
460 if (p + 2 > end)
461 goto short_pkt;
462 p++; /* fileid */
463 len = ntohl(*p++);
464 p += XDR_QUADLEN(len) + 1; /* name plus cookie */
465 if (len > NFS2_MAXNAMLEN) {
fe82a183 466 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
1da177e4
LT
467 len);
468 goto err_unmap;
469 }
470 if (p + 2 > end)
471 goto short_pkt;
472 entry = p;
473 }
caa02bd5
JL
474
475 /*
476 * Apparently some server sends responses that are a valid size, but
477 * contain no entries, and have value_follows==0 and EOF==0. For
478 * those, just set the EOF marker.
479 */
480 if (!nr && entry[1] == 0) {
481 dprintk("NFS: readdir reply truncated!\n");
482 entry[1] = 1;
483 }
1da177e4
LT
484 out:
485 kunmap_atomic(kaddr, KM_USER0);
486 return nr;
487 short_pkt:
caa02bd5
JL
488 /*
489 * When we get a short packet there are 2 possibilities. We can
490 * return an error, or fix up the response to look like a valid
491 * response and return what we have so far. If there are no
492 * entries and the packet was short, then return -EIO. If there
493 * are valid entries in the response, return them and pretend that
494 * the call was successful, but incomplete. The caller can retry the
495 * readdir starting at the last cookie.
496 */
1da177e4 497 entry[0] = entry[1] = 0;
caa02bd5
JL
498 if (!nr)
499 nr = -errno_NFSERR_IO;
1da177e4
LT
500 goto out;
501err_unmap:
502 nr = -errno_NFSERR_IO;
503 goto out;
504}
505
0dbb4c67
AV
506__be32 *
507nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
1da177e4
LT
508{
509 if (!*p++) {
510 if (!*p)
511 return ERR_PTR(-EAGAIN);
512 entry->eof = 1;
513 return ERR_PTR(-EBADCOOKIE);
514 }
515
516 entry->ino = ntohl(*p++);
517 entry->len = ntohl(*p++);
518 entry->name = (const char *) p;
519 p += XDR_QUADLEN(entry->len);
520 entry->prev_cookie = entry->cookie;
521 entry->cookie = ntohl(*p++);
522 entry->eof = !p[0] && p[1];
523
524 return p;
525}
526
527/*
528 * NFS XDR decode functions
529 */
530/*
531 * Decode simple status reply
532 */
533static int
9d787a75 534nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
1da177e4
LT
535{
536 int status;
537
538 if ((status = ntohl(*p++)) != 0)
856dff3d 539 status = nfs_stat_to_errno(status);
1da177e4
LT
540 return status;
541}
542
543/*
544 * Decode attrstat reply
545 * GETATTR, SETATTR, WRITE
546 */
547static int
9d787a75 548nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
549{
550 int status;
551
552 if ((status = ntohl(*p++)))
856dff3d 553 return nfs_stat_to_errno(status);
1da177e4
LT
554 xdr_decode_fattr(p, fattr);
555 return 0;
556}
557
558/*
559 * Decode diropres reply
560 * LOOKUP, CREATE, MKDIR
561 */
562static int
9d787a75 563nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
1da177e4
LT
564{
565 int status;
566
567 if ((status = ntohl(*p++)))
856dff3d 568 return nfs_stat_to_errno(status);
1da177e4
LT
569 p = xdr_decode_fhandle(p, res->fh);
570 xdr_decode_fattr(p, res->fattr);
571 return 0;
572}
573
574/*
575 * Encode READLINK args
576 */
577static int
9d787a75 578nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
1da177e4 579{
1be27f36 580 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
581 unsigned int replen;
582
583 p = xdr_encode_fhandle(p, args->fh);
584 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
585
586 /* Inline the page array */
587 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
588 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
589 return 0;
590}
591
592/*
593 * Decode READLINK reply
594 */
595static int
9d787a75 596nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
1da177e4
LT
597{
598 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
599 struct kvec *iov = rcvbuf->head;
6232dbbc
CL
600 size_t hdrlen;
601 u32 len, recvd;
1da177e4
LT
602 char *kaddr;
603 int status;
604
605 if ((status = ntohl(*p++)))
856dff3d 606 return nfs_stat_to_errno(status);
1da177e4
LT
607 /* Convert length of symlink */
608 len = ntohl(*p++);
6232dbbc 609 if (len >= rcvbuf->page_len) {
fe82a183 610 dprintk("nfs: server returned giant symlink!\n");
1da177e4
LT
611 return -ENAMETOOLONG;
612 }
613 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
614 if (iov->iov_len < hdrlen) {
fe82a183 615 dprintk("NFS: READLINK reply header overflowed:"
6232dbbc 616 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
617 return -errno_NFSERR_IO;
618 } else if (iov->iov_len != hdrlen) {
619 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
620 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
621 }
622 recvd = req->rq_rcv_buf.len - hdrlen;
623 if (recvd < len) {
fe82a183 624 dprintk("NFS: server cheating in readlink reply: "
1da177e4
LT
625 "count %u > recvd %u\n", len, recvd);
626 return -EIO;
627 }
628
629 /* NULL terminate the string we got */
630 kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
631 kaddr[len+rcvbuf->page_base] = '\0';
632 kunmap_atomic(kaddr, KM_USER0);
633 return 0;
634}
635
636/*
637 * Decode WRITE reply
638 */
639static int
9d787a75 640nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1da177e4
LT
641{
642 res->verf->committed = NFS_FILE_SYNC;
643 return nfs_xdr_attrstat(req, p, res->fattr);
644}
645
646/*
647 * Decode STATFS reply
648 */
649static int
9d787a75 650nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
1da177e4
LT
651{
652 int status;
653
654 if ((status = ntohl(*p++)))
856dff3d 655 return nfs_stat_to_errno(status);
1da177e4
LT
656
657 res->tsize = ntohl(*p++);
658 res->bsize = ntohl(*p++);
659 res->blocks = ntohl(*p++);
660 res->bfree = ntohl(*p++);
661 res->bavail = ntohl(*p++);
662 return 0;
663}
664
665/*
666 * We need to translate between nfs status return values and
667 * the local errno values which may not be the same.
668 */
669static struct {
670 int stat;
671 int errno;
672} nfs_errtbl[] = {
673 { NFS_OK, 0 },
856dff3d
BH
674 { NFSERR_PERM, -EPERM },
675 { NFSERR_NOENT, -ENOENT },
676 { NFSERR_IO, -errno_NFSERR_IO},
677 { NFSERR_NXIO, -ENXIO },
678/* { NFSERR_EAGAIN, -EAGAIN }, */
679 { NFSERR_ACCES, -EACCES },
680 { NFSERR_EXIST, -EEXIST },
681 { NFSERR_XDEV, -EXDEV },
682 { NFSERR_NODEV, -ENODEV },
683 { NFSERR_NOTDIR, -ENOTDIR },
684 { NFSERR_ISDIR, -EISDIR },
685 { NFSERR_INVAL, -EINVAL },
686 { NFSERR_FBIG, -EFBIG },
687 { NFSERR_NOSPC, -ENOSPC },
688 { NFSERR_ROFS, -EROFS },
689 { NFSERR_MLINK, -EMLINK },
690 { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
691 { NFSERR_NOTEMPTY, -ENOTEMPTY },
692 { NFSERR_DQUOT, -EDQUOT },
693 { NFSERR_STALE, -ESTALE },
694 { NFSERR_REMOTE, -EREMOTE },
1da177e4 695#ifdef EWFLUSH
856dff3d 696 { NFSERR_WFLUSH, -EWFLUSH },
1da177e4 697#endif
856dff3d
BH
698 { NFSERR_BADHANDLE, -EBADHANDLE },
699 { NFSERR_NOT_SYNC, -ENOTSYNC },
700 { NFSERR_BAD_COOKIE, -EBADCOOKIE },
701 { NFSERR_NOTSUPP, -ENOTSUPP },
702 { NFSERR_TOOSMALL, -ETOOSMALL },
703 { NFSERR_SERVERFAULT, -ESERVERFAULT },
704 { NFSERR_BADTYPE, -EBADTYPE },
705 { NFSERR_JUKEBOX, -EJUKEBOX },
706 { -1, -EIO }
1da177e4
LT
707};
708
709/*
710 * Convert an NFS error code to a local one.
711 * This one is used jointly by NFSv2 and NFSv3.
712 */
713int
714nfs_stat_to_errno(int stat)
715{
716 int i;
717
718 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
719 if (nfs_errtbl[i].stat == stat)
720 return nfs_errtbl[i].errno;
721 }
fe82a183 722 dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
1da177e4
LT
723 return nfs_errtbl[i].errno;
724}
725
1da177e4
LT
726#define PROC(proc, argtype, restype, timer) \
727[NFSPROC_##proc] = { \
728 .p_proc = NFSPROC_##proc, \
729 .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \
730 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
2bea90d4
CL
731 .p_arglen = NFS_##argtype##_sz, \
732 .p_replen = NFS_##restype##_sz, \
cc0175c1
CL
733 .p_timer = timer, \
734 .p_statidx = NFSPROC_##proc, \
735 .p_name = #proc, \
1da177e4
LT
736 }
737struct rpc_procinfo nfs_procedures[] = {
738 PROC(GETATTR, fhandle, attrstat, 1),
739 PROC(SETATTR, sattrargs, attrstat, 0),
740 PROC(LOOKUP, diropargs, diropres, 2),
741 PROC(READLINK, readlinkargs, readlinkres, 3),
742 PROC(READ, readargs, readres, 3),
743 PROC(WRITE, writeargs, writeres, 4),
744 PROC(CREATE, createargs, diropres, 0),
4fdc17b2 745 PROC(REMOVE, removeargs, stat, 0),
1da177e4
LT
746 PROC(RENAME, renameargs, stat, 0),
747 PROC(LINK, linkargs, stat, 0),
748 PROC(SYMLINK, symlinkargs, stat, 0),
749 PROC(MKDIR, createargs, diropres, 0),
750 PROC(RMDIR, diropargs, stat, 0),
751 PROC(READDIR, readdirargs, readdirres, 3),
752 PROC(STATFS, fhandle, statfsres, 0),
753};
754
755struct rpc_version nfs_version2 = {
756 .number = 2,
e8c96f8c 757 .nrprocs = ARRAY_SIZE(nfs_procedures),
1da177e4
LT
758 .procs = nfs_procedures
759};