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