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 30extern 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 */ 87static 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 */ 105static inline u32 * 106xdr_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 113static inline u32 * 114xdr_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 */ 132static inline u32 * 133xdr_encode_time(u32 *p, time_t time) 134{ 135 *p++ = htonl(time); 136 *p++ = 0; 137 return p; 138} 139 140static inline u32 * 141xdr_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 148static inline u32 * 149xdr_encode_time3(u32 *p, u64 time) 150{ 151 *p++ = htonl(time >> 32); 152 *p++ = htonl(time & 0xFFFFFFFF); 153 return p; 154} 155 156static u32 * 157xdr_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 187static inline u32 * 188xdr_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 233static inline u32 * 234xdr_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 243static inline u32 * 244xdr_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 251static inline u32 * 252xdr_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 260static inline u32 * 261xdr_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 */ 273static int 274nfs3_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 */ 283static int 284nfs3_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 */ 294static int 295nfs3_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 */ 309static int 310nfs3_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 */ 321static int 322nfs3_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 */ 335static int 336nfs3_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 */ 357static int 358nfs3_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 */ 378static int 379nfs3_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 */ 398static int 399nfs3_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 */ 411static int 412nfs3_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 */ 425static int 426nfs3_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 */ 444static int 445nfs3_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 */ 458static int 459nfs3_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 */ 471static int 472nfs3_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 */ 500static int 501nfs3_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; 594err_unmap: 595 kunmap(*page); 596 return -errno_NFSERR_IO; 597} 598 599u32 * 600nfs3_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 */ 643static int 644nfs3_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 */ 659static int 660nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy) 661{ 662 return 0; 663} 664 665/* 666 * Decode attrstat reply. 667 */ 668static int 669nfs3_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 */ 683static int 684nfs3_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 */ 697static int 698nfs3_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 */ 716static int 717nfs3_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 728static int 729nfs3_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 */ 747static int 748nfs3_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 */ 785static int 786nfs3_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 */ 836static int 837nfs3_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 */ 858static int 859nfs3_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 */ 885static int 886nfs3_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 */ 900static int 901nfs3_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 */ 915static int 916nfs3_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 */ 941static int 942nfs3_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 */ 969static int 970nfs3_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 */ 990static int 991nfs3_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 1017static 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 1042struct rpc_version nfs_version3 = { 1043 3, 1044 sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]), 1045 nfs3_procedures 1046}; 1047 1048