FreeBSD/Linux Kernel Cross Reference
sys/fs/nfs/nfs3xdr.c
1 /*
2 * linux/fs/nfs/nfs3xdr.c
3 *
4 * XDR functions to encode/decode NFSv3 RPC arguments and results.
5 *
6 * Copyright (C) 1996, 1997 Olaf Kirch
7 */
8
9 #include <linux/param.h>
10 #include <linux/sched.h>
11 #include <linux/mm.h>
12 #include <linux/slab.h>
13 #include <linux/utsname.h>
14 #include <linux/errno.h>
15 #include <linux/string.h>
16 #include <linux/in.h>
17 #include <linux/pagemap.h>
18 #include <linux/proc_fs.h>
19 #include <linux/kdev_t.h>
20 #include <linux/sunrpc/clnt.h>
21 #include <linux/nfs.h>
22 #include <linux/nfs3.h>
23 #include <linux/nfs_fs.h>
24
25 #define NFSDBG_FACILITY NFSDBG_XDR
26
27 /* Mapping from NFS error code to "errno" error code. */
28 #define errno_NFSERR_IO EIO
29
30 extern int nfs_stat_to_errno(int);
31
32 /*
33 * Declare the space requirements for NFS arguments and replies as
34 * number of 32bit-words
35 */
36 #define NFS3_fhandle_sz 1+16
37 #define NFS3_fh_sz NFS3_fhandle_sz /* shorthand */
38 #define NFS3_sattr_sz 15
39 #define NFS3_filename_sz 1+(NFS3_MAXNAMLEN>>2)
40 #define NFS3_path_sz 1+(NFS3_MAXPATHLEN>>2)
41 #define NFS3_fattr_sz 21
42 #define NFS3_wcc_attr_sz 6
43 #define NFS3_pre_op_attr_sz 1+NFS3_wcc_attr_sz
44 #define NFS3_post_op_attr_sz 1+NFS3_fattr_sz
45 #define NFS3_wcc_data_sz NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
46 #define NFS3_fsstat_sz
47 #define NFS3_fsinfo_sz
48 #define NFS3_pathconf_sz
49 #define NFS3_entry_sz NFS3_filename_sz+3
50
51 #define NFS3_enc_void_sz 0
52 #define NFS3_sattrargs_sz NFS3_fh_sz+NFS3_sattr_sz+3
53 #define NFS3_diropargs_sz NFS3_fh_sz+NFS3_filename_sz
54 #define NFS3_accessargs_sz NFS3_fh_sz+1
55 #define NFS3_readlinkargs_sz NFS3_fh_sz
56 #define NFS3_readargs_sz NFS3_fh_sz+3
57 #define NFS3_writeargs_sz NFS3_fh_sz+5
58 #define NFS3_createargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
59 #define NFS3_mkdirargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
60 #define NFS3_symlinkargs_sz NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
61 #define NFS3_mknodargs_sz NFS3_diropargs_sz+2+NFS3_sattr_sz
62 #define NFS3_renameargs_sz NFS3_diropargs_sz+NFS3_diropargs_sz
63 #define NFS3_linkargs_sz NFS3_fh_sz+NFS3_diropargs_sz
64 #define NFS3_readdirargs_sz NFS3_fh_sz+2
65 #define NFS3_commitargs_sz NFS3_fh_sz+3
66
67 #define NFS3_dec_void_sz 0
68 #define NFS3_attrstat_sz 1+NFS3_fattr_sz
69 #define NFS3_wccstat_sz 1+NFS3_wcc_data_sz
70 #define NFS3_lookupres_sz 1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
71 #define NFS3_accessres_sz 1+NFS3_post_op_attr_sz+1
72 #define NFS3_readlinkres_sz 1+NFS3_post_op_attr_sz
73 #define NFS3_readres_sz 1+NFS3_post_op_attr_sz+3
74 #define NFS3_writeres_sz 1+NFS3_wcc_data_sz+4
75 #define NFS3_createres_sz 1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
76 #define NFS3_renameres_sz 1+(2 * NFS3_wcc_data_sz)
77 #define NFS3_linkres_sz 1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
78 #define NFS3_readdirres_sz 1+NFS3_post_op_attr_sz+2
79 #define NFS3_fsstatres_sz 1+NFS3_post_op_attr_sz+13
80 #define NFS3_fsinfores_sz 1+NFS3_post_op_attr_sz+12
81 #define NFS3_pathconfres_sz 1+NFS3_post_op_attr_sz+6
82 #define NFS3_commitres_sz 1+NFS3_wcc_data_sz+2
83
84 /*
85 * Map file type to S_IFMT bits
86 */
87 static struct {
88 unsigned int mode;
89 unsigned int nfs2type;
90 } nfs_type2fmt[] = {
91 { 0, NFNON },
92 { S_IFREG, NFREG },
93 { S_IFDIR, NFDIR },
94 { S_IFBLK, NFBLK },
95 { S_IFCHR, NFCHR },
96 { S_IFLNK, NFLNK },
97 { S_IFSOCK, NFSOCK },
98 { S_IFIFO, NFFIFO },
99 { 0, NFBAD }
100 };
101
102 /*
103 * Common NFS XDR functions as inlines
104 */
105 static inline u32 *
106 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
107 {
108 *p++ = htonl(fh->size);
109 memcpy(p, fh->data, fh->size);
110 return p + XDR_QUADLEN(fh->size);
111 }
112
113 static inline u32 *
114 xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
115 {
116 /*
117 * Zero all nonused bytes
118 */
119 memset((u8 *)fh, 0, sizeof(*fh));
120 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
121 memcpy(fh->data, p, fh->size);
122 return p + XDR_QUADLEN(fh->size);
123 }
124 return NULL;
125 }
126
127 /*
128 * Encode/decode time.
129 * Since the VFS doesn't care for fractional times, we ignore the
130 * nanosecond field.
131 */
132 static inline u32 *
133 xdr_encode_time(u32 *p, time_t time)
134 {
135 *p++ = htonl(time);
136 *p++ = 0;
137 return p;
138 }
139
140 static inline u32 *
141 xdr_decode_time3(u32 *p, u64 *timep)
142 {
143 u64 tmp = (u64)ntohl(*p++) << 32;
144 *timep = tmp + (u64)ntohl(*p++);
145 return p;
146 }
147
148 static inline u32 *
149 xdr_encode_time3(u32 *p, u64 time)
150 {
151 *p++ = htonl(time >> 32);
152 *p++ = htonl(time & 0xFFFFFFFF);
153 return p;
154 }
155
156 static u32 *
157 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
158 {
159 unsigned int type;
160 int fmode;
161
162 type = ntohl(*p++);
163 if (type >= NF3BAD)
164 type = NF3BAD;
165 fmode = nfs_type2fmt[type].mode;
166 fattr->type = nfs_type2fmt[type].nfs2type;
167 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
168 fattr->nlink = ntohl(*p++);
169 fattr->uid = ntohl(*p++);
170 fattr->gid = ntohl(*p++);
171 p = xdr_decode_hyper(p, &fattr->size);
172 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
173 /* Turn remote device info into Linux-specific dev_t */
174 fattr->rdev = ntohl(*p++) << MINORBITS;
175 fattr->rdev |= ntohl(*p++) & MINORMASK;
176 p = xdr_decode_hyper(p, &fattr->fsid);
177 p = xdr_decode_hyper(p, &fattr->fileid);
178 p = xdr_decode_time3(p, &fattr->atime);
179 p = xdr_decode_time3(p, &fattr->mtime);
180 p = xdr_decode_time3(p, &fattr->ctime);
181
182 /* Update the mode bits */
183 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
184 return p;
185 }
186
187 static inline u32 *
188 xdr_encode_sattr(u32 *p, struct iattr *attr)
189 {
190 if (attr->ia_valid & ATTR_MODE) {
191 *p++ = xdr_one;
192 *p++ = htonl(attr->ia_mode);
193 } else {
194 *p++ = xdr_zero;
195 }
196 if (attr->ia_valid & ATTR_UID) {
197 *p++ = xdr_one;
198 *p++ = htonl(attr->ia_uid);
199 } else {
200 *p++ = xdr_zero;
201 }
202 if (attr->ia_valid & ATTR_GID) {
203 *p++ = xdr_one;
204 *p++ = htonl(attr->ia_gid);
205 } else {
206 *p++ = xdr_zero;
207 }
208 if (attr->ia_valid & ATTR_SIZE) {
209 *p++ = xdr_one;
210 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
211 } else {
212 *p++ = xdr_zero;
213 }
214 if (attr->ia_valid & ATTR_ATIME_SET) {
215 *p++ = xdr_two;
216 p = xdr_encode_time(p, attr->ia_atime);
217 } else if (attr->ia_valid & ATTR_ATIME) {
218 *p++ = xdr_one;
219 } else {
220 *p++ = xdr_zero;
221 }
222 if (attr->ia_valid & ATTR_MTIME_SET) {
223 *p++ = xdr_two;
224 p = xdr_encode_time(p, attr->ia_mtime);
225 } else if (attr->ia_valid & ATTR_MTIME) {
226 *p++ = xdr_one;
227 } else {
228 *p++ = xdr_zero;
229 }
230 return p;
231 }
232
233 static inline u32 *
234 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
235 {
236 p = xdr_decode_hyper(p, &fattr->pre_size);
237 p = xdr_decode_time3(p, &fattr->pre_mtime);
238 p = xdr_decode_time3(p, &fattr->pre_ctime);
239 fattr->valid |= NFS_ATTR_WCC;
240 return p;
241 }
242
243 static inline u32 *
244 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
245 {
246 if (*p++)
247 p = xdr_decode_fattr(p, fattr);
248 return p;
249 }
250
251 static inline u32 *
252 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
253 {
254 if (*p++)
255 return xdr_decode_wcc_attr(p, fattr);
256 return p;
257 }
258
259
260 static inline u32 *
261 xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
262 {
263 p = xdr_decode_pre_op_attr(p, fattr);
264 return xdr_decode_post_op_attr(p, fattr);
265 }
266
267 /*
268 * NFS encode functions
269 */
270 /*
271 * Encode void argument
272 */
273 static int
274 nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
275 {
276 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
277 return 0;
278 }
279
280 /*
281 * Encode file handle argument
282 */
283 static int
284 nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
285 {
286 p = xdr_encode_fhandle(p, fh);
287 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
288 return 0;
289 }
290
291 /*
292 * Encode SETATTR arguments
293 */
294 static int
295 nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
296 {
297 p = xdr_encode_fhandle(p, args->fh);
298 p = xdr_encode_sattr(p, args->sattr);
299 *p++ = htonl(args->guard);
300 if (args->guard)
301 p = xdr_encode_time3(p, args->guardtime);
302 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
303 return 0;
304 }
305
306 /*
307 * Encode directory ops argument
308 */
309 static int
310 nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
311 {
312 p = xdr_encode_fhandle(p, args->fh);
313 p = xdr_encode_array(p, args->name, args->len);
314 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
315 return 0;
316 }
317
318 /*
319 * Encode access() argument
320 */
321 static int
322 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
323 {
324 p = xdr_encode_fhandle(p, args->fh);
325 *p++ = htonl(args->access);
326 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
327 return 0;
328 }
329
330 /*
331 * Arguments to a READ call. Since we read data directly into the page
332 * cache, we also set up the reply iovec here so that iov[1] points
333 * exactly to the page we want to fetch.
334 */
335 static int
336 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
337 {
338 struct rpc_auth *auth = req->rq_task->tk_auth;
339 unsigned int replen;
340 u32 count = args->count;
341
342 p = xdr_encode_fhandle(p, args->fh);
343 p = xdr_encode_hyper(p, args->offset);
344 *p++ = htonl(count);
345 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
346
347 /* Inline the page array */
348 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
349 xdr_inline_pages(&req->rq_rcv_buf, replen,
350 args->pages, args->pgbase, count);
351 return 0;
352 }
353
354 /*
355 * Write arguments. Splice the buffer to be written into the iovec.
356 */
357 static int
358 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
359 {
360 struct xdr_buf *sndbuf = &req->rq_snd_buf;
361 u32 count = args->count;
362
363 p = xdr_encode_fhandle(p, args->fh);
364 p = xdr_encode_hyper(p, args->offset);
365 *p++ = htonl(count);
366 *p++ = htonl(args->stable);
367 *p++ = htonl(count);
368 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
369
370 /* Copy the page array */
371 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
372 return 0;
373 }
374
375 /*
376 * Encode CREATE arguments
377 */
378 static int
379 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
380 {
381 p = xdr_encode_fhandle(p, args->fh);
382 p = xdr_encode_array(p, args->name, args->len);
383
384 *p++ = htonl(args->createmode);
385 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
386 *p++ = args->verifier[0];
387 *p++ = args->verifier[1];
388 } else
389 p = xdr_encode_sattr(p, args->sattr);
390
391 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
392 return 0;
393 }
394
395 /*
396 * Encode MKDIR arguments
397 */
398 static int
399 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
400 {
401 p = xdr_encode_fhandle(p, args->fh);
402 p = xdr_encode_array(p, args->name, args->len);
403 p = xdr_encode_sattr(p, args->sattr);
404 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
405 return 0;
406 }
407
408 /*
409 * Encode SYMLINK arguments
410 */
411 static int
412 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
413 {
414 p = xdr_encode_fhandle(p, args->fromfh);
415 p = xdr_encode_array(p, args->fromname, args->fromlen);
416 p = xdr_encode_sattr(p, args->sattr);
417 p = xdr_encode_array(p, args->topath, args->tolen);
418 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
419 return 0;
420 }
421
422 /*
423 * Encode MKNOD arguments
424 */
425 static int
426 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
427 {
428 p = xdr_encode_fhandle(p, args->fh);
429 p = xdr_encode_array(p, args->name, args->len);
430 *p++ = htonl(args->type);
431 p = xdr_encode_sattr(p, args->sattr);
432 if (args->type == NF3CHR || args->type == NF3BLK) {
433 *p++ = htonl(args->rdev >> MINORBITS);
434 *p++ = htonl(args->rdev & MINORMASK);
435 }
436
437 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
438 return 0;
439 }
440
441 /*
442 * Encode RENAME arguments
443 */
444 static int
445 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
446 {
447 p = xdr_encode_fhandle(p, args->fromfh);
448 p = xdr_encode_array(p, args->fromname, args->fromlen);
449 p = xdr_encode_fhandle(p, args->tofh);
450 p = xdr_encode_array(p, args->toname, args->tolen);
451 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
452 return 0;
453 }
454
455 /*
456 * Encode LINK arguments
457 */
458 static int
459 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
460 {
461 p = xdr_encode_fhandle(p, args->fromfh);
462 p = xdr_encode_fhandle(p, args->tofh);
463 p = xdr_encode_array(p, args->toname, args->tolen);
464 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
465 return 0;
466 }
467
468 /*
469 * Encode arguments to readdir call
470 */
471 static int
472 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
473 {
474 struct rpc_auth *auth = req->rq_task->tk_auth;
475 unsigned int replen;
476 u32 count = args->count;
477
478 p = xdr_encode_fhandle(p, args->fh);
479 p = xdr_encode_hyper(p, args->cookie);
480 *p++ = args->verf[0];
481 *p++ = args->verf[1];
482 if (args->plus) {
483 /* readdirplus: need dircount + buffer size.
484 * We just make sure we make dircount big enough */
485 *p++ = htonl(count >> 3);
486 }
487 *p++ = htonl(count);
488 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
489
490 /* Inline the page array */
491 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
492 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
493 return 0;
494 }
495
496 /*
497 * Decode the result of a readdir call.
498 * We just check for syntactical correctness.
499 */
500 static int
501 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
502 {
503 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
504 struct iovec *iov = rcvbuf->head;
505 struct page **page;
506 int hdrlen, recvd;
507 int status, nr;
508 unsigned int len, pglen;
509 u32 *entry, *end;
510
511 status = ntohl(*p++);
512 /* Decode post_op_attrs */
513 p = xdr_decode_post_op_attr(p, res->dir_attr);
514 if (status)
515 return -nfs_stat_to_errno(status);
516 /* Decode verifier cookie */
517 if (res->verf) {
518 res->verf[0] = *p++;
519 res->verf[1] = *p++;
520 } else {
521 p += 2;
522 }
523
524 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
525 if (iov->iov_len < hdrlen) {
526 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
527 "length %d > %Zu\n", hdrlen, iov->iov_len);
528 return -errno_NFSERR_IO;
529 } else if (iov->iov_len != hdrlen) {
530 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
531 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
532 }
533
534 pglen = rcvbuf->page_len;
535 recvd = req->rq_received - hdrlen;
536 if (pglen > recvd)
537 pglen = recvd;
538 page = rcvbuf->pages;
539 p = kmap(*page);
540 end = (u32 *)((char *)p + pglen);
541 entry = p;
542 for (nr = 0; *p++; nr++) {
543 if (p + 3 > end)
544 goto short_pkt;
545 p += 2; /* inode # */
546 len = ntohl(*p++); /* string length */
547 p += XDR_QUADLEN(len) + 2; /* name + cookie */
548 if (len > NFS3_MAXNAMLEN) {
549 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
550 len);
551 goto err_unmap;
552 }
553
554 if (res->plus) {
555 /* post_op_attr */
556 if (p > end)
557 goto short_pkt;
558 if (*p++) {
559 p += 21;
560 if (p > end)
561 goto short_pkt;
562 }
563 /* post_op_fh3 */
564 if (*p++) {
565 if (p > end)
566 goto short_pkt;
567 len = ntohl(*p++);
568 if (len > NFS3_FHSIZE) {
569 printk(KERN_WARNING "NFS: giant filehandle in "
570 "readdir (len %x)!\n", len);
571 goto err_unmap;
572 }
573 p += XDR_QUADLEN(len);
574 }
575 }
576
577 if (p + 2 > end)
578 goto short_pkt;
579 entry = p;
580 }
581 if (!nr && (entry[0] != 0 || entry[1] == 0))
582 goto short_pkt;
583 out:
584 kunmap(*page);
585 return nr;
586 short_pkt:
587 entry[0] = entry[1] = 0;
588 /* truncate listing ? */
589 if (!nr) {
590 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
591 entry[1] = 1;
592 }
593 goto out;
594 err_unmap:
595 kunmap(*page);
596 return -errno_NFSERR_IO;
597 }
598
599 u32 *
600 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
601 {
602 struct nfs_entry old = *entry;
603
604 if (!*p++) {
605 if (!*p)
606 return ERR_PTR(-EAGAIN);
607 entry->eof = 1;
608 return ERR_PTR(-EBADCOOKIE);
609 }
610
611 p = xdr_decode_hyper(p, &entry->ino);
612 entry->len = ntohl(*p++);
613 entry->name = (const char *) p;
614 p += XDR_QUADLEN(entry->len);
615 entry->prev_cookie = entry->cookie;
616 p = xdr_decode_hyper(p, &entry->cookie);
617
618 if (plus) {
619 p = xdr_decode_post_op_attr(p, &entry->fattr);
620 /* In fact, a post_op_fh3: */
621 if (*p++) {
622 p = xdr_decode_fhandle(p, &entry->fh);
623 /* Ugh -- server reply was truncated */
624 if (p == NULL) {
625 dprintk("NFS: FH truncated\n");
626 *entry = old;
627 return ERR_PTR(-EAGAIN);
628 }
629 } else {
630 /* If we don't get a file handle, the attrs
631 * aren't worth a lot. */
632 entry->fattr.valid = 0;
633 }
634 }
635
636 entry->eof = !p[0] && p[1];
637 return p;
638 }
639
640 /*
641 * Encode COMMIT arguments
642 */
643 static int
644 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
645 {
646 p = xdr_encode_fhandle(p, args->fh);
647 p = xdr_encode_hyper(p, args->offset);
648 *p++ = htonl(args->count);
649 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
650 return 0;
651 }
652
653 /*
654 * NFS XDR decode functions
655 */
656 /*
657 * Decode void reply
658 */
659 static int
660 nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
661 {
662 return 0;
663 }
664
665 /*
666 * Decode attrstat reply.
667 */
668 static int
669 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
670 {
671 int status;
672
673 if ((status = ntohl(*p++)))
674 return -nfs_stat_to_errno(status);
675 xdr_decode_fattr(p, fattr);
676 return 0;
677 }
678
679 /*
680 * Decode status+wcc_data reply
681 * SATTR, REMOVE, RMDIR
682 */
683 static int
684 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
685 {
686 int status;
687
688 if ((status = ntohl(*p++)))
689 status = -nfs_stat_to_errno(status);
690 xdr_decode_wcc_data(p, fattr);
691 return status;
692 }
693
694 /*
695 * Decode LOOKUP reply
696 */
697 static int
698 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
699 {
700 int status;
701
702 if ((status = ntohl(*p++))) {
703 status = -nfs_stat_to_errno(status);
704 } else {
705 if (!(p = xdr_decode_fhandle(p, res->fh)))
706 return -errno_NFSERR_IO;
707 p = xdr_decode_post_op_attr(p, res->fattr);
708 }
709 xdr_decode_post_op_attr(p, res->dir_attr);
710 return status;
711 }
712
713 /*
714 * Decode ACCESS reply
715 */
716 static int
717 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
718 {
719 int status = ntohl(*p++);
720
721 p = xdr_decode_post_op_attr(p, res->fattr);
722 if (status)
723 return -nfs_stat_to_errno(status);
724 res->access = ntohl(*p++);
725 return 0;
726 }
727
728 static int
729 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
730 {
731 struct rpc_auth *auth = req->rq_task->tk_auth;
732 unsigned int replen;
733 u32 count = args->count - 4;
734
735 p = xdr_encode_fhandle(p, args->fh);
736 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
737
738 /* Inline the page array */
739 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
740 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
741 return 0;
742 }
743
744 /*
745 * Decode READLINK reply
746 */
747 static int
748 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
749 {
750 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
751 struct iovec *iov = rcvbuf->head;
752 unsigned int hdrlen;
753 u32 *strlen, len;
754 char *string;
755 int status;
756
757 status = ntohl(*p++);
758 p = xdr_decode_post_op_attr(p, fattr);
759
760 if (status != 0)
761 return -nfs_stat_to_errno(status);
762
763 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
764 if (iov->iov_len > hdrlen) {
765 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
766 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
767 }
768
769 strlen = (u32*)kmap(rcvbuf->pages[0]);
770 /* Convert length of symlink */
771 len = ntohl(*strlen);
772 if (len > rcvbuf->page_len)
773 len = rcvbuf->page_len;
774 *strlen = len;
775 /* NULL terminate the string we got */
776 string = (char *)(strlen + 1);
777 string[len] = 0;
778 kunmap(rcvbuf->pages[0]);
779 return 0;
780 }
781
782 /*
783 * Decode READ reply
784 */
785 static int
786 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
787 {
788 struct iovec *iov = req->rq_rvec;
789 int status, count, ocount, recvd, hdrlen;
790
791 status = ntohl(*p++);
792 p = xdr_decode_post_op_attr(p, res->fattr);
793
794 if (status != 0)
795 return -nfs_stat_to_errno(status);
796
797 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
798 * in that it puts the count both in the res struct and in the
799 * opaque data count. */
800 count = ntohl(*p++);
801 res->eof = ntohl(*p++);
802 ocount = ntohl(*p++);
803
804 if (ocount != count) {
805 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
806 return -errno_NFSERR_IO;
807 }
808
809 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
810 if (iov->iov_len < hdrlen) {
811 printk(KERN_WARNING "NFS: READ reply header overflowed:"
812 "length %d > %Zu\n", hdrlen, iov->iov_len);
813 return -errno_NFSERR_IO;
814 } else if (iov->iov_len != hdrlen) {
815 dprintk("NFS: READ header is short. iovec will be shifted.\n");
816 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
817 }
818
819 recvd = req->rq_received - hdrlen;
820 if (count > recvd) {
821 printk(KERN_WARNING "NFS: server cheating in read reply: "
822 "count %d > recvd %d\n", count, recvd);
823 count = recvd;
824 res->eof = 0;
825 }
826
827 if (count < res->count)
828 res->count = count;
829
830 return count;
831 }
832
833 /*
834 * Decode WRITE response
835 */
836 static int
837 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
838 {
839 int status;
840
841 status = ntohl(*p++);
842 p = xdr_decode_wcc_data(p, res->fattr);
843
844 if (status != 0)
845 return -nfs_stat_to_errno(status);
846
847 res->count = ntohl(*p++);
848 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
849 res->verf->verifier[0] = *p++;
850 res->verf->verifier[1] = *p++;
851
852 return res->count;
853 }
854
855 /*
856 * Decode a CREATE response
857 */
858 static int
859 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
860 {
861 int status;
862
863 status = ntohl(*p++);
864 if (status == 0) {
865 if (*p++) {
866 if (!(p = xdr_decode_fhandle(p, res->fh)))
867 return -errno_NFSERR_IO;
868 p = xdr_decode_post_op_attr(p, res->fattr);
869 } else {
870 memset(res->fh, 0, sizeof(*res->fh));
871 /* Do decode post_op_attr but set it to NULL */
872 p = xdr_decode_post_op_attr(p, res->fattr);
873 res->fattr->valid = 0;
874 }
875 } else {
876 status = -nfs_stat_to_errno(status);
877 }
878 p = xdr_decode_wcc_data(p, res->dir_attr);
879 return status;
880 }
881
882 /*
883 * Decode RENAME reply
884 */
885 static int
886 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
887 {
888 int status;
889
890 if ((status = ntohl(*p++)) != 0)
891 status = -nfs_stat_to_errno(status);
892 p = xdr_decode_wcc_data(p, res->fromattr);
893 p = xdr_decode_wcc_data(p, res->toattr);
894 return status;
895 }
896
897 /*
898 * Decode LINK reply
899 */
900 static int
901 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
902 {
903 int status;
904
905 if ((status = ntohl(*p++)) != 0)
906 status = -nfs_stat_to_errno(status);
907 p = xdr_decode_post_op_attr(p, res->fattr);
908 p = xdr_decode_wcc_data(p, res->dir_attr);
909 return status;
910 }
911
912 /*
913 * Decode FSSTAT reply
914 */
915 static int
916 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
917 {
918 struct nfs_fattr dummy;
919 int status;
920
921 status = ntohl(*p++);
922
923 p = xdr_decode_post_op_attr(p, &dummy);
924 if (status != 0)
925 return -nfs_stat_to_errno(status);
926
927 p = xdr_decode_hyper(p, &res->tbytes);
928 p = xdr_decode_hyper(p, &res->fbytes);
929 p = xdr_decode_hyper(p, &res->abytes);
930 p = xdr_decode_hyper(p, &res->tfiles);
931 p = xdr_decode_hyper(p, &res->ffiles);
932 p = xdr_decode_hyper(p, &res->afiles);
933
934 /* ignore invarsec */
935 return 0;
936 }
937
938 /*
939 * Decode FSINFO reply
940 */
941 static int
942 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
943 {
944 struct nfs_fattr dummy;
945 int status;
946
947 status = ntohl(*p++);
948
949 p = xdr_decode_post_op_attr(p, &dummy);
950 if (status != 0)
951 return -nfs_stat_to_errno(status);
952
953 res->rtmax = ntohl(*p++);
954 res->rtpref = ntohl(*p++);
955 res->rtmult = ntohl(*p++);
956 res->wtmax = ntohl(*p++);
957 res->wtpref = ntohl(*p++);
958 res->wtmult = ntohl(*p++);
959 res->dtpref = ntohl(*p++);
960 p = xdr_decode_hyper(p, &res->maxfilesize);
961
962 /* ignore time_delta and properties */
963 return 0;
964 }
965
966 /*
967 * Decode PATHCONF reply
968 */
969 static int
970 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
971 {
972 struct nfs_fattr dummy;
973 int status;
974
975 status = ntohl(*p++);
976
977 p = xdr_decode_post_op_attr(p, &dummy);
978 if (status != 0)
979 return -nfs_stat_to_errno(status);
980 res->linkmax = ntohl(*p++);
981 res->namelen = ntohl(*p++);
982
983 /* ignore remaining fields */
984 return 0;
985 }
986
987 /*
988 * Decode COMMIT reply
989 */
990 static int
991 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
992 {
993 int status;
994
995 status = ntohl(*p++);
996 p = xdr_decode_wcc_data(p, res->fattr);
997 if (status != 0)
998 return -nfs_stat_to_errno(status);
999
1000 res->verf->verifier[0] = *p++;
1001 res->verf->verifier[1] = *p++;
1002 return 0;
1003 }
1004
1005 #ifndef MAX
1006 # define MAX(a, b) (((a) > (b))? (a) : (b))
1007 #endif
1008
1009 #define PROC(proc, argtype, restype, timer) \
1010 { .p_procname = "nfs3_" #proc, \
1011 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1012 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1013 .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
1014 .p_timer = timer \
1015 }
1016
1017 static struct rpc_procinfo nfs3_procedures[22] = {
1018 PROC(null, enc_void, dec_void, 0),
1019 PROC(getattr, fhandle, attrstat, 1),
1020 PROC(setattr, sattrargs, wccstat, 0),
1021 PROC(lookup, diropargs, lookupres, 2),
1022 PROC(access, accessargs, accessres, 1),
1023 PROC(readlink, readlinkargs, readlinkres, 3),
1024 PROC(read, readargs, readres, 3),
1025 PROC(write, writeargs, writeres, 4),
1026 PROC(create, createargs, createres, 0),
1027 PROC(mkdir, mkdirargs, createres, 0),
1028 PROC(symlink, symlinkargs, createres, 0),
1029 PROC(mknod, mknodargs, createres, 0),
1030 PROC(remove, diropargs, wccstat, 0),
1031 PROC(rmdir, diropargs, wccstat, 0),
1032 PROC(rename, renameargs, renameres, 0),
1033 PROC(link, linkargs, linkres, 0),
1034 PROC(readdir, readdirargs, readdirres, 3),
1035 PROC(readdirplus, readdirargs, readdirres, 3),
1036 PROC(fsstat, fhandle, fsstatres, 0),
1037 PROC(fsinfo, fhandle, fsinfores, 0),
1038 PROC(pathconf, fhandle, pathconfres, 0),
1039 PROC(commit, commitargs, commitres, 5),
1040 };
1041
1042 struct rpc_version nfs_version3 = {
1043 3,
1044 sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1045 nfs3_procedures
1046 };
1047
Cache object: c2d9d4c5e9d8d19c99e529a66bc92744
|