1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 #include <sys/param.h> 28 #include <sys/types.h> 29 #include <sys/systm.h> 30 #include <sys/cred.h> 31 #include <sys/proc.h> 32 #include <sys/user.h> 33 #include <sys/time.h> 34 #include <sys/vnode.h> 35 #include <sys/vfs.h> 36 #include <sys/file.h> 37 #include <sys/filio.h> 38 #include <sys/uio.h> 39 #include <sys/buf.h> 40 #include <sys/mman.h> 41 #include <sys/tiuser.h> 42 #include <sys/pathname.h> 43 #include <sys/dirent.h> 44 #include <sys/conf.h> 45 #include <sys/debug.h> 46 #include <sys/vmsystm.h> 47 #include <sys/fcntl.h> 48 #include <sys/flock.h> 49 #include <sys/fbuf.h> 50 #include <sys/swap.h> 51 #include <sys/errno.h> 52 #include <sys/sysmacros.h> 53 #include <sys/disp.h> 54 #include <sys/kmem.h> 55 #include <sys/cmn_err.h> 56 #include <sys/vtrace.h> 57 #include <sys/mount.h> 58 #include <sys/dnlc.h> 59 #include <sys/stat.h> 60 #include <rpc/types.h> 61 62 #include <vm/hat.h> 63 #include <vm/as.h> 64 #include <vm/page.h> 65 #include <vm/pvn.h> 66 #include <vm/seg.h> 67 #include <vm/seg_map.h> 68 #include <vm/seg_vn.h> 69 #include <vm/rm.h> 70 #include <sys/fs/cachefs_fs.h> 71 #include <sys/fs/cachefs_dlog.h> 72 #include <sys/fs/cachefs_ioctl.h> 73 #include <sys/fs/cachefs_dir.h> 74 #include <sys/fs/cachefs_dlog.h> 75 #include "fs/fs_subr.h" 76 77 void cachefs_addhash(struct cnode *); 78 79 80 /* 81 * Local functions 82 */ 83 static void sync_metadata(cnode_t *); 84 static void drop_backvp(cnode_t *); 85 static void allow_pendrm(cnode_t *cp); 86 static int cachefs_unpack_common(vnode_t *vp); 87 static int cachefs_unpackall_list(cachefscache_t *cachep, 88 enum cachefs_rl_type type); 89 static void cachefs_modified_fix(fscache_t *fscp); 90 static void cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp); 91 92 #if (defined(_SYSCALL32_IMPL) || defined(_LP64)) 93 94 #define CACHEFS_DECL(type, handle) \ 95 type handle 96 97 #define CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type) \ 98 tmp_ptr = (type *)(tmp_addr) 99 100 #define CACHEFS_FID_COPYOUT(in_fidp, out_fidp) \ 101 CACHEFS_FID_COPY((fid_t *)(in_fidp), (cfs_fid_t *)(out_fidp)) 102 103 #define CACHEFS_FID_COPYIN(in_fidp, out_fidp) \ 104 CACHEFS_FID_COPY((cfs_fid_t *)(in_fidp), (fid_t *)(out_fidp)) 105 106 #define CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error) \ 107 if (!error) { \ 108 CACHEFS_VATTR_TO_CFS_VATTR_COPY((vattr_t *)(in_vattrp), \ 109 (cfs_vattr_t *)(out_vattrp), error); \ 110 } 111 112 #define CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp) \ 113 CACHEFS_CFS_VATTR_TO_VATTR_COPY((cfs_vattr_t *)(in_vattrp), \ 114 (vattr_t *)(out_vattrp)) 115 116 #else /* not _SYSCALL32_IMPL || _LP64 */ 117 118 #define CACHEFS_DECL(type, handle) 119 120 #define CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type) \ 121 tmp_ptr = (type *)(in_addr) 122 123 #define CACHEFS_FID_COPYOUT(in_fidp, out_fidp) 124 125 #define CACHEFS_FID_COPYIN(in_fidp, out_fidp) 126 127 #define CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error) 128 129 #define CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp) 130 131 #endif /* _SYSCALL32_IMPL || _LP64 */ 132 133 /* 134 * Conjure up a credential from the partial credential stored in 135 * a file. This is bogus and cachefs should really be fixed, but 136 * this maintains maximum compatibility. 137 * dl_cred *cr points to a basic credential followed directly by a buffer that 138 * takes a number of groups. 139 */ 140 141 static cred_t * 142 conj_cred(dl_cred_t *cr) 143 { 144 cred_t *newcr = crget(); 145 146 (void) crsetresuid(newcr, cr->cr_ruid, cr->cr_uid, cr->cr_suid); 147 (void) crsetresgid(newcr, cr->cr_rgid, cr->cr_gid, cr->cr_sgid); 148 149 (void) crsetgroups(newcr, MIN(NGROUPS_MAX_DEFAULT, cr->cr_ngroups), 150 cr->cr_groups); 151 152 return (newcr); 153 } 154 /* 155 * Pack a file in the cache 156 * dvp is the directory the file resides in. 157 * name is the name of the file. 158 * Returns 0 or an error if could not perform the operation. 159 */ 160 int 161 cachefs_pack(struct vnode *dvp, char *name, cred_t *cr) 162 { 163 fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp)); 164 int error = 0; 165 int connected = 0; 166 vnode_t *vp; 167 168 /* 169 * Return if NFSv4 is the backfs (no caching). 170 */ 171 if (CFS_ISFS_BACKFS_NFSV4(fscp)) { 172 goto out; 173 } 174 175 for (;;) { 176 /* get access to the file system */ 177 error = cachefs_cd_access(fscp, connected, 0); 178 if (error) 179 break; 180 181 /* lookup the file name */ 182 error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL, 183 cr); 184 if (error == 0) { 185 error = cachefs_pack_common(vp, cr); 186 VN_RELE(vp); 187 } 188 if (CFS_TIMEOUT(fscp, error)) { 189 if (fscp->fs_cdconnected == CFS_CD_CONNECTED) { 190 cachefs_cd_release(fscp); 191 cachefs_cd_timedout(fscp); 192 connected = 0; 193 continue; 194 } else { 195 cachefs_cd_release(fscp); 196 connected = 1; 197 continue; 198 } 199 } 200 cachefs_cd_release(fscp); 201 break; 202 } 203 204 out: 205 return (error); 206 } 207 /* 208 * Packs the file belonging to the passed in vnode. 209 */ 210 int 211 cachefs_pack_common(vnode_t *vp, cred_t *cr) 212 { 213 cnode_t *cp = VTOC(vp); 214 fscache_t *fscp = C_TO_FSCACHE(cp); 215 int error = 0; 216 offset_t off; 217 caddr_t buf; 218 int buflen; 219 rl_entry_t rl_ent; 220 u_offset_t cnode_size; 221 222 rw_enter(&cp->c_rwlock, RW_WRITER); 223 mutex_enter(&cp->c_statelock); 224 225 /* done if cannot write to cache */ 226 if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) { 227 error = EROFS; 228 goto out; 229 } 230 231 /* done if not usable */ 232 if (cp->c_flags & (CN_STALE | CN_DESTROY)) { 233 error = ESTALE; 234 goto out; 235 } 236 237 /* make sure up to date */ 238 error = CFSOP_CHECK_COBJECT(fscp, cp, C_BACK_CHECK, cr); 239 if (error) 240 goto out; 241 242 /* make it cachable */ 243 cp->c_flags &= ~CN_NOCACHE; 244 245 /* get a metadata slot if we do not have one yet */ 246 if (cp->c_flags & CN_ALLOC_PENDING) { 247 if (cp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) { 248 (void) filegrp_allocattr(cp->c_filegrp); 249 } 250 error = filegrp_create_metadata(cp->c_filegrp, 251 &cp->c_metadata, &cp->c_id); 252 if (error) 253 goto out; 254 cp->c_flags &= ~CN_ALLOC_PENDING; 255 cp->c_flags |= CN_UPDATED; 256 } 257 258 /* cache the ACL if necessary */ 259 if (((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0) && 260 (cachefs_vtype_aclok(vp)) && 261 ((cp->c_metadata.md_flags & MD_ACL) == 0)) { 262 error = cachefs_cacheacl(cp, NULL); 263 if (error != 0) 264 goto out; 265 } 266 267 /* directory */ 268 if (vp->v_type == VDIR) { 269 if (cp->c_metadata.md_flags & MD_POPULATED) 270 goto out; 271 272 if (error = cachefs_dir_fill(cp, cr)) 273 goto out; 274 } 275 276 /* regular file */ 277 else if (vp->v_type == VREG) { 278 if (cp->c_metadata.md_flags & MD_POPULATED) 279 goto out; 280 281 if (cp->c_backvp == NULL) { 282 error = cachefs_getbackvp(fscp, cp); 283 if (error) 284 goto out; 285 } 286 if (cp->c_frontvp == NULL) { 287 error = cachefs_getfrontfile(cp); 288 if (error) 289 goto out; 290 } 291 /* populate the file */ 292 off = (offset_t)0; 293 cnode_size = cp->c_attr.va_size; 294 while (off < cnode_size) { 295 if (!cachefs_check_allocmap(cp, off)) { 296 u_offset_t popoff; 297 size_t popsize; 298 299 cachefs_cluster_allocmap(off, &popoff, 300 &popsize, (size_t)DEF_POP_SIZE, cp); 301 if (popsize != 0) { 302 error = cachefs_populate(cp, popoff, 303 popsize, cp->c_frontvp, 304 cp->c_backvp, cp->c_size, cr); 305 if (error) 306 goto out; 307 else 308 cp->c_flags |= (CN_UPDATED | 309 CN_NEED_FRONT_SYNC | 310 CN_POPULATION_PENDING); 311 popsize = popsize - (off - popoff); 312 } 313 } 314 off += PAGESIZE; 315 } 316 } 317 318 /* symbolic link */ 319 else if (vp->v_type == VLNK) { 320 if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK)) 321 goto out; 322 323 /* get the sym link contents from the back fs */ 324 error = cachefs_readlink_back(cp, cr, &buf, &buflen); 325 if (error) 326 goto out; 327 328 /* try to cache the sym link */ 329 error = cachefs_stuffsymlink(cp, buf, buflen); 330 cachefs_kmem_free(buf, MAXPATHLEN); 331 } 332 333 /* assume that all other types fit in the attributes */ 334 335 out: 336 /* get the rl slot if needed */ 337 if ((error == 0) && (cp->c_metadata.md_rlno == 0)) { 338 rl_ent.rl_fileno = cp->c_id.cid_fileno; 339 rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0; 340 rl_ent.rl_fsid = fscp->fs_cfsid; 341 rl_ent.rl_attrc = 0; 342 cp->c_metadata.md_rltype = CACHEFS_RL_NONE; 343 error = cachefs_rl_alloc(fscp->fs_cache, &rl_ent, 344 &cp->c_metadata.md_rlno); 345 if (error == 0) 346 error = filegrp_ffhold(cp->c_filegrp); 347 } 348 349 /* mark the file as packed */ 350 if (error == 0) { 351 /* modified takes precedence over packed */ 352 if (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) { 353 cachefs_rlent_moveto(fscp->fs_cache, 354 CACHEFS_RL_PACKED, cp->c_metadata.md_rlno, 355 cp->c_metadata.md_frontblks); 356 cp->c_metadata.md_rltype = CACHEFS_RL_PACKED; 357 } 358 cp->c_metadata.md_flags |= MD_PACKED; 359 cp->c_flags |= CN_UPDATED; 360 } 361 362 mutex_exit(&cp->c_statelock); 363 rw_exit(&cp->c_rwlock); 364 365 return (error); 366 } 367 368 /* 369 * Unpack a file from the cache 370 * dvp is the directory the file resides in. 371 * name is the name of the file. 372 * Returns 0 or an error if could not perform the operation. 373 */ 374 int 375 cachefs_unpack(struct vnode *dvp, char *name, cred_t *cr) 376 { 377 fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp)); 378 int error = 0; 379 int connected = 0; 380 vnode_t *vp; 381 382 /* Return error if NFSv4 is the backfs (no caching) */ 383 if (CFS_ISFS_BACKFS_NFSV4(fscp)) { 384 goto out; 385 } 386 387 for (;;) { 388 /* get access to the file system */ 389 error = cachefs_cd_access(fscp, connected, 0); 390 if (error) 391 break; 392 393 /* lookup the file name */ 394 error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL, 395 cr); 396 if (error == 0) { 397 error = cachefs_unpack_common(vp); 398 VN_RELE(vp); 399 } 400 if (CFS_TIMEOUT(fscp, error)) { 401 if (fscp->fs_cdconnected == CFS_CD_CONNECTED) { 402 cachefs_cd_release(fscp); 403 cachefs_cd_timedout(fscp); 404 connected = 0; 405 continue; 406 } else { 407 cachefs_cd_release(fscp); 408 connected = 1; 409 continue; 410 } 411 } 412 cachefs_cd_release(fscp); 413 break; 414 } 415 out: 416 return (error); 417 } 418 419 /* 420 * Unpacks the file belonging to the passed in vnode. 421 */ 422 static int 423 cachefs_unpack_common(vnode_t *vp) 424 { 425 cnode_t *cp = VTOC(vp); 426 fscache_t *fscp = C_TO_FSCACHE(cp); 427 int error = 0; 428 429 mutex_enter(&cp->c_statelock); 430 431 /* nothing to do if not packed */ 432 if ((cp->c_metadata.md_flags & MD_PACKED) == 0) 433 goto out; 434 435 /* nothing to do if cannot modify cache */ 436 if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) { 437 error = EROFS; 438 goto out; 439 } 440 441 /* mark file as no longer packed */ 442 ASSERT(cp->c_metadata.md_rlno); 443 cp->c_metadata.md_flags &= ~MD_PACKED; 444 cp->c_flags |= CN_UPDATED; 445 446 /* done if file has been modified */ 447 if (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED) 448 goto out; 449 450 /* if there is no front file */ 451 if ((cp->c_metadata.md_flags & MD_FILE) == 0) { 452 /* nuke front file resources */ 453 filegrp_ffrele(cp->c_filegrp); 454 cachefs_rlent_moveto(fscp->fs_cache, 455 CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0); 456 cp->c_metadata.md_rlno = 0; 457 cp->c_metadata.md_rltype = CACHEFS_RL_NONE; 458 } 459 460 /* else move the front file to the active list */ 461 else { 462 cachefs_rlent_moveto(fscp->fs_cache, 463 CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno, 464 cp->c_metadata.md_frontblks); 465 cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE; 466 } 467 468 out: 469 mutex_exit(&cp->c_statelock); 470 return (error); 471 } 472 473 /* 474 * Returns packing information on a file. 475 * dvp is the directory the file resides in. 476 * name is the name of the file. 477 * *statusp is set to the status of the file 478 * Returns 0 or an error if could not perform the operation. 479 */ 480 int 481 cachefs_packinfo(struct vnode *dvp, char *name, int *statusp, cred_t *cr) 482 { 483 fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp)); 484 struct vnode *vp; 485 struct cnode *cp; 486 int error; 487 int connected = 0; 488 489 *statusp = 0; 490 491 /* 492 * Return if NFSv4 is the backfs (no caching). 493 */ 494 if (CFS_ISFS_BACKFS_NFSV4(fscp)) { 495 goto out; 496 } 497 498 for (;;) { 499 /* get access to the file system */ 500 error = cachefs_cd_access(fscp, connected, 0); 501 if (error) 502 break; 503 504 /* lookup the file name */ 505 error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL, 506 cr); 507 if (CFS_TIMEOUT(fscp, error)) { 508 if (fscp->fs_cdconnected == CFS_CD_CONNECTED) { 509 cachefs_cd_release(fscp); 510 cachefs_cd_timedout(fscp); 511 connected = 0; 512 continue; 513 } else { 514 cachefs_cd_release(fscp); 515 connected = 1; 516 continue; 517 } 518 } 519 if (error) 520 break; 521 cp = VTOC(vp); 522 523 mutex_enter(&cp->c_statelock); 524 if (cp->c_metadata.md_flags & MD_PACKED) 525 *statusp |= CACHEFS_PACKED_FILE; 526 if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK)) 527 *statusp |= CACHEFS_PACKED_DATA; 528 else if ((vp->v_type != VREG) && 529 (vp->v_type != VDIR) && 530 (vp->v_type != VLNK)) 531 *statusp |= CACHEFS_PACKED_DATA; 532 else if (cp->c_size == 0) 533 *statusp |= CACHEFS_PACKED_DATA; 534 if (cp->c_flags & CN_NOCACHE) 535 *statusp |= CACHEFS_PACKED_NOCACHE; 536 mutex_exit(&cp->c_statelock); 537 538 VN_RELE(vp); 539 cachefs_cd_release(fscp); 540 break; 541 } 542 543 out: 544 return (error); 545 } 546 547 /* 548 * Finds all packed files in the cache and unpacks them. 549 */ 550 int 551 cachefs_unpackall(vnode_t *vp) 552 { 553 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 554 cachefscache_t *cachep = fscp->fs_cache; 555 int error; 556 557 /* 558 * Return if NFSv4 is the backfs (no caching). 559 */ 560 if (CFS_ISFS_BACKFS_NFSV4(fscp)) { 561 goto out; 562 } 563 564 error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED); 565 if (error) 566 goto out; 567 error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED_PENDING); 568 out: 569 return (error); 570 } 571 572 /* 573 * Finds all packed files on the specified list and unpacks them. 574 */ 575 static int 576 cachefs_unpackall_list(cachefscache_t *cachep, enum cachefs_rl_type type) 577 { 578 fscache_t *fscp = NULL; 579 cnode_t *cp; 580 int error = 0; 581 rl_entry_t rl_ent; 582 cfs_cid_t cid; 583 584 rl_ent.rl_current = type; 585 for (;;) { 586 /* get the next entry on the specified resource list */ 587 error = cachefs_rlent_data(cachep, &rl_ent, NULL); 588 if (error) { 589 error = 0; 590 break; 591 } 592 593 /* if the fscp we have does not match */ 594 if ((fscp == NULL) || (fscp->fs_cfsid != rl_ent.rl_fsid)) { 595 if (fscp) { 596 cachefs_cd_release(fscp); 597 fscache_rele(fscp); 598 fscp = NULL; 599 } 600 601 /* get the file system cache object for this fsid */ 602 mutex_enter(&cachep->c_fslistlock); 603 fscp = fscache_list_find(cachep, rl_ent.rl_fsid); 604 if (fscp == NULL) { 605 fscp = fscache_create(cachep); 606 error = fscache_activate(fscp, rl_ent.rl_fsid, 607 NULL, NULL, 0); 608 if (error) { 609 cmn_err(CE_WARN, 610 "cachefs: cache error, run fsck\n"); 611 fscache_destroy(fscp); 612 fscp = NULL; 613 mutex_exit(&cachep->c_fslistlock); 614 break; 615 } 616 fscache_list_add(cachep, fscp); 617 } 618 fscache_hold(fscp); 619 mutex_exit(&cachep->c_fslistlock); 620 621 /* get access to the file system */ 622 error = cachefs_cd_access(fscp, 0, 0); 623 if (error) { 624 fscache_rele(fscp); 625 fscp = NULL; 626 break; 627 } 628 } 629 630 /* get the cnode for the file */ 631 cid.cid_fileno = rl_ent.rl_fileno; 632 cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0; 633 error = cachefs_cnode_make(&cid, fscp, 634 NULL, NULL, NULL, kcred, 0, &cp); 635 if (error) { 636 #ifdef CFSDEBUG 637 CFS_DEBUG(CFSDEBUG_IOCTL) 638 printf("cachefs: cul: could not find %llu\n", 639 (u_longlong_t)cid.cid_fileno); 640 delay(5*hz); 641 #endif 642 continue; 643 } 644 645 /* unpack the file */ 646 (void) cachefs_unpack_common(CTOV(cp)); 647 VN_RELE(CTOV(cp)); 648 } 649 650 /* free up allocated resources */ 651 if (fscp) { 652 cachefs_cd_release(fscp); 653 fscache_rele(fscp); 654 } 655 return (error); 656 } 657 658 /* 659 * Identifies this process as the cachefsd. 660 * Stays this way until close is done. 661 */ 662 int 663 /*ARGSUSED*/ 664 cachefs_io_daemonid(vnode_t *vp, void *dinp, void *doutp) 665 { 666 int error = 0; 667 668 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 669 cachefscache_t *cachep = fscp->fs_cache; 670 671 mutex_enter(&fscp->fs_cdlock); 672 673 /* can only do this on the root of the file system */ 674 if (vp != fscp->fs_rootvp) 675 error = ENOENT; 676 677 /* else if there already is a daemon running */ 678 else if (fscp->fs_cddaemonid) 679 error = EBUSY; 680 681 /* else use the pid to identify the daemon */ 682 else { 683 fscp->fs_cddaemonid = ttoproc(curthread)->p_pid; 684 cv_broadcast(&fscp->fs_cdwaitcv); 685 } 686 687 mutex_exit(&fscp->fs_cdlock); 688 689 if (error == 0) { 690 /* the daemon that takes care of root is special */ 691 if (fscp->fs_flags & CFS_FS_ROOTFS) { 692 mutex_enter(&cachep->c_contentslock); 693 ASSERT(cachep->c_rootdaemonid == 0); 694 cachep->c_rootdaemonid = fscp->fs_cddaemonid; 695 mutex_exit(&cachep->c_contentslock); 696 } 697 } 698 return (error); 699 } 700 701 /* 702 * Returns the current state in doutp 703 */ 704 int 705 /*ARGSUSED*/ 706 cachefs_io_stateget(vnode_t *vp, void *dinp, void *doutp) 707 { 708 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 709 int *statep = (int *)doutp; 710 int state; 711 712 /* 713 * Only called in support of disconnectable operation, so assert 714 * that this is not called when NFSv4 is the backfilesytem. 715 */ 716 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 717 718 mutex_enter(&fscp->fs_cdlock); 719 switch (fscp->fs_cdconnected) { 720 case CFS_CD_CONNECTED: 721 state = CFS_FS_CONNECTED; 722 break; 723 case CFS_CD_DISCONNECTED: 724 state = CFS_FS_DISCONNECTED; 725 break; 726 case CFS_CD_RECONNECTING: 727 state = CFS_FS_RECONNECTING; 728 break; 729 default: 730 ASSERT(0); 731 break; 732 } 733 mutex_exit(&fscp->fs_cdlock); 734 735 *statep = state; 736 return (0); 737 } 738 739 /* 740 * Sets the state of the file system. 741 */ 742 int 743 /*ARGSUSED*/ 744 cachefs_io_stateset(vnode_t *vp, void *dinp, void *doutp) 745 { 746 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 747 int error = 0; 748 int nosig = 1; 749 int state = *(int *)dinp; 750 751 /* 752 * State should not be changeable and always be connected if 753 * NFSv4 is in use. 754 */ 755 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 756 757 /* wait until the file system is quiet */ 758 mutex_enter(&fscp->fs_cdlock); 759 if (fscp->fs_cdtransition == 1) { 760 /* if someone is already changing the state */ 761 mutex_exit(&fscp->fs_cdlock); 762 return (0); 763 } 764 fscp->fs_cdtransition = 1; 765 while (nosig && (fscp->fs_cdrefcnt != 0)) { 766 nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock); 767 } 768 if (!nosig) { 769 fscp->fs_cdtransition = 0; 770 cv_broadcast(&fscp->fs_cdwaitcv); 771 mutex_exit(&fscp->fs_cdlock); 772 return (EINTR); 773 } 774 mutex_exit(&fscp->fs_cdlock); 775 776 switch (state) { 777 case CFS_FS_CONNECTED: 778 /* done if already in this state */ 779 if (fscp->fs_cdconnected == CFS_CD_CONNECTED) 780 break; 781 782 mutex_enter(&fscp->fs_cdlock); 783 fscp->fs_cdconnected = CFS_CD_CONNECTED; 784 mutex_exit(&fscp->fs_cdlock); 785 786 /* fix up modified files */ 787 cachefs_modified_fix(fscp); 788 789 #if 0 790 if (fscp->fs_hostname != NULL) 791 printf("\ncachefs:server - %s", 792 fscp->fs_hostname); 793 if (fscp->fs_mntpt != NULL) 794 printf("\ncachefs:mount point - %s", 795 fscp->fs_mntpt); 796 if (fscp->fs_backfsname != NULL) 797 printf("\ncachefs:back filesystem - %s", 798 fscp->fs_backfsname); 799 printf("\nok\n"); 800 #else 801 if (fscp->fs_hostname && fscp->fs_backfsname) 802 printf("cachefs: %s:%s ok\n", 803 fscp->fs_hostname, fscp->fs_backfsname); 804 else 805 printf("cachefs: server ok\n"); 806 #endif 807 808 /* allow deletion of renamed open files to proceed */ 809 cachefs_cnode_traverse(fscp, allow_pendrm); 810 break; 811 812 case CFS_FS_DISCONNECTED: 813 /* done if already in this state */ 814 if (fscp->fs_cdconnected == CFS_CD_DISCONNECTED) 815 break; 816 817 /* drop all back vps */ 818 cachefs_cnode_traverse(fscp, drop_backvp); 819 820 821 mutex_enter(&fscp->fs_cdlock); 822 fscp->fs_cdconnected = CFS_CD_DISCONNECTED; 823 mutex_exit(&fscp->fs_cdlock); 824 825 #if 0 826 if (fscp->fs_hostname != NULL) 827 printf("\ncachefs:server - %s", 828 fscp->fs_hostname); 829 if (fscp->fs_mntpt != NULL) 830 printf("\ncachefs:mount point - %s", 831 fscp->fs_mntpt); 832 if (fscp->fs_backfsname != NULL) 833 printf("\ncachefs:back filesystem - %s", 834 fscp->fs_backfsname); 835 printf("\nnot responding still trying\n"); 836 #else 837 if (fscp->fs_hostname && fscp->fs_backfsname) 838 printf("cachefs: %s:%s not responding still trying\n", 839 fscp->fs_hostname, fscp->fs_backfsname); 840 else 841 printf("cachefs: server not responding still trying\n"); 842 #endif 843 break; 844 845 case CFS_FS_RECONNECTING: 846 /* done if already in this state */ 847 if (fscp->fs_cdconnected == CFS_CD_RECONNECTING) 848 break; 849 850 /* 851 * Before we enter disconnected state we sync all metadata, 852 * this allows us to read metadata directly in subsequent 853 * calls so we don't need to allocate cnodes when 854 * we just need metadata information. 855 */ 856 /* XXX bob: need to eliminate this */ 857 cachefs_cnode_traverse(fscp, sync_metadata); 858 859 mutex_enter(&fscp->fs_cdlock); 860 fscp->fs_cdconnected = CFS_CD_RECONNECTING; 861 mutex_exit(&fscp->fs_cdlock); 862 863 /* no longer need dlog active */ 864 cachefs_dlog_teardown(fscp); 865 break; 866 867 default: 868 error = ENOTTY; 869 break; 870 } 871 872 mutex_enter(&fscp->fs_cdlock); 873 fscp->fs_cdtransition = 0; 874 cv_broadcast(&fscp->fs_cdwaitcv); 875 mutex_exit(&fscp->fs_cdlock); 876 return (error); 877 } 878 879 /* 880 * Blocks until the file system switches 881 * out of the connected state. 882 */ 883 int 884 /*ARGSUSED*/ 885 cachefs_io_xwait(vnode_t *vp, void *dinp, void *doutp) 886 { 887 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 888 int nosig = 1; 889 890 /* 891 * Only called in support of disconnectable operation, so assert 892 * that this is not used when NFSv4 is the backfilesytem. 893 */ 894 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 895 896 mutex_enter(&fscp->fs_cdlock); 897 while (nosig && 898 (fscp->fs_cdconnected == CFS_CD_CONNECTED)) { 899 nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock); 900 } 901 mutex_exit(&fscp->fs_cdlock); 902 if (!nosig) 903 return (EINTR); 904 905 return (0); 906 } 907 908 #define RL_HEAD(cachep, type) \ 909 (&(cachep->c_rlinfo.rl_items[CACHEFS_RL_INDEX(type)])) 910 911 /* 912 * Returns some statistics about the cache. 913 */ 914 #define CFS_STAT_FACTOR (MAXBSIZE / 1024) 915 int 916 /*ARGSUSED*/ 917 cachefs_io_getstats(vnode_t *vp, void *dinp, void *doutp) 918 { 919 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 920 cachefscache_t *cachep = fscp->fs_cache; 921 struct statvfs64 sb; 922 fsblkcnt64_t avail = 0; 923 fsblkcnt64_t blocks; 924 int error; 925 cachefsio_getstats_t *gsp = (cachefsio_getstats_t *)doutp; 926 927 /* determine number of blocks available to the cache */ 928 error = VFS_STATVFS(cachep->c_dirvp->v_vfsp, &sb); 929 if (error == 0) { 930 blocks = (fsblkcnt64_t)(cachep->c_label.cl_maxblks - 931 cachep->c_usage.cu_blksused); 932 if ((longlong_t)blocks < (longlong_t)0) 933 blocks = (fsblkcnt64_t)0; 934 avail = (sb.f_bfree * sb.f_frsize) / MAXBSIZE; 935 if (blocks < avail) 936 avail = blocks; 937 } 938 939 gsp->gs_total = cachep->c_usage.cu_blksused * CFS_STAT_FACTOR; 940 gsp->gs_gc = RL_HEAD(cachep, CACHEFS_RL_GC)->rli_blkcnt * 941 CFS_STAT_FACTOR; 942 gsp->gs_active = RL_HEAD(cachep, CACHEFS_RL_ACTIVE)->rli_blkcnt * 943 CFS_STAT_FACTOR; 944 gsp->gs_packed = RL_HEAD(cachep, CACHEFS_RL_PACKED)->rli_blkcnt * 945 CFS_STAT_FACTOR; 946 gsp->gs_free = (long)(avail * CFS_STAT_FACTOR); 947 gsp->gs_gctime = cachep->c_rlinfo.rl_gctime; 948 return (0); 949 } 950 951 /* 952 * This looks to see if the specified file exists in the cache. 953 * 0 is returned if it exists 954 * ENOENT is returned if it doesn't exist. 955 */ 956 int 957 /*ARGSUSED*/ 958 cachefs_io_exists(vnode_t *vp, void *dinp, void *doutp) 959 { 960 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 961 cnode_t *cp = NULL; 962 int error; 963 cfs_cid_t *cidp = (cfs_cid_t *)dinp; 964 965 /* 966 * Only called in support of disconnectable operation, so assert 967 * that this is not called when NFSv4 is the backfilesytem. 968 */ 969 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 970 971 /* find the cnode of the file */ 972 error = cachefs_cnode_make(cidp, fscp, 973 NULL, NULL, NULL, kcred, 0, &cp); 974 if (error) 975 return (ENOENT); 976 977 if ((cp->c_flags & (CN_DESTROY | CN_NOCACHE)) || 978 !(cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK))) 979 error = ENOENT; 980 981 VN_RELE(CTOV(cp)); 982 return (error); 983 984 } 985 986 /* 987 * Moves the specified file to the lost+found directory for the 988 * cached file system. 989 * Invalidates cached data and attributes. 990 * Returns 0 or an error if could not perform operation. 991 */ 992 int 993 cachefs_io_lostfound(vnode_t *vp, void *dinp, void *doutp) 994 { 995 int error; 996 cnode_t *cp = NULL; 997 fscache_t *fscp; 998 cachefscache_t *cachep; 999 cachefsio_lostfound_arg_t *lfp; 1000 cachefsio_lostfound_return_t *rp; 1001 1002 lfp = (cachefsio_lostfound_arg_t *)dinp; 1003 rp = (cachefsio_lostfound_return_t *)doutp; 1004 1005 fscp = C_TO_FSCACHE(VTOC(vp)); 1006 cachep = fscp->fs_cache; 1007 1008 ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0); 1009 1010 /* 1011 * Only called in support of disconnectable operation, so assert 1012 * that this is not called when NFSv4 is the backfilesytem. 1013 */ 1014 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1015 1016 /* find the cnode of the file */ 1017 error = cachefs_cnode_make(&lfp->lf_cid, fscp, 1018 NULL, NULL, NULL, kcred, 0, &cp); 1019 if (error) { 1020 error = ENOENT; 1021 goto out; 1022 } 1023 1024 mutex_enter(&cp->c_statelock); 1025 1026 /* must be regular file and modified */ 1027 if ((cp->c_attr.va_type != VREG) || 1028 (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED)) { 1029 mutex_exit(&cp->c_statelock); 1030 error = EINVAL; 1031 goto out; 1032 } 1033 1034 /* move to lost+found */ 1035 error = cachefs_cnode_lostfound(cp, lfp->lf_name); 1036 mutex_exit(&cp->c_statelock); 1037 1038 if (error == 0) 1039 (void) strcpy(rp->lf_name, lfp->lf_name); 1040 out: 1041 if (cp) 1042 VN_RELE(CTOV(cp)); 1043 1044 return (error); 1045 } 1046 1047 /* 1048 * Given a cid, returns info about the file in the cache. 1049 */ 1050 int 1051 cachefs_io_getinfo(vnode_t *vp, void *dinp, void *doutp) 1052 { 1053 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1054 struct cnode *dcp = NULL; 1055 struct cnode *cp = NULL; 1056 struct vattr va; 1057 u_offset_t blockoff = 0; 1058 struct fbuf *fbp; 1059 int offset = 0; 1060 int error = 0; 1061 cfs_cid_t *fcidp; 1062 cachefsio_getinfo_t *infop; 1063 1064 /* 1065 * Only called in support of disconnectable operation, so assert 1066 * that this is not called when NFSv4 is the backfilesytem. 1067 */ 1068 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1069 1070 fcidp = (cfs_cid_t *)dinp; 1071 infop = (cachefsio_getinfo_t *)doutp; 1072 1073 /* find the cnode of the file */ 1074 error = cachefs_cnode_make(fcidp, fscp, NULL, NULL, NULL, 1075 kcred, 0, &cp); 1076 if (error) { 1077 error = ENOENT; 1078 goto out; 1079 } 1080 1081 infop->gi_cid = *fcidp; 1082 infop->gi_modified = (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED); 1083 CACHEFS_VATTR_TO_CFS_VATTR_COPY(&cp->c_attr, &infop->gi_attr, error); 1084 infop->gi_pcid = cp->c_metadata.md_parent; 1085 infop->gi_name[0] = '\0'; 1086 infop->gi_seq = cp->c_metadata.md_seq; 1087 if (error || (cp->c_metadata.md_parent.cid_fileno == 0)) 1088 goto out; 1089 1090 /* try to get the cnode of the parent dir */ 1091 error = cachefs_cnode_make(&cp->c_metadata.md_parent, fscp, 1092 NULL, NULL, NULL, kcred, 0, &dcp); 1093 if (error) { 1094 error = 0; 1095 goto out; 1096 } 1097 1098 /* make sure a directory and populated */ 1099 if ((((dcp->c_flags & CN_ASYNC_POPULATE) == 0) || 1100 ((dcp->c_metadata.md_flags & MD_POPULATED) == 0)) && 1101 (CTOV(dcp)->v_type == VDIR)) { 1102 error = 0; 1103 goto out; 1104 } 1105 1106 /* get the front file */ 1107 if (dcp->c_frontvp == NULL) { 1108 mutex_enter(&dcp->c_statelock); 1109 error = cachefs_getfrontfile(dcp); 1110 mutex_exit(&dcp->c_statelock); 1111 if (error) { 1112 error = 0; 1113 goto out; 1114 } 1115 1116 /* make sure frontvp is still populated */ 1117 if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) { 1118 error = 0; 1119 goto out; 1120 } 1121 } 1122 1123 /* Get the length of the directory */ 1124 va.va_mask = AT_SIZE; 1125 error = VOP_GETATTR(dcp->c_frontvp, &va, 0, kcred, NULL); 1126 if (error) { 1127 error = 0; 1128 goto out; 1129 } 1130 1131 /* XXX bob: change this to use cachfs_dir_read */ 1132 /* We have found the parent, now we open the dir and look for file */ 1133 while (blockoff < va.va_size) { 1134 offset = 0; 1135 error = fbread(dcp->c_frontvp, (offset_t)blockoff, MAXBSIZE, 1136 S_OTHER, &fbp); 1137 if (error) 1138 goto out; 1139 while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) { 1140 struct c_dirent *dep; 1141 dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr + 1142 offset); 1143 if ((dep->d_flag & CDE_VALID) && 1144 (bcmp(&dep->d_id, &infop->gi_cid, 1145 sizeof (cfs_cid_t)) == 0)) { 1146 /* found the name */ 1147 (void) strcpy(infop->gi_name, dep->d_name); 1148 fbrelse(fbp, S_OTHER); 1149 goto out; 1150 } 1151 offset += dep->d_length; 1152 } 1153 fbrelse(fbp, S_OTHER); 1154 fbp = NULL; 1155 blockoff += MAXBSIZE; 1156 1157 } 1158 out: 1159 if (cp) 1160 VN_RELE(CTOV(cp)); 1161 if (dcp) 1162 VN_RELE(CTOV(dcp)); 1163 return (error); 1164 } 1165 1166 /* 1167 * Given a file number, this functions returns the fid 1168 * for the back file system. 1169 * Returns ENOENT if file does not exist. 1170 * Returns ENOMSG if fid is not valid, ie: local file. 1171 */ 1172 int 1173 cachefs_io_cidtofid(vnode_t *vp, void *dinp, void *doutp) 1174 { 1175 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1176 cnode_t *cp = NULL; 1177 int error; 1178 cfs_cid_t *cidp = (cfs_cid_t *)dinp; 1179 cfs_fid_t *fidp = (cfs_fid_t *)doutp; 1180 1181 /* 1182 * Only called in support of disconnectable operation, so assert 1183 * that this is not called when NFSv4 is the backfilesytem. 1184 */ 1185 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1186 1187 /* get the cnode for the file */ 1188 error = cachefs_cnode_make(cidp, fscp, NULL, NULL, NULL, kcred, 0, &cp); 1189 if (error) 1190 goto out; 1191 1192 /* if local file, fid is a local fid and is not valid */ 1193 if (cp->c_id.cid_flags & CFS_CID_LOCAL) { 1194 error = ENOMSG; 1195 goto out; 1196 } 1197 1198 /* copy out the fid */ 1199 CACHEFS_FID_COPY(&cp->c_cookie, fidp); 1200 1201 out: 1202 if (cp) 1203 VN_RELE(CTOV(cp)); 1204 return (error); 1205 } 1206 1207 /* 1208 * This performs a getattr on the back file system given 1209 * a fid that is passed in. 1210 * 1211 * The backfid is in gafid->cg_backfid, the creds to use for 1212 * this operation are in gafid->cg_cred. The attributes are 1213 * returned in gafid->cg_attr 1214 * 1215 * the error returned is 0 if successful, nozero if not 1216 */ 1217 int 1218 cachefs_io_getattrfid(vnode_t *vp, void *dinp, void *doutp) 1219 { 1220 vnode_t *backvp = NULL; 1221 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1222 int error = 0; 1223 cred_t *cr; 1224 cachefsio_getattrfid_t *gafid; 1225 fid_t *tmpfidp; 1226 vattr_t *tmpvap; 1227 cfs_vattr_t *attrp; 1228 CACHEFS_DECL(fid_t, tmpfid); 1229 CACHEFS_DECL(vattr_t, va); 1230 1231 /* 1232 * Only called in support of disconnectable operation, so assert 1233 * that this is not called when NFSv4 is the backfilesytem. 1234 */ 1235 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1236 1237 gafid = (cachefsio_getattrfid_t *)dinp; 1238 attrp = (cfs_vattr_t *)doutp; 1239 1240 /* Get a vnode for the back file */ 1241 CACHEFS_TMPPTR_SET(&gafid->cg_backfid, &tmpfid, tmpfidp, fid_t); 1242 CACHEFS_FID_COPYIN(&gafid->cg_backfid, tmpfidp); 1243 error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp); 1244 if (error) 1245 return (error); 1246 1247 cr = conj_cred(&gafid->cg_cred); 1248 CACHEFS_TMPPTR_SET(attrp, &va, tmpvap, vattr_t); 1249 tmpvap->va_mask = AT_ALL; 1250 error = VOP_GETATTR(backvp, tmpvap, 0, cr, NULL); 1251 CACHEFS_VATTR_COPYOUT(tmpvap, attrp, error); 1252 crfree(cr); 1253 1254 /* VFS_VGET performs a VN_HOLD on the vp */ 1255 VN_RELE(backvp); 1256 1257 return (error); 1258 } 1259 1260 1261 /* 1262 * This performs a getattr on the back file system. Instead of 1263 * passing the fid to perform the gettr on we are given the 1264 * parent directory fid and a name. 1265 */ 1266 int 1267 cachefs_io_getattrname(vnode_t *vp, void *dinp, void *doutp) 1268 { 1269 vnode_t *pbackvp = NULL; 1270 vnode_t *cbackvp = NULL; 1271 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1272 int error = 0; 1273 cred_t *cr; 1274 fid_t *tmpfidp; 1275 vattr_t *tmpvap; 1276 cachefsio_getattrname_arg_t *gap; 1277 cachefsio_getattrname_return_t *retp; 1278 CACHEFS_DECL(fid_t, tmpfid); 1279 CACHEFS_DECL(vattr_t, va); 1280 1281 /* 1282 * Only called in support of disconnectable operation, so assert 1283 * that this is not called when NFSv4 is the backfilesytem. 1284 */ 1285 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1286 1287 gap = (cachefsio_getattrname_arg_t *)dinp; 1288 retp = (cachefsio_getattrname_return_t *)doutp; 1289 1290 /* Get a vnode for the parent directory */ 1291 CACHEFS_TMPPTR_SET(&gap->cg_dir, &tmpfid, tmpfidp, fid_t); 1292 CACHEFS_FID_COPYIN(&gap->cg_dir, tmpfidp); 1293 error = VFS_VGET(fscp->fs_backvfsp, &pbackvp, tmpfidp); 1294 if (error) 1295 return (error); 1296 1297 /* lookup the file name */ 1298 cr = conj_cred(&gap->cg_cred); 1299 error = VOP_LOOKUP(pbackvp, gap->cg_name, &cbackvp, 1300 (struct pathname *)NULL, 0, (vnode_t *)NULL, cr, NULL, NULL, NULL); 1301 if (error) { 1302 crfree(cr); 1303 VN_RELE(pbackvp); 1304 return (error); 1305 } 1306 1307 CACHEFS_TMPPTR_SET(&retp->cg_attr, &va, tmpvap, vattr_t); 1308 tmpvap->va_mask = AT_ALL; 1309 error = VOP_GETATTR(cbackvp, tmpvap, 0, cr, NULL); 1310 CACHEFS_VATTR_COPYOUT(tmpvap, &retp->cg_attr, error); 1311 if (!error) { 1312 CACHEFS_TMPPTR_SET(&retp->cg_fid, &tmpfid, tmpfidp, fid_t); 1313 tmpfidp->fid_len = MAXFIDSZ; 1314 error = VOP_FID(cbackvp, tmpfidp, NULL); 1315 CACHEFS_FID_COPYOUT(tmpfidp, &retp->cg_fid); 1316 } 1317 1318 crfree(cr); 1319 VN_RELE(cbackvp); 1320 VN_RELE(pbackvp); 1321 return (error); 1322 } 1323 1324 /* 1325 * This will return the fid of the root of this mount point. 1326 */ 1327 int 1328 /*ARGSUSED*/ 1329 cachefs_io_rootfid(vnode_t *vp, void *dinp, void *doutp) 1330 { 1331 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1332 cfs_fid_t *rootfid = (cfs_fid_t *)doutp; 1333 1334 /* 1335 * Only called in support of disconnectable operation, so assert 1336 * that this is not called when NFSv4 is the backfilesytem. 1337 */ 1338 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1339 1340 CACHEFS_FID_COPY(&VTOC(fscp->fs_rootvp)->c_metadata.md_cookie, rootfid); 1341 return (0); 1342 } 1343 1344 /* 1345 * Pushes the data associated with a file back to the file server. 1346 */ 1347 int 1348 cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp) 1349 { 1350 vnode_t *backvp = NULL; 1351 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1352 caddr_t buffer = NULL; 1353 int error = 0; 1354 cnode_t *cp; 1355 size_t amt; 1356 u_offset_t size; 1357 vattr_t va; 1358 offset_t off; 1359 cred_t *cr = NULL; 1360 fid_t *tmpfidp; 1361 cachefsio_pushback_arg_t *pbp; 1362 cachefsio_pushback_return_t *retp; 1363 CACHEFS_DECL(fid_t, tmpfid); 1364 1365 /* 1366 * Only called in support of disconnectable operation, so assert 1367 * that this is not called when NFSv4 is the backfilesytem. 1368 */ 1369 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1370 1371 pbp = (cachefsio_pushback_arg_t *)dinp; 1372 retp = (cachefsio_pushback_return_t *)doutp; 1373 1374 cr = conj_cred(&pbp->pb_cred); 1375 1376 /* get the backvp to push to */ 1377 CACHEFS_TMPPTR_SET(&pbp->pb_fid, &tmpfid, tmpfidp, fid_t); 1378 CACHEFS_FID_COPYIN(&pbp->pb_fid, tmpfidp); 1379 error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp); 1380 if (error) { 1381 backvp = NULL; 1382 goto out; 1383 } 1384 1385 /* Get the cnode for the file we are to push back */ 1386 error = cachefs_cnode_make(&pbp->pb_cid, fscp, 1387 NULL, NULL, NULL, cr, 0, &cp); 1388 if (error) { 1389 goto out; 1390 } 1391 1392 /* must be a regular file */ 1393 if (cp->c_attr.va_type != VREG) { 1394 error = EINVAL; 1395 goto out; 1396 } 1397 1398 mutex_enter(&cp->c_statelock); 1399 1400 /* get the front file */ 1401 if (cp->c_frontvp == NULL) { 1402 error = cachefs_getfrontfile(cp); 1403 if (error) { 1404 mutex_exit(&cp->c_statelock); 1405 goto out; 1406 } 1407 } 1408 1409 /* better be populated */ 1410 if ((cp->c_metadata.md_flags & MD_POPULATED) == 0) { 1411 mutex_exit(&cp->c_statelock); 1412 error = EINVAL; 1413 goto out; 1414 } 1415 1416 /* do open so NFS gets correct creds on writes */ 1417 error = VOP_OPEN(&backvp, FWRITE, cr, NULL); 1418 if (error) { 1419 mutex_exit(&cp->c_statelock); 1420 goto out; 1421 } 1422 1423 buffer = cachefs_kmem_alloc(MAXBSIZE, KM_SLEEP); 1424 1425 /* Read the data from the cache and write it to the server */ 1426 /* XXX why not use segmapio? */ 1427 off = 0; 1428 for (size = cp->c_size; size != 0; size -= amt) { 1429 if (size > MAXBSIZE) 1430 amt = MAXBSIZE; 1431 else 1432 amt = size; 1433 1434 /* read a block of data from the front file */ 1435 error = vn_rdwr(UIO_READ, cp->c_frontvp, buffer, 1436 amt, off, UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0); 1437 if (error) { 1438 mutex_exit(&cp->c_statelock); 1439 goto out; 1440 } 1441 1442 /* write the block of data to the back file */ 1443 error = vn_rdwr(UIO_WRITE, backvp, buffer, amt, off, 1444 UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0); 1445 if (error) { 1446 mutex_exit(&cp->c_statelock); 1447 goto out; 1448 } 1449 off += amt; 1450 } 1451 1452 error = VOP_FSYNC(backvp, FSYNC, cr, NULL); 1453 if (error == 0) 1454 error = VOP_CLOSE(backvp, FWRITE, 1, (offset_t)0, cr, NULL); 1455 if (error) { 1456 mutex_exit(&cp->c_statelock); 1457 goto out; 1458 } 1459 1460 cp->c_metadata.md_flags |= MD_PUSHDONE; 1461 cp->c_metadata.md_flags &= ~MD_PUTPAGE; 1462 cp->c_metadata.md_flags |= MD_NEEDATTRS; 1463 cp->c_flags |= CN_UPDATED; 1464 mutex_exit(&cp->c_statelock); 1465 1466 /* 1467 * if we have successfully stored the data, we need the 1468 * new ctime and mtimes. 1469 */ 1470 va.va_mask = AT_ALL; 1471 error = VOP_GETATTR(backvp, &va, 0, cr, NULL); 1472 if (error) 1473 goto out; 1474 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->pb_ctime, error); 1475 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->pb_mtime, error); 1476 1477 out: 1478 if (buffer) 1479 cachefs_kmem_free(buffer, MAXBSIZE); 1480 if (cp) 1481 VN_RELE(CTOV(cp)); 1482 if (backvp) 1483 VN_RELE(backvp); 1484 if (cr) 1485 crfree(cr); 1486 return (error); 1487 } 1488 1489 /* 1490 * Create a file on the back file system. 1491 */ 1492 int 1493 cachefs_io_create(vnode_t *vp, void *dinp, void *doutp) 1494 { 1495 vnode_t *dvp = NULL; 1496 vnode_t *cvp = NULL; 1497 cnode_t *cp = NULL; 1498 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1499 vattr_t va, *tmpvap; 1500 int error = 0; 1501 cred_t *cr = NULL; 1502 fid_t *tmpfidp; 1503 cachefsio_create_arg_t *crp; 1504 cachefsio_create_return_t *retp; 1505 CACHEFS_DECL(fid_t, tmpfid); 1506 1507 /* 1508 * Only called in support of disconnectable operation, so assert 1509 * that this is not called when NFSv4 is the backfilesytem. 1510 */ 1511 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1512 1513 crp = (cachefsio_create_arg_t *)dinp; 1514 retp = (cachefsio_create_return_t *)doutp; 1515 1516 /* get a vnode for the parent directory */ 1517 CACHEFS_TMPPTR_SET(&crp->cr_backfid, &tmpfid, tmpfidp, fid_t); 1518 CACHEFS_FID_COPYIN(&crp->cr_backfid, tmpfidp); 1519 error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp); 1520 if (error) 1521 goto out; 1522 1523 cr = conj_cred(&crp->cr_cred); 1524 1525 /* do the create */ 1526 CACHEFS_TMPPTR_SET(&crp->cr_va, &va, tmpvap, vattr_t); 1527 CACHEFS_VATTR_COPYIN(&crp->cr_va, tmpvap); 1528 error = VOP_CREATE(dvp, crp->cr_name, tmpvap, 1529 crp->cr_exclusive, crp->cr_mode, &cvp, cr, 0, NULL, NULL); 1530 if (error) 1531 goto out; 1532 1533 /* get the fid of the file */ 1534 CACHEFS_TMPPTR_SET(&retp->cr_newfid, &tmpfid, tmpfidp, fid_t); 1535 tmpfidp->fid_len = MAXFIDSZ; 1536 error = VOP_FID(cvp, tmpfidp, NULL); 1537 if (error) 1538 goto out; 1539 CACHEFS_FID_COPYOUT(tmpfidp, &retp->cr_newfid); 1540 1541 /* get attributes for the file */ 1542 va.va_mask = AT_ALL; 1543 error = VOP_GETATTR(cvp, &va, 0, cr, NULL); 1544 if (error) 1545 goto out; 1546 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->cr_ctime, error); 1547 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->cr_mtime, error); 1548 if (error) 1549 goto out; 1550 1551 /* update the cnode for this file with the new info */ 1552 error = cachefs_cnode_make(&crp->cr_cid, fscp, 1553 NULL, NULL, NULL, cr, 0, &cp); 1554 if (error) { 1555 error = 0; 1556 goto out; 1557 } 1558 1559 mutex_enter(&cp->c_statelock); 1560 ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL); 1561 cp->c_attr.va_nodeid = va.va_nodeid; 1562 cp->c_metadata.md_flags |= MD_CREATEDONE; 1563 cp->c_metadata.md_flags |= MD_NEEDATTRS; 1564 cp->c_metadata.md_cookie = *tmpfidp; 1565 cp->c_flags |= CN_UPDATED; 1566 mutex_exit(&cp->c_statelock); 1567 1568 out: 1569 if (cr) 1570 crfree(cr); 1571 if (dvp) 1572 VN_RELE(dvp); 1573 if (cvp) 1574 VN_RELE(cvp); 1575 if (cp) 1576 VN_RELE(CTOV(cp)); 1577 return (error); 1578 } 1579 1580 /* 1581 * Remove a file on the back file system. 1582 * Returns 0 or an error if could not perform operation. 1583 */ 1584 int 1585 cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp) 1586 { 1587 vnode_t *dvp = NULL; 1588 vnode_t *cvp; 1589 cred_t *cr = NULL; 1590 vattr_t va; 1591 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1592 int error; 1593 fid_t child_fid, *child_fidp; 1594 cachefsio_remove_t *rmp = (cachefsio_remove_t *)dinp; 1595 cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp; 1596 1597 /* 1598 * Only called in support of disconnectable operation, so assert 1599 * that this is not called when NFSv4 is the backfilesytem. 1600 */ 1601 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1602 1603 /* Get a vnode for the directory */ 1604 CACHEFS_TMPPTR_SET(&rmp->rm_fid, &child_fid, child_fidp, fid_t); 1605 CACHEFS_FID_COPYIN(&rmp->rm_fid, child_fidp); 1606 error = VFS_VGET(fscp->fs_backvfsp, &dvp, child_fidp); 1607 if (error) { 1608 dvp = NULL; 1609 goto out; 1610 } 1611 1612 cr = conj_cred(&rmp->rm_cred); 1613 1614 /* if the caller wants the ctime after the remove */ 1615 if (ctimep) { 1616 error = VOP_LOOKUP(dvp, rmp->rm_name, &cvp, NULL, 0, NULL, cr, 1617 NULL, NULL, NULL); 1618 if (error == 0) { 1619 child_fid.fid_len = MAXFIDSZ; 1620 error = VOP_FID(cvp, &child_fid, NULL); 1621 VN_RELE(cvp); 1622 } 1623 if (error) 1624 goto out; 1625 } 1626 1627 /* do the remove */ 1628 error = VOP_REMOVE(dvp, rmp->rm_name, cr, NULL, 0); 1629 if (error) 1630 goto out; 1631 1632 /* get the new ctime if requested */ 1633 if (ctimep) { 1634 error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid); 1635 if (error == 0) { 1636 va.va_mask = AT_ALL; 1637 error = VOP_GETATTR(cvp, &va, 0, cr, NULL); 1638 if (error == 0) { 1639 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, 1640 ctimep, error); 1641 } 1642 VN_RELE(cvp); 1643 } 1644 cachefs_iosetneedattrs(fscp, &rmp->rm_cid); 1645 } 1646 1647 out: 1648 if (cr) 1649 crfree(cr); 1650 if (dvp) 1651 VN_RELE(dvp); 1652 return (error); 1653 } 1654 1655 /* 1656 * Perform a link on the back file system. 1657 * Returns 0 or an error if could not perform operation. 1658 */ 1659 int 1660 cachefs_io_link(vnode_t *vp, void *dinp, void *doutp) 1661 { 1662 vnode_t *dvp = NULL; 1663 vnode_t *lvp = NULL; 1664 vattr_t va; 1665 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1666 int error = 0; 1667 cred_t *cr = NULL; 1668 fid_t *tmpfidp; 1669 cachefsio_link_t *linkp = (cachefsio_link_t *)dinp; 1670 cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp; 1671 CACHEFS_DECL(fid_t, tmpfid); 1672 1673 /* 1674 * Only called in support of disconnectable operation, so assert 1675 * that this is not called when NFSv4 is the backfilesytem. 1676 */ 1677 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1678 1679 /* Get a vnode parent directory */ 1680 CACHEFS_TMPPTR_SET(&linkp->ln_dirfid, &tmpfid, tmpfidp, fid_t); 1681 CACHEFS_FID_COPYIN(&linkp->ln_dirfid, tmpfidp); 1682 error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp); 1683 if (error) { 1684 dvp = NULL; 1685 goto out; 1686 } 1687 1688 /* Get a vnode file to link to */ 1689 CACHEFS_TMPPTR_SET(&linkp->ln_filefid, &tmpfid, tmpfidp, fid_t); 1690 CACHEFS_FID_COPYIN(&linkp->ln_filefid, tmpfidp); 1691 error = VFS_VGET(fscp->fs_backvfsp, &lvp, tmpfidp); 1692 if (error) { 1693 lvp = NULL; 1694 goto out; 1695 } 1696 1697 cr = conj_cred(&linkp->ln_cred); 1698 1699 /* do the link */ 1700 error = VOP_LINK(dvp, lvp, linkp->ln_name, cr, NULL, 0); 1701 if (error) 1702 goto out; 1703 1704 /* get the ctime */ 1705 va.va_mask = AT_ALL; 1706 error = VOP_GETATTR(lvp, &va, 0, cr, NULL); 1707 if (error) 1708 goto out; 1709 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, ctimep, error); 1710 if (error) 1711 goto out; 1712 1713 cachefs_iosetneedattrs(fscp, &linkp->ln_cid); 1714 out: 1715 if (cr) 1716 crfree(cr); 1717 if (dvp) 1718 VN_RELE(dvp); 1719 if (lvp) 1720 VN_RELE(lvp); 1721 return (error); 1722 } 1723 1724 /* 1725 * Rename the file on the back file system. 1726 * Returns 0 or an error if could not perform operation. 1727 */ 1728 int 1729 cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp) 1730 { 1731 vnode_t *odvp = NULL; 1732 vnode_t *ndvp = NULL; 1733 cred_t *cr = NULL; 1734 vnode_t *cvp = NULL; 1735 vattr_t va; 1736 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1737 int error = 0; 1738 fid_t child_fid, *child_fidp; 1739 cachefsio_rename_arg_t *rnp; 1740 cachefsio_rename_return_t *retp; 1741 1742 /* 1743 * Only called in support of disconnectable operation, so assert 1744 * that this is not called when NFSv4 is the backfilesytem. 1745 */ 1746 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1747 1748 rnp = (cachefsio_rename_arg_t *)dinp; 1749 retp = (cachefsio_rename_return_t *)doutp; 1750 1751 /* Get vnode of old parent directory */ 1752 CACHEFS_TMPPTR_SET(&rnp->rn_olddir, &child_fid, child_fidp, fid_t); 1753 CACHEFS_FID_COPYIN(&rnp->rn_olddir, child_fidp); 1754 error = VFS_VGET(fscp->fs_backvfsp, &odvp, child_fidp); 1755 if (error) { 1756 odvp = NULL; 1757 goto out; 1758 } 1759 1760 /* Get vnode of new parent directory */ 1761 CACHEFS_TMPPTR_SET(&rnp->rn_newdir, &child_fid, child_fidp, fid_t); 1762 CACHEFS_FID_COPYIN(&rnp->rn_newdir, child_fidp); 1763 error = VFS_VGET(fscp->fs_backvfsp, &ndvp, child_fidp); 1764 if (error) { 1765 ndvp = NULL; 1766 goto out; 1767 } 1768 1769 cr = conj_cred(&rnp->rn_cred); 1770 1771 /* if the caller wants the ctime of the target after deletion */ 1772 if (rnp->rn_del_getctime) { 1773 error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, 1774 NULL, cr, NULL, NULL, NULL); 1775 if (error) { 1776 cvp = NULL; /* paranoia */ 1777 goto out; 1778 } 1779 1780 child_fid.fid_len = MAXFIDSZ; 1781 error = VOP_FID(cvp, &child_fid, NULL); 1782 if (error) 1783 goto out; 1784 VN_RELE(cvp); 1785 cvp = NULL; 1786 } 1787 1788 /* do the rename */ 1789 error = VOP_RENAME(odvp, rnp->rn_oldname, ndvp, rnp->rn_newname, cr, 1790 NULL, 0); 1791 if (error) 1792 goto out; 1793 1794 /* get the new ctime on the renamed file */ 1795 error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, NULL, cr, 1796 NULL, NULL, NULL); 1797 if (error) 1798 goto out; 1799 1800 va.va_mask = AT_ALL; 1801 error = VOP_GETATTR(cvp, &va, 0, cr, NULL); 1802 if (error) 1803 goto out; 1804 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_ctime, error); 1805 VN_RELE(cvp); 1806 cvp = NULL; 1807 if (error) 1808 goto out; 1809 1810 cachefs_iosetneedattrs(fscp, &rnp->rn_cid); 1811 1812 /* get the new ctime if requested of the deleted target */ 1813 if (rnp->rn_del_getctime) { 1814 error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid); 1815 if (error) { 1816 cvp = NULL; 1817 goto out; 1818 } 1819 va.va_mask = AT_ALL; 1820 error = VOP_GETATTR(cvp, &va, 0, cr, NULL); 1821 if (error) 1822 goto out; 1823 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_del_ctime, 1824 error); 1825 VN_RELE(cvp); 1826 cvp = NULL; 1827 if (error) 1828 goto out; 1829 cachefs_iosetneedattrs(fscp, &rnp->rn_del_cid); 1830 } 1831 1832 out: 1833 if (cr) 1834 crfree(cr); 1835 if (cvp) 1836 VN_RELE(cvp); 1837 if (odvp) 1838 VN_RELE(odvp); 1839 if (ndvp) 1840 VN_RELE(ndvp); 1841 return (error); 1842 } 1843 1844 /* 1845 * Make a directory on the backfs. 1846 * Returns 0 or an error if could not perform operation. 1847 */ 1848 int 1849 cachefs_io_mkdir(vnode_t *vp, void *dinp, void *doutp) 1850 { 1851 vnode_t *dvp = NULL; 1852 vnode_t *cvp = NULL; 1853 cnode_t *cp = NULL; 1854 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1855 int error = 0; 1856 cred_t *cr = NULL; 1857 fid_t *tmpfidp; 1858 vattr_t va, *tmpvap; 1859 cachefsio_mkdir_t *mdirp = (cachefsio_mkdir_t *)dinp; 1860 cfs_fid_t *fidp = (cfs_fid_t *)doutp; 1861 CACHEFS_DECL(fid_t, tmpfid); 1862 1863 /* 1864 * Only called in support of disconnectable operation, so assert 1865 * that this is not called when NFSv4 is the backfilesytem. 1866 */ 1867 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1868 1869 /* Get vnode of parent directory */ 1870 CACHEFS_TMPPTR_SET(&mdirp->md_dirfid, &tmpfid, tmpfidp, fid_t); 1871 CACHEFS_FID_COPYIN(&mdirp->md_dirfid, tmpfidp); 1872 error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp); 1873 if (error) { 1874 dvp = NULL; 1875 goto out; 1876 } 1877 1878 cr = conj_cred(&mdirp->md_cred); 1879 1880 /* make the directory */ 1881 CACHEFS_TMPPTR_SET(&mdirp->md_vattr, &va, tmpvap, vattr_t); 1882 CACHEFS_VATTR_COPYIN(&mdirp->md_vattr, tmpvap); 1883 error = VOP_MKDIR(dvp, mdirp->md_name, tmpvap, &cvp, cr, NULL, 0, NULL); 1884 if (error) { 1885 if (error != EEXIST) 1886 goto out; 1887 1888 /* if the directory already exists, then use it */ 1889 error = VOP_LOOKUP(dvp, mdirp->md_name, &cvp, 1890 NULL, 0, NULL, cr, NULL, NULL, NULL); 1891 if (error) { 1892 cvp = NULL; 1893 goto out; 1894 } 1895 if (cvp->v_type != VDIR) { 1896 error = EINVAL; 1897 goto out; 1898 } 1899 } 1900 1901 /* get the fid of the directory */ 1902 CACHEFS_TMPPTR_SET(fidp, &tmpfid, tmpfidp, fid_t); 1903 tmpfidp->fid_len = MAXFIDSZ; 1904 error = VOP_FID(cvp, tmpfidp, NULL); 1905 if (error) 1906 goto out; 1907 CACHEFS_FID_COPYOUT(tmpfidp, fidp); 1908 1909 /* get attributes of the directory */ 1910 va.va_mask = AT_ALL; 1911 error = VOP_GETATTR(cvp, &va, 0, cr, NULL); 1912 if (error) 1913 goto out; 1914 1915 /* update the cnode for this dir with the new fid */ 1916 error = cachefs_cnode_make(&mdirp->md_cid, fscp, 1917 NULL, NULL, NULL, cr, 0, &cp); 1918 if (error) { 1919 error = 0; 1920 goto out; 1921 } 1922 mutex_enter(&cp->c_statelock); 1923 ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL); 1924 cp->c_metadata.md_cookie = *tmpfidp; 1925 cp->c_metadata.md_flags |= MD_CREATEDONE; 1926 cp->c_metadata.md_flags |= MD_NEEDATTRS; 1927 cp->c_attr.va_nodeid = va.va_nodeid; 1928 cp->c_flags |= CN_UPDATED; 1929 mutex_exit(&cp->c_statelock); 1930 out: 1931 if (cr) 1932 crfree(cr); 1933 if (dvp) 1934 VN_RELE(dvp); 1935 if (cvp) 1936 VN_RELE(cvp); 1937 if (cp) 1938 VN_RELE(CTOV(cp)); 1939 return (error); 1940 } 1941 1942 /* 1943 * Perform a rmdir on the back file system. 1944 * Returns 0 or an error if could not perform operation. 1945 */ 1946 int 1947 /*ARGSUSED*/ 1948 cachefs_io_rmdir(vnode_t *vp, void *dinp, void *doutp) 1949 { 1950 vnode_t *dvp = NULL; 1951 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1952 int error; 1953 cred_t *cr; 1954 fid_t *tmpfidp; 1955 cachefsio_rmdir_t *rdp = (cachefsio_rmdir_t *)dinp; 1956 CACHEFS_DECL(fid_t, tmpfid); 1957 1958 /* 1959 * Only called in support of disconnectable operation, so assert 1960 * that this is not called when NFSv4 is the backfilesytem. 1961 */ 1962 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1963 1964 /* Get a vnode for the back file */ 1965 CACHEFS_TMPPTR_SET(&rdp->rd_dirfid, &tmpfid, tmpfidp, fid_t); 1966 CACHEFS_FID_COPYIN(&rdp->rd_dirfid, tmpfidp); 1967 error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp); 1968 if (error) { 1969 dvp = NULL; 1970 return (error); 1971 } 1972 1973 cr = conj_cred(&rdp->rd_cred); 1974 error = VOP_RMDIR(dvp, rdp->rd_name, dvp, cr, NULL, 0); 1975 crfree(cr); 1976 1977 VN_RELE(dvp); 1978 return (error); 1979 } 1980 1981 /* 1982 * create a symlink on the back file system 1983 * Returns 0 or an error if could not perform operation. 1984 */ 1985 int 1986 cachefs_io_symlink(vnode_t *vp, void *dinp, void *doutp) 1987 { 1988 vnode_t *dvp = NULL; 1989 vnode_t *svp = NULL; 1990 cnode_t *cp = NULL; 1991 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 1992 fid_t *tmpfidp; 1993 vattr_t va, *tmpvap; 1994 int error = 0; 1995 cred_t *cr = NULL; 1996 cachefsio_symlink_arg_t *symp; 1997 cachefsio_symlink_return_t *retp; 1998 CACHEFS_DECL(fid_t, tmpfid); 1999 2000 /* 2001 * Only called in support of disconnectable operation, so assert 2002 * that this is not called when NFSv4 is the backfilesytem. 2003 */ 2004 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 2005 2006 symp = (cachefsio_symlink_arg_t *)dinp; 2007 retp = (cachefsio_symlink_return_t *)doutp; 2008 2009 /* get a vnode for the back directory */ 2010 CACHEFS_TMPPTR_SET(&symp->sy_dirfid, &tmpfid, tmpfidp, fid_t); 2011 CACHEFS_FID_COPYIN(&symp->sy_dirfid, tmpfidp); 2012 error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp); 2013 if (error) { 2014 dvp = NULL; 2015 goto out; 2016 } 2017 2018 cr = conj_cred(&symp->sy_cred); 2019 2020 /* create the symlink */ 2021 CACHEFS_TMPPTR_SET(&symp->sy_vattr, &va, tmpvap, vattr_t); 2022 CACHEFS_VATTR_COPYIN(&symp->sy_vattr, tmpvap); 2023 error = VOP_SYMLINK(dvp, symp->sy_name, tmpvap, 2024 symp->sy_link, cr, NULL, 0); 2025 if (error) 2026 goto out; 2027 2028 /* get the vnode for the symlink */ 2029 error = VOP_LOOKUP(dvp, symp->sy_name, &svp, NULL, 0, NULL, cr, 2030 NULL, NULL, NULL); 2031 if (error) 2032 goto out; 2033 2034 /* get the attributes of the symlink */ 2035 va.va_mask = AT_ALL; 2036 error = VOP_GETATTR(svp, &va, 0, cr, NULL); 2037 if (error) 2038 goto out; 2039 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sy_ctime, error); 2040 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sy_mtime, error); 2041 if (error) 2042 goto out; 2043 2044 /* get the fid */ 2045 CACHEFS_TMPPTR_SET(&retp->sy_newfid, &tmpfid, tmpfidp, fid_t); 2046 tmpfidp->fid_len = MAXFIDSZ; 2047 error = VOP_FID(svp, tmpfidp, NULL); 2048 if (error) 2049 goto out; 2050 CACHEFS_FID_COPYOUT(tmpfidp, &retp->sy_newfid); 2051 2052 /* update the cnode for this file with the new info */ 2053 error = cachefs_cnode_make(&symp->sy_cid, fscp, 2054 NULL, NULL, NULL, cr, 0, &cp); 2055 if (error) { 2056 error = 0; 2057 goto out; 2058 } 2059 mutex_enter(&cp->c_statelock); 2060 ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL); 2061 cp->c_metadata.md_cookie = *tmpfidp; 2062 cp->c_metadata.md_flags |= MD_CREATEDONE; 2063 cp->c_metadata.md_flags |= MD_NEEDATTRS; 2064 cp->c_attr.va_nodeid = va.va_nodeid; 2065 cp->c_flags |= CN_UPDATED; 2066 mutex_exit(&cp->c_statelock); 2067 2068 out: 2069 if (cr) 2070 crfree(cr); 2071 if (dvp) 2072 VN_RELE(dvp); 2073 if (svp) 2074 VN_RELE(svp); 2075 if (cp) 2076 VN_RELE(CTOV(cp)); 2077 return (error); 2078 } 2079 2080 /* 2081 * Perform setattr on the back file system. 2082 * Returns 0 or an error if could not perform operation. 2083 */ 2084 int 2085 cachefs_io_setattr(vnode_t *vp, void *dinp, void *doutp) 2086 { 2087 vnode_t *cvp = NULL; 2088 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 2089 fid_t *tmpfidp; 2090 vattr_t va, *tmpvap; 2091 int error = 0; 2092 cred_t *cr = NULL; 2093 cachefsio_setattr_arg_t *sap; 2094 cachefsio_setattr_return_t *retp; 2095 CACHEFS_DECL(fid_t, tmpfid); 2096 2097 /* 2098 * Only called in support of disconnectable operation, so assert 2099 * that this is not called when NFSv4 is the backfilesytem. 2100 */ 2101 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 2102 2103 sap = (cachefsio_setattr_arg_t *)dinp; 2104 retp = (cachefsio_setattr_return_t *)doutp; 2105 2106 /* get a vnode for the back directory */ 2107 CACHEFS_TMPPTR_SET(&sap->sa_backfid, &tmpfid, tmpfidp, fid_t); 2108 CACHEFS_FID_COPYIN(&sap->sa_backfid, tmpfidp); 2109 error = VFS_VGET(fscp->fs_backvfsp, &cvp, tmpfidp); 2110 if (error) { 2111 cvp = NULL; 2112 goto out; 2113 } 2114 2115 cr = conj_cred(&sap->sa_cred); 2116 2117 /* perform the setattr */ 2118 CACHEFS_TMPPTR_SET(&sap->sa_vattr, &va, tmpvap, vattr_t); 2119 CACHEFS_VATTR_COPYIN(&sap->sa_vattr, tmpvap); 2120 error = VOP_SETATTR(cvp, tmpvap, 0, cr, NULL); 2121 if (error) 2122 goto out; 2123 2124 /* get the new ctime and mtime */ 2125 va.va_mask = AT_ALL; 2126 error = VOP_GETATTR(cvp, &va, 0, cr, NULL); 2127 if (error) 2128 goto out; 2129 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sa_ctime, error); 2130 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sa_mtime, error); 2131 if (error) 2132 goto out; 2133 2134 cachefs_iosetneedattrs(fscp, &sap->sa_cid); 2135 out: 2136 if (cr) 2137 crfree(cr); 2138 if (cvp) 2139 VN_RELE(cvp); 2140 return (error); 2141 } 2142 2143 int 2144 cachefs_io_setsecattr(vnode_t *vp, void *dinp, void *doutp) 2145 { 2146 int error = 0; 2147 fscache_t *fscp = C_TO_FSCACHE(VTOC(vp)); 2148 vnode_t *tvp = NULL; 2149 vsecattr_t vsec; 2150 vattr_t va; 2151 cred_t *cr = NULL; 2152 fid_t *tmpfidp; 2153 cachefsio_setsecattr_arg_t *ssap; 2154 cachefsio_setsecattr_return_t *retp; 2155 CACHEFS_DECL(fid_t, tmpfid); 2156 2157 /* 2158 * Only called in support of disconnectable operation, so assert 2159 * that this is not called when NFSv4 is the backfilesytem. 2160 */ 2161 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 2162 2163 ssap = (cachefsio_setsecattr_arg_t *)dinp; 2164 retp = (cachefsio_setsecattr_return_t *)doutp; 2165 2166 /* get vnode of back file to do VOP_SETSECATTR to */ 2167 CACHEFS_TMPPTR_SET(&ssap->sc_backfid, &tmpfid, tmpfidp, fid_t); 2168 CACHEFS_FID_COPYIN(&ssap->sc_backfid, tmpfidp); 2169 error = VFS_VGET(fscp->fs_backvfsp, &tvp, tmpfidp); 2170 if (error != 0) { 2171 tvp = NULL; 2172 goto out; 2173 } 2174 2175 /* get the creds */ 2176 cr = conj_cred(&ssap->sc_cred); 2177 2178 /* form the vsecattr_t */ 2179 vsec.vsa_mask = ssap->sc_mask; 2180 vsec.vsa_aclcnt = ssap->sc_aclcnt; 2181 vsec.vsa_dfaclcnt = ssap->sc_dfaclcnt; 2182 vsec.vsa_aclentp = ssap->sc_acl; 2183 vsec.vsa_dfaclentp = ssap->sc_acl + ssap->sc_aclcnt; 2184 2185 /* set the ACL */ 2186 (void) VOP_RWLOCK(tvp, V_WRITELOCK_TRUE, NULL); 2187 error = VOP_SETSECATTR(tvp, &vsec, 0, cr, NULL); 2188 VOP_RWUNLOCK(tvp, V_WRITELOCK_TRUE, NULL); 2189 if (error != 0) 2190 goto out; 2191 2192 /* get the new ctime and mtime */ 2193 va.va_mask = AT_ALL; 2194 error = VOP_GETATTR(tvp, &va, 0, cr, NULL); 2195 if (error) 2196 goto out; 2197 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sc_ctime, error); 2198 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sc_mtime, error); 2199 if (error) 2200 goto out; 2201 2202 cachefs_iosetneedattrs(fscp, &ssap->sc_cid); 2203 out: 2204 2205 if (cr != NULL) 2206 crfree(cr); 2207 if (tvp != NULL) 2208 VN_RELE(tvp); 2209 2210 return (error); 2211 } 2212 2213 static void 2214 sync_metadata(cnode_t *cp) 2215 { 2216 if (cp->c_flags & (CN_STALE | CN_DESTROY)) 2217 return; 2218 (void) cachefs_sync_metadata(cp); 2219 } 2220 2221 static void 2222 drop_backvp(cnode_t *cp) 2223 { 2224 if (cp->c_backvp) { 2225 mutex_enter(&cp->c_statelock); 2226 if (cp->c_backvp) { 2227 /* dump any pages, may be a dirty one */ 2228 (void) VOP_PUTPAGE(cp->c_backvp, (offset_t)0, 0, 2229 B_INVAL | B_TRUNC, kcred, NULL); 2230 } 2231 mutex_exit(&cp->c_statelock); 2232 } 2233 } 2234 2235 static void 2236 allow_pendrm(cnode_t *cp) 2237 { 2238 if (cp->c_flags & CN_PENDRM) { 2239 mutex_enter(&cp->c_statelock); 2240 if (cp->c_flags & CN_PENDRM) { 2241 cp->c_flags &= ~CN_PENDRM; 2242 VN_RELE(CTOV(cp)); 2243 } 2244 mutex_exit(&cp->c_statelock); 2245 } 2246 } 2247 2248 static void 2249 cachefs_modified_fix(fscache_t *fscp) 2250 { 2251 cnode_t *cp; 2252 int error = 0; 2253 rl_entry_t rl_ent; 2254 cfs_cid_t cid; 2255 cachefscache_t *cachep = fscp->fs_cache; 2256 enum cachefs_rl_type type; 2257 cachefs_metadata_t *mdp; 2258 int timedout = 0; 2259 struct vattr va; 2260 2261 /* XXX just return if fs is in error ro mode */ 2262 2263 /* lock out other users of the MF list */ 2264 mutex_enter(&cachep->c_mflock); 2265 2266 /* move the modified entries for this file system to the MF list */ 2267 cachefs_move_modified_to_mf(cachep, fscp); 2268 2269 rl_ent.rl_current = CACHEFS_RL_MF; 2270 for (;;) { 2271 /* get the next entry on the MF list */ 2272 error = cachefs_rlent_data(cachep, &rl_ent, NULL); 2273 if (error) { 2274 error = 0; 2275 break; 2276 } 2277 ASSERT(fscp->fs_cfsid == rl_ent.rl_fsid); 2278 2279 /* get the cnode for the file */ 2280 cid.cid_fileno = rl_ent.rl_fileno; 2281 cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0; 2282 error = cachefs_cnode_make(&cid, fscp, 2283 NULL, NULL, NULL, kcred, 0, &cp); 2284 if (error) { 2285 #ifdef CFSDEBUG 2286 CFS_DEBUG(CFSDEBUG_IOCTL) 2287 printf("cachefs: mf: could not find %llu\n", 2288 (u_longlong_t)cid.cid_fileno); 2289 delay(5*hz); 2290 #endif 2291 /* XXX this will loop forever, maybe put fs in */ 2292 /* ro mode */ 2293 continue; 2294 } 2295 2296 mutex_enter(&cp->c_statelock); 2297 2298 mdp = &cp->c_metadata; 2299 2300 /* if a regular file that has not been pushed */ 2301 if ((cp->c_attr.va_type == VREG) && 2302 (((mdp->md_flags & (MD_PUSHDONE | MD_PUTPAGE)) == 2303 MD_PUTPAGE))) { 2304 /* move the file to lost+found */ 2305 error = cachefs_cnode_lostfound(cp, NULL); 2306 if (error) { 2307 /* XXX put fs in ro mode */ 2308 /* XXX need to drain MF list */ 2309 panic("lostfound failed %d", error); 2310 } 2311 mutex_exit(&cp->c_statelock); 2312 VN_RELE(CTOV(cp)); 2313 continue; 2314 } 2315 2316 /* if a local file */ 2317 if (cp->c_id.cid_flags & CFS_CID_LOCAL) { 2318 /* if the file was not created */ 2319 if ((cp->c_metadata.md_flags & MD_CREATEDONE) == 0) { 2320 /* do not allow cnode to be used */ 2321 cachefs_cnode_stale(cp); 2322 mutex_exit(&cp->c_statelock); 2323 VN_RELE(CTOV(cp)); 2324 continue; 2325 } 2326 2327 /* save the local fileno for later getattrs */ 2328 mdp->md_localfileno = cp->c_id.cid_fileno; 2329 mutex_exit(&cp->c_statelock); 2330 2331 /* register the mapping from old to new fileno */ 2332 mutex_enter(&fscp->fs_fslock); 2333 cachefs_inum_register(fscp, cp->c_attr.va_nodeid, 2334 mdp->md_localfileno); 2335 cachefs_inum_register(fscp, mdp->md_localfileno, 0); 2336 mutex_exit(&fscp->fs_fslock); 2337 2338 /* move to new location in the cache */ 2339 cachefs_cnode_move(cp); 2340 mutex_enter(&cp->c_statelock); 2341 } 2342 2343 /* else if a modified file that needs to have its mode fixed */ 2344 else if ((cp->c_metadata.md_flags & MD_FILE) && 2345 (cp->c_attr.va_type == VREG)) { 2346 2347 if (cp->c_frontvp == NULL) 2348 (void) cachefs_getfrontfile(cp); 2349 if (cp->c_frontvp) { 2350 /* mark file as no longer modified */ 2351 va.va_mode = 0666; 2352 va.va_mask = AT_MODE; 2353 error = VOP_SETATTR(cp->c_frontvp, &va, 2354 0, kcred, NULL); 2355 if (error) { 2356 cmn_err(CE_WARN, 2357 "Cannot change ff mode.\n"); 2358 } 2359 } 2360 } 2361 2362 2363 /* if there is a rl entry, put it on the correct list */ 2364 if (mdp->md_rlno) { 2365 if (mdp->md_flags & MD_PACKED) { 2366 if ((mdp->md_flags & MD_POPULATED) || 2367 ((mdp->md_flags & MD_FILE) == 0)) 2368 type = CACHEFS_RL_PACKED; 2369 else 2370 type = CACHEFS_RL_PACKED_PENDING; 2371 cachefs_rlent_moveto(fscp->fs_cache, type, 2372 mdp->md_rlno, mdp->md_frontblks); 2373 mdp->md_rltype = type; 2374 } else if (mdp->md_flags & MD_FILE) { 2375 type = CACHEFS_RL_ACTIVE; 2376 cachefs_rlent_moveto(fscp->fs_cache, type, 2377 mdp->md_rlno, mdp->md_frontblks); 2378 mdp->md_rltype = type; 2379 } else { 2380 type = CACHEFS_RL_FREE; 2381 cachefs_rlent_moveto(fscp->fs_cache, type, 2382 mdp->md_rlno, 0); 2383 filegrp_ffrele(cp->c_filegrp); 2384 mdp->md_rlno = 0; 2385 mdp->md_rltype = CACHEFS_RL_NONE; 2386 } 2387 } 2388 mdp->md_flags &= ~(MD_CREATEDONE | MD_PUTPAGE | 2389 MD_PUSHDONE | MD_MAPPING); 2390 2391 /* if a directory, populate it */ 2392 if (CTOV(cp)->v_type == VDIR) { 2393 /* XXX hack for now */ 2394 mdp->md_flags |= MD_INVALREADDIR; 2395 dnlc_purge_vp(CTOV(cp)); 2396 2397 mdp->md_flags |= MD_NEEDATTRS; 2398 } 2399 2400 if (!timedout) { 2401 error = CFSOP_CHECK_COBJECT(fscp, cp, 0, kcred); 2402 if (CFS_TIMEOUT(fscp, error)) 2403 timedout = 1; 2404 else if ((error == 0) && 2405 ((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0)) { 2406 if (cachefs_vtype_aclok(CTOV(cp)) && 2407 ((cp->c_flags & CN_NOCACHE) == 0)) 2408 (void) cachefs_cacheacl(cp, NULL); 2409 } 2410 } 2411 2412 cp->c_flags |= CN_UPDATED; 2413 mutex_exit(&cp->c_statelock); 2414 VN_RELE(CTOV(cp)); 2415 } 2416 mutex_exit(&cachep->c_mflock); 2417 } 2418 2419 void 2420 cachefs_inum_register(fscache_t *fscp, ino64_t real, ino64_t fake) 2421 { 2422 cachefs_inum_trans_t *tbl; 2423 int toff, thop; 2424 int i; 2425 2426 ASSERT(MUTEX_HELD(&fscp->fs_fslock)); 2427 2428 /* 2429 * first, see if an empty slot exists. 2430 */ 2431 2432 for (i = 0; i < fscp->fs_inum_size; i++) 2433 if (fscp->fs_inum_trans[i].cit_real == 0) 2434 break; 2435 2436 /* 2437 * if there are no empty slots, try to grow the table. 2438 */ 2439 2440 if (i >= fscp->fs_inum_size) { 2441 cachefs_inum_trans_t *oldtbl; 2442 int oldsize, newsize = 0; 2443 2444 /* 2445 * try to fetch a new table size that's bigger than 2446 * our current size 2447 */ 2448 2449 for (i = 0; cachefs_hash_sizes[i] != 0; i++) 2450 if (cachefs_hash_sizes[i] > fscp->fs_inum_size) { 2451 newsize = cachefs_hash_sizes[i]; 2452 break; 2453 } 2454 2455 /* 2456 * if we're out of larger twin-primes, give up. thus, 2457 * the inode numbers in some directory entries might 2458 * change at reconnect, and disagree with what stat() 2459 * says. this isn't worth panicing over, but it does 2460 * merit a warning message. 2461 */ 2462 if (newsize == 0) { 2463 /* only print hash table warning once */ 2464 if ((fscp->fs_flags & CFS_FS_HASHPRINT) == 0) { 2465 cmn_err(CE_WARN, 2466 "cachefs: inode hash table full\n"); 2467 fscp->fs_flags |= CFS_FS_HASHPRINT; 2468 } 2469 return; 2470 } 2471 2472 /* set up this fscp with a new hash table */ 2473 2474 oldtbl = fscp->fs_inum_trans; 2475 oldsize = fscp->fs_inum_size; 2476 fscp->fs_inum_size = newsize; 2477 fscp->fs_inum_trans = (cachefs_inum_trans_t *) 2478 cachefs_kmem_zalloc(sizeof (cachefs_inum_trans_t) * newsize, 2479 KM_SLEEP); 2480 2481 /* 2482 * re-insert all of the old values. this will never 2483 * go more than one level into recursion-land. 2484 */ 2485 2486 for (i = 0; i < oldsize; i++) { 2487 tbl = oldtbl + i; 2488 if (tbl->cit_real != 0) { 2489 cachefs_inum_register(fscp, tbl->cit_real, 2490 tbl->cit_fake); 2491 } else { 2492 ASSERT(0); 2493 } 2494 } 2495 2496 if (oldsize > 0) 2497 cachefs_kmem_free(oldtbl, oldsize * 2498 sizeof (cachefs_inum_trans_t)); 2499 } 2500 2501 /* 2502 * compute values for the hash table. see ken rosen's 2503 * `elementary number theory and its applications' for one 2504 * description of double hashing. 2505 */ 2506 2507 toff = (int)(real % fscp->fs_inum_size); 2508 thop = (int)(real % (fscp->fs_inum_size - 2)) + 1; 2509 2510 /* 2511 * since we know the hash table isn't full when we get here, 2512 * this loop shouldn't terminate except via the `break'. 2513 */ 2514 2515 for (i = 0; i < fscp->fs_inum_size; i++) { 2516 tbl = fscp->fs_inum_trans + toff; 2517 if ((tbl->cit_real == 0) || (tbl->cit_real == real)) { 2518 tbl->cit_real = real; 2519 tbl->cit_fake = fake; 2520 break; 2521 } 2522 2523 toff += thop; 2524 toff %= fscp->fs_inum_size; 2525 } 2526 ASSERT(i < fscp->fs_inum_size); 2527 } 2528 2529 /* 2530 * given an inode number, map it to the inode number that should be 2531 * put in a directory entry before its copied out. 2532 * 2533 * don't call this function unless there is a fscp->fs_inum_trans 2534 * table that has real entries in it! 2535 */ 2536 2537 ino64_t 2538 cachefs_inum_real2fake(fscache_t *fscp, ino64_t real) 2539 { 2540 cachefs_inum_trans_t *tbl; 2541 ino64_t rc = real; 2542 int toff, thop; 2543 int i; 2544 2545 ASSERT(fscp->fs_inum_size > 0); 2546 ASSERT(MUTEX_HELD(&fscp->fs_fslock)); 2547 2548 toff = (int)(real % fscp->fs_inum_size); 2549 thop = (int)(real % (fscp->fs_inum_size - 2)) + 1; 2550 2551 for (i = 0; i < fscp->fs_inum_size; i++) { 2552 tbl = fscp->fs_inum_trans + toff; 2553 2554 if (tbl->cit_real == 0) { 2555 break; 2556 } else if (tbl->cit_real == real) { 2557 rc = tbl->cit_fake; 2558 break; 2559 } 2560 2561 toff += thop; 2562 toff %= fscp->fs_inum_size; 2563 } 2564 2565 return (rc); 2566 } 2567 2568 /* 2569 * Passed a cid, finds the cnode and sets the MD_NEEDATTRS bit 2570 * in the metadata. 2571 */ 2572 static void 2573 cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp) 2574 { 2575 int error; 2576 cnode_t *cp; 2577 2578 error = cachefs_cnode_make(cidp, fscp, 2579 NULL, NULL, NULL, kcred, 0, &cp); 2580 if (error) 2581 return; 2582 2583 mutex_enter(&cp->c_statelock); 2584 cp->c_metadata.md_flags |= MD_NEEDATTRS; 2585 cp->c_flags |= CN_UPDATED; 2586 mutex_exit(&cp->c_statelock); 2587 2588 VN_RELE(CTOV(cp)); 2589 }