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/sched.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>
26
27 #define NFSDBG_FACILITY NFSDBG_XDR
28 /* #define NFS_PARANOIA 1 */
29
30 extern int nfs_stat_to_errno(int stat);
31
32 /* Mapping from NFS error code to "errno" error code. */
33 #define errno_NFSERR_IO EIO
34
35 /*
36 * Declare the space requirements for NFS arguments and replies as
37 * number of 32bit-words
38 */
39 #define NFS_fhandle_sz 8
40 #define NFS_sattr_sz 8
41 #define NFS_filename_sz 1+(NFS2_MAXNAMLEN>>2)
42 #define NFS_path_sz 1+(NFS2_MAXPATHLEN>>2)
43 #define NFS_fattr_sz 17
44 #define NFS_info_sz 5
45 #define NFS_entry_sz NFS_filename_sz+3
46
47 #define NFS_enc_void_sz 0
48 #define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz
49 #define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz
50 #define NFS_readlinkargs_sz NFS_fhandle_sz
51 #define NFS_readargs_sz NFS_fhandle_sz+3
52 #define NFS_writeargs_sz NFS_fhandle_sz+4
53 #define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz
54 #define NFS_renameargs_sz NFS_diropargs_sz+NFS_diropargs_sz
55 #define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz
56 #define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
57 #define NFS_readdirargs_sz NFS_fhandle_sz+2
58
59 #define NFS_dec_void_sz 0
60 #define NFS_attrstat_sz 1+NFS_fattr_sz
61 #define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz
62 #define NFS_readlinkres_sz 1
63 #define NFS_readres_sz 1+NFS_fattr_sz+1
64 #define NFS_writeres_sz NFS_attrstat_sz
65 #define NFS_stat_sz 1
66 #define NFS_readdirres_sz 1
67 #define NFS_statfsres_sz 1+NFS_info_sz
68
69 /*
70 * Common NFS XDR functions as inlines
71 */
72 static inline u32 *
xdr_encode_fhandle(u32 * p,struct nfs_fh * fhandle)73 xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
74 {
75 memcpy(p, fhandle->data, NFS2_FHSIZE);
76 return p + XDR_QUADLEN(NFS2_FHSIZE);
77 }
78
79 static inline u32 *
xdr_decode_fhandle(u32 * p,struct nfs_fh * fhandle)80 xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
81 {
82 /* Zero handle first to allow comparisons */
83 memset(fhandle, 0, sizeof(*fhandle));
84 /* NFSv2 handles have a fixed length */
85 fhandle->size = NFS2_FHSIZE;
86 memcpy(fhandle->data, p, NFS2_FHSIZE);
87 return p + XDR_QUADLEN(NFS2_FHSIZE);
88 }
89
90 static inline u32*
xdr_decode_time(u32 * p,u64 * timep)91 xdr_decode_time(u32 *p, u64 *timep)
92 {
93 u64 tmp = (u64)ntohl(*p++) << 32;
94 *timep = tmp + (u64)ntohl(*p++);
95 return p;
96 }
97
98 static u32 *
xdr_decode_fattr(u32 * p,struct nfs_fattr * fattr)99 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
100 {
101 fattr->type = (enum nfs_ftype) ntohl(*p++);
102 fattr->mode = ntohl(*p++);
103 fattr->nlink = ntohl(*p++);
104 fattr->uid = ntohl(*p++);
105 fattr->gid = ntohl(*p++);
106 fattr->size = ntohl(*p++);
107 fattr->du.nfs2.blocksize = ntohl(*p++);
108 fattr->rdev = ntohl(*p++);
109 fattr->du.nfs2.blocks = ntohl(*p++);
110 fattr->fsid = ntohl(*p++);
111 fattr->fileid = ntohl(*p++);
112 p = xdr_decode_time(p, &fattr->atime);
113 p = xdr_decode_time(p, &fattr->mtime);
114 p = xdr_decode_time(p, &fattr->ctime);
115 fattr->valid |= NFS_ATTR_FATTR;
116 if (fattr->type == NFCHR && fattr->rdev == NFS2_FIFO_DEV) {
117 fattr->type = NFFIFO;
118 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
119 fattr->rdev = 0;
120 }
121 return p;
122 }
123
124 #define SATTR(p, attr, flag, field) \
125 *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
126 static inline u32 *
xdr_encode_sattr(u32 * p,struct iattr * attr)127 xdr_encode_sattr(u32 *p, struct iattr *attr)
128 {
129 SATTR(p, attr, ATTR_MODE, ia_mode);
130 SATTR(p, attr, ATTR_UID, ia_uid);
131 SATTR(p, attr, ATTR_GID, ia_gid);
132 SATTR(p, attr, ATTR_SIZE, ia_size);
133
134 if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
135 *p++ = htonl(attr->ia_atime);
136 *p++ = 0;
137 } else {
138 *p++ = ~(u32) 0;
139 *p++ = ~(u32) 0;
140 }
141
142 if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
143 *p++ = htonl(attr->ia_mtime);
144 *p++ = 0;
145 } else {
146 *p++ = ~(u32) 0;
147 *p++ = ~(u32) 0;
148 }
149 return p;
150 }
151 #undef SATTR
152
153 /*
154 * NFS encode functions
155 */
156 /*
157 * Encode void argument
158 */
159 static int
nfs_xdr_enc_void(struct rpc_rqst * req,u32 * p,void * dummy)160 nfs_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
161 {
162 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
163 return 0;
164 }
165
166 /*
167 * Encode file handle argument
168 * GETATTR, READLINK, STATFS
169 */
170 static int
nfs_xdr_fhandle(struct rpc_rqst * req,u32 * p,struct nfs_fh * fh)171 nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
172 {
173 p = xdr_encode_fhandle(p, fh);
174 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
175 return 0;
176 }
177
178 /*
179 * Encode SETATTR arguments
180 */
181 static int
nfs_xdr_sattrargs(struct rpc_rqst * req,u32 * p,struct nfs_sattrargs * args)182 nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
183 {
184 p = xdr_encode_fhandle(p, args->fh);
185 p = xdr_encode_sattr(p, args->sattr);
186 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
187 return 0;
188 }
189
190 /*
191 * Encode directory ops argument
192 * LOOKUP, REMOVE, RMDIR
193 */
194 static int
nfs_xdr_diropargs(struct rpc_rqst * req,u32 * p,struct nfs_diropargs * args)195 nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
196 {
197 p = xdr_encode_fhandle(p, args->fh);
198 p = xdr_encode_array(p, args->name, args->len);
199 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
200 return 0;
201 }
202
203 /*
204 * Arguments to a READ call. Since we read data directly into the page
205 * cache, we also set up the reply iovec here so that iov[1] points
206 * exactly to the page we want to fetch.
207 */
208 static int
nfs_xdr_readargs(struct rpc_rqst * req,u32 * p,struct nfs_readargs * args)209 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
210 {
211 struct rpc_auth *auth = req->rq_task->tk_auth;
212 unsigned int replen;
213 u32 offset = (u32)args->offset;
214 u32 count = args->count;
215
216 p = xdr_encode_fhandle(p, args->fh);
217 *p++ = htonl(offset);
218 *p++ = htonl(count);
219 *p++ = htonl(count);
220 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
221
222 /* Inline the page array */
223 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
224 xdr_inline_pages(&req->rq_rcv_buf, replen,
225 args->pages, args->pgbase, count);
226 return 0;
227 }
228
229 /*
230 * Decode READ reply
231 */
232 static int
nfs_xdr_readres(struct rpc_rqst * req,u32 * p,struct nfs_readres * res)233 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
234 {
235 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
236 struct iovec *iov = req->rq_rvec;
237 int status, count, recvd, hdrlen;
238
239 if ((status = ntohl(*p++)))
240 return -nfs_stat_to_errno(status);
241 p = xdr_decode_fattr(p, res->fattr);
242
243 count = ntohl(*p++);
244 res->eof = 0;
245 if (rcvbuf->page_len) {
246 u32 end = page_offset(rcvbuf->pages[0]) + rcvbuf->page_base + count;
247 if (end >= res->fattr->size)
248 res->eof = 1;
249 }
250 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
251 if (iov->iov_len < hdrlen) {
252 printk(KERN_WARNING "NFS: READ reply header overflowed:"
253 "length %d > %Zu\n", hdrlen, iov->iov_len);
254 return -errno_NFSERR_IO;
255 } else if (iov->iov_len != hdrlen) {
256 dprintk("NFS: READ header is short. iovec will be shifted.\n");
257 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
258 }
259
260 recvd = req->rq_received - hdrlen;
261 if (count > recvd) {
262 printk(KERN_WARNING "NFS: server cheating in read reply: "
263 "count %d > recvd %d\n", count, recvd);
264 count = recvd;
265 res->eof = 0;
266 }
267
268 dprintk("RPC: readres OK count %d\n", count);
269 if (count < res->count)
270 res->count = count;
271
272 return count;
273 }
274
275
276 /*
277 * Write arguments. Splice the buffer to be written into the iovec.
278 */
279 static int
nfs_xdr_writeargs(struct rpc_rqst * req,u32 * p,struct nfs_writeargs * args)280 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
281 {
282 struct xdr_buf *sndbuf = &req->rq_snd_buf;
283 u32 offset = (u32)args->offset;
284 u32 count = args->count;
285
286 p = xdr_encode_fhandle(p, args->fh);
287 *p++ = htonl(offset);
288 *p++ = htonl(offset);
289 *p++ = htonl(count);
290 *p++ = htonl(count);
291 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
292
293 /* Copy the page array */
294 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
295 return 0;
296 }
297
298 /*
299 * Encode create arguments
300 * CREATE, MKDIR
301 */
302 static int
nfs_xdr_createargs(struct rpc_rqst * req,u32 * p,struct nfs_createargs * args)303 nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
304 {
305 p = xdr_encode_fhandle(p, args->fh);
306 p = xdr_encode_array(p, args->name, args->len);
307 p = xdr_encode_sattr(p, args->sattr);
308 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
309 return 0;
310 }
311
312 /*
313 * Encode RENAME arguments
314 */
315 static int
nfs_xdr_renameargs(struct rpc_rqst * req,u32 * p,struct nfs_renameargs * args)316 nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
317 {
318 p = xdr_encode_fhandle(p, args->fromfh);
319 p = xdr_encode_array(p, args->fromname, args->fromlen);
320 p = xdr_encode_fhandle(p, args->tofh);
321 p = xdr_encode_array(p, args->toname, args->tolen);
322 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
323 return 0;
324 }
325
326 /*
327 * Encode LINK arguments
328 */
329 static int
nfs_xdr_linkargs(struct rpc_rqst * req,u32 * p,struct nfs_linkargs * args)330 nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
331 {
332 p = xdr_encode_fhandle(p, args->fromfh);
333 p = xdr_encode_fhandle(p, args->tofh);
334 p = xdr_encode_array(p, args->toname, args->tolen);
335 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
336 return 0;
337 }
338
339 /*
340 * Encode SYMLINK arguments
341 */
342 static int
nfs_xdr_symlinkargs(struct rpc_rqst * req,u32 * p,struct nfs_symlinkargs * args)343 nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
344 {
345 p = xdr_encode_fhandle(p, args->fromfh);
346 p = xdr_encode_array(p, args->fromname, args->fromlen);
347 p = xdr_encode_array(p, args->topath, args->tolen);
348 p = xdr_encode_sattr(p, args->sattr);
349 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
350 return 0;
351 }
352
353 /*
354 * Encode arguments to readdir call
355 */
356 static int
nfs_xdr_readdirargs(struct rpc_rqst * req,u32 * p,struct nfs_readdirargs * args)357 nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
358 {
359 struct rpc_task *task = req->rq_task;
360 struct rpc_auth *auth = task->tk_auth;
361 unsigned int replen;
362 u32 count = args->count;
363
364 /*
365 * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
366 * to be in longwords ... check whether to convert the size.
367 */
368 if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
369 count = count >> 2;
370
371 p = xdr_encode_fhandle(p, args->fh);
372 *p++ = htonl(args->cookie);
373 *p++ = htonl(count); /* see above */
374 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
375
376 /* Inline the page array */
377 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
378 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
379 return 0;
380 }
381
382 /*
383 * Decode the result of a readdir call.
384 * We're not really decoding anymore, we just leave the buffer untouched
385 * and only check that it is syntactically correct.
386 * The real decoding happens in nfs_decode_entry below, called directly
387 * from nfs_readdir for each entry.
388 */
389 static int
nfs_xdr_readdirres(struct rpc_rqst * req,u32 * p,void * dummy)390 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
391 {
392 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
393 struct iovec *iov = rcvbuf->head;
394 struct page **page;
395 int hdrlen, recvd;
396 int status, nr;
397 unsigned int len, pglen;
398 u32 *end, *entry;
399
400 if ((status = ntohl(*p++)))
401 return -nfs_stat_to_errno(status);
402
403 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
404 if (iov->iov_len < hdrlen) {
405 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
406 "length %d > %Zu\n", hdrlen, iov->iov_len);
407 return -errno_NFSERR_IO;
408 } else if (iov->iov_len != hdrlen) {
409 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
410 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
411 }
412
413 pglen = rcvbuf->page_len;
414 recvd = req->rq_received - hdrlen;
415 if (pglen > recvd)
416 pglen = recvd;
417 page = rcvbuf->pages;
418 p = kmap(*page);
419 entry = p;
420 end = (u32 *)((char *)p + pglen);
421 for (nr = 0; *p++; nr++) {
422 if (p + 2 > end)
423 goto short_pkt;
424 p++; /* fileid */
425 len = ntohl(*p++);
426 p += XDR_QUADLEN(len) + 1; /* name plus cookie */
427 if (len > NFS2_MAXNAMLEN) {
428 printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
429 len);
430 goto err_unmap;
431 }
432 if (p + 2 > end)
433 goto short_pkt;
434 entry = p;
435 }
436 if (!nr && (entry[0] != 0 || entry[1] == 0))
437 goto short_pkt;
438 out:
439 kunmap(*page);
440 return nr;
441 short_pkt:
442 entry[0] = entry[1] = 0;
443 /* truncate listing ? */
444 if (!nr) {
445 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
446 entry[1] = 1;
447 }
448 goto out;
449 err_unmap:
450 kunmap(*page);
451 return -errno_NFSERR_IO;
452 }
453
454 u32 *
nfs_decode_dirent(u32 * p,struct nfs_entry * entry,int plus)455 nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
456 {
457 if (!*p++) {
458 if (!*p)
459 return ERR_PTR(-EAGAIN);
460 entry->eof = 1;
461 return ERR_PTR(-EBADCOOKIE);
462 }
463
464 entry->ino = ntohl(*p++);
465 entry->len = ntohl(*p++);
466 entry->name = (const char *) p;
467 p += XDR_QUADLEN(entry->len);
468 entry->prev_cookie = entry->cookie;
469 entry->cookie = ntohl(*p++);
470 entry->eof = !p[0] && p[1];
471
472 return p;
473 }
474
475 /*
476 * NFS XDR decode functions
477 */
478 /*
479 * Decode void reply
480 */
481 static int
nfs_xdr_dec_void(struct rpc_rqst * req,u32 * p,void * dummy)482 nfs_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
483 {
484 return 0;
485 }
486
487 /*
488 * Decode simple status reply
489 */
490 static int
nfs_xdr_stat(struct rpc_rqst * req,u32 * p,void * dummy)491 nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
492 {
493 int status;
494
495 if ((status = ntohl(*p++)) != 0)
496 status = -nfs_stat_to_errno(status);
497 return status;
498 }
499
500 /*
501 * Decode attrstat reply
502 * GETATTR, SETATTR, WRITE
503 */
504 static int
nfs_xdr_attrstat(struct rpc_rqst * req,u32 * p,struct nfs_fattr * fattr)505 nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
506 {
507 int status;
508
509 if ((status = ntohl(*p++)))
510 return -nfs_stat_to_errno(status);
511 xdr_decode_fattr(p, fattr);
512 return 0;
513 }
514
515 /*
516 * Decode diropres reply
517 * LOOKUP, CREATE, MKDIR
518 */
519 static int
nfs_xdr_diropres(struct rpc_rqst * req,u32 * p,struct nfs_diropok * res)520 nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
521 {
522 int status;
523
524 if ((status = ntohl(*p++)))
525 return -nfs_stat_to_errno(status);
526 p = xdr_decode_fhandle(p, res->fh);
527 xdr_decode_fattr(p, res->fattr);
528 return 0;
529 }
530
531 /*
532 * Encode READLINK args
533 */
534 static int
nfs_xdr_readlinkargs(struct rpc_rqst * req,u32 * p,struct nfs_readlinkargs * args)535 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
536 {
537 struct rpc_auth *auth = req->rq_task->tk_auth;
538 unsigned int replen;
539 u32 count = args->count - 4;
540
541 p = xdr_encode_fhandle(p, args->fh);
542 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
543
544 /* Inline the page array */
545 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
546 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
547 return 0;
548 }
549
550 /*
551 * Decode READLINK reply
552 */
553 static int
nfs_xdr_readlinkres(struct rpc_rqst * req,u32 * p,void * dummy)554 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
555 {
556 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
557 struct iovec *iov = rcvbuf->head;
558 unsigned int hdrlen;
559 u32 *strlen, len;
560 char *string;
561 int status;
562
563 if ((status = ntohl(*p++)))
564 return -nfs_stat_to_errno(status);
565 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
566 if (iov->iov_len > hdrlen) {
567 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
568 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
569 }
570
571 strlen = (u32*)kmap(rcvbuf->pages[0]);
572 /* Convert length of symlink */
573 len = ntohl(*strlen);
574 if (len >= rcvbuf->page_len - sizeof(u32) || len > NFS2_MAXPATHLEN) {
575 dprintk("NFS: server returned giant symlink!\n");
576 kunmap(rcvbuf->pages[0]);
577 return -ENAMETOOLONG;
578 }
579 *strlen = len;
580 /* NULL terminate the string we got */
581 string = (char *)(strlen + 1);
582 string[len] = 0;
583 kunmap(rcvbuf->pages[0]);
584 return 0;
585 }
586
587 /*
588 * Decode WRITE reply
589 */
590 static int
nfs_xdr_writeres(struct rpc_rqst * req,u32 * p,struct nfs_writeres * res)591 nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
592 {
593 res->verf->committed = NFS_FILE_SYNC;
594 return nfs_xdr_attrstat(req, p, res->fattr);
595 }
596
597 /*
598 * Decode STATFS reply
599 */
600 static int
nfs_xdr_statfsres(struct rpc_rqst * req,u32 * p,struct nfs_fsinfo * res)601 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
602 {
603 int status;
604 u32 xfer_size;
605
606 if ((status = ntohl(*p++)))
607 return -nfs_stat_to_errno(status);
608
609 /* For NFSv2, we more or less have to guess the preferred
610 * read/write/readdir sizes from the single 'transfer size'
611 * value.
612 */
613 xfer_size = ntohl(*p++); /* tsize */
614 res->rtmax = 8 * 1024;
615 res->rtpref = xfer_size;
616 res->rtmult = xfer_size;
617 res->wtmax = 8 * 1024;
618 res->wtpref = xfer_size;
619 res->wtmult = xfer_size;
620 res->dtpref = PAGE_CACHE_SIZE;
621 res->maxfilesize = 0x7FFFFFFF; /* just a guess */
622 res->bsize = ntohl(*p++);
623
624 res->tbytes = ntohl(*p++) * res->bsize;
625 res->fbytes = ntohl(*p++) * res->bsize;
626 res->abytes = ntohl(*p++) * res->bsize;
627 res->tfiles = 0;
628 res->ffiles = 0;
629 res->afiles = 0;
630 res->namelen = 0;
631
632 return 0;
633 }
634
635 /*
636 * We need to translate between nfs status return values and
637 * the local errno values which may not be the same.
638 */
639 static struct {
640 int stat;
641 int errno;
642 } nfs_errtbl[] = {
643 { NFS_OK, 0 },
644 { NFSERR_PERM, EPERM },
645 { NFSERR_NOENT, ENOENT },
646 { NFSERR_IO, errno_NFSERR_IO },
647 { NFSERR_NXIO, ENXIO },
648 /* { NFSERR_EAGAIN, EAGAIN }, */
649 { NFSERR_ACCES, EACCES },
650 { NFSERR_EXIST, EEXIST },
651 { NFSERR_XDEV, EXDEV },
652 { NFSERR_NODEV, ENODEV },
653 { NFSERR_NOTDIR, ENOTDIR },
654 { NFSERR_ISDIR, EISDIR },
655 { NFSERR_INVAL, EINVAL },
656 { NFSERR_FBIG, EFBIG },
657 { NFSERR_NOSPC, ENOSPC },
658 { NFSERR_ROFS, EROFS },
659 { NFSERR_MLINK, EMLINK },
660 { NFSERR_NAMETOOLONG, ENAMETOOLONG },
661 { NFSERR_NOTEMPTY, ENOTEMPTY },
662 { NFSERR_DQUOT, EDQUOT },
663 { NFSERR_STALE, ESTALE },
664 { NFSERR_REMOTE, EREMOTE },
665 #ifdef EWFLUSH
666 { NFSERR_WFLUSH, EWFLUSH },
667 #endif
668 { NFSERR_BADHANDLE, EBADHANDLE },
669 { NFSERR_NOT_SYNC, ENOTSYNC },
670 { NFSERR_BAD_COOKIE, EBADCOOKIE },
671 { NFSERR_NOTSUPP, ENOTSUPP },
672 { NFSERR_TOOSMALL, ETOOSMALL },
673 { NFSERR_SERVERFAULT, ESERVERFAULT },
674 { NFSERR_BADTYPE, EBADTYPE },
675 { NFSERR_JUKEBOX, EJUKEBOX },
676 { -1, EIO }
677 };
678
679 /*
680 * Convert an NFS error code to a local one.
681 * This one is used jointly by NFSv2 and NFSv3.
682 */
683 int
nfs_stat_to_errno(int stat)684 nfs_stat_to_errno(int stat)
685 {
686 int i;
687
688 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
689 if (nfs_errtbl[i].stat == stat)
690 return nfs_errtbl[i].errno;
691 }
692 printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
693 return nfs_errtbl[i].errno;
694 }
695
696 #ifndef MAX
697 # define MAX(a, b) (((a) > (b))? (a) : (b))
698 #endif
699
700 #define PROC(proc, argtype, restype, timer) \
701 { .p_procname = "nfs_" #proc, \
702 .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \
703 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
704 .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
705 .p_timer = timer \
706 }
707 static struct rpc_procinfo nfs_procedures[18] = {
708 PROC(null, enc_void, dec_void, 0),
709 PROC(getattr, fhandle, attrstat, 1),
710 PROC(setattr, sattrargs, attrstat, 0),
711 PROC(root, enc_void, dec_void, 0),
712 PROC(lookup, diropargs, diropres, 2),
713 PROC(readlink, readlinkargs, readlinkres, 3),
714 PROC(read, readargs, readres, 3),
715 PROC(writecache, enc_void, dec_void, 0),
716 PROC(write, writeargs, writeres, 4),
717 PROC(create, createargs, diropres, 0),
718 PROC(remove, diropargs, stat, 0),
719 PROC(rename, renameargs, stat, 0),
720 PROC(link, linkargs, stat, 0),
721 PROC(symlink, symlinkargs, stat, 0),
722 PROC(mkdir, createargs, diropres, 0),
723 PROC(rmdir, diropargs, stat, 0),
724 PROC(readdir, readdirargs, readdirres, 3),
725 PROC(statfs, fhandle, statfsres, 0),
726 };
727
728 struct rpc_version nfs_version2 = {
729 2,
730 sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
731 nfs_procedures
732 };
733