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