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