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