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