1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Process version 2 NFS requests. 4 * 5 * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> 6 */ 7 8 #include <linux/namei.h> 9 10 #include "cache.h" 11 #include "xdr.h" 12 #include "vfs.h" 13 14 #define NFSDDBG_FACILITY NFSDDBG_PROC 15 16 static __be32 17 nfsd_proc_null(struct svc_rqst *rqstp) 18 { 19 return rpc_success; 20 } 21 22 /* 23 * Get a file's attributes 24 * N.B. After this call resp->fh needs an fh_put 25 */ 26 static __be32 27 nfsd_proc_getattr(struct svc_rqst *rqstp) 28 { 29 struct nfsd_fhandle *argp = rqstp->rq_argp; 30 struct nfsd_attrstat *resp = rqstp->rq_resp; 31 32 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 33 34 fh_copy(&resp->fh, &argp->fh); 35 resp->status = fh_verify(rqstp, &resp->fh, 0, 36 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); 37 if (resp->status != nfs_ok) 38 goto out; 39 resp->status = fh_getattr(&resp->fh, &resp->stat); 40 out: 41 return rpc_success; 42 } 43 44 /* 45 * Set a file's attributes 46 * N.B. After this call resp->fh needs an fh_put 47 */ 48 static __be32 49 nfsd_proc_setattr(struct svc_rqst *rqstp) 50 { 51 struct nfsd_sattrargs *argp = rqstp->rq_argp; 52 struct nfsd_attrstat *resp = rqstp->rq_resp; 53 struct iattr *iap = &argp->attrs; 54 struct nfsd_attrs attrs = { 55 .na_iattr = iap, 56 }; 57 struct svc_fh *fhp; 58 59 dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", 60 SVCFH_fmt(&argp->fh), 61 argp->attrs.ia_valid, (long) argp->attrs.ia_size); 62 63 fhp = fh_copy(&resp->fh, &argp->fh); 64 65 /* 66 * NFSv2 does not differentiate between "set-[ac]time-to-now" 67 * which only requires access, and "set-[ac]time-to-X" which 68 * requires ownership. 69 * So if it looks like it might be "set both to the same time which 70 * is close to now", and if setattr_prepare fails, then we 71 * convert to "set to now" instead of "set to explicit time" 72 * 73 * We only call setattr_prepare as the last test as technically 74 * it is not an interface that we should be using. 75 */ 76 #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) 77 #define MAX_TOUCH_TIME_ERROR (30*60) 78 if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && 79 iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) { 80 /* 81 * Looks probable. 82 * 83 * Now just make sure time is in the right ballpark. 84 * Solaris, at least, doesn't seem to care what the time 85 * request is. We require it be within 30 minutes of now. 86 */ 87 time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds(); 88 89 resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); 90 if (resp->status != nfs_ok) 91 goto out; 92 93 if (delta < 0) 94 delta = -delta; 95 if (delta < MAX_TOUCH_TIME_ERROR && 96 setattr_prepare(&nop_mnt_idmap, fhp->fh_dentry, iap) != 0) { 97 /* 98 * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. 99 * This will cause notify_change to set these times 100 * to "now" 101 */ 102 iap->ia_valid &= ~BOTH_TIME_SET; 103 } 104 } 105 106 resp->status = nfsd_setattr(rqstp, fhp, &attrs, NULL); 107 if (resp->status != nfs_ok) 108 goto out; 109 110 resp->status = fh_getattr(&resp->fh, &resp->stat); 111 out: 112 return rpc_success; 113 } 114 115 /* Obsolete, replaced by MNTPROC_MNT. */ 116 static __be32 117 nfsd_proc_root(struct svc_rqst *rqstp) 118 { 119 return rpc_success; 120 } 121 122 /* 123 * Look up a path name component 124 * Note: the dentry in the resp->fh may be negative if the file 125 * doesn't exist yet. 126 * N.B. After this call resp->fh needs an fh_put 127 */ 128 static __be32 129 nfsd_proc_lookup(struct svc_rqst *rqstp) 130 { 131 struct nfsd_diropargs *argp = rqstp->rq_argp; 132 struct nfsd_diropres *resp = rqstp->rq_resp; 133 134 dprintk("nfsd: LOOKUP %s %.*s\n", 135 SVCFH_fmt(&argp->fh), argp->len, argp->name); 136 137 fh_init(&resp->fh, NFS_FHSIZE); 138 resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len, 139 &resp->fh); 140 fh_put(&argp->fh); 141 if (resp->status != nfs_ok) 142 goto out; 143 144 resp->status = fh_getattr(&resp->fh, &resp->stat); 145 out: 146 return rpc_success; 147 } 148 149 /* 150 * Read a symlink. 151 */ 152 static __be32 153 nfsd_proc_readlink(struct svc_rqst *rqstp) 154 { 155 struct nfsd_fhandle *argp = rqstp->rq_argp; 156 struct nfsd_readlinkres *resp = rqstp->rq_resp; 157 158 dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); 159 160 /* Read the symlink. */ 161 resp->len = NFS_MAXPATHLEN; 162 resp->page = *(rqstp->rq_next_page++); 163 resp->status = nfsd_readlink(rqstp, &argp->fh, 164 page_address(resp->page), &resp->len); 165 166 fh_put(&argp->fh); 167 return rpc_success; 168 } 169 170 /* 171 * Read a portion of a file. 172 * N.B. After this call resp->fh needs an fh_put 173 */ 174 static __be32 175 nfsd_proc_read(struct svc_rqst *rqstp) 176 { 177 struct nfsd_readargs *argp = rqstp->rq_argp; 178 struct nfsd_readres *resp = rqstp->rq_resp; 179 u32 eof; 180 181 dprintk("nfsd: READ %s %d bytes at %d\n", 182 SVCFH_fmt(&argp->fh), 183 argp->count, argp->offset); 184 185 argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2); 186 argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen); 187 188 resp->pages = rqstp->rq_next_page; 189 190 /* Obtain buffer pointer for payload. 19 is 1 word for 191 * status, 17 words for fattr, and 1 word for the byte count. 192 */ 193 svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); 194 195 resp->count = argp->count; 196 fh_copy(&resp->fh, &argp->fh); 197 resp->status = nfsd_read(rqstp, &resp->fh, argp->offset, 198 &resp->count, &eof); 199 if (resp->status == nfs_ok) 200 resp->status = fh_getattr(&resp->fh, &resp->stat); 201 else if (resp->status == nfserr_jukebox) 202 set_bit(RQ_DROPME, &rqstp->rq_flags); 203 return rpc_success; 204 } 205 206 /* Reserved */ 207 static __be32 208 nfsd_proc_writecache(struct svc_rqst *rqstp) 209 { 210 return rpc_success; 211 } 212 213 /* 214 * Write data to a file 215 * N.B. After this call resp->fh needs an fh_put 216 */ 217 static __be32 218 nfsd_proc_write(struct svc_rqst *rqstp) 219 { 220 struct nfsd_writeargs *argp = rqstp->rq_argp; 221 struct nfsd_attrstat *resp = rqstp->rq_resp; 222 unsigned long cnt = argp->len; 223 unsigned int nvecs; 224 225 dprintk("nfsd: WRITE %s %u bytes at %d\n", 226 SVCFH_fmt(&argp->fh), 227 argp->len, argp->offset); 228 229 nvecs = svc_fill_write_vector(rqstp, &argp->payload); 230 231 resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), 232 argp->offset, rqstp->rq_vec, nvecs, 233 &cnt, NFS_DATA_SYNC, NULL); 234 if (resp->status == nfs_ok) 235 resp->status = fh_getattr(&resp->fh, &resp->stat); 236 else if (resp->status == nfserr_jukebox) 237 set_bit(RQ_DROPME, &rqstp->rq_flags); 238 return rpc_success; 239 } 240 241 /* 242 * CREATE processing is complicated. The keyword here is `overloaded.' 243 * The parent directory is kept locked between the check for existence 244 * and the actual create() call in compliance with VFS protocols. 245 * N.B. After this call _both_ argp->fh and resp->fh need an fh_put 246 */ 247 static __be32 248 nfsd_proc_create(struct svc_rqst *rqstp) 249 { 250 struct nfsd_createargs *argp = rqstp->rq_argp; 251 struct nfsd_diropres *resp = rqstp->rq_resp; 252 svc_fh *dirfhp = &argp->fh; 253 svc_fh *newfhp = &resp->fh; 254 struct iattr *attr = &argp->attrs; 255 struct nfsd_attrs attrs = { 256 .na_iattr = attr, 257 }; 258 struct inode *inode; 259 struct dentry *dchild; 260 int type, mode; 261 int hosterr; 262 dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size); 263 264 dprintk("nfsd: CREATE %s %.*s\n", 265 SVCFH_fmt(dirfhp), argp->len, argp->name); 266 267 /* First verify the parent file handle */ 268 resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC); 269 if (resp->status != nfs_ok) 270 goto done; /* must fh_put dirfhp even on error */ 271 272 /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */ 273 274 resp->status = nfserr_exist; 275 if (isdotent(argp->name, argp->len)) 276 goto done; 277 hosterr = fh_want_write(dirfhp); 278 if (hosterr) { 279 resp->status = nfserrno(hosterr); 280 goto done; 281 } 282 283 inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT); 284 dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); 285 if (IS_ERR(dchild)) { 286 resp->status = nfserrno(PTR_ERR(dchild)); 287 goto out_unlock; 288 } 289 fh_init(newfhp, NFS_FHSIZE); 290 resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); 291 if (!resp->status && d_really_is_negative(dchild)) 292 resp->status = nfserr_noent; 293 dput(dchild); 294 if (resp->status) { 295 if (resp->status != nfserr_noent) 296 goto out_unlock; 297 /* 298 * If the new file handle wasn't verified, we can't tell 299 * whether the file exists or not. Time to bail ... 300 */ 301 resp->status = nfserr_acces; 302 if (!newfhp->fh_dentry) { 303 printk(KERN_WARNING 304 "nfsd_proc_create: file handle not verified\n"); 305 goto out_unlock; 306 } 307 } 308 309 inode = d_inode(newfhp->fh_dentry); 310 311 /* Unfudge the mode bits */ 312 if (attr->ia_valid & ATTR_MODE) { 313 type = attr->ia_mode & S_IFMT; 314 mode = attr->ia_mode & ~S_IFMT; 315 if (!type) { 316 /* no type, so if target exists, assume same as that, 317 * else assume a file */ 318 if (inode) { 319 type = inode->i_mode & S_IFMT; 320 switch(type) { 321 case S_IFCHR: 322 case S_IFBLK: 323 /* reserve rdev for later checking */ 324 rdev = inode->i_rdev; 325 attr->ia_valid |= ATTR_SIZE; 326 327 fallthrough; 328 case S_IFIFO: 329 /* this is probably a permission check.. 330 * at least IRIX implements perm checking on 331 * echo thing > device-special-file-or-pipe 332 * by doing a CREATE with type==0 333 */ 334 resp->status = nfsd_permission(rqstp, 335 newfhp->fh_export, 336 newfhp->fh_dentry, 337 NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); 338 if (resp->status && resp->status != nfserr_rofs) 339 goto out_unlock; 340 } 341 } else 342 type = S_IFREG; 343 } 344 } else if (inode) { 345 type = inode->i_mode & S_IFMT; 346 mode = inode->i_mode & ~S_IFMT; 347 } else { 348 type = S_IFREG; 349 mode = 0; /* ??? */ 350 } 351 352 attr->ia_valid |= ATTR_MODE; 353 attr->ia_mode = mode; 354 355 /* Special treatment for non-regular files according to the 356 * gospel of sun micro 357 */ 358 if (type != S_IFREG) { 359 if (type != S_IFBLK && type != S_IFCHR) { 360 rdev = 0; 361 } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { 362 /* If you think you've seen the worst, grok this. */ 363 type = S_IFIFO; 364 } else { 365 /* Okay, char or block special */ 366 if (!rdev) 367 rdev = wanted; 368 } 369 370 /* we've used the SIZE information, so discard it */ 371 attr->ia_valid &= ~ATTR_SIZE; 372 373 /* Make sure the type and device matches */ 374 resp->status = nfserr_exist; 375 if (inode && inode_wrong_type(inode, type)) 376 goto out_unlock; 377 } 378 379 resp->status = nfs_ok; 380 if (!inode) { 381 /* File doesn't exist. Create it and set attrs */ 382 resp->status = nfsd_create_locked(rqstp, dirfhp, &attrs, type, 383 rdev, newfhp); 384 } else if (type == S_IFREG) { 385 dprintk("nfsd: existing %s, valid=%x, size=%ld\n", 386 argp->name, attr->ia_valid, (long) attr->ia_size); 387 /* File already exists. We ignore all attributes except 388 * size, so that creat() behaves exactly like 389 * open(..., O_CREAT|O_TRUNC|O_WRONLY). 390 */ 391 attr->ia_valid &= ATTR_SIZE; 392 if (attr->ia_valid) 393 resp->status = nfsd_setattr(rqstp, newfhp, &attrs, 394 NULL); 395 } 396 397 out_unlock: 398 inode_unlock(dirfhp->fh_dentry->d_inode); 399 fh_drop_write(dirfhp); 400 done: 401 fh_put(dirfhp); 402 if (resp->status != nfs_ok) 403 goto out; 404 resp->status = fh_getattr(&resp->fh, &resp->stat); 405 out: 406 return rpc_success; 407 } 408 409 static __be32 410 nfsd_proc_remove(struct svc_rqst *rqstp) 411 { 412 struct nfsd_diropargs *argp = rqstp->rq_argp; 413 struct nfsd_stat *resp = rqstp->rq_resp; 414 415 dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh), 416 argp->len, argp->name); 417 418 /* Unlink. -SIFDIR means file must not be a directory */ 419 resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, 420 argp->name, argp->len); 421 fh_put(&argp->fh); 422 return rpc_success; 423 } 424 425 static __be32 426 nfsd_proc_rename(struct svc_rqst *rqstp) 427 { 428 struct nfsd_renameargs *argp = rqstp->rq_argp; 429 struct nfsd_stat *resp = rqstp->rq_resp; 430 431 dprintk("nfsd: RENAME %s %.*s -> \n", 432 SVCFH_fmt(&argp->ffh), argp->flen, argp->fname); 433 dprintk("nfsd: -> %s %.*s\n", 434 SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname); 435 436 resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen, 437 &argp->tfh, argp->tname, argp->tlen); 438 fh_put(&argp->ffh); 439 fh_put(&argp->tfh); 440 return rpc_success; 441 } 442 443 static __be32 444 nfsd_proc_link(struct svc_rqst *rqstp) 445 { 446 struct nfsd_linkargs *argp = rqstp->rq_argp; 447 struct nfsd_stat *resp = rqstp->rq_resp; 448 449 dprintk("nfsd: LINK %s ->\n", 450 SVCFH_fmt(&argp->ffh)); 451 dprintk("nfsd: %s %.*s\n", 452 SVCFH_fmt(&argp->tfh), 453 argp->tlen, 454 argp->tname); 455 456 resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen, 457 &argp->ffh); 458 fh_put(&argp->ffh); 459 fh_put(&argp->tfh); 460 return rpc_success; 461 } 462 463 static __be32 464 nfsd_proc_symlink(struct svc_rqst *rqstp) 465 { 466 struct nfsd_symlinkargs *argp = rqstp->rq_argp; 467 struct nfsd_stat *resp = rqstp->rq_resp; 468 struct nfsd_attrs attrs = { 469 .na_iattr = &argp->attrs, 470 }; 471 struct svc_fh newfh; 472 473 if (argp->tlen > NFS_MAXPATHLEN) { 474 resp->status = nfserr_nametoolong; 475 goto out; 476 } 477 478 argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first, 479 page_address(rqstp->rq_arg.pages[0]), 480 argp->tlen); 481 if (IS_ERR(argp->tname)) { 482 resp->status = nfserrno(PTR_ERR(argp->tname)); 483 goto out; 484 } 485 486 dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n", 487 SVCFH_fmt(&argp->ffh), argp->flen, argp->fname, 488 argp->tlen, argp->tname); 489 490 fh_init(&newfh, NFS_FHSIZE); 491 resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, 492 argp->tname, &attrs, &newfh); 493 494 kfree(argp->tname); 495 fh_put(&argp->ffh); 496 fh_put(&newfh); 497 out: 498 return rpc_success; 499 } 500 501 /* 502 * Make directory. This operation is not idempotent. 503 * N.B. After this call resp->fh needs an fh_put 504 */ 505 static __be32 506 nfsd_proc_mkdir(struct svc_rqst *rqstp) 507 { 508 struct nfsd_createargs *argp = rqstp->rq_argp; 509 struct nfsd_diropres *resp = rqstp->rq_resp; 510 struct nfsd_attrs attrs = { 511 .na_iattr = &argp->attrs, 512 }; 513 514 dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); 515 516 if (resp->fh.fh_dentry) { 517 printk(KERN_WARNING 518 "nfsd_proc_mkdir: response already verified??\n"); 519 } 520 521 argp->attrs.ia_valid &= ~ATTR_SIZE; 522 fh_init(&resp->fh, NFS_FHSIZE); 523 resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, 524 &attrs, S_IFDIR, 0, &resp->fh); 525 fh_put(&argp->fh); 526 if (resp->status != nfs_ok) 527 goto out; 528 529 resp->status = fh_getattr(&resp->fh, &resp->stat); 530 out: 531 return rpc_success; 532 } 533 534 /* 535 * Remove a directory 536 */ 537 static __be32 538 nfsd_proc_rmdir(struct svc_rqst *rqstp) 539 { 540 struct nfsd_diropargs *argp = rqstp->rq_argp; 541 struct nfsd_stat *resp = rqstp->rq_resp; 542 543 dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); 544 545 resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, 546 argp->name, argp->len); 547 fh_put(&argp->fh); 548 return rpc_success; 549 } 550 551 static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, 552 struct nfsd_readdirres *resp, 553 u32 count) 554 { 555 struct xdr_buf *buf = &resp->dirlist; 556 struct xdr_stream *xdr = &resp->xdr; 557 558 memset(buf, 0, sizeof(*buf)); 559 560 /* Reserve room for the NULL ptr & eof flag (-2 words) */ 561 buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), (u32)PAGE_SIZE); 562 buf->buflen -= XDR_UNIT * 2; 563 buf->pages = rqstp->rq_next_page; 564 rqstp->rq_next_page++; 565 566 xdr_init_encode_pages(xdr, buf, buf->pages, NULL); 567 } 568 569 /* 570 * Read a portion of a directory. 571 */ 572 static __be32 573 nfsd_proc_readdir(struct svc_rqst *rqstp) 574 { 575 struct nfsd_readdirargs *argp = rqstp->rq_argp; 576 struct nfsd_readdirres *resp = rqstp->rq_resp; 577 loff_t offset; 578 579 dprintk("nfsd: READDIR %s %d bytes at %d\n", 580 SVCFH_fmt(&argp->fh), 581 argp->count, argp->cookie); 582 583 nfsd_init_dirlist_pages(rqstp, resp, argp->count); 584 585 resp->common.err = nfs_ok; 586 resp->cookie_offset = 0; 587 offset = argp->cookie; 588 resp->status = nfsd_readdir(rqstp, &argp->fh, &offset, 589 &resp->common, nfssvc_encode_entry); 590 nfssvc_encode_nfscookie(resp, offset); 591 592 fh_put(&argp->fh); 593 return rpc_success; 594 } 595 596 /* 597 * Get file system info 598 */ 599 static __be32 600 nfsd_proc_statfs(struct svc_rqst *rqstp) 601 { 602 struct nfsd_fhandle *argp = rqstp->rq_argp; 603 struct nfsd_statfsres *resp = rqstp->rq_resp; 604 605 dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh)); 606 607 resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 608 NFSD_MAY_BYPASS_GSS_ON_ROOT); 609 fh_put(&argp->fh); 610 return rpc_success; 611 } 612 613 /* 614 * NFSv2 Server procedures. 615 * Only the results of non-idempotent operations are cached. 616 */ 617 618 #define ST 1 /* status */ 619 #define FH 8 /* filehandle */ 620 #define AT 18 /* attributes */ 621 622 static const struct svc_procedure nfsd_procedures2[18] = { 623 [NFSPROC_NULL] = { 624 .pc_func = nfsd_proc_null, 625 .pc_decode = nfssvc_decode_voidarg, 626 .pc_encode = nfssvc_encode_voidres, 627 .pc_argsize = sizeof(struct nfsd_voidargs), 628 .pc_argzero = sizeof(struct nfsd_voidargs), 629 .pc_ressize = sizeof(struct nfsd_voidres), 630 .pc_cachetype = RC_NOCACHE, 631 .pc_xdrressize = 0, 632 .pc_name = "NULL", 633 }, 634 [NFSPROC_GETATTR] = { 635 .pc_func = nfsd_proc_getattr, 636 .pc_decode = nfssvc_decode_fhandleargs, 637 .pc_encode = nfssvc_encode_attrstatres, 638 .pc_release = nfssvc_release_attrstat, 639 .pc_argsize = sizeof(struct nfsd_fhandle), 640 .pc_argzero = sizeof(struct nfsd_fhandle), 641 .pc_ressize = sizeof(struct nfsd_attrstat), 642 .pc_cachetype = RC_NOCACHE, 643 .pc_xdrressize = ST+AT, 644 .pc_name = "GETATTR", 645 }, 646 [NFSPROC_SETATTR] = { 647 .pc_func = nfsd_proc_setattr, 648 .pc_decode = nfssvc_decode_sattrargs, 649 .pc_encode = nfssvc_encode_attrstatres, 650 .pc_release = nfssvc_release_attrstat, 651 .pc_argsize = sizeof(struct nfsd_sattrargs), 652 .pc_argzero = sizeof(struct nfsd_sattrargs), 653 .pc_ressize = sizeof(struct nfsd_attrstat), 654 .pc_cachetype = RC_REPLBUFF, 655 .pc_xdrressize = ST+AT, 656 .pc_name = "SETATTR", 657 }, 658 [NFSPROC_ROOT] = { 659 .pc_func = nfsd_proc_root, 660 .pc_decode = nfssvc_decode_voidarg, 661 .pc_encode = nfssvc_encode_voidres, 662 .pc_argsize = sizeof(struct nfsd_voidargs), 663 .pc_argzero = sizeof(struct nfsd_voidargs), 664 .pc_ressize = sizeof(struct nfsd_voidres), 665 .pc_cachetype = RC_NOCACHE, 666 .pc_xdrressize = 0, 667 .pc_name = "ROOT", 668 }, 669 [NFSPROC_LOOKUP] = { 670 .pc_func = nfsd_proc_lookup, 671 .pc_decode = nfssvc_decode_diropargs, 672 .pc_encode = nfssvc_encode_diropres, 673 .pc_release = nfssvc_release_diropres, 674 .pc_argsize = sizeof(struct nfsd_diropargs), 675 .pc_argzero = sizeof(struct nfsd_diropargs), 676 .pc_ressize = sizeof(struct nfsd_diropres), 677 .pc_cachetype = RC_NOCACHE, 678 .pc_xdrressize = ST+FH+AT, 679 .pc_name = "LOOKUP", 680 }, 681 [NFSPROC_READLINK] = { 682 .pc_func = nfsd_proc_readlink, 683 .pc_decode = nfssvc_decode_fhandleargs, 684 .pc_encode = nfssvc_encode_readlinkres, 685 .pc_argsize = sizeof(struct nfsd_fhandle), 686 .pc_argzero = sizeof(struct nfsd_fhandle), 687 .pc_ressize = sizeof(struct nfsd_readlinkres), 688 .pc_cachetype = RC_NOCACHE, 689 .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, 690 .pc_name = "READLINK", 691 }, 692 [NFSPROC_READ] = { 693 .pc_func = nfsd_proc_read, 694 .pc_decode = nfssvc_decode_readargs, 695 .pc_encode = nfssvc_encode_readres, 696 .pc_release = nfssvc_release_readres, 697 .pc_argsize = sizeof(struct nfsd_readargs), 698 .pc_argzero = sizeof(struct nfsd_readargs), 699 .pc_ressize = sizeof(struct nfsd_readres), 700 .pc_cachetype = RC_NOCACHE, 701 .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, 702 .pc_name = "READ", 703 }, 704 [NFSPROC_WRITECACHE] = { 705 .pc_func = nfsd_proc_writecache, 706 .pc_decode = nfssvc_decode_voidarg, 707 .pc_encode = nfssvc_encode_voidres, 708 .pc_argsize = sizeof(struct nfsd_voidargs), 709 .pc_argzero = sizeof(struct nfsd_voidargs), 710 .pc_ressize = sizeof(struct nfsd_voidres), 711 .pc_cachetype = RC_NOCACHE, 712 .pc_xdrressize = 0, 713 .pc_name = "WRITECACHE", 714 }, 715 [NFSPROC_WRITE] = { 716 .pc_func = nfsd_proc_write, 717 .pc_decode = nfssvc_decode_writeargs, 718 .pc_encode = nfssvc_encode_attrstatres, 719 .pc_release = nfssvc_release_attrstat, 720 .pc_argsize = sizeof(struct nfsd_writeargs), 721 .pc_argzero = sizeof(struct nfsd_writeargs), 722 .pc_ressize = sizeof(struct nfsd_attrstat), 723 .pc_cachetype = RC_REPLBUFF, 724 .pc_xdrressize = ST+AT, 725 .pc_name = "WRITE", 726 }, 727 [NFSPROC_CREATE] = { 728 .pc_func = nfsd_proc_create, 729 .pc_decode = nfssvc_decode_createargs, 730 .pc_encode = nfssvc_encode_diropres, 731 .pc_release = nfssvc_release_diropres, 732 .pc_argsize = sizeof(struct nfsd_createargs), 733 .pc_argzero = sizeof(struct nfsd_createargs), 734 .pc_ressize = sizeof(struct nfsd_diropres), 735 .pc_cachetype = RC_REPLBUFF, 736 .pc_xdrressize = ST+FH+AT, 737 .pc_name = "CREATE", 738 }, 739 [NFSPROC_REMOVE] = { 740 .pc_func = nfsd_proc_remove, 741 .pc_decode = nfssvc_decode_diropargs, 742 .pc_encode = nfssvc_encode_statres, 743 .pc_argsize = sizeof(struct nfsd_diropargs), 744 .pc_argzero = sizeof(struct nfsd_diropargs), 745 .pc_ressize = sizeof(struct nfsd_stat), 746 .pc_cachetype = RC_REPLSTAT, 747 .pc_xdrressize = ST, 748 .pc_name = "REMOVE", 749 }, 750 [NFSPROC_RENAME] = { 751 .pc_func = nfsd_proc_rename, 752 .pc_decode = nfssvc_decode_renameargs, 753 .pc_encode = nfssvc_encode_statres, 754 .pc_argsize = sizeof(struct nfsd_renameargs), 755 .pc_argzero = sizeof(struct nfsd_renameargs), 756 .pc_ressize = sizeof(struct nfsd_stat), 757 .pc_cachetype = RC_REPLSTAT, 758 .pc_xdrressize = ST, 759 .pc_name = "RENAME", 760 }, 761 [NFSPROC_LINK] = { 762 .pc_func = nfsd_proc_link, 763 .pc_decode = nfssvc_decode_linkargs, 764 .pc_encode = nfssvc_encode_statres, 765 .pc_argsize = sizeof(struct nfsd_linkargs), 766 .pc_argzero = sizeof(struct nfsd_linkargs), 767 .pc_ressize = sizeof(struct nfsd_stat), 768 .pc_cachetype = RC_REPLSTAT, 769 .pc_xdrressize = ST, 770 .pc_name = "LINK", 771 }, 772 [NFSPROC_SYMLINK] = { 773 .pc_func = nfsd_proc_symlink, 774 .pc_decode = nfssvc_decode_symlinkargs, 775 .pc_encode = nfssvc_encode_statres, 776 .pc_argsize = sizeof(struct nfsd_symlinkargs), 777 .pc_argzero = sizeof(struct nfsd_symlinkargs), 778 .pc_ressize = sizeof(struct nfsd_stat), 779 .pc_cachetype = RC_REPLSTAT, 780 .pc_xdrressize = ST, 781 .pc_name = "SYMLINK", 782 }, 783 [NFSPROC_MKDIR] = { 784 .pc_func = nfsd_proc_mkdir, 785 .pc_decode = nfssvc_decode_createargs, 786 .pc_encode = nfssvc_encode_diropres, 787 .pc_release = nfssvc_release_diropres, 788 .pc_argsize = sizeof(struct nfsd_createargs), 789 .pc_argzero = sizeof(struct nfsd_createargs), 790 .pc_ressize = sizeof(struct nfsd_diropres), 791 .pc_cachetype = RC_REPLBUFF, 792 .pc_xdrressize = ST+FH+AT, 793 .pc_name = "MKDIR", 794 }, 795 [NFSPROC_RMDIR] = { 796 .pc_func = nfsd_proc_rmdir, 797 .pc_decode = nfssvc_decode_diropargs, 798 .pc_encode = nfssvc_encode_statres, 799 .pc_argsize = sizeof(struct nfsd_diropargs), 800 .pc_argzero = sizeof(struct nfsd_diropargs), 801 .pc_ressize = sizeof(struct nfsd_stat), 802 .pc_cachetype = RC_REPLSTAT, 803 .pc_xdrressize = ST, 804 .pc_name = "RMDIR", 805 }, 806 [NFSPROC_READDIR] = { 807 .pc_func = nfsd_proc_readdir, 808 .pc_decode = nfssvc_decode_readdirargs, 809 .pc_encode = nfssvc_encode_readdirres, 810 .pc_argsize = sizeof(struct nfsd_readdirargs), 811 .pc_argzero = sizeof(struct nfsd_readdirargs), 812 .pc_ressize = sizeof(struct nfsd_readdirres), 813 .pc_cachetype = RC_NOCACHE, 814 .pc_name = "READDIR", 815 }, 816 [NFSPROC_STATFS] = { 817 .pc_func = nfsd_proc_statfs, 818 .pc_decode = nfssvc_decode_fhandleargs, 819 .pc_encode = nfssvc_encode_statfsres, 820 .pc_argsize = sizeof(struct nfsd_fhandle), 821 .pc_argzero = sizeof(struct nfsd_fhandle), 822 .pc_ressize = sizeof(struct nfsd_statfsres), 823 .pc_cachetype = RC_NOCACHE, 824 .pc_xdrressize = ST+5, 825 .pc_name = "STATFS", 826 }, 827 }; 828 829 static DEFINE_PER_CPU_ALIGNED(unsigned long, 830 nfsd_count2[ARRAY_SIZE(nfsd_procedures2)]); 831 const struct svc_version nfsd_version2 = { 832 .vs_vers = 2, 833 .vs_nproc = ARRAY_SIZE(nfsd_procedures2), 834 .vs_proc = nfsd_procedures2, 835 .vs_count = nfsd_count2, 836 .vs_dispatch = nfsd_dispatch, 837 .vs_xdrsize = NFS2_SVC_XDRSIZE, 838 }; 839