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