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