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