1 /* 2 * linux/fs/nfsd/nfs3proc.c 3 * 4 * Process version 3 NFS requests. 5 * 6 * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de> 7 */ 8 9 #include <linux/linkage.h> 10 #include <linux/time.h> 11 #include <linux/errno.h> 12 #include <linux/fs.h> 13 #include <linux/ext2_fs.h> 14 #include <linux/stat.h> 15 #include <linux/fcntl.h> 16 #include <linux/net.h> 17 #include <linux/in.h> 18 #include <linux/unistd.h> 19 #include <linux/slab.h> 20 #include <linux/major.h> 21 22 #include <linux/sunrpc/svc.h> 23 #include <linux/nfsd/nfsd.h> 24 #include <linux/nfsd/cache.h> 25 #include <linux/nfsd/xdr3.h> 26 #include <linux/nfs3.h> 27 28 #define NFSDDBG_FACILITY NFSDDBG_PROC 29 30 #define RETURN_STATUS(st) { resp->status = (st); return (st); } 31 32 static int nfs3_ftypes[] = { 33 0, /* NF3NON */ 34 S_IFREG, /* NF3REG */ 35 S_IFDIR, /* NF3DIR */ 36 S_IFBLK, /* NF3BLK */ 37 S_IFCHR, /* NF3CHR */ 38 S_IFLNK, /* NF3LNK */ 39 S_IFSOCK, /* NF3SOCK */ 40 S_IFIFO, /* NF3FIFO */ 41 }; 42 43 /* 44 * NULL call. 45 */ 46 static __be32 47 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 48 { 49 return nfs_ok; 50 } 51 52 /* 53 * Get a file's attributes 54 */ 55 static __be32 56 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, 57 struct nfsd3_attrstat *resp) 58 { 59 int err; 60 __be32 nfserr; 61 62 dprintk("nfsd: GETATTR(3) %s\n", 63 SVCFH_fmt(&argp->fh)); 64 65 fh_copy(&resp->fh, &argp->fh); 66 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); 67 if (nfserr) 68 RETURN_STATUS(nfserr); 69 70 err = vfs_getattr(resp->fh.fh_export->ex_path.mnt, 71 resp->fh.fh_dentry, &resp->stat); 72 nfserr = nfserrno(err); 73 74 RETURN_STATUS(nfserr); 75 } 76 77 /* 78 * Set a file's attributes 79 */ 80 static __be32 81 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, 82 struct nfsd3_attrstat *resp) 83 { 84 __be32 nfserr; 85 86 dprintk("nfsd: SETATTR(3) %s\n", 87 SVCFH_fmt(&argp->fh)); 88 89 fh_copy(&resp->fh, &argp->fh); 90 nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs, 91 argp->check_guard, argp->guardtime); 92 RETURN_STATUS(nfserr); 93 } 94 95 /* 96 * Look up a path name component 97 */ 98 static __be32 99 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, 100 struct nfsd3_diropres *resp) 101 { 102 __be32 nfserr; 103 104 dprintk("nfsd: LOOKUP(3) %s %.*s\n", 105 SVCFH_fmt(&argp->fh), 106 argp->len, 107 argp->name); 108 109 fh_copy(&resp->dirfh, &argp->fh); 110 fh_init(&resp->fh, NFS3_FHSIZE); 111 112 nfserr = nfsd_lookup(rqstp, &resp->dirfh, 113 argp->name, 114 argp->len, 115 &resp->fh); 116 RETURN_STATUS(nfserr); 117 } 118 119 /* 120 * Check file access 121 */ 122 static __be32 123 nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, 124 struct nfsd3_accessres *resp) 125 { 126 __be32 nfserr; 127 128 dprintk("nfsd: ACCESS(3) %s 0x%x\n", 129 SVCFH_fmt(&argp->fh), 130 argp->access); 131 132 fh_copy(&resp->fh, &argp->fh); 133 resp->access = argp->access; 134 nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); 135 RETURN_STATUS(nfserr); 136 } 137 138 /* 139 * Read a symlink. 140 */ 141 static __be32 142 nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp, 143 struct nfsd3_readlinkres *resp) 144 { 145 __be32 nfserr; 146 147 dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh)); 148 149 /* Read the symlink. */ 150 fh_copy(&resp->fh, &argp->fh); 151 resp->len = NFS3_MAXPATHLEN; 152 nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len); 153 RETURN_STATUS(nfserr); 154 } 155 156 /* 157 * Read a portion of a file. 158 */ 159 static __be32 160 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, 161 struct nfsd3_readres *resp) 162 { 163 __be32 nfserr; 164 u32 max_blocksize = svc_max_payload(rqstp); 165 166 dprintk("nfsd: READ(3) %s %lu bytes at %lu\n", 167 SVCFH_fmt(&argp->fh), 168 (unsigned long) argp->count, 169 (unsigned long) argp->offset); 170 171 /* Obtain buffer pointer for payload. 172 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof) 173 * + 1 (xdr opaque byte count) = 26 174 */ 175 176 resp->count = argp->count; 177 if (max_blocksize < resp->count) 178 resp->count = max_blocksize; 179 180 svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); 181 182 fh_copy(&resp->fh, &argp->fh); 183 nfserr = nfsd_read(rqstp, &resp->fh, NULL, 184 argp->offset, 185 rqstp->rq_vec, argp->vlen, 186 &resp->count); 187 if (nfserr == 0) { 188 struct inode *inode = resp->fh.fh_dentry->d_inode; 189 190 resp->eof = (argp->offset + resp->count) >= inode->i_size; 191 } 192 193 RETURN_STATUS(nfserr); 194 } 195 196 /* 197 * Write data to a file 198 */ 199 static __be32 200 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, 201 struct nfsd3_writeres *resp) 202 { 203 __be32 nfserr; 204 205 dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n", 206 SVCFH_fmt(&argp->fh), 207 argp->len, 208 (unsigned long) argp->offset, 209 argp->stable? " stable" : ""); 210 211 fh_copy(&resp->fh, &argp->fh); 212 resp->committed = argp->stable; 213 nfserr = nfsd_write(rqstp, &resp->fh, NULL, 214 argp->offset, 215 rqstp->rq_vec, argp->vlen, 216 argp->len, 217 &resp->committed); 218 resp->count = argp->count; 219 RETURN_STATUS(nfserr); 220 } 221 222 /* 223 * With NFSv3, CREATE processing is a lot easier than with NFSv2. 224 * At least in theory; we'll see how it fares in practice when the 225 * first reports about SunOS compatibility problems start to pour in... 226 */ 227 static __be32 228 nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, 229 struct nfsd3_diropres *resp) 230 { 231 svc_fh *dirfhp, *newfhp = NULL; 232 struct iattr *attr; 233 __be32 nfserr; 234 235 dprintk("nfsd: CREATE(3) %s %.*s\n", 236 SVCFH_fmt(&argp->fh), 237 argp->len, 238 argp->name); 239 240 dirfhp = fh_copy(&resp->dirfh, &argp->fh); 241 newfhp = fh_init(&resp->fh, NFS3_FHSIZE); 242 attr = &argp->attrs; 243 244 /* Get the directory inode */ 245 nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_CREATE); 246 if (nfserr) 247 RETURN_STATUS(nfserr); 248 249 /* Unfudge the mode bits */ 250 attr->ia_mode &= ~S_IFMT; 251 if (!(attr->ia_valid & ATTR_MODE)) { 252 attr->ia_valid |= ATTR_MODE; 253 attr->ia_mode = S_IFREG; 254 } else { 255 attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG; 256 } 257 258 /* Now create the file and set attributes */ 259 nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len, 260 attr, newfhp, 261 argp->createmode, argp->verf, NULL, NULL); 262 263 RETURN_STATUS(nfserr); 264 } 265 266 /* 267 * Make directory. This operation is not idempotent. 268 */ 269 static __be32 270 nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, 271 struct nfsd3_diropres *resp) 272 { 273 __be32 nfserr; 274 275 dprintk("nfsd: MKDIR(3) %s %.*s\n", 276 SVCFH_fmt(&argp->fh), 277 argp->len, 278 argp->name); 279 280 argp->attrs.ia_valid &= ~ATTR_SIZE; 281 fh_copy(&resp->dirfh, &argp->fh); 282 fh_init(&resp->fh, NFS3_FHSIZE); 283 nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, 284 &argp->attrs, S_IFDIR, 0, &resp->fh); 285 286 RETURN_STATUS(nfserr); 287 } 288 289 static __be32 290 nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, 291 struct nfsd3_diropres *resp) 292 { 293 __be32 nfserr; 294 295 dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n", 296 SVCFH_fmt(&argp->ffh), 297 argp->flen, argp->fname, 298 argp->tlen, argp->tname); 299 300 fh_copy(&resp->dirfh, &argp->ffh); 301 fh_init(&resp->fh, NFS3_FHSIZE); 302 nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen, 303 argp->tname, argp->tlen, 304 &resp->fh, &argp->attrs); 305 RETURN_STATUS(nfserr); 306 } 307 308 /* 309 * Make socket/fifo/device. 310 */ 311 static __be32 312 nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, 313 struct nfsd3_diropres *resp) 314 { 315 __be32 nfserr; 316 int type; 317 dev_t rdev = 0; 318 319 dprintk("nfsd: MKNOD(3) %s %.*s\n", 320 SVCFH_fmt(&argp->fh), 321 argp->len, 322 argp->name); 323 324 fh_copy(&resp->dirfh, &argp->fh); 325 fh_init(&resp->fh, NFS3_FHSIZE); 326 327 if (argp->ftype == 0 || argp->ftype >= NF3BAD) 328 RETURN_STATUS(nfserr_inval); 329 if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) { 330 rdev = MKDEV(argp->major, argp->minor); 331 if (MAJOR(rdev) != argp->major || 332 MINOR(rdev) != argp->minor) 333 RETURN_STATUS(nfserr_inval); 334 } else 335 if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) 336 RETURN_STATUS(nfserr_inval); 337 338 type = nfs3_ftypes[argp->ftype]; 339 nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, 340 &argp->attrs, type, rdev, &resp->fh); 341 342 RETURN_STATUS(nfserr); 343 } 344 345 /* 346 * Remove file/fifo/socket etc. 347 */ 348 static __be32 349 nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, 350 struct nfsd3_attrstat *resp) 351 { 352 __be32 nfserr; 353 354 dprintk("nfsd: REMOVE(3) %s %.*s\n", 355 SVCFH_fmt(&argp->fh), 356 argp->len, 357 argp->name); 358 359 /* Unlink. -S_IFDIR means file must not be a directory */ 360 fh_copy(&resp->fh, &argp->fh); 361 nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); 362 RETURN_STATUS(nfserr); 363 } 364 365 /* 366 * Remove a directory 367 */ 368 static __be32 369 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, 370 struct nfsd3_attrstat *resp) 371 { 372 __be32 nfserr; 373 374 dprintk("nfsd: RMDIR(3) %s %.*s\n", 375 SVCFH_fmt(&argp->fh), 376 argp->len, 377 argp->name); 378 379 fh_copy(&resp->fh, &argp->fh); 380 nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); 381 RETURN_STATUS(nfserr); 382 } 383 384 static __be32 385 nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, 386 struct nfsd3_renameres *resp) 387 { 388 __be32 nfserr; 389 390 dprintk("nfsd: RENAME(3) %s %.*s ->\n", 391 SVCFH_fmt(&argp->ffh), 392 argp->flen, 393 argp->fname); 394 dprintk("nfsd: -> %s %.*s\n", 395 SVCFH_fmt(&argp->tfh), 396 argp->tlen, 397 argp->tname); 398 399 fh_copy(&resp->ffh, &argp->ffh); 400 fh_copy(&resp->tfh, &argp->tfh); 401 nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen, 402 &resp->tfh, argp->tname, argp->tlen); 403 RETURN_STATUS(nfserr); 404 } 405 406 static __be32 407 nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, 408 struct nfsd3_linkres *resp) 409 { 410 __be32 nfserr; 411 412 dprintk("nfsd: LINK(3) %s ->\n", 413 SVCFH_fmt(&argp->ffh)); 414 dprintk("nfsd: -> %s %.*s\n", 415 SVCFH_fmt(&argp->tfh), 416 argp->tlen, 417 argp->tname); 418 419 fh_copy(&resp->fh, &argp->ffh); 420 fh_copy(&resp->tfh, &argp->tfh); 421 nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen, 422 &resp->fh); 423 RETURN_STATUS(nfserr); 424 } 425 426 /* 427 * Read a portion of a directory. 428 */ 429 static __be32 430 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, 431 struct nfsd3_readdirres *resp) 432 { 433 __be32 nfserr; 434 int count; 435 436 dprintk("nfsd: READDIR(3) %s %d bytes at %d\n", 437 SVCFH_fmt(&argp->fh), 438 argp->count, (u32) argp->cookie); 439 440 /* Make sure we've room for the NULL ptr & eof flag, and shrink to 441 * client read size */ 442 count = (argp->count >> 2) - 2; 443 444 /* Read directory and encode entries on the fly */ 445 fh_copy(&resp->fh, &argp->fh); 446 447 resp->buflen = count; 448 resp->common.err = nfs_ok; 449 resp->buffer = argp->buffer; 450 resp->rqstp = rqstp; 451 nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie, 452 &resp->common, nfs3svc_encode_entry); 453 memcpy(resp->verf, argp->verf, 8); 454 resp->count = resp->buffer - argp->buffer; 455 if (resp->offset) 456 xdr_encode_hyper(resp->offset, argp->cookie); 457 458 RETURN_STATUS(nfserr); 459 } 460 461 /* 462 * Read a portion of a directory, including file handles and attrs. 463 * For now, we choose to ignore the dircount parameter. 464 */ 465 static __be32 466 nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, 467 struct nfsd3_readdirres *resp) 468 { 469 __be32 nfserr; 470 int count = 0; 471 loff_t offset; 472 int i; 473 caddr_t page_addr = NULL; 474 475 dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n", 476 SVCFH_fmt(&argp->fh), 477 argp->count, (u32) argp->cookie); 478 479 /* Convert byte count to number of words (i.e. >> 2), 480 * and reserve room for the NULL ptr & eof flag (-2 words) */ 481 resp->count = (argp->count >> 2) - 2; 482 483 /* Read directory and encode entries on the fly */ 484 fh_copy(&resp->fh, &argp->fh); 485 486 resp->common.err = nfs_ok; 487 resp->buffer = argp->buffer; 488 resp->buflen = resp->count; 489 resp->rqstp = rqstp; 490 offset = argp->cookie; 491 nfserr = nfsd_readdir(rqstp, &resp->fh, 492 &offset, 493 &resp->common, 494 nfs3svc_encode_entry_plus); 495 memcpy(resp->verf, argp->verf, 8); 496 for (i=1; i<rqstp->rq_resused ; i++) { 497 page_addr = page_address(rqstp->rq_respages[i]); 498 499 if (((caddr_t)resp->buffer >= page_addr) && 500 ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) { 501 count += (caddr_t)resp->buffer - page_addr; 502 break; 503 } 504 count += PAGE_SIZE; 505 } 506 resp->count = count >> 2; 507 if (resp->offset) { 508 if (unlikely(resp->offset1)) { 509 /* we ended up with offset on a page boundary */ 510 *resp->offset = htonl(offset >> 32); 511 *resp->offset1 = htonl(offset & 0xffffffff); 512 resp->offset1 = NULL; 513 } else { 514 xdr_encode_hyper(resp->offset, offset); 515 } 516 } 517 518 RETURN_STATUS(nfserr); 519 } 520 521 /* 522 * Get file system stats 523 */ 524 static __be32 525 nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, 526 struct nfsd3_fsstatres *resp) 527 { 528 __be32 nfserr; 529 530 dprintk("nfsd: FSSTAT(3) %s\n", 531 SVCFH_fmt(&argp->fh)); 532 533 nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats); 534 fh_put(&argp->fh); 535 RETURN_STATUS(nfserr); 536 } 537 538 /* 539 * Get file system info 540 */ 541 static __be32 542 nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, 543 struct nfsd3_fsinfores *resp) 544 { 545 __be32 nfserr; 546 u32 max_blocksize = svc_max_payload(rqstp); 547 548 dprintk("nfsd: FSINFO(3) %s\n", 549 SVCFH_fmt(&argp->fh)); 550 551 resp->f_rtmax = max_blocksize; 552 resp->f_rtpref = max_blocksize; 553 resp->f_rtmult = PAGE_SIZE; 554 resp->f_wtmax = max_blocksize; 555 resp->f_wtpref = max_blocksize; 556 resp->f_wtmult = PAGE_SIZE; 557 resp->f_dtpref = PAGE_SIZE; 558 resp->f_maxfilesize = ~(u32) 0; 559 resp->f_properties = NFS3_FSF_DEFAULT; 560 561 nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); 562 563 /* Check special features of the file system. May request 564 * different read/write sizes for file systems known to have 565 * problems with large blocks */ 566 if (nfserr == 0) { 567 struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; 568 569 /* Note that we don't care for remote fs's here */ 570 if (sb->s_magic == 0x4d44 /* MSDOS_SUPER_MAGIC */) { 571 resp->f_properties = NFS3_FSF_BILLYBOY; 572 } 573 resp->f_maxfilesize = sb->s_maxbytes; 574 } 575 576 fh_put(&argp->fh); 577 RETURN_STATUS(nfserr); 578 } 579 580 /* 581 * Get pathconf info for the specified file 582 */ 583 static __be32 584 nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, 585 struct nfsd3_pathconfres *resp) 586 { 587 __be32 nfserr; 588 589 dprintk("nfsd: PATHCONF(3) %s\n", 590 SVCFH_fmt(&argp->fh)); 591 592 /* Set default pathconf */ 593 resp->p_link_max = 255; /* at least */ 594 resp->p_name_max = 255; /* at least */ 595 resp->p_no_trunc = 0; 596 resp->p_chown_restricted = 1; 597 resp->p_case_insensitive = 0; 598 resp->p_case_preserving = 1; 599 600 nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); 601 602 if (nfserr == 0) { 603 struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; 604 605 /* Note that we don't care for remote fs's here */ 606 switch (sb->s_magic) { 607 case EXT2_SUPER_MAGIC: 608 resp->p_link_max = EXT2_LINK_MAX; 609 resp->p_name_max = EXT2_NAME_LEN; 610 break; 611 case 0x4d44: /* MSDOS_SUPER_MAGIC */ 612 resp->p_case_insensitive = 1; 613 resp->p_case_preserving = 0; 614 break; 615 } 616 } 617 618 fh_put(&argp->fh); 619 RETURN_STATUS(nfserr); 620 } 621 622 623 /* 624 * Commit a file (range) to stable storage. 625 */ 626 static __be32 627 nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, 628 struct nfsd3_commitres *resp) 629 { 630 __be32 nfserr; 631 632 dprintk("nfsd: COMMIT(3) %s %u@%Lu\n", 633 SVCFH_fmt(&argp->fh), 634 argp->count, 635 (unsigned long long) argp->offset); 636 637 if (argp->offset > NFS_OFFSET_MAX) 638 RETURN_STATUS(nfserr_inval); 639 640 fh_copy(&resp->fh, &argp->fh); 641 nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count); 642 643 RETURN_STATUS(nfserr); 644 } 645 646 647 /* 648 * NFSv3 Server procedures. 649 * Only the results of non-idempotent operations are cached. 650 */ 651 #define nfs3svc_decode_voidargs NULL 652 #define nfs3svc_release_void NULL 653 #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle 654 #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat 655 #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat 656 #define nfsd3_mkdirargs nfsd3_createargs 657 #define nfsd3_readdirplusargs nfsd3_readdirargs 658 #define nfsd3_fhandleargs nfsd_fhandle 659 #define nfsd3_fhandleres nfsd3_attrstat 660 #define nfsd3_attrstatres nfsd3_attrstat 661 #define nfsd3_wccstatres nfsd3_attrstat 662 #define nfsd3_createres nfsd3_diropres 663 #define nfsd3_voidres nfsd3_voidargs 664 struct nfsd3_voidargs { int dummy; }; 665 666 #define PROC(name, argt, rest, relt, cache, respsize) \ 667 { (svc_procfunc) nfsd3_proc_##name, \ 668 (kxdrproc_t) nfs3svc_decode_##argt##args, \ 669 (kxdrproc_t) nfs3svc_encode_##rest##res, \ 670 (kxdrproc_t) nfs3svc_release_##relt, \ 671 sizeof(struct nfsd3_##argt##args), \ 672 sizeof(struct nfsd3_##rest##res), \ 673 0, \ 674 cache, \ 675 respsize, \ 676 } 677 678 #define ST 1 /* status*/ 679 #define FH 17 /* filehandle with length */ 680 #define AT 21 /* attributes */ 681 #define pAT (1+AT) /* post attributes - conditional */ 682 #define WC (7+pAT) /* WCC attributes */ 683 684 static struct svc_procedure nfsd_procedures3[22] = { 685 PROC(null, void, void, void, RC_NOCACHE, ST), 686 PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), 687 PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF, ST+WC), 688 PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT), 689 PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1), 690 PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4), 691 PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE/4), 692 PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4), 693 PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), 694 PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), 695 PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), 696 PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), 697 PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), 698 PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), 699 PROC(rename, rename, rename, fhandle2, RC_REPLBUFF, ST+WC+WC), 700 PROC(link, link, link, fhandle2, RC_REPLBUFF, ST+pAT+WC), 701 PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE, 0), 702 PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE, 0), 703 PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE, ST+pAT+2*6+1), 704 PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE, ST+pAT+12), 705 PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE, ST+pAT+6), 706 PROC(commit, commit, commit, fhandle, RC_NOCACHE, ST+WC+2), 707 }; 708 709 struct svc_version nfsd_version3 = { 710 .vs_vers = 3, 711 .vs_nproc = 22, 712 .vs_proc = nfsd_procedures3, 713 .vs_dispatch = nfsd_dispatch, 714 .vs_xdrsize = NFS3_SVC_XDRSIZE, 715 }; 716