1 /* 2 * fs/nfsd/nfs4proc.c 3 * 4 * Server-side procedures for NFSv4. 5 * 6 * Copyright (c) 2002 The Regents of the University of Michigan. 7 * All rights reserved. 8 * 9 * Kendrick Smith <kmsmith@umich.edu> 10 * Andy Adamson <andros@umich.edu> 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 32 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <linux/param.h> 39 #include <linux/major.h> 40 #include <linux/slab.h> 41 #include <linux/file.h> 42 43 #include <linux/sunrpc/svc.h> 44 #include <linux/nfsd/nfsd.h> 45 #include <linux/nfsd/cache.h> 46 #include <linux/nfs4.h> 47 #include <linux/nfsd/state.h> 48 #include <linux/nfsd/xdr4.h> 49 #include <linux/nfs4_acl.h> 50 #include <linux/sunrpc/gss_api.h> 51 52 #define NFSDDBG_FACILITY NFSDDBG_PROC 53 54 static inline void 55 fh_dup2(struct svc_fh *dst, struct svc_fh *src) 56 { 57 fh_put(dst); 58 dget(src->fh_dentry); 59 if (src->fh_export) 60 cache_get(&src->fh_export->h); 61 *dst = *src; 62 } 63 64 static __be32 65 do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode) 66 { 67 __be32 status; 68 69 if (open->op_truncate && 70 !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 71 return nfserr_inval; 72 73 if (open->op_share_access & NFS4_SHARE_ACCESS_READ) 74 accmode |= NFSD_MAY_READ; 75 if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 76 accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC); 77 if (open->op_share_deny & NFS4_SHARE_DENY_WRITE) 78 accmode |= NFSD_MAY_WRITE; 79 80 status = fh_verify(rqstp, current_fh, S_IFREG, accmode); 81 82 return status; 83 } 84 85 static __be32 86 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 87 { 88 struct svc_fh resfh; 89 __be32 status; 90 int created = 0; 91 92 fh_init(&resfh, NFS4_FHSIZE); 93 open->op_truncate = 0; 94 95 if (open->op_create) { 96 /* FIXME: check session persistence and pnfs flags. 97 * The nfsv4.1 spec requires the following semantics: 98 * 99 * Persistent | pNFS | Server REQUIRED | Client Allowed 100 * Reply Cache | server | | 101 * -------------+--------+-----------------+-------------------- 102 * no | no | EXCLUSIVE4_1 | EXCLUSIVE4_1 103 * | | | (SHOULD) 104 * | | and EXCLUSIVE4 | or EXCLUSIVE4 105 * | | | (SHOULD NOT) 106 * no | yes | EXCLUSIVE4_1 | EXCLUSIVE4_1 107 * yes | no | GUARDED4 | GUARDED4 108 * yes | yes | GUARDED4 | GUARDED4 109 */ 110 111 /* 112 * Note: create modes (UNCHECKED,GUARDED...) are the same 113 * in NFSv4 as in v3. 114 */ 115 status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data, 116 open->op_fname.len, &open->op_iattr, 117 &resfh, open->op_createmode, 118 (u32 *)open->op_verf.data, 119 &open->op_truncate, &created); 120 121 /* 122 * Following rfc 3530 14.2.16, use the returned bitmask 123 * to indicate which attributes we used to store the 124 * verifier: 125 */ 126 if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0) 127 open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS | 128 FATTR4_WORD1_TIME_MODIFY); 129 } else { 130 status = nfsd_lookup(rqstp, current_fh, 131 open->op_fname.data, open->op_fname.len, &resfh); 132 fh_unlock(current_fh); 133 } 134 if (status) 135 goto out; 136 137 set_change_info(&open->op_cinfo, current_fh); 138 fh_dup2(current_fh, &resfh); 139 140 /* set reply cache */ 141 fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh, 142 &resfh.fh_handle); 143 if (!created) 144 status = do_open_permission(rqstp, current_fh, open, 145 NFSD_MAY_NOP); 146 147 out: 148 fh_put(&resfh); 149 return status; 150 } 151 152 static __be32 153 do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 154 { 155 __be32 status; 156 157 /* Only reclaims from previously confirmed clients are valid */ 158 if ((status = nfs4_check_open_reclaim(&open->op_clientid))) 159 return status; 160 161 /* We don't know the target directory, and therefore can not 162 * set the change info 163 */ 164 165 memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); 166 167 /* set replay cache */ 168 fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh, 169 ¤t_fh->fh_handle); 170 171 open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && 172 (open->op_iattr.ia_size == 0); 173 174 status = do_open_permission(rqstp, current_fh, open, 175 NFSD_MAY_OWNER_OVERRIDE); 176 177 return status; 178 } 179 180 static void 181 copy_clientid(clientid_t *clid, struct nfsd4_session *session) 182 { 183 struct nfsd4_sessionid *sid = 184 (struct nfsd4_sessionid *)session->se_sessionid.data; 185 186 clid->cl_boot = sid->clientid.cl_boot; 187 clid->cl_id = sid->clientid.cl_id; 188 } 189 190 static __be32 191 nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 192 struct nfsd4_open *open) 193 { 194 __be32 status; 195 struct nfsd4_compoundres *resp; 196 197 dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", 198 (int)open->op_fname.len, open->op_fname.data, 199 open->op_stateowner); 200 201 /* This check required by spec. */ 202 if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) 203 return nfserr_inval; 204 205 if (nfsd4_has_session(cstate)) 206 copy_clientid(&open->op_clientid, cstate->session); 207 208 nfs4_lock_state(); 209 210 /* check seqid for replay. set nfs4_owner */ 211 resp = rqstp->rq_resp; 212 status = nfsd4_process_open1(&resp->cstate, open); 213 if (status == nfserr_replay_me) { 214 struct nfs4_replay *rp = &open->op_stateowner->so_replay; 215 fh_put(&cstate->current_fh); 216 fh_copy_shallow(&cstate->current_fh.fh_handle, 217 &rp->rp_openfh); 218 status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); 219 if (status) 220 dprintk("nfsd4_open: replay failed" 221 " restoring previous filehandle\n"); 222 else 223 status = nfserr_replay_me; 224 } 225 if (status) 226 goto out; 227 228 /* Openowner is now set, so sequence id will get bumped. Now we need 229 * these checks before we do any creates: */ 230 status = nfserr_grace; 231 if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) 232 goto out; 233 status = nfserr_no_grace; 234 if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 235 goto out; 236 237 switch (open->op_claim_type) { 238 case NFS4_OPEN_CLAIM_DELEGATE_CUR: 239 case NFS4_OPEN_CLAIM_NULL: 240 /* 241 * (1) set CURRENT_FH to the file being opened, 242 * creating it if necessary, (2) set open->op_cinfo, 243 * (3) set open->op_truncate if the file is to be 244 * truncated after opening, (4) do permission checking. 245 */ 246 status = do_open_lookup(rqstp, &cstate->current_fh, 247 open); 248 if (status) 249 goto out; 250 break; 251 case NFS4_OPEN_CLAIM_PREVIOUS: 252 open->op_stateowner->so_confirmed = 1; 253 /* 254 * The CURRENT_FH is already set to the file being 255 * opened. (1) set open->op_cinfo, (2) set 256 * open->op_truncate if the file is to be truncated 257 * after opening, (3) do permission checking. 258 */ 259 status = do_open_fhandle(rqstp, &cstate->current_fh, 260 open); 261 if (status) 262 goto out; 263 break; 264 case NFS4_OPEN_CLAIM_DELEGATE_PREV: 265 open->op_stateowner->so_confirmed = 1; 266 dprintk("NFSD: unsupported OPEN claim type %d\n", 267 open->op_claim_type); 268 status = nfserr_notsupp; 269 goto out; 270 default: 271 dprintk("NFSD: Invalid OPEN claim type %d\n", 272 open->op_claim_type); 273 status = nfserr_inval; 274 goto out; 275 } 276 /* 277 * nfsd4_process_open2() does the actual opening of the file. If 278 * successful, it (1) truncates the file if open->op_truncate was 279 * set, (2) sets open->op_stateid, (3) sets open->op_delegation. 280 */ 281 status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); 282 out: 283 if (open->op_stateowner) { 284 nfs4_get_stateowner(open->op_stateowner); 285 cstate->replay_owner = open->op_stateowner; 286 } 287 nfs4_unlock_state(); 288 return status; 289 } 290 291 /* 292 * filehandle-manipulating ops. 293 */ 294 static __be32 295 nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 296 struct svc_fh **getfh) 297 { 298 if (!cstate->current_fh.fh_dentry) 299 return nfserr_nofilehandle; 300 301 *getfh = &cstate->current_fh; 302 return nfs_ok; 303 } 304 305 static __be32 306 nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 307 struct nfsd4_putfh *putfh) 308 { 309 fh_put(&cstate->current_fh); 310 cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; 311 memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, 312 putfh->pf_fhlen); 313 return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); 314 } 315 316 static __be32 317 nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 318 void *arg) 319 { 320 __be32 status; 321 322 fh_put(&cstate->current_fh); 323 status = exp_pseudoroot(rqstp, &cstate->current_fh); 324 return status; 325 } 326 327 static __be32 328 nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 329 void *arg) 330 { 331 if (!cstate->save_fh.fh_dentry) 332 return nfserr_restorefh; 333 334 fh_dup2(&cstate->current_fh, &cstate->save_fh); 335 return nfs_ok; 336 } 337 338 static __be32 339 nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 340 void *arg) 341 { 342 if (!cstate->current_fh.fh_dentry) 343 return nfserr_nofilehandle; 344 345 fh_dup2(&cstate->save_fh, &cstate->current_fh); 346 return nfs_ok; 347 } 348 349 /* 350 * misc nfsv4 ops 351 */ 352 static __be32 353 nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 354 struct nfsd4_access *access) 355 { 356 if (access->ac_req_access & ~NFS3_ACCESS_FULL) 357 return nfserr_inval; 358 359 access->ac_resp_access = access->ac_req_access; 360 return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access, 361 &access->ac_supported); 362 } 363 364 static __be32 365 nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 366 struct nfsd4_commit *commit) 367 { 368 __be32 status; 369 370 u32 *p = (u32 *)commit->co_verf.data; 371 *p++ = nfssvc_boot.tv_sec; 372 *p++ = nfssvc_boot.tv_usec; 373 374 status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, 375 commit->co_count); 376 if (status == nfserr_symlink) 377 status = nfserr_inval; 378 return status; 379 } 380 381 static __be32 382 nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 383 struct nfsd4_create *create) 384 { 385 struct svc_fh resfh; 386 __be32 status; 387 dev_t rdev; 388 389 fh_init(&resfh, NFS4_FHSIZE); 390 391 status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, 392 NFSD_MAY_CREATE); 393 if (status == nfserr_symlink) 394 status = nfserr_notdir; 395 if (status) 396 return status; 397 398 switch (create->cr_type) { 399 case NF4LNK: 400 /* ugh! we have to null-terminate the linktext, or 401 * vfs_symlink() will choke. it is always safe to 402 * null-terminate by brute force, since at worst we 403 * will overwrite the first byte of the create namelen 404 * in the XDR buffer, which has already been extracted 405 * during XDR decode. 406 */ 407 create->cr_linkname[create->cr_linklen] = 0; 408 409 status = nfsd_symlink(rqstp, &cstate->current_fh, 410 create->cr_name, create->cr_namelen, 411 create->cr_linkname, create->cr_linklen, 412 &resfh, &create->cr_iattr); 413 break; 414 415 case NF4BLK: 416 rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); 417 if (MAJOR(rdev) != create->cr_specdata1 || 418 MINOR(rdev) != create->cr_specdata2) 419 return nfserr_inval; 420 status = nfsd_create(rqstp, &cstate->current_fh, 421 create->cr_name, create->cr_namelen, 422 &create->cr_iattr, S_IFBLK, rdev, &resfh); 423 break; 424 425 case NF4CHR: 426 rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); 427 if (MAJOR(rdev) != create->cr_specdata1 || 428 MINOR(rdev) != create->cr_specdata2) 429 return nfserr_inval; 430 status = nfsd_create(rqstp, &cstate->current_fh, 431 create->cr_name, create->cr_namelen, 432 &create->cr_iattr,S_IFCHR, rdev, &resfh); 433 break; 434 435 case NF4SOCK: 436 status = nfsd_create(rqstp, &cstate->current_fh, 437 create->cr_name, create->cr_namelen, 438 &create->cr_iattr, S_IFSOCK, 0, &resfh); 439 break; 440 441 case NF4FIFO: 442 status = nfsd_create(rqstp, &cstate->current_fh, 443 create->cr_name, create->cr_namelen, 444 &create->cr_iattr, S_IFIFO, 0, &resfh); 445 break; 446 447 case NF4DIR: 448 create->cr_iattr.ia_valid &= ~ATTR_SIZE; 449 status = nfsd_create(rqstp, &cstate->current_fh, 450 create->cr_name, create->cr_namelen, 451 &create->cr_iattr, S_IFDIR, 0, &resfh); 452 break; 453 454 default: 455 status = nfserr_badtype; 456 } 457 458 if (!status) { 459 fh_unlock(&cstate->current_fh); 460 set_change_info(&create->cr_cinfo, &cstate->current_fh); 461 fh_dup2(&cstate->current_fh, &resfh); 462 } 463 464 fh_put(&resfh); 465 return status; 466 } 467 468 static __be32 469 nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 470 struct nfsd4_getattr *getattr) 471 { 472 __be32 status; 473 474 status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); 475 if (status) 476 return status; 477 478 if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1) 479 return nfserr_inval; 480 481 getattr->ga_bmval[0] &= nfsd_suppattrs0(cstate->minorversion); 482 getattr->ga_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); 483 getattr->ga_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); 484 485 getattr->ga_fhp = &cstate->current_fh; 486 return nfs_ok; 487 } 488 489 static __be32 490 nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 491 struct nfsd4_link *link) 492 { 493 __be32 status = nfserr_nofilehandle; 494 495 if (!cstate->save_fh.fh_dentry) 496 return status; 497 status = nfsd_link(rqstp, &cstate->current_fh, 498 link->li_name, link->li_namelen, &cstate->save_fh); 499 if (!status) 500 set_change_info(&link->li_cinfo, &cstate->current_fh); 501 return status; 502 } 503 504 static __be32 505 nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 506 void *arg) 507 { 508 struct svc_fh tmp_fh; 509 __be32 ret; 510 511 fh_init(&tmp_fh, NFS4_FHSIZE); 512 ret = exp_pseudoroot(rqstp, &tmp_fh); 513 if (ret) 514 return ret; 515 if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { 516 fh_put(&tmp_fh); 517 return nfserr_noent; 518 } 519 fh_put(&tmp_fh); 520 return nfsd_lookup(rqstp, &cstate->current_fh, 521 "..", 2, &cstate->current_fh); 522 } 523 524 static __be32 525 nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 526 struct nfsd4_lookup *lookup) 527 { 528 return nfsd_lookup(rqstp, &cstate->current_fh, 529 lookup->lo_name, lookup->lo_len, 530 &cstate->current_fh); 531 } 532 533 static __be32 534 nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 535 struct nfsd4_read *read) 536 { 537 __be32 status; 538 539 /* no need to check permission - this will be done in nfsd_read() */ 540 541 read->rd_filp = NULL; 542 if (read->rd_offset >= OFFSET_MAX) 543 return nfserr_inval; 544 545 nfs4_lock_state(); 546 /* check stateid */ 547 if ((status = nfs4_preprocess_stateid_op(cstate, &read->rd_stateid, 548 RD_STATE, &read->rd_filp))) { 549 dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); 550 goto out; 551 } 552 if (read->rd_filp) 553 get_file(read->rd_filp); 554 status = nfs_ok; 555 out: 556 nfs4_unlock_state(); 557 read->rd_rqstp = rqstp; 558 read->rd_fhp = &cstate->current_fh; 559 return status; 560 } 561 562 static __be32 563 nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 564 struct nfsd4_readdir *readdir) 565 { 566 u64 cookie = readdir->rd_cookie; 567 static const nfs4_verifier zeroverf; 568 569 /* no need to check permission - this will be done in nfsd_readdir() */ 570 571 if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1) 572 return nfserr_inval; 573 574 readdir->rd_bmval[0] &= nfsd_suppattrs0(cstate->minorversion); 575 readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); 576 readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); 577 578 if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) || 579 (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) 580 return nfserr_bad_cookie; 581 582 readdir->rd_rqstp = rqstp; 583 readdir->rd_fhp = &cstate->current_fh; 584 return nfs_ok; 585 } 586 587 static __be32 588 nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 589 struct nfsd4_readlink *readlink) 590 { 591 readlink->rl_rqstp = rqstp; 592 readlink->rl_fhp = &cstate->current_fh; 593 return nfs_ok; 594 } 595 596 static __be32 597 nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 598 struct nfsd4_remove *remove) 599 { 600 __be32 status; 601 602 if (locks_in_grace()) 603 return nfserr_grace; 604 status = nfsd_unlink(rqstp, &cstate->current_fh, 0, 605 remove->rm_name, remove->rm_namelen); 606 if (status == nfserr_symlink) 607 return nfserr_notdir; 608 if (!status) { 609 fh_unlock(&cstate->current_fh); 610 set_change_info(&remove->rm_cinfo, &cstate->current_fh); 611 } 612 return status; 613 } 614 615 static __be32 616 nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 617 struct nfsd4_rename *rename) 618 { 619 __be32 status = nfserr_nofilehandle; 620 621 if (!cstate->save_fh.fh_dentry) 622 return status; 623 if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags 624 & NFSEXP_NOSUBTREECHECK)) 625 return nfserr_grace; 626 status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, 627 rename->rn_snamelen, &cstate->current_fh, 628 rename->rn_tname, rename->rn_tnamelen); 629 630 /* the underlying filesystem returns different error's than required 631 * by NFSv4. both save_fh and current_fh have been verified.. */ 632 if (status == nfserr_isdir) 633 status = nfserr_exist; 634 else if ((status == nfserr_notdir) && 635 (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) && 636 S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode))) 637 status = nfserr_exist; 638 else if (status == nfserr_symlink) 639 status = nfserr_notdir; 640 641 if (!status) { 642 set_change_info(&rename->rn_sinfo, &cstate->current_fh); 643 set_change_info(&rename->rn_tinfo, &cstate->save_fh); 644 } 645 return status; 646 } 647 648 static __be32 649 nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 650 struct nfsd4_secinfo *secinfo) 651 { 652 struct svc_fh resfh; 653 struct svc_export *exp; 654 struct dentry *dentry; 655 __be32 err; 656 657 fh_init(&resfh, NFS4_FHSIZE); 658 err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, 659 secinfo->si_name, secinfo->si_namelen, 660 &exp, &dentry); 661 if (err) 662 return err; 663 if (dentry->d_inode == NULL) { 664 exp_put(exp); 665 err = nfserr_noent; 666 } else 667 secinfo->si_exp = exp; 668 dput(dentry); 669 return err; 670 } 671 672 static __be32 673 nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 674 struct nfsd4_setattr *setattr) 675 { 676 __be32 status = nfs_ok; 677 678 if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { 679 nfs4_lock_state(); 680 status = nfs4_preprocess_stateid_op(cstate, 681 &setattr->sa_stateid, WR_STATE, NULL); 682 nfs4_unlock_state(); 683 if (status) { 684 dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); 685 return status; 686 } 687 } 688 status = mnt_want_write(cstate->current_fh.fh_export->ex_path.mnt); 689 if (status) 690 return status; 691 status = nfs_ok; 692 if (setattr->sa_acl != NULL) 693 status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, 694 setattr->sa_acl); 695 if (status) 696 goto out; 697 status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, 698 0, (time_t)0); 699 out: 700 mnt_drop_write(cstate->current_fh.fh_export->ex_path.mnt); 701 return status; 702 } 703 704 static __be32 705 nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 706 struct nfsd4_write *write) 707 { 708 stateid_t *stateid = &write->wr_stateid; 709 struct file *filp = NULL; 710 u32 *p; 711 __be32 status = nfs_ok; 712 unsigned long cnt; 713 714 /* no need to check permission - this will be done in nfsd_write() */ 715 716 if (write->wr_offset >= OFFSET_MAX) 717 return nfserr_inval; 718 719 nfs4_lock_state(); 720 status = nfs4_preprocess_stateid_op(cstate, stateid, WR_STATE, &filp); 721 if (filp) 722 get_file(filp); 723 nfs4_unlock_state(); 724 725 if (status) { 726 dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); 727 return status; 728 } 729 730 cnt = write->wr_buflen; 731 write->wr_how_written = write->wr_stable_how; 732 p = (u32 *)write->wr_verifier.data; 733 *p++ = nfssvc_boot.tv_sec; 734 *p++ = nfssvc_boot.tv_usec; 735 736 status = nfsd_write(rqstp, &cstate->current_fh, filp, 737 write->wr_offset, rqstp->rq_vec, write->wr_vlen, 738 &cnt, &write->wr_how_written); 739 if (filp) 740 fput(filp); 741 742 write->wr_bytes_written = cnt; 743 744 if (status == nfserr_symlink) 745 status = nfserr_inval; 746 return status; 747 } 748 749 /* This routine never returns NFS_OK! If there are no other errors, it 750 * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the 751 * attributes matched. VERIFY is implemented by mapping NFSERR_SAME 752 * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. 753 */ 754 static __be32 755 _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 756 struct nfsd4_verify *verify) 757 { 758 __be32 *buf, *p; 759 int count; 760 __be32 status; 761 762 status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); 763 if (status) 764 return status; 765 766 if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) 767 || (verify->ve_bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) 768 || (verify->ve_bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) 769 return nfserr_attrnotsupp; 770 if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) 771 || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) 772 return nfserr_inval; 773 if (verify->ve_attrlen & 3) 774 return nfserr_inval; 775 776 /* count in words: 777 * bitmap_len(1) + bitmap(2) + attr_len(1) = 4 778 */ 779 count = 4 + (verify->ve_attrlen >> 2); 780 buf = kmalloc(count << 2, GFP_KERNEL); 781 if (!buf) 782 return nfserr_resource; 783 784 status = nfsd4_encode_fattr(&cstate->current_fh, 785 cstate->current_fh.fh_export, 786 cstate->current_fh.fh_dentry, buf, 787 &count, verify->ve_bmval, 788 rqstp, 0); 789 790 /* this means that nfsd4_encode_fattr() ran out of space */ 791 if (status == nfserr_resource && count == 0) 792 status = nfserr_not_same; 793 if (status) 794 goto out_kfree; 795 796 /* skip bitmap */ 797 p = buf + 1 + ntohl(buf[0]); 798 status = nfserr_not_same; 799 if (ntohl(*p++) != verify->ve_attrlen) 800 goto out_kfree; 801 if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen)) 802 status = nfserr_same; 803 804 out_kfree: 805 kfree(buf); 806 return status; 807 } 808 809 static __be32 810 nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 811 struct nfsd4_verify *verify) 812 { 813 __be32 status; 814 815 status = _nfsd4_verify(rqstp, cstate, verify); 816 return status == nfserr_not_same ? nfs_ok : status; 817 } 818 819 static __be32 820 nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 821 struct nfsd4_verify *verify) 822 { 823 __be32 status; 824 825 status = _nfsd4_verify(rqstp, cstate, verify); 826 return status == nfserr_same ? nfs_ok : status; 827 } 828 829 /* 830 * NULL call. 831 */ 832 static __be32 833 nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 834 { 835 return nfs_ok; 836 } 837 838 static inline void nfsd4_increment_op_stats(u32 opnum) 839 { 840 if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP) 841 nfsdstats.nfs4_opcount[opnum]++; 842 } 843 844 typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, 845 void *); 846 enum nfsd4_op_flags { 847 ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ 848 ALLOWED_ON_ABSENT_FS = 2 << 0, /* ops processed on absent fs */ 849 ALLOWED_AS_FIRST_OP = 3 << 0, /* ops reqired first in compound */ 850 }; 851 852 struct nfsd4_operation { 853 nfsd4op_func op_func; 854 u32 op_flags; 855 char *op_name; 856 }; 857 858 static struct nfsd4_operation nfsd4_ops[]; 859 860 static const char *nfsd4_op_name(unsigned opnum); 861 862 /* 863 * This is a replay of a compound for which no cache entry pages 864 * were used. Encode the sequence operation, and if cachethis is FALSE 865 * encode the uncache rep error on the next operation. 866 */ 867 static __be32 868 nfsd4_enc_uncached_replay(struct nfsd4_compoundargs *args, 869 struct nfsd4_compoundres *resp) 870 { 871 struct nfsd4_op *op; 872 873 dprintk("--> %s resp->opcnt %d ce_cachethis %u \n", __func__, 874 resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis); 875 876 /* Encode the replayed sequence operation */ 877 BUG_ON(resp->opcnt != 1); 878 op = &args->ops[resp->opcnt - 1]; 879 nfsd4_encode_operation(resp, op); 880 881 /*return nfserr_retry_uncached_rep in next operation. */ 882 if (resp->cstate.slot->sl_cache_entry.ce_cachethis == 0) { 883 op = &args->ops[resp->opcnt++]; 884 op->status = nfserr_retry_uncached_rep; 885 nfsd4_encode_operation(resp, op); 886 } 887 return op->status; 888 } 889 890 /* 891 * Enforce NFSv4.1 COMPOUND ordering rules. 892 * 893 * TODO: 894 * - enforce NFS4ERR_NOT_ONLY_OP, 895 * - DESTROY_SESSION MUST be the final operation in the COMPOUND request. 896 */ 897 static bool nfs41_op_ordering_ok(struct nfsd4_compoundargs *args) 898 { 899 if (args->minorversion && args->opcnt > 0) { 900 struct nfsd4_op *op = &args->ops[0]; 901 return (op->status == nfserr_op_illegal) || 902 (nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP); 903 } 904 return true; 905 } 906 907 /* 908 * COMPOUND call. 909 */ 910 static __be32 911 nfsd4_proc_compound(struct svc_rqst *rqstp, 912 struct nfsd4_compoundargs *args, 913 struct nfsd4_compoundres *resp) 914 { 915 struct nfsd4_op *op; 916 struct nfsd4_operation *opdesc; 917 struct nfsd4_compound_state *cstate = &resp->cstate; 918 int slack_bytes; 919 __be32 status; 920 921 resp->xbuf = &rqstp->rq_res; 922 resp->p = rqstp->rq_res.head[0].iov_base + 923 rqstp->rq_res.head[0].iov_len; 924 resp->tagp = resp->p; 925 /* reserve space for: taglen, tag, and opcnt */ 926 resp->p += 2 + XDR_QUADLEN(args->taglen); 927 resp->end = rqstp->rq_res.head[0].iov_base + PAGE_SIZE; 928 resp->taglen = args->taglen; 929 resp->tag = args->tag; 930 resp->opcnt = 0; 931 resp->rqstp = rqstp; 932 resp->cstate.minorversion = args->minorversion; 933 resp->cstate.replay_owner = NULL; 934 fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); 935 fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); 936 /* Use the deferral mechanism only for NFSv4.0 compounds */ 937 rqstp->rq_usedeferral = (args->minorversion == 0); 938 939 /* 940 * According to RFC3010, this takes precedence over all other errors. 941 */ 942 status = nfserr_minor_vers_mismatch; 943 if (args->minorversion > nfsd_supported_minorversion) 944 goto out; 945 946 if (!nfs41_op_ordering_ok(args)) { 947 op = &args->ops[0]; 948 op->status = nfserr_sequence_pos; 949 goto encode_op; 950 } 951 952 status = nfs_ok; 953 while (!status && resp->opcnt < args->opcnt) { 954 op = &args->ops[resp->opcnt++]; 955 956 dprintk("nfsv4 compound op #%d/%d: %d (%s)\n", 957 resp->opcnt, args->opcnt, op->opnum, 958 nfsd4_op_name(op->opnum)); 959 /* 960 * The XDR decode routines may have pre-set op->status; 961 * for example, if there is a miscellaneous XDR error 962 * it will be set to nfserr_bad_xdr. 963 */ 964 if (op->status) 965 goto encode_op; 966 967 /* We must be able to encode a successful response to 968 * this operation, with enough room left over to encode a 969 * failed response to the next operation. If we don't 970 * have enough room, fail with ERR_RESOURCE. 971 */ 972 slack_bytes = (char *)resp->end - (char *)resp->p; 973 if (slack_bytes < COMPOUND_SLACK_SPACE 974 + COMPOUND_ERR_SLACK_SPACE) { 975 BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE); 976 op->status = nfserr_resource; 977 goto encode_op; 978 } 979 980 opdesc = &nfsd4_ops[op->opnum]; 981 982 if (!cstate->current_fh.fh_dentry) { 983 if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { 984 op->status = nfserr_nofilehandle; 985 goto encode_op; 986 } 987 } else if (cstate->current_fh.fh_export->ex_fslocs.migrated && 988 !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { 989 op->status = nfserr_moved; 990 goto encode_op; 991 } 992 993 if (opdesc->op_func) 994 op->status = opdesc->op_func(rqstp, cstate, &op->u); 995 else 996 BUG_ON(op->status == nfs_ok); 997 998 encode_op: 999 /* Only from SEQUENCE or CREATE_SESSION */ 1000 if (resp->cstate.status == nfserr_replay_cache) { 1001 dprintk("%s NFS4.1 replay from cache\n", __func__); 1002 if (nfsd4_not_cached(resp)) 1003 status = nfsd4_enc_uncached_replay(args, resp); 1004 else 1005 status = op->status; 1006 goto out; 1007 } 1008 if (op->status == nfserr_replay_me) { 1009 op->replay = &cstate->replay_owner->so_replay; 1010 nfsd4_encode_replay(resp, op); 1011 status = op->status = op->replay->rp_status; 1012 } else { 1013 nfsd4_encode_operation(resp, op); 1014 status = op->status; 1015 } 1016 1017 dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n", 1018 args->ops, args->opcnt, resp->opcnt, op->opnum, 1019 be32_to_cpu(status)); 1020 1021 if (cstate->replay_owner) { 1022 nfs4_put_stateowner(cstate->replay_owner); 1023 cstate->replay_owner = NULL; 1024 } 1025 /* XXX Ugh, we need to get rid of this kind of special case: */ 1026 if (op->opnum == OP_READ && op->u.read.rd_filp) 1027 fput(op->u.read.rd_filp); 1028 1029 nfsd4_increment_op_stats(op->opnum); 1030 } 1031 if (!rqstp->rq_usedeferral && status == nfserr_dropit) { 1032 dprintk("%s Dropit - send NFS4ERR_DELAY\n", __func__); 1033 status = nfserr_jukebox; 1034 } 1035 1036 resp->cstate.status = status; 1037 fh_put(&resp->cstate.current_fh); 1038 fh_put(&resp->cstate.save_fh); 1039 BUG_ON(resp->cstate.replay_owner); 1040 out: 1041 nfsd4_release_compoundargs(args); 1042 /* Reset deferral mechanism for RPC deferrals */ 1043 rqstp->rq_usedeferral = 1; 1044 dprintk("nfsv4 compound returned %d\n", ntohl(status)); 1045 return status; 1046 } 1047 1048 static struct nfsd4_operation nfsd4_ops[] = { 1049 [OP_ACCESS] = { 1050 .op_func = (nfsd4op_func)nfsd4_access, 1051 .op_name = "OP_ACCESS", 1052 }, 1053 [OP_CLOSE] = { 1054 .op_func = (nfsd4op_func)nfsd4_close, 1055 .op_name = "OP_CLOSE", 1056 }, 1057 [OP_COMMIT] = { 1058 .op_func = (nfsd4op_func)nfsd4_commit, 1059 .op_name = "OP_COMMIT", 1060 }, 1061 [OP_CREATE] = { 1062 .op_func = (nfsd4op_func)nfsd4_create, 1063 .op_name = "OP_CREATE", 1064 }, 1065 [OP_DELEGRETURN] = { 1066 .op_func = (nfsd4op_func)nfsd4_delegreturn, 1067 .op_name = "OP_DELEGRETURN", 1068 }, 1069 [OP_GETATTR] = { 1070 .op_func = (nfsd4op_func)nfsd4_getattr, 1071 .op_flags = ALLOWED_ON_ABSENT_FS, 1072 .op_name = "OP_GETATTR", 1073 }, 1074 [OP_GETFH] = { 1075 .op_func = (nfsd4op_func)nfsd4_getfh, 1076 .op_name = "OP_GETFH", 1077 }, 1078 [OP_LINK] = { 1079 .op_func = (nfsd4op_func)nfsd4_link, 1080 .op_name = "OP_LINK", 1081 }, 1082 [OP_LOCK] = { 1083 .op_func = (nfsd4op_func)nfsd4_lock, 1084 .op_name = "OP_LOCK", 1085 }, 1086 [OP_LOCKT] = { 1087 .op_func = (nfsd4op_func)nfsd4_lockt, 1088 .op_name = "OP_LOCKT", 1089 }, 1090 [OP_LOCKU] = { 1091 .op_func = (nfsd4op_func)nfsd4_locku, 1092 .op_name = "OP_LOCKU", 1093 }, 1094 [OP_LOOKUP] = { 1095 .op_func = (nfsd4op_func)nfsd4_lookup, 1096 .op_name = "OP_LOOKUP", 1097 }, 1098 [OP_LOOKUPP] = { 1099 .op_func = (nfsd4op_func)nfsd4_lookupp, 1100 .op_name = "OP_LOOKUPP", 1101 }, 1102 [OP_NVERIFY] = { 1103 .op_func = (nfsd4op_func)nfsd4_nverify, 1104 .op_name = "OP_NVERIFY", 1105 }, 1106 [OP_OPEN] = { 1107 .op_func = (nfsd4op_func)nfsd4_open, 1108 .op_name = "OP_OPEN", 1109 }, 1110 [OP_OPEN_CONFIRM] = { 1111 .op_func = (nfsd4op_func)nfsd4_open_confirm, 1112 .op_name = "OP_OPEN_CONFIRM", 1113 }, 1114 [OP_OPEN_DOWNGRADE] = { 1115 .op_func = (nfsd4op_func)nfsd4_open_downgrade, 1116 .op_name = "OP_OPEN_DOWNGRADE", 1117 }, 1118 [OP_PUTFH] = { 1119 .op_func = (nfsd4op_func)nfsd4_putfh, 1120 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1121 .op_name = "OP_PUTFH", 1122 }, 1123 [OP_PUTPUBFH] = { 1124 .op_func = (nfsd4op_func)nfsd4_putrootfh, 1125 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1126 .op_name = "OP_PUTPUBFH", 1127 }, 1128 [OP_PUTROOTFH] = { 1129 .op_func = (nfsd4op_func)nfsd4_putrootfh, 1130 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1131 .op_name = "OP_PUTROOTFH", 1132 }, 1133 [OP_READ] = { 1134 .op_func = (nfsd4op_func)nfsd4_read, 1135 .op_name = "OP_READ", 1136 }, 1137 [OP_READDIR] = { 1138 .op_func = (nfsd4op_func)nfsd4_readdir, 1139 .op_name = "OP_READDIR", 1140 }, 1141 [OP_READLINK] = { 1142 .op_func = (nfsd4op_func)nfsd4_readlink, 1143 .op_name = "OP_READLINK", 1144 }, 1145 [OP_REMOVE] = { 1146 .op_func = (nfsd4op_func)nfsd4_remove, 1147 .op_name = "OP_REMOVE", 1148 }, 1149 [OP_RENAME] = { 1150 .op_name = "OP_RENAME", 1151 .op_func = (nfsd4op_func)nfsd4_rename, 1152 }, 1153 [OP_RENEW] = { 1154 .op_func = (nfsd4op_func)nfsd4_renew, 1155 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1156 .op_name = "OP_RENEW", 1157 }, 1158 [OP_RESTOREFH] = { 1159 .op_func = (nfsd4op_func)nfsd4_restorefh, 1160 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1161 .op_name = "OP_RESTOREFH", 1162 }, 1163 [OP_SAVEFH] = { 1164 .op_func = (nfsd4op_func)nfsd4_savefh, 1165 .op_name = "OP_SAVEFH", 1166 }, 1167 [OP_SECINFO] = { 1168 .op_func = (nfsd4op_func)nfsd4_secinfo, 1169 .op_name = "OP_SECINFO", 1170 }, 1171 [OP_SETATTR] = { 1172 .op_func = (nfsd4op_func)nfsd4_setattr, 1173 .op_name = "OP_SETATTR", 1174 }, 1175 [OP_SETCLIENTID] = { 1176 .op_func = (nfsd4op_func)nfsd4_setclientid, 1177 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1178 .op_name = "OP_SETCLIENTID", 1179 }, 1180 [OP_SETCLIENTID_CONFIRM] = { 1181 .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, 1182 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1183 .op_name = "OP_SETCLIENTID_CONFIRM", 1184 }, 1185 [OP_VERIFY] = { 1186 .op_func = (nfsd4op_func)nfsd4_verify, 1187 .op_name = "OP_VERIFY", 1188 }, 1189 [OP_WRITE] = { 1190 .op_func = (nfsd4op_func)nfsd4_write, 1191 .op_name = "OP_WRITE", 1192 }, 1193 [OP_RELEASE_LOCKOWNER] = { 1194 .op_func = (nfsd4op_func)nfsd4_release_lockowner, 1195 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1196 .op_name = "OP_RELEASE_LOCKOWNER", 1197 }, 1198 1199 /* NFSv4.1 operations */ 1200 [OP_EXCHANGE_ID] = { 1201 .op_func = (nfsd4op_func)nfsd4_exchange_id, 1202 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, 1203 .op_name = "OP_EXCHANGE_ID", 1204 }, 1205 [OP_CREATE_SESSION] = { 1206 .op_func = (nfsd4op_func)nfsd4_create_session, 1207 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, 1208 .op_name = "OP_CREATE_SESSION", 1209 }, 1210 [OP_DESTROY_SESSION] = { 1211 .op_func = (nfsd4op_func)nfsd4_destroy_session, 1212 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, 1213 .op_name = "OP_DESTROY_SESSION", 1214 }, 1215 [OP_SEQUENCE] = { 1216 .op_func = (nfsd4op_func)nfsd4_sequence, 1217 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, 1218 .op_name = "OP_SEQUENCE", 1219 }, 1220 }; 1221 1222 static const char *nfsd4_op_name(unsigned opnum) 1223 { 1224 if (opnum < ARRAY_SIZE(nfsd4_ops)) 1225 return nfsd4_ops[opnum].op_name; 1226 return "unknown_operation"; 1227 } 1228 1229 #define nfs4svc_decode_voidargs NULL 1230 #define nfs4svc_release_void NULL 1231 #define nfsd4_voidres nfsd4_voidargs 1232 #define nfs4svc_release_compound NULL 1233 struct nfsd4_voidargs { int dummy; }; 1234 1235 #define PROC(name, argt, rest, relt, cache, respsize) \ 1236 { (svc_procfunc) nfsd4_proc_##name, \ 1237 (kxdrproc_t) nfs4svc_decode_##argt##args, \ 1238 (kxdrproc_t) nfs4svc_encode_##rest##res, \ 1239 (kxdrproc_t) nfs4svc_release_##relt, \ 1240 sizeof(struct nfsd4_##argt##args), \ 1241 sizeof(struct nfsd4_##rest##res), \ 1242 0, \ 1243 cache, \ 1244 respsize, \ 1245 } 1246 1247 /* 1248 * TODO: At the present time, the NFSv4 server does not do XID caching 1249 * of requests. Implementing XID caching would not be a serious problem, 1250 * although it would require a mild change in interfaces since one 1251 * doesn't know whether an NFSv4 request is idempotent until after the 1252 * XDR decode. However, XID caching totally confuses pynfs (Peter 1253 * Astrand's regression testsuite for NFSv4 servers), which reuses 1254 * XID's liberally, so I've left it unimplemented until pynfs generates 1255 * better XID's. 1256 */ 1257 static struct svc_procedure nfsd_procedures4[2] = { 1258 PROC(null, void, void, void, RC_NOCACHE, 1), 1259 PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4) 1260 }; 1261 1262 struct svc_version nfsd_version4 = { 1263 .vs_vers = 4, 1264 .vs_nproc = 2, 1265 .vs_proc = nfsd_procedures4, 1266 .vs_dispatch = nfsd_dispatch, 1267 .vs_xdrsize = NFS4_SVC_XDRSIZE, 1268 }; 1269 1270 /* 1271 * Local variables: 1272 * c-basic-offset: 8 1273 * End: 1274 */ 1275