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