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