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