[IPIP]: Use proper net in (mostly) routing calls.
[deliverable/linux.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
LT
122{
123 u32 rdev;
124 fattr->type = (enum nfs_ftype) ntohl(*p++);
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);
139 fattr->valid |= NFS_ATTR_FATTR;
140 fattr->rdev = new_decode_dev(rdev);
141 if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) {
142 fattr->type = NFFIFO;
143 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
144 fattr->rdev = 0;
145 }
1da177e4
LT
146 return p;
147}
148
9d787a75
AV
149static inline __be32 *
150xdr_encode_sattr(__be32 *p, struct iattr *attr)
1da177e4 151{
9d787a75 152 const __be32 not_set = __constant_htonl(0xFFFFFFFF);
eadb8c14
TM
153
154 *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
155 *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
156 *p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set;
157 *p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set;
1da177e4
LT
158
159 if (attr->ia_valid & ATTR_ATIME_SET) {
160 p = xdr_encode_time(p, &attr->ia_atime);
161 } else if (attr->ia_valid & ATTR_ATIME) {
162 p = xdr_encode_current_server_time(p, &attr->ia_atime);
163 } else {
eadb8c14
TM
164 *p++ = not_set;
165 *p++ = not_set;
1da177e4
LT
166 }
167
168 if (attr->ia_valid & ATTR_MTIME_SET) {
169 p = xdr_encode_time(p, &attr->ia_mtime);
170 } else if (attr->ia_valid & ATTR_MTIME) {
171 p = xdr_encode_current_server_time(p, &attr->ia_mtime);
172 } else {
eadb8c14
TM
173 *p++ = not_set;
174 *p++ = not_set;
1da177e4
LT
175 }
176 return p;
177}
1da177e4
LT
178
179/*
180 * NFS encode functions
181 */
182/*
183 * Encode file handle argument
184 * GETATTR, READLINK, STATFS
185 */
186static int
9d787a75 187nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
1da177e4
LT
188{
189 p = xdr_encode_fhandle(p, fh);
190 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
191 return 0;
192}
193
194/*
195 * Encode SETATTR arguments
196 */
197static int
9d787a75 198nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
1da177e4
LT
199{
200 p = xdr_encode_fhandle(p, args->fh);
201 p = xdr_encode_sattr(p, args->sattr);
202 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
203 return 0;
204}
205
206/*
207 * Encode directory ops argument
4fdc17b2 208 * LOOKUP, RMDIR
1da177e4
LT
209 */
210static int
9d787a75 211nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
1da177e4
LT
212{
213 p = xdr_encode_fhandle(p, args->fh);
214 p = xdr_encode_array(p, args->name, args->len);
215 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
216 return 0;
217}
218
4fdc17b2
TM
219/*
220 * Encode REMOVE argument
221 */
222static int
223nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
224{
225 p = xdr_encode_fhandle(p, args->fh);
226 p = xdr_encode_array(p, args->name.name, args->name.len);
227 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
228 return 0;
229}
230
1da177e4
LT
231/*
232 * Arguments to a READ call. Since we read data directly into the page
233 * cache, we also set up the reply iovec here so that iov[1] points
234 * exactly to the page we want to fetch.
235 */
236static int
9d787a75 237nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
1da177e4 238{
1be27f36 239 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
240 unsigned int replen;
241 u32 offset = (u32)args->offset;
242 u32 count = args->count;
243
244 p = xdr_encode_fhandle(p, args->fh);
245 *p++ = htonl(offset);
246 *p++ = htonl(count);
247 *p++ = htonl(count);
248 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
249
250 /* Inline the page array */
251 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
252 xdr_inline_pages(&req->rq_rcv_buf, replen,
253 args->pages, args->pgbase, count);
4f22ccc3 254 req->rq_rcv_buf.flags |= XDRBUF_READ;
1da177e4
LT
255 return 0;
256}
257
258/*
259 * Decode READ reply
260 */
261static int
9d787a75 262nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
1da177e4
LT
263{
264 struct kvec *iov = req->rq_rcv_buf.head;
6232dbbc
CL
265 size_t hdrlen;
266 u32 count, recvd;
267 int status;
1da177e4
LT
268
269 if ((status = ntohl(*p++)))
270 return -nfs_stat_to_errno(status);
271 p = xdr_decode_fattr(p, res->fattr);
272
273 count = ntohl(*p++);
274 res->eof = 0;
275 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
276 if (iov->iov_len < hdrlen) {
fe82a183 277 dprintk("NFS: READ reply header overflowed:"
6232dbbc 278 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
279 return -errno_NFSERR_IO;
280 } else if (iov->iov_len != hdrlen) {
281 dprintk("NFS: READ header is short. iovec will be shifted.\n");
282 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
283 }
284
285 recvd = req->rq_rcv_buf.len - hdrlen;
286 if (count > recvd) {
fe82a183 287 dprintk("NFS: server cheating in read reply: "
6232dbbc 288 "count %u > recvd %u\n", count, recvd);
1da177e4
LT
289 count = recvd;
290 }
291
6232dbbc 292 dprintk("RPC: readres OK count %u\n", count);
1da177e4
LT
293 if (count < res->count)
294 res->count = count;
295
296 return count;
297}
298
299
300/*
301 * Write arguments. Splice the buffer to be written into the iovec.
302 */
303static int
9d787a75 304nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
1da177e4
LT
305{
306 struct xdr_buf *sndbuf = &req->rq_snd_buf;
307 u32 offset = (u32)args->offset;
308 u32 count = args->count;
309
310 p = xdr_encode_fhandle(p, args->fh);
311 *p++ = htonl(offset);
312 *p++ = htonl(offset);
313 *p++ = htonl(count);
314 *p++ = htonl(count);
315 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
316
317 /* Copy the page array */
318 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
4f22ccc3 319 sndbuf->flags |= XDRBUF_WRITE;
1da177e4
LT
320 return 0;
321}
322
323/*
324 * Encode create arguments
325 * CREATE, MKDIR
326 */
327static int
9d787a75 328nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
1da177e4
LT
329{
330 p = xdr_encode_fhandle(p, args->fh);
331 p = xdr_encode_array(p, args->name, args->len);
332 p = xdr_encode_sattr(p, args->sattr);
333 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
334 return 0;
335}
336
337/*
338 * Encode RENAME arguments
339 */
340static int
9d787a75 341nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
1da177e4
LT
342{
343 p = xdr_encode_fhandle(p, args->fromfh);
344 p = xdr_encode_array(p, args->fromname, args->fromlen);
345 p = xdr_encode_fhandle(p, args->tofh);
346 p = xdr_encode_array(p, args->toname, args->tolen);
347 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
348 return 0;
349}
350
351/*
352 * Encode LINK arguments
353 */
354static int
9d787a75 355nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
1da177e4
LT
356{
357 p = xdr_encode_fhandle(p, args->fromfh);
358 p = xdr_encode_fhandle(p, args->tofh);
359 p = xdr_encode_array(p, args->toname, args->tolen);
360 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
361 return 0;
362}
363
364/*
365 * Encode SYMLINK arguments
366 */
367static int
9d787a75 368nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
1da177e4 369{
94a6d753
CL
370 struct xdr_buf *sndbuf = &req->rq_snd_buf;
371 size_t pad;
372
1da177e4
LT
373 p = xdr_encode_fhandle(p, args->fromfh);
374 p = xdr_encode_array(p, args->fromname, args->fromlen);
94a6d753
CL
375 *p++ = htonl(args->pathlen);
376 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
377
378 xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
379
380 /*
381 * xdr_encode_pages may have added a few bytes to ensure the
382 * pathname ends on a 4-byte boundary. Start encoding the
383 * attributes after the pad bytes.
384 */
385 pad = sndbuf->tail->iov_len;
386 if (pad > 0)
387 p++;
1da177e4 388 p = xdr_encode_sattr(p, args->sattr);
94a6d753 389 sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
1da177e4
LT
390 return 0;
391}
392
393/*
394 * Encode arguments to readdir call
395 */
396static int
9d787a75 397nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
1da177e4
LT
398{
399 struct rpc_task *task = req->rq_task;
1be27f36 400 struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
401 unsigned int replen;
402 u32 count = args->count;
403
404 p = xdr_encode_fhandle(p, args->fh);
405 *p++ = htonl(args->cookie);
406 *p++ = htonl(count); /* see above */
407 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
408
409 /* Inline the page array */
410 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
411 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
412 return 0;
413}
414
415/*
416 * Decode the result of a readdir call.
417 * We're not really decoding anymore, we just leave the buffer untouched
418 * and only check that it is syntactically correct.
419 * The real decoding happens in nfs_decode_entry below, called directly
420 * from nfs_readdir for each entry.
421 */
422static int
9d787a75 423nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
1da177e4
LT
424{
425 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
426 struct kvec *iov = rcvbuf->head;
427 struct page **page;
6232dbbc
CL
428 size_t hdrlen;
429 unsigned int pglen, recvd;
430 u32 len;
1da177e4 431 int status, nr;
9d787a75 432 __be32 *end, *entry, *kaddr;
1da177e4
LT
433
434 if ((status = ntohl(*p++)))
435 return -nfs_stat_to_errno(status);
436
437 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
438 if (iov->iov_len < hdrlen) {
fe82a183 439 dprintk("NFS: READDIR reply header overflowed:"
6232dbbc 440 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
441 return -errno_NFSERR_IO;
442 } else if (iov->iov_len != hdrlen) {
443 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
444 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
445 }
446
447 pglen = rcvbuf->page_len;
448 recvd = rcvbuf->len - hdrlen;
449 if (pglen > recvd)
450 pglen = recvd;
451 page = rcvbuf->pages;
9d787a75
AV
452 kaddr = p = kmap_atomic(*page, KM_USER0);
453 end = (__be32 *)((char *)p + pglen);
1da177e4
LT
454 entry = p;
455 for (nr = 0; *p++; nr++) {
456 if (p + 2 > end)
457 goto short_pkt;
458 p++; /* fileid */
459 len = ntohl(*p++);
460 p += XDR_QUADLEN(len) + 1; /* name plus cookie */
461 if (len > NFS2_MAXNAMLEN) {
fe82a183 462 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
1da177e4
LT
463 len);
464 goto err_unmap;
465 }
466 if (p + 2 > end)
467 goto short_pkt;
468 entry = p;
469 }
470 if (!nr && (entry[0] != 0 || entry[1] == 0))
471 goto short_pkt;
472 out:
473 kunmap_atomic(kaddr, KM_USER0);
474 return nr;
475 short_pkt:
476 entry[0] = entry[1] = 0;
477 /* truncate listing ? */
478 if (!nr) {
fe82a183 479 dprintk("NFS: readdir reply truncated!\n");
1da177e4
LT
480 entry[1] = 1;
481 }
482 goto out;
483err_unmap:
484 nr = -errno_NFSERR_IO;
485 goto out;
486}
487
0dbb4c67
AV
488__be32 *
489nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
1da177e4
LT
490{
491 if (!*p++) {
492 if (!*p)
493 return ERR_PTR(-EAGAIN);
494 entry->eof = 1;
495 return ERR_PTR(-EBADCOOKIE);
496 }
497
498 entry->ino = ntohl(*p++);
499 entry->len = ntohl(*p++);
500 entry->name = (const char *) p;
501 p += XDR_QUADLEN(entry->len);
502 entry->prev_cookie = entry->cookie;
503 entry->cookie = ntohl(*p++);
504 entry->eof = !p[0] && p[1];
505
506 return p;
507}
508
509/*
510 * NFS XDR decode functions
511 */
512/*
513 * Decode simple status reply
514 */
515static int
9d787a75 516nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
1da177e4
LT
517{
518 int status;
519
520 if ((status = ntohl(*p++)) != 0)
521 status = -nfs_stat_to_errno(status);
522 return status;
523}
524
525/*
526 * Decode attrstat reply
527 * GETATTR, SETATTR, WRITE
528 */
529static int
9d787a75 530nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
531{
532 int status;
533
534 if ((status = ntohl(*p++)))
535 return -nfs_stat_to_errno(status);
536 xdr_decode_fattr(p, fattr);
537 return 0;
538}
539
540/*
541 * Decode diropres reply
542 * LOOKUP, CREATE, MKDIR
543 */
544static int
9d787a75 545nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
1da177e4
LT
546{
547 int status;
548
549 if ((status = ntohl(*p++)))
550 return -nfs_stat_to_errno(status);
551 p = xdr_decode_fhandle(p, res->fh);
552 xdr_decode_fattr(p, res->fattr);
553 return 0;
554}
555
556/*
557 * Encode READLINK args
558 */
559static int
9d787a75 560nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
1da177e4 561{
1be27f36 562 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
563 unsigned int replen;
564
565 p = xdr_encode_fhandle(p, args->fh);
566 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
567
568 /* Inline the page array */
569 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
570 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
571 return 0;
572}
573
574/*
575 * Decode READLINK reply
576 */
577static int
9d787a75 578nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
1da177e4
LT
579{
580 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
581 struct kvec *iov = rcvbuf->head;
6232dbbc
CL
582 size_t hdrlen;
583 u32 len, recvd;
1da177e4
LT
584 char *kaddr;
585 int status;
586
587 if ((status = ntohl(*p++)))
588 return -nfs_stat_to_errno(status);
589 /* Convert length of symlink */
590 len = ntohl(*p++);
6232dbbc 591 if (len >= rcvbuf->page_len) {
fe82a183 592 dprintk("nfs: server returned giant symlink!\n");
1da177e4
LT
593 return -ENAMETOOLONG;
594 }
595 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
596 if (iov->iov_len < hdrlen) {
fe82a183 597 dprintk("NFS: READLINK reply header overflowed:"
6232dbbc 598 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
599 return -errno_NFSERR_IO;
600 } else if (iov->iov_len != hdrlen) {
601 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
602 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
603 }
604 recvd = req->rq_rcv_buf.len - hdrlen;
605 if (recvd < len) {
fe82a183 606 dprintk("NFS: server cheating in readlink reply: "
1da177e4
LT
607 "count %u > recvd %u\n", len, recvd);
608 return -EIO;
609 }
610
611 /* NULL terminate the string we got */
612 kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
613 kaddr[len+rcvbuf->page_base] = '\0';
614 kunmap_atomic(kaddr, KM_USER0);
615 return 0;
616}
617
618/*
619 * Decode WRITE reply
620 */
621static int
9d787a75 622nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1da177e4
LT
623{
624 res->verf->committed = NFS_FILE_SYNC;
625 return nfs_xdr_attrstat(req, p, res->fattr);
626}
627
628/*
629 * Decode STATFS reply
630 */
631static int
9d787a75 632nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
1da177e4
LT
633{
634 int status;
635
636 if ((status = ntohl(*p++)))
637 return -nfs_stat_to_errno(status);
638
639 res->tsize = ntohl(*p++);
640 res->bsize = ntohl(*p++);
641 res->blocks = ntohl(*p++);
642 res->bfree = ntohl(*p++);
643 res->bavail = ntohl(*p++);
644 return 0;
645}
646
647/*
648 * We need to translate between nfs status return values and
649 * the local errno values which may not be the same.
650 */
651static struct {
652 int stat;
653 int errno;
654} nfs_errtbl[] = {
655 { NFS_OK, 0 },
656 { NFSERR_PERM, EPERM },
657 { NFSERR_NOENT, ENOENT },
658 { NFSERR_IO, errno_NFSERR_IO },
659 { NFSERR_NXIO, ENXIO },
660/* { NFSERR_EAGAIN, EAGAIN }, */
661 { NFSERR_ACCES, EACCES },
662 { NFSERR_EXIST, EEXIST },
663 { NFSERR_XDEV, EXDEV },
664 { NFSERR_NODEV, ENODEV },
665 { NFSERR_NOTDIR, ENOTDIR },
666 { NFSERR_ISDIR, EISDIR },
667 { NFSERR_INVAL, EINVAL },
668 { NFSERR_FBIG, EFBIG },
669 { NFSERR_NOSPC, ENOSPC },
670 { NFSERR_ROFS, EROFS },
671 { NFSERR_MLINK, EMLINK },
672 { NFSERR_NAMETOOLONG, ENAMETOOLONG },
673 { NFSERR_NOTEMPTY, ENOTEMPTY },
674 { NFSERR_DQUOT, EDQUOT },
675 { NFSERR_STALE, ESTALE },
676 { NFSERR_REMOTE, EREMOTE },
677#ifdef EWFLUSH
678 { NFSERR_WFLUSH, EWFLUSH },
679#endif
680 { NFSERR_BADHANDLE, EBADHANDLE },
681 { NFSERR_NOT_SYNC, ENOTSYNC },
682 { NFSERR_BAD_COOKIE, EBADCOOKIE },
683 { NFSERR_NOTSUPP, ENOTSUPP },
684 { NFSERR_TOOSMALL, ETOOSMALL },
685 { NFSERR_SERVERFAULT, ESERVERFAULT },
686 { NFSERR_BADTYPE, EBADTYPE },
687 { NFSERR_JUKEBOX, EJUKEBOX },
688 { -1, EIO }
689};
690
691/*
692 * Convert an NFS error code to a local one.
693 * This one is used jointly by NFSv2 and NFSv3.
694 */
695int
696nfs_stat_to_errno(int stat)
697{
698 int i;
699
700 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
701 if (nfs_errtbl[i].stat == stat)
702 return nfs_errtbl[i].errno;
703 }
fe82a183 704 dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
1da177e4
LT
705 return nfs_errtbl[i].errno;
706}
707
1da177e4
LT
708#define PROC(proc, argtype, restype, timer) \
709[NFSPROC_##proc] = { \
710 .p_proc = NFSPROC_##proc, \
711 .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \
712 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
2bea90d4
CL
713 .p_arglen = NFS_##argtype##_sz, \
714 .p_replen = NFS_##restype##_sz, \
cc0175c1
CL
715 .p_timer = timer, \
716 .p_statidx = NFSPROC_##proc, \
717 .p_name = #proc, \
1da177e4
LT
718 }
719struct rpc_procinfo nfs_procedures[] = {
720 PROC(GETATTR, fhandle, attrstat, 1),
721 PROC(SETATTR, sattrargs, attrstat, 0),
722 PROC(LOOKUP, diropargs, diropres, 2),
723 PROC(READLINK, readlinkargs, readlinkres, 3),
724 PROC(READ, readargs, readres, 3),
725 PROC(WRITE, writeargs, writeres, 4),
726 PROC(CREATE, createargs, diropres, 0),
4fdc17b2 727 PROC(REMOVE, removeargs, stat, 0),
1da177e4
LT
728 PROC(RENAME, renameargs, stat, 0),
729 PROC(LINK, linkargs, stat, 0),
730 PROC(SYMLINK, symlinkargs, stat, 0),
731 PROC(MKDIR, createargs, diropres, 0),
732 PROC(RMDIR, diropargs, stat, 0),
733 PROC(READDIR, readdirargs, readdirres, 3),
734 PROC(STATFS, fhandle, statfsres, 0),
735};
736
737struct rpc_version nfs_version2 = {
738 .number = 2,
e8c96f8c 739 .nrprocs = ARRAY_SIZE(nfs_procedures),
1da177e4
LT
740 .procs = nfs_procedures
741};
This page took 0.350828 seconds and 5 git commands to generate.