1 /* 2 * linux/fs/nfsd/nfs3xdr.c 3 * 4 * XDR support for nfsd/protocol version 3. 5 * 6 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> 7 * 8 * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()! 9 */ 10 11 #include <linux/types.h> 12 #include <linux/time.h> 13 #include <linux/nfs3.h> 14 #include <linux/list.h> 15 #include <linux/spinlock.h> 16 #include <linux/dcache.h> 17 #include <linux/namei.h> 18 #include <linux/mm.h> 19 #include <linux/vfs.h> 20 #include <linux/sunrpc/xdr.h> 21 #include <linux/sunrpc/svc.h> 22 #include <linux/nfsd/nfsd.h> 23 #include <linux/nfsd/xdr3.h> 24 25 #define NFSDDBG_FACILITY NFSDDBG_XDR 26 27 #ifdef NFSD_OPTIMIZE_SPACE 28 # define inline 29 #endif 30 31 32 /* 33 * Mapping of S_IF* types to NFS file types 34 */ 35 static u32 nfs3_ftypes[] = { 36 NF3NON, NF3FIFO, NF3CHR, NF3BAD, 37 NF3DIR, NF3BAD, NF3BLK, NF3BAD, 38 NF3REG, NF3BAD, NF3LNK, NF3BAD, 39 NF3SOCK, NF3BAD, NF3LNK, NF3BAD, 40 }; 41 42 /* 43 * XDR functions for basic NFS types 44 */ 45 static inline u32 * 46 encode_time3(u32 *p, struct timespec *time) 47 { 48 *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec); 49 return p; 50 } 51 52 static inline u32 * 53 decode_time3(u32 *p, struct timespec *time) 54 { 55 time->tv_sec = ntohl(*p++); 56 time->tv_nsec = ntohl(*p++); 57 return p; 58 } 59 60 static inline u32 * 61 decode_fh(u32 *p, struct svc_fh *fhp) 62 { 63 unsigned int size; 64 fh_init(fhp, NFS3_FHSIZE); 65 size = ntohl(*p++); 66 if (size > NFS3_FHSIZE) 67 return NULL; 68 69 memcpy(&fhp->fh_handle.fh_base, p, size); 70 fhp->fh_handle.fh_size = size; 71 return p + XDR_QUADLEN(size); 72 } 73 74 /* Helper function for NFSv3 ACL code */ 75 u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp) 76 { 77 return decode_fh(p, fhp); 78 } 79 80 static inline u32 * 81 encode_fh(u32 *p, struct svc_fh *fhp) 82 { 83 unsigned int size = fhp->fh_handle.fh_size; 84 *p++ = htonl(size); 85 if (size) p[XDR_QUADLEN(size)-1]=0; 86 memcpy(p, &fhp->fh_handle.fh_base, size); 87 return p + XDR_QUADLEN(size); 88 } 89 90 /* 91 * Decode a file name and make sure that the path contains 92 * no slashes or null bytes. 93 */ 94 static inline u32 * 95 decode_filename(u32 *p, char **namp, int *lenp) 96 { 97 char *name; 98 int i; 99 100 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) { 101 for (i = 0, name = *namp; i < *lenp; i++, name++) { 102 if (*name == '\0' || *name == '/') 103 return NULL; 104 } 105 } 106 107 return p; 108 } 109 110 static inline u32 * 111 decode_sattr3(u32 *p, struct iattr *iap) 112 { 113 u32 tmp; 114 115 iap->ia_valid = 0; 116 117 if (*p++) { 118 iap->ia_valid |= ATTR_MODE; 119 iap->ia_mode = ntohl(*p++); 120 } 121 if (*p++) { 122 iap->ia_valid |= ATTR_UID; 123 iap->ia_uid = ntohl(*p++); 124 } 125 if (*p++) { 126 iap->ia_valid |= ATTR_GID; 127 iap->ia_gid = ntohl(*p++); 128 } 129 if (*p++) { 130 u64 newsize; 131 132 iap->ia_valid |= ATTR_SIZE; 133 p = xdr_decode_hyper(p, &newsize); 134 if (newsize <= NFS_OFFSET_MAX) 135 iap->ia_size = newsize; 136 else 137 iap->ia_size = NFS_OFFSET_MAX; 138 } 139 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ 140 iap->ia_valid |= ATTR_ATIME; 141 } else if (tmp == 2) { /* set to client time */ 142 iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; 143 iap->ia_atime.tv_sec = ntohl(*p++); 144 iap->ia_atime.tv_nsec = ntohl(*p++); 145 } 146 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ 147 iap->ia_valid |= ATTR_MTIME; 148 } else if (tmp == 2) { /* set to client time */ 149 iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; 150 iap->ia_mtime.tv_sec = ntohl(*p++); 151 iap->ia_mtime.tv_nsec = ntohl(*p++); 152 } 153 return p; 154 } 155 156 static inline u32 * 157 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp, 158 struct kstat *stat) 159 { 160 struct dentry *dentry = fhp->fh_dentry; 161 struct timespec time; 162 163 *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); 164 *p++ = htonl((u32) stat->mode); 165 *p++ = htonl((u32) stat->nlink); 166 *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid)); 167 *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid)); 168 if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) { 169 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); 170 } else { 171 p = xdr_encode_hyper(p, (u64) stat->size); 172 } 173 p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); 174 *p++ = htonl((u32) MAJOR(stat->rdev)); 175 *p++ = htonl((u32) MINOR(stat->rdev)); 176 if (is_fsid(fhp, rqstp->rq_reffh)) 177 p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); 178 else 179 p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat->dev)); 180 p = xdr_encode_hyper(p, (u64) stat->ino); 181 p = encode_time3(p, &stat->atime); 182 lease_get_mtime(dentry->d_inode, &time); 183 p = encode_time3(p, &time); 184 p = encode_time3(p, &stat->ctime); 185 186 return p; 187 } 188 189 static inline u32 * 190 encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) 191 { 192 struct inode *inode = fhp->fh_dentry->d_inode; 193 194 /* Attributes to follow */ 195 *p++ = xdr_one; 196 197 *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]); 198 *p++ = htonl((u32) fhp->fh_post_mode); 199 *p++ = htonl((u32) fhp->fh_post_nlink); 200 *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid)); 201 *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid)); 202 if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) { 203 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); 204 } else { 205 p = xdr_encode_hyper(p, (u64) fhp->fh_post_size); 206 } 207 p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); 208 *p++ = fhp->fh_post_rdev[0]; 209 *p++ = fhp->fh_post_rdev[1]; 210 if (is_fsid(fhp, rqstp->rq_reffh)) 211 p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); 212 else 213 p = xdr_encode_hyper(p, (u64)huge_encode_dev(inode->i_sb->s_dev)); 214 p = xdr_encode_hyper(p, (u64) inode->i_ino); 215 p = encode_time3(p, &fhp->fh_post_atime); 216 p = encode_time3(p, &fhp->fh_post_mtime); 217 p = encode_time3(p, &fhp->fh_post_ctime); 218 219 return p; 220 } 221 222 /* 223 * Encode post-operation attributes. 224 * The inode may be NULL if the call failed because of a stale file 225 * handle. In this case, no attributes are returned. 226 */ 227 static u32 * 228 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) 229 { 230 struct dentry *dentry = fhp->fh_dentry; 231 if (dentry && dentry->d_inode != NULL) { 232 int err; 233 struct kstat stat; 234 235 err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat); 236 if (!err) { 237 *p++ = xdr_one; /* attributes follow */ 238 return encode_fattr3(rqstp, p, fhp, &stat); 239 } 240 } 241 *p++ = xdr_zero; 242 return p; 243 } 244 245 /* Helper for NFSv3 ACLs */ 246 u32 * 247 nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) 248 { 249 return encode_post_op_attr(rqstp, p, fhp); 250 } 251 252 /* 253 * Enocde weak cache consistency data 254 */ 255 static u32 * 256 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) 257 { 258 struct dentry *dentry = fhp->fh_dentry; 259 260 if (dentry && dentry->d_inode && fhp->fh_post_saved) { 261 if (fhp->fh_pre_saved) { 262 *p++ = xdr_one; 263 p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size); 264 p = encode_time3(p, &fhp->fh_pre_mtime); 265 p = encode_time3(p, &fhp->fh_pre_ctime); 266 } else { 267 *p++ = xdr_zero; 268 } 269 return encode_saved_post_attr(rqstp, p, fhp); 270 } 271 /* no pre- or post-attrs */ 272 *p++ = xdr_zero; 273 return encode_post_op_attr(rqstp, p, fhp); 274 } 275 276 277 /* 278 * XDR decode functions 279 */ 280 int 281 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args) 282 { 283 if (!(p = decode_fh(p, &args->fh))) 284 return 0; 285 return xdr_argsize_check(rqstp, p); 286 } 287 288 int 289 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, 290 struct nfsd3_sattrargs *args) 291 { 292 if (!(p = decode_fh(p, &args->fh)) 293 || !(p = decode_sattr3(p, &args->attrs))) 294 return 0; 295 296 if ((args->check_guard = ntohl(*p++)) != 0) { 297 struct timespec time; 298 p = decode_time3(p, &time); 299 args->guardtime = time.tv_sec; 300 } 301 302 return xdr_argsize_check(rqstp, p); 303 } 304 305 int 306 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, 307 struct nfsd3_diropargs *args) 308 { 309 if (!(p = decode_fh(p, &args->fh)) 310 || !(p = decode_filename(p, &args->name, &args->len))) 311 return 0; 312 313 return xdr_argsize_check(rqstp, p); 314 } 315 316 int 317 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, 318 struct nfsd3_accessargs *args) 319 { 320 if (!(p = decode_fh(p, &args->fh))) 321 return 0; 322 args->access = ntohl(*p++); 323 324 return xdr_argsize_check(rqstp, p); 325 } 326 327 int 328 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, 329 struct nfsd3_readargs *args) 330 { 331 unsigned int len; 332 int v,pn; 333 334 if (!(p = decode_fh(p, &args->fh)) 335 || !(p = xdr_decode_hyper(p, &args->offset))) 336 return 0; 337 338 len = args->count = ntohl(*p++); 339 340 if (len > NFSSVC_MAXBLKSIZE) 341 len = NFSSVC_MAXBLKSIZE; 342 343 /* set up the kvec */ 344 v=0; 345 while (len > 0) { 346 pn = rqstp->rq_resused; 347 svc_take_page(rqstp); 348 args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]); 349 args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE; 350 len -= args->vec[v].iov_len; 351 v++; 352 } 353 args->vlen = v; 354 return xdr_argsize_check(rqstp, p); 355 } 356 357 int 358 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, 359 struct nfsd3_writeargs *args) 360 { 361 unsigned int len, v, hdr; 362 363 if (!(p = decode_fh(p, &args->fh)) 364 || !(p = xdr_decode_hyper(p, &args->offset))) 365 return 0; 366 367 args->count = ntohl(*p++); 368 args->stable = ntohl(*p++); 369 len = args->len = ntohl(*p++); 370 371 hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; 372 if (rqstp->rq_arg.len < hdr || 373 rqstp->rq_arg.len - hdr < len) 374 return 0; 375 376 args->vec[0].iov_base = (void*)p; 377 args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; 378 379 if (len > NFSSVC_MAXBLKSIZE) 380 len = NFSSVC_MAXBLKSIZE; 381 v= 0; 382 while (len > args->vec[v].iov_len) { 383 len -= args->vec[v].iov_len; 384 v++; 385 args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]); 386 args->vec[v].iov_len = PAGE_SIZE; 387 } 388 args->vec[v].iov_len = len; 389 args->vlen = v+1; 390 391 return args->count == args->len && args->vec[0].iov_len > 0; 392 } 393 394 int 395 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p, 396 struct nfsd3_createargs *args) 397 { 398 if (!(p = decode_fh(p, &args->fh)) 399 || !(p = decode_filename(p, &args->name, &args->len))) 400 return 0; 401 402 switch (args->createmode = ntohl(*p++)) { 403 case NFS3_CREATE_UNCHECKED: 404 case NFS3_CREATE_GUARDED: 405 if (!(p = decode_sattr3(p, &args->attrs))) 406 return 0; 407 break; 408 case NFS3_CREATE_EXCLUSIVE: 409 args->verf = p; 410 p += 2; 411 break; 412 default: 413 return 0; 414 } 415 416 return xdr_argsize_check(rqstp, p); 417 } 418 int 419 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p, 420 struct nfsd3_createargs *args) 421 { 422 if (!(p = decode_fh(p, &args->fh)) 423 || !(p = decode_filename(p, &args->name, &args->len)) 424 || !(p = decode_sattr3(p, &args->attrs))) 425 return 0; 426 427 return xdr_argsize_check(rqstp, p); 428 } 429 430 int 431 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, 432 struct nfsd3_symlinkargs *args) 433 { 434 unsigned int len; 435 int avail; 436 char *old, *new; 437 struct kvec *vec; 438 439 if (!(p = decode_fh(p, &args->ffh)) 440 || !(p = decode_filename(p, &args->fname, &args->flen)) 441 || !(p = decode_sattr3(p, &args->attrs)) 442 ) 443 return 0; 444 /* now decode the pathname, which might be larger than the first page. 445 * As we have to check for nul's anyway, we copy it into a new page 446 * This page appears in the rq_res.pages list, but as pages_len is always 447 * 0, it won't get in the way 448 */ 449 svc_take_page(rqstp); 450 len = ntohl(*p++); 451 if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE) 452 return 0; 453 args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); 454 args->tlen = len; 455 /* first copy and check from the first page */ 456 old = (char*)p; 457 vec = &rqstp->rq_arg.head[0]; 458 avail = vec->iov_len - (old - (char*)vec->iov_base); 459 while (len && avail && *old) { 460 *new++ = *old++; 461 len--; 462 avail--; 463 } 464 /* now copy next page if there is one */ 465 if (len && !avail && rqstp->rq_arg.page_len) { 466 avail = rqstp->rq_arg.page_len; 467 if (avail > PAGE_SIZE) avail = PAGE_SIZE; 468 old = page_address(rqstp->rq_arg.pages[0]); 469 } 470 while (len && avail && *old) { 471 *new++ = *old++; 472 len--; 473 avail--; 474 } 475 *new = '\0'; 476 if (len) 477 return 0; 478 479 return 1; 480 } 481 482 int 483 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p, 484 struct nfsd3_mknodargs *args) 485 { 486 if (!(p = decode_fh(p, &args->fh)) 487 || !(p = decode_filename(p, &args->name, &args->len))) 488 return 0; 489 490 args->ftype = ntohl(*p++); 491 492 if (args->ftype == NF3BLK || args->ftype == NF3CHR 493 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) { 494 if (!(p = decode_sattr3(p, &args->attrs))) 495 return 0; 496 } 497 498 if (args->ftype == NF3BLK || args->ftype == NF3CHR) { 499 args->major = ntohl(*p++); 500 args->minor = ntohl(*p++); 501 } 502 503 return xdr_argsize_check(rqstp, p); 504 } 505 506 int 507 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, 508 struct nfsd3_renameargs *args) 509 { 510 if (!(p = decode_fh(p, &args->ffh)) 511 || !(p = decode_filename(p, &args->fname, &args->flen)) 512 || !(p = decode_fh(p, &args->tfh)) 513 || !(p = decode_filename(p, &args->tname, &args->tlen))) 514 return 0; 515 516 return xdr_argsize_check(rqstp, p); 517 } 518 519 int 520 nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, 521 struct nfsd3_readlinkargs *args) 522 { 523 if (!(p = decode_fh(p, &args->fh))) 524 return 0; 525 svc_take_page(rqstp); 526 args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); 527 528 return xdr_argsize_check(rqstp, p); 529 } 530 531 int 532 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, 533 struct nfsd3_linkargs *args) 534 { 535 if (!(p = decode_fh(p, &args->ffh)) 536 || !(p = decode_fh(p, &args->tfh)) 537 || !(p = decode_filename(p, &args->tname, &args->tlen))) 538 return 0; 539 540 return xdr_argsize_check(rqstp, p); 541 } 542 543 int 544 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, 545 struct nfsd3_readdirargs *args) 546 { 547 if (!(p = decode_fh(p, &args->fh))) 548 return 0; 549 p = xdr_decode_hyper(p, &args->cookie); 550 args->verf = p; p += 2; 551 args->dircount = ~0; 552 args->count = ntohl(*p++); 553 554 if (args->count > PAGE_SIZE) 555 args->count = PAGE_SIZE; 556 557 svc_take_page(rqstp); 558 args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); 559 560 return xdr_argsize_check(rqstp, p); 561 } 562 563 int 564 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p, 565 struct nfsd3_readdirargs *args) 566 { 567 int len, pn; 568 569 if (!(p = decode_fh(p, &args->fh))) 570 return 0; 571 p = xdr_decode_hyper(p, &args->cookie); 572 args->verf = p; p += 2; 573 args->dircount = ntohl(*p++); 574 args->count = ntohl(*p++); 575 576 len = (args->count > NFSSVC_MAXBLKSIZE) ? NFSSVC_MAXBLKSIZE : 577 args->count; 578 args->count = len; 579 580 while (len > 0) { 581 pn = rqstp->rq_resused; 582 svc_take_page(rqstp); 583 if (!args->buffer) 584 args->buffer = page_address(rqstp->rq_respages[pn]); 585 len -= PAGE_SIZE; 586 } 587 588 return xdr_argsize_check(rqstp, p); 589 } 590 591 int 592 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p, 593 struct nfsd3_commitargs *args) 594 { 595 if (!(p = decode_fh(p, &args->fh))) 596 return 0; 597 p = xdr_decode_hyper(p, &args->offset); 598 args->count = ntohl(*p++); 599 600 return xdr_argsize_check(rqstp, p); 601 } 602 603 /* 604 * XDR encode functions 605 */ 606 /* 607 * There must be an encoding function for void results so svc_process 608 * will work properly. 609 */ 610 int 611 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy) 612 { 613 return xdr_ressize_check(rqstp, p); 614 } 615 616 /* GETATTR */ 617 int 618 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p, 619 struct nfsd3_attrstat *resp) 620 { 621 if (resp->status == 0) 622 p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat); 623 return xdr_ressize_check(rqstp, p); 624 } 625 626 /* SETATTR, REMOVE, RMDIR */ 627 int 628 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p, 629 struct nfsd3_attrstat *resp) 630 { 631 p = encode_wcc_data(rqstp, p, &resp->fh); 632 return xdr_ressize_check(rqstp, p); 633 } 634 635 /* LOOKUP */ 636 int 637 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p, 638 struct nfsd3_diropres *resp) 639 { 640 if (resp->status == 0) { 641 p = encode_fh(p, &resp->fh); 642 p = encode_post_op_attr(rqstp, p, &resp->fh); 643 } 644 p = encode_post_op_attr(rqstp, p, &resp->dirfh); 645 return xdr_ressize_check(rqstp, p); 646 } 647 648 /* ACCESS */ 649 int 650 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p, 651 struct nfsd3_accessres *resp) 652 { 653 p = encode_post_op_attr(rqstp, p, &resp->fh); 654 if (resp->status == 0) 655 *p++ = htonl(resp->access); 656 return xdr_ressize_check(rqstp, p); 657 } 658 659 /* READLINK */ 660 int 661 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p, 662 struct nfsd3_readlinkres *resp) 663 { 664 p = encode_post_op_attr(rqstp, p, &resp->fh); 665 if (resp->status == 0) { 666 *p++ = htonl(resp->len); 667 xdr_ressize_check(rqstp, p); 668 rqstp->rq_res.page_len = resp->len; 669 if (resp->len & 3) { 670 /* need to pad the tail */ 671 rqstp->rq_restailpage = 0; 672 rqstp->rq_res.tail[0].iov_base = p; 673 *p = 0; 674 rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); 675 } 676 return 1; 677 } else 678 return xdr_ressize_check(rqstp, p); 679 } 680 681 /* READ */ 682 int 683 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p, 684 struct nfsd3_readres *resp) 685 { 686 p = encode_post_op_attr(rqstp, p, &resp->fh); 687 if (resp->status == 0) { 688 *p++ = htonl(resp->count); 689 *p++ = htonl(resp->eof); 690 *p++ = htonl(resp->count); /* xdr opaque count */ 691 xdr_ressize_check(rqstp, p); 692 /* now update rqstp->rq_res to reflect data aswell */ 693 rqstp->rq_res.page_len = resp->count; 694 if (resp->count & 3) { 695 /* need to pad the tail */ 696 rqstp->rq_restailpage = 0; 697 rqstp->rq_res.tail[0].iov_base = p; 698 *p = 0; 699 rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3); 700 } 701 return 1; 702 } else 703 return xdr_ressize_check(rqstp, p); 704 } 705 706 /* WRITE */ 707 int 708 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p, 709 struct nfsd3_writeres *resp) 710 { 711 p = encode_wcc_data(rqstp, p, &resp->fh); 712 if (resp->status == 0) { 713 *p++ = htonl(resp->count); 714 *p++ = htonl(resp->committed); 715 *p++ = htonl(nfssvc_boot.tv_sec); 716 *p++ = htonl(nfssvc_boot.tv_usec); 717 } 718 return xdr_ressize_check(rqstp, p); 719 } 720 721 /* CREATE, MKDIR, SYMLINK, MKNOD */ 722 int 723 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p, 724 struct nfsd3_diropres *resp) 725 { 726 if (resp->status == 0) { 727 *p++ = xdr_one; 728 p = encode_fh(p, &resp->fh); 729 p = encode_post_op_attr(rqstp, p, &resp->fh); 730 } 731 p = encode_wcc_data(rqstp, p, &resp->dirfh); 732 return xdr_ressize_check(rqstp, p); 733 } 734 735 /* RENAME */ 736 int 737 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p, 738 struct nfsd3_renameres *resp) 739 { 740 p = encode_wcc_data(rqstp, p, &resp->ffh); 741 p = encode_wcc_data(rqstp, p, &resp->tfh); 742 return xdr_ressize_check(rqstp, p); 743 } 744 745 /* LINK */ 746 int 747 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p, 748 struct nfsd3_linkres *resp) 749 { 750 p = encode_post_op_attr(rqstp, p, &resp->fh); 751 p = encode_wcc_data(rqstp, p, &resp->tfh); 752 return xdr_ressize_check(rqstp, p); 753 } 754 755 /* READDIR */ 756 int 757 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, 758 struct nfsd3_readdirres *resp) 759 { 760 p = encode_post_op_attr(rqstp, p, &resp->fh); 761 762 if (resp->status == 0) { 763 /* stupid readdir cookie */ 764 memcpy(p, resp->verf, 8); p += 2; 765 xdr_ressize_check(rqstp, p); 766 if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE) 767 return 1; /*No room for trailer */ 768 rqstp->rq_res.page_len = (resp->count) << 2; 769 770 /* add the 'tail' to the end of the 'head' page - page 0. */ 771 rqstp->rq_restailpage = 0; 772 rqstp->rq_res.tail[0].iov_base = p; 773 *p++ = 0; /* no more entries */ 774 *p++ = htonl(resp->common.err == nfserr_eof); 775 rqstp->rq_res.tail[0].iov_len = 2<<2; 776 return 1; 777 } else 778 return xdr_ressize_check(rqstp, p); 779 } 780 781 static inline u32 * 782 encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name, 783 int namlen, ino_t ino) 784 { 785 *p++ = xdr_one; /* mark entry present */ 786 p = xdr_encode_hyper(p, ino); /* file id */ 787 p = xdr_encode_array(p, name, namlen);/* name length & name */ 788 789 cd->offset = p; /* remember pointer */ 790 p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */ 791 792 return p; 793 } 794 795 static inline u32 * 796 encode_entryplus_baggage(struct nfsd3_readdirres *cd, u32 *p, 797 struct svc_fh *fhp) 798 { 799 p = encode_post_op_attr(cd->rqstp, p, fhp); 800 *p++ = xdr_one; /* yes, a file handle follows */ 801 p = encode_fh(p, fhp); 802 fh_put(fhp); 803 return p; 804 } 805 806 static int 807 compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, 808 const char *name, int namlen) 809 { 810 struct svc_export *exp; 811 struct dentry *dparent, *dchild; 812 int rv = 0; 813 814 dparent = cd->fh.fh_dentry; 815 exp = cd->fh.fh_export; 816 817 fh_init(fhp, NFS3_FHSIZE); 818 if (isdotent(name, namlen)) { 819 if (namlen == 2) { 820 dchild = dget_parent(dparent); 821 if (dchild == dparent) { 822 /* filesystem root - cannot return filehandle for ".." */ 823 dput(dchild); 824 return 1; 825 } 826 } else 827 dchild = dget(dparent); 828 } else 829 dchild = lookup_one_len(name, dparent, namlen); 830 if (IS_ERR(dchild)) 831 return 1; 832 if (d_mountpoint(dchild) || 833 fh_compose(fhp, exp, dchild, &cd->fh) != 0 || 834 !dchild->d_inode) 835 rv = 1; 836 dput(dchild); 837 return rv; 838 } 839 840 /* 841 * Encode a directory entry. This one works for both normal readdir 842 * and readdirplus. 843 * The normal readdir reply requires 2 (fileid) + 1 (stringlen) 844 * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen. 845 * 846 * The readdirplus baggage is 1+21 words for post_op_attr, plus the 847 * file handle. 848 */ 849 850 #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1) 851 #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) 852 static int 853 encode_entry(struct readdir_cd *ccd, const char *name, 854 int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus) 855 { 856 struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, 857 common); 858 u32 *p = cd->buffer; 859 caddr_t curr_page_addr = NULL; 860 int pn; /* current page number */ 861 int slen; /* string (name) length */ 862 int elen; /* estimated entry length in words */ 863 int num_entry_words = 0; /* actual number of words */ 864 865 if (cd->offset) { 866 u64 offset64 = offset; 867 868 if (unlikely(cd->offset1)) { 869 /* we ended up with offset on a page boundary */ 870 *cd->offset = htonl(offset64 >> 32); 871 *cd->offset1 = htonl(offset64 & 0xffffffff); 872 cd->offset1 = NULL; 873 } else { 874 xdr_encode_hyper(cd->offset, (u64) offset); 875 } 876 } 877 878 /* 879 dprintk("encode_entry(%.*s @%ld%s)\n", 880 namlen, name, (long) offset, plus? " plus" : ""); 881 */ 882 883 /* truncate filename if too long */ 884 if (namlen > NFS3_MAXNAMLEN) 885 namlen = NFS3_MAXNAMLEN; 886 887 slen = XDR_QUADLEN(namlen); 888 elen = slen + NFS3_ENTRY_BAGGAGE 889 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0); 890 891 if (cd->buflen < elen) { 892 cd->common.err = nfserr_toosmall; 893 return -EINVAL; 894 } 895 896 /* determine which page in rq_respages[] we are currently filling */ 897 for (pn=1; pn < cd->rqstp->rq_resused; pn++) { 898 curr_page_addr = page_address(cd->rqstp->rq_respages[pn]); 899 900 if (((caddr_t)cd->buffer >= curr_page_addr) && 901 ((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE)) 902 break; 903 } 904 905 if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) { 906 /* encode entry in current page */ 907 908 p = encode_entry_baggage(cd, p, name, namlen, ino); 909 910 /* throw in readdirplus baggage */ 911 if (plus) { 912 struct svc_fh fh; 913 914 if (compose_entry_fh(cd, &fh, name, namlen) > 0) { 915 *p++ = 0; 916 *p++ = 0; 917 } else 918 p = encode_entryplus_baggage(cd, p, &fh); 919 } 920 num_entry_words = p - cd->buffer; 921 } else if (cd->rqstp->rq_respages[pn+1] != NULL) { 922 /* temporarily encode entry into next page, then move back to 923 * current and next page in rq_respages[] */ 924 u32 *p1, *tmp; 925 int len1, len2; 926 927 /* grab next page for temporary storage of entry */ 928 p1 = tmp = page_address(cd->rqstp->rq_respages[pn+1]); 929 930 p1 = encode_entry_baggage(cd, p1, name, namlen, ino); 931 932 /* throw in readdirplus baggage */ 933 if (plus) { 934 struct svc_fh fh; 935 936 if (compose_entry_fh(cd, &fh, name, namlen) > 0) { 937 /* zero out the filehandle */ 938 *p1++ = 0; 939 *p1++ = 0; 940 } else 941 p1 = encode_entryplus_baggage(cd, p1, &fh); 942 } 943 944 /* determine entry word length and lengths to go in pages */ 945 num_entry_words = p1 - tmp; 946 len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer; 947 if ((num_entry_words << 2) < len1) { 948 /* the actual number of words in the entry is less 949 * than elen and can still fit in the current page 950 */ 951 memmove(p, tmp, num_entry_words << 2); 952 p += num_entry_words; 953 954 /* update offset */ 955 cd->offset = cd->buffer + (cd->offset - tmp); 956 } else { 957 unsigned int offset_r = (cd->offset - tmp) << 2; 958 959 /* update pointer to offset location. 960 * This is a 64bit quantity, so we need to 961 * deal with 3 cases: 962 * - entirely in first page 963 * - entirely in second page 964 * - 4 bytes in each page 965 */ 966 if (offset_r + 8 <= len1) { 967 cd->offset = p + (cd->offset - tmp); 968 } else if (offset_r >= len1) { 969 cd->offset -= len1 >> 2; 970 } else { 971 /* sitting on the fence */ 972 BUG_ON(offset_r != len1 - 4); 973 cd->offset = p + (cd->offset - tmp); 974 cd->offset1 = tmp; 975 } 976 977 len2 = (num_entry_words << 2) - len1; 978 979 /* move from temp page to current and next pages */ 980 memmove(p, tmp, len1); 981 memmove(tmp, (caddr_t)tmp+len1, len2); 982 983 p = tmp + (len2 >> 2); 984 } 985 } 986 else { 987 cd->common.err = nfserr_toosmall; 988 return -EINVAL; 989 } 990 991 cd->buflen -= num_entry_words; 992 cd->buffer = p; 993 cd->common.err = nfs_ok; 994 return 0; 995 996 } 997 998 int 999 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name, 1000 int namlen, loff_t offset, ino_t ino, unsigned int d_type) 1001 { 1002 return encode_entry(cd, name, namlen, offset, ino, d_type, 0); 1003 } 1004 1005 int 1006 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name, 1007 int namlen, loff_t offset, ino_t ino, unsigned int d_type) 1008 { 1009 return encode_entry(cd, name, namlen, offset, ino, d_type, 1); 1010 } 1011 1012 /* FSSTAT */ 1013 int 1014 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p, 1015 struct nfsd3_fsstatres *resp) 1016 { 1017 struct kstatfs *s = &resp->stats; 1018 u64 bs = s->f_bsize; 1019 1020 *p++ = xdr_zero; /* no post_op_attr */ 1021 1022 if (resp->status == 0) { 1023 p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */ 1024 p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */ 1025 p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */ 1026 p = xdr_encode_hyper(p, s->f_files); /* total inodes */ 1027 p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */ 1028 p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */ 1029 *p++ = htonl(resp->invarsec); /* mean unchanged time */ 1030 } 1031 return xdr_ressize_check(rqstp, p); 1032 } 1033 1034 /* FSINFO */ 1035 int 1036 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p, 1037 struct nfsd3_fsinfores *resp) 1038 { 1039 *p++ = xdr_zero; /* no post_op_attr */ 1040 1041 if (resp->status == 0) { 1042 *p++ = htonl(resp->f_rtmax); 1043 *p++ = htonl(resp->f_rtpref); 1044 *p++ = htonl(resp->f_rtmult); 1045 *p++ = htonl(resp->f_wtmax); 1046 *p++ = htonl(resp->f_wtpref); 1047 *p++ = htonl(resp->f_wtmult); 1048 *p++ = htonl(resp->f_dtpref); 1049 p = xdr_encode_hyper(p, resp->f_maxfilesize); 1050 *p++ = xdr_one; 1051 *p++ = xdr_zero; 1052 *p++ = htonl(resp->f_properties); 1053 } 1054 1055 return xdr_ressize_check(rqstp, p); 1056 } 1057 1058 /* PATHCONF */ 1059 int 1060 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p, 1061 struct nfsd3_pathconfres *resp) 1062 { 1063 *p++ = xdr_zero; /* no post_op_attr */ 1064 1065 if (resp->status == 0) { 1066 *p++ = htonl(resp->p_link_max); 1067 *p++ = htonl(resp->p_name_max); 1068 *p++ = htonl(resp->p_no_trunc); 1069 *p++ = htonl(resp->p_chown_restricted); 1070 *p++ = htonl(resp->p_case_insensitive); 1071 *p++ = htonl(resp->p_case_preserving); 1072 } 1073 1074 return xdr_ressize_check(rqstp, p); 1075 } 1076 1077 /* COMMIT */ 1078 int 1079 nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p, 1080 struct nfsd3_commitres *resp) 1081 { 1082 p = encode_wcc_data(rqstp, p, &resp->fh); 1083 /* Write verifier */ 1084 if (resp->status == 0) { 1085 *p++ = htonl(nfssvc_boot.tv_sec); 1086 *p++ = htonl(nfssvc_boot.tv_usec); 1087 } 1088 return xdr_ressize_check(rqstp, p); 1089 } 1090 1091 /* 1092 * XDR release functions 1093 */ 1094 int 1095 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p, 1096 struct nfsd3_attrstat *resp) 1097 { 1098 fh_put(&resp->fh); 1099 return 1; 1100 } 1101 1102 int 1103 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p, 1104 struct nfsd3_fhandle_pair *resp) 1105 { 1106 fh_put(&resp->fh1); 1107 fh_put(&resp->fh2); 1108 return 1; 1109 } 1110