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 2005 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/file.h> 32 #include <sys/cred.h> 33 #include <sys/proc.h> 34 #include <sys/user.h> 35 #include <sys/vfs.h> 36 #include <sys/vnode.h> 37 #include <sys/pathname.h> 38 #include <sys/uio.h> 39 #include <sys/tiuser.h> 40 #include <sys/sysmacros.h> 41 #include <sys/kmem.h> 42 #include <sys/mount.h> 43 #include <sys/ioctl.h> 44 #include <sys/statvfs.h> 45 #include <sys/errno.h> 46 #include <sys/debug.h> 47 #include <sys/cmn_err.h> 48 #include <sys/utsname.h> 49 #include <sys/modctl.h> 50 #include <sys/stat.h> 51 #include <sys/fcntl.h> 52 #include <sys/fbuf.h> 53 #include <rpc/types.h> 54 55 #include <vm/hat.h> 56 #include <vm/as.h> 57 #include <vm/page.h> 58 #include <vm/pvn.h> 59 #include <vm/seg.h> 60 #include <vm/seg_map.h> 61 #include <vm/seg_vn.h> 62 #include <vm/rm.h> 63 #include <sys/fs/cachefs_fs.h> 64 #include <sys/fs/cachefs_dlog.h> 65 #include <sys/fs/cachefs_ioctl.h> 66 67 /* external references */ 68 extern struct cachefsops nopcfsops, strictcfsops, codcfsops; 69 70 /* forward references */ 71 int fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp); 72 int fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp); 73 static int fscache_info_sync(fscache_t *fscp); 74 75 struct kmem_cache *cachefs_fscache_cache = NULL; 76 77 /* 78 * ------------------------------------------------------------------ 79 * 80 * fscache_create 81 * 82 * Description: 83 * Creates a fscache object. 84 * Arguments: 85 * cachep cache to create fscache object for 86 * Returns: 87 * Returns a fscache object. 88 * Preconditions: 89 * precond(cachep) 90 */ 91 92 fscache_t * 93 fscache_create(cachefscache_t *cachep) 94 { 95 fscache_t *fscp; 96 97 /* create and initialize the fscache object */ 98 fscp = kmem_cache_alloc(cachefs_fscache_cache, KM_SLEEP); 99 100 bzero(fscp, sizeof (*fscp)); 101 102 mutex_init(&fscp->fs_fslock, NULL, MUTEX_DEFAULT, NULL); 103 mutex_init(&fscp->fs_idlelock, NULL, MUTEX_DEFAULT, NULL); 104 mutex_init(&fscp->fs_dlock, NULL, MUTEX_DEFAULT, NULL); 105 mutex_init(&fscp->fs_cdlock, NULL, MUTEX_DEFAULT, NULL); 106 cv_init(&fscp->fs_cdwaitcv, NULL, CV_DEFAULT, NULL); 107 108 fscp->fs_cache = cachep; 109 fscp->fs_info.fi_mntflags = CFS_WRITE_AROUND; 110 fscp->fs_info.fi_popsize = DEF_POP_SIZE; 111 fscp->fs_info.fi_fgsize = DEF_FILEGRP_SIZE; 112 fscp->fs_cfsops = &nopcfsops; 113 fscp->fs_consttype = CFS_FS_CONST_NOCONST; 114 fscp->fs_acregmin = 30; 115 fscp->fs_acregmax = 30; 116 fscp->fs_acdirmin = 30; 117 fscp->fs_acdirmax = 30; 118 fscp->fs_cdconnected = CFS_CD_CONNECTED; 119 fscp->fs_mntpt = NULL; 120 fscp->fs_hostname = NULL; 121 fscp->fs_backfsname = NULL; 122 cachefs_workq_init(&fscp->fs_workq); 123 return (fscp); 124 } 125 126 /* 127 * ------------------------------------------------------------------ 128 * 129 * fscache_destroy 130 * 131 * Description: 132 * Destroys the fscache object. 133 * Arguments: 134 * fscp the fscache object to destroy 135 * Returns: 136 * Preconditions: 137 * precond(fscp) 138 * precond(fs_ref == 0) 139 */ 140 141 void 142 fscache_destroy(fscache_t *fscp) 143 { 144 size_t strl; 145 146 ASSERT(fscp->fs_ref == 0); 147 148 (void) fscache_info_sync(fscp); 149 150 if (fscp->fs_mntpt) { 151 strl = strlen(fscp->fs_mntpt); 152 if (strl != 0) 153 kmem_free(fscp->fs_mntpt, strl + 1); 154 } 155 if (fscp->fs_hostname) { 156 strl = strlen(fscp->fs_hostname); 157 if (strl != 0) 158 kmem_free(fscp->fs_hostname, strl + 1); 159 } 160 if (fscp->fs_backfsname) { 161 strl = strlen(fscp->fs_backfsname); 162 if (strl != 0) 163 kmem_free(fscp->fs_backfsname, strl + 1); 164 } 165 166 /* drop the inum translation table */ 167 if (fscp->fs_inum_size > 0) 168 cachefs_kmem_free(fscp->fs_inum_trans, 169 fscp->fs_inum_size * sizeof (cachefs_inum_trans_t)); 170 171 /* drop references to the fscache directory */ 172 if (fscp->fs_fscdirvp) 173 VN_RELE(fscp->fs_fscdirvp); 174 if (fscp->fs_fsattrdir) 175 VN_RELE(fscp->fs_fsattrdir); 176 if (fscp->fs_infovp) 177 VN_RELE(fscp->fs_infovp); 178 179 /* drop logging references */ 180 cachefs_dlog_teardown(fscp); 181 182 mutex_destroy(&fscp->fs_fslock); 183 mutex_destroy(&fscp->fs_idlelock); 184 mutex_destroy(&fscp->fs_dlock); 185 mutex_destroy(&fscp->fs_cdlock); 186 cv_destroy(&fscp->fs_cdwaitcv); 187 188 kmem_cache_free(cachefs_fscache_cache, fscp); 189 } 190 191 /* 192 * ------------------------------------------------------------------ 193 * 194 * fscache_setup 195 * 196 * Description: 197 * Activates a fscache by associating the fscache object 198 * with on disk data. 199 * If the fscache directory of the specified fsid exists then 200 * it will be used. 201 * Otherwise a new fscache directory will be created using namep 202 * and optp with fsid being ignored. However if namep or optp 203 * are not NULL or the cache is in NOFILL then this routine fails. 204 * Arguments: 205 * fscp the fscache object to activate 206 * fsid unique identifier for the cache 207 * namep name of the cache 208 * optp options for the cache 209 * Returns: 210 * Returns 0 for success, !0 on failure. 211 * Preconditions: 212 * precond(fscp) 213 * precond(the cache must not be in NOCACHE mode) 214 * precond(the cache must not alread by active) 215 */ 216 217 static int 218 fscache_setup(fscache_t *fscp, ino64_t fsid, char *namep, 219 struct cachefsoptions *optp, ino64_t backfileno, int setflags) 220 { 221 int error; 222 cachefscache_t *cachep = fscp->fs_cache; 223 224 ASSERT((cachep->c_flags & CACHE_NOCACHE) == 0); 225 226 /* see if the fscache directory already exists */ 227 error = fscdir_find(cachep, fsid, fscp); 228 if (error) { 229 /* return error if cannot create the directory */ 230 if ((namep == NULL) || (optp == NULL) || 231 (cachep->c_flags & CACHE_NOFILL)) { 232 return (error); 233 } 234 if (backfileno == 0) 235 return (EAGAIN); 236 237 /* remember the root back fileno for disconnected mounts */ 238 fscp->fs_info.fi_root = backfileno; 239 240 /* copy options into the fscache */ 241 fscp->fs_info.fi_mntflags = optp->opt_flags; 242 fscp->fs_info.fi_popsize = optp->opt_popsize; 243 fscp->fs_info.fi_fgsize = optp->opt_fgsize; 244 fscp->fs_flags |= CFS_FS_DIRTYINFO; 245 246 /* create the directory */ 247 error = fscdir_create(cachep, namep, fscp); 248 if (error) { 249 if (error == ENOSPC) 250 cmn_err(CE_WARN, 251 "CacheFS: not enough space to create %s", 252 namep); 253 else 254 cmn_err(CE_WARN, 255 "CacheFS: error %d creating %s", 256 error, namep); 257 return (error); 258 } 259 } else if (optp) { 260 /* compare the options to make sure they are compatable */ 261 error = fscache_compare_options(fscp, optp); 262 if (error) { 263 cmn_err(CE_WARN, 264 "CacheFS: mount failed, options do not match."); 265 return (error); 266 } 267 268 /* copy options into the fscache */ 269 fscp->fs_info.fi_mntflags = optp->opt_flags; 270 fscp->fs_info.fi_popsize = optp->opt_popsize; 271 fscp->fs_info.fi_fgsize = optp->opt_fgsize; 272 fscp->fs_flags |= CFS_FS_DIRTYINFO; 273 274 /* 275 * The fileid of the root of the filesystem can change 276 * in NFSv4, so make sure we update the fi_root 277 * with the new filenumber. 278 */ 279 if (CFS_ISFS_BACKFS_NFSV4(fscp) && 280 fscp->fs_info.fi_root != backfileno) { 281 fscp->fs_info.fi_root = backfileno; 282 } 283 } 284 285 if (setflags) { 286 mutex_enter(&fscp->fs_fslock); 287 fscp->fs_flags |= CFS_FS_READ; 288 if ((cachep->c_flags & CACHE_NOFILL) == 0) 289 fscp->fs_flags |= CFS_FS_WRITE; 290 mutex_exit(&fscp->fs_fslock); 291 } 292 293 return (0); 294 } 295 296 /* 297 * ------------------------------------------------------------------ 298 * 299 * fscache_activate 300 * 301 * Description: 302 * A wrapper routine for fscache_setup, telling it to setup the 303 * fscache for general use. 304 * 305 */ 306 int 307 fscache_activate(fscache_t *fscp, ino64_t fsid, char *namep, 308 struct cachefsoptions *optp, ino64_t backfileno) 309 { 310 return (fscache_setup(fscp, fsid, namep, optp, backfileno, 1)); 311 } 312 313 /* 314 * ------------------------------------------------------------------ 315 * 316 * fscache_enable 317 * 318 * Description: 319 * A wrapper routine for fscache_setup, telling it to create a 320 * fscache that can be used during remount. In this case the 321 * fscache flags that allow general use are not yet turned on. 322 * A later call to fscache_activate_rw will set the flags. 323 * 324 */ 325 int 326 fscache_enable(fscache_t *fscp, ino64_t fsid, char *namep, 327 struct cachefsoptions *optp, ino64_t backfileno) 328 { 329 return (fscache_setup(fscp, fsid, namep, optp, backfileno, 0)); 330 } 331 332 /* 333 * ------------------------------------------------------------------ 334 * 335 * fscache_activate_rw 336 * 337 * Description: 338 * Makes the fscache both readable and writable. 339 * Arguments: 340 * fscp fscache object 341 * Returns: 342 * Preconditions: 343 * precond(fscp) 344 */ 345 346 void 347 fscache_activate_rw(fscache_t *fscp) 348 { 349 mutex_enter(&fscp->fs_fslock); 350 fscp->fs_flags |= (CFS_FS_WRITE|CFS_FS_READ); 351 mutex_exit(&fscp->fs_fslock); 352 } 353 354 /* 355 * ------------------------------------------------------------------ 356 * 357 * fscache_hold 358 * 359 * Description: 360 * Increments the reference count on the fscache object 361 * Arguments: 362 * fscp fscache object to incriment reference count on 363 * Returns: 364 * Preconditions: 365 * precond(fscp) 366 */ 367 368 void 369 fscache_hold(fscache_t *fscp) 370 { 371 mutex_enter(&fscp->fs_fslock); 372 fscp->fs_ref++; 373 ASSERT(fscp->fs_ref > 0); 374 mutex_exit(&fscp->fs_fslock); 375 } 376 377 /* 378 * ------------------------------------------------------------------ 379 * 380 * fscache_rele 381 * 382 * Description: 383 * Decriments the reference count on the fscache object 384 * Arguments: 385 * fscp fscache object to decriment reference count on 386 * Returns: 387 * Preconditions: 388 * precond(fscp) 389 */ 390 391 void 392 fscache_rele(fscache_t *fscp) 393 { 394 mutex_enter(&fscp->fs_fslock); 395 ASSERT(fscp->fs_ref > 0); 396 fscp->fs_ref--; 397 mutex_exit(&fscp->fs_fslock); 398 } 399 400 /* 401 * ------------------------------------------------------------------ 402 * 403 * fscache_cnodecnt 404 * 405 * Description: 406 * Changes the count of number of cnodes on this fscache 407 * by the specified amount. 408 * Arguments: 409 * fscp fscache object to to modify count on 410 * cnt amount to adjust by 411 * Returns: 412 * Returns new count of number of cnodes. 413 * Preconditions: 414 * precond(fscp) 415 */ 416 417 int 418 fscache_cnodecnt(fscache_t *fscp, int cnt) 419 { 420 int xx; 421 422 mutex_enter(&fscp->fs_fslock); 423 fscp->fs_cnodecnt += cnt; 424 ASSERT(fscp->fs_cnodecnt >= 0); 425 xx = fscp->fs_cnodecnt; 426 mutex_exit(&fscp->fs_fslock); 427 return (xx); 428 } 429 430 /* 431 * ------------------------------------------------------------------ 432 * 433 * fscache_mounted 434 * 435 * Description: 436 * Called to indicate the the fscache is mounted. 437 * Arguments: 438 * fscp fscache object 439 * cfsvfsp cachefs vfsp 440 * backvfsp vfsp of back file system 441 * Returns: 442 * Returns 0 for success, -1 if the cache is already mounted. 443 * Preconditions: 444 * precond(fscp) 445 */ 446 447 int 448 fscache_mounted(fscache_t *fscp, struct vfs *cfsvfsp, struct vfs *backvfsp) 449 { 450 int error = 0; 451 452 mutex_enter(&fscp->fs_fslock); 453 if (fscp->fs_flags & CFS_FS_MOUNTED) { 454 error = -1; 455 goto out; 456 } 457 458 fscp->fs_backvfsp = backvfsp; 459 fscp->fs_cfsvfsp = cfsvfsp; 460 gethrestime(&fscp->fs_cod_time); 461 fscp->fs_flags |= CFS_FS_MOUNTED; 462 463 if (CFS_ISFS_SNR(fscp)) { 464 /* 465 * If there is a dlog file present, then we assume the cache 466 * was left in disconnected mode. 467 * Also if the back file system was not mounted we also 468 * start off in disconnected mode. 469 */ 470 error = cachefs_dlog_setup(fscp, 0); 471 if (!error || (backvfsp == NULL)) { 472 mutex_enter(&fscp->fs_cdlock); 473 fscp->fs_cdconnected = CFS_CD_DISCONNECTED; 474 fscp->fs_cdtransition = 0; 475 cv_broadcast(&fscp->fs_cdwaitcv); 476 mutex_exit(&fscp->fs_cdlock); 477 } 478 479 /* invalidate any local fileno mappings */ 480 fscp->fs_info.fi_resetfileno++; 481 fscp->fs_flags |= CFS_FS_DIRTYINFO; 482 483 /* if connected, invalidate any local time mappings */ 484 if (backvfsp) 485 fscp->fs_info.fi_resettimes++; 486 } 487 488 error = 0; 489 490 /* set up the consistency mode */ 491 if (fscp->fs_info.fi_mntflags & CFS_NOCONST_MODE) { 492 fscp->fs_cfsops = &nopcfsops; 493 fscp->fs_consttype = CFS_FS_CONST_NOCONST; 494 } else if (fscp->fs_info.fi_mntflags & CFS_CODCONST_MODE) { 495 fscp->fs_cfsops = &codcfsops; 496 fscp->fs_consttype = CFS_FS_CONST_CODCONST; 497 } else { 498 fscp->fs_cfsops = &strictcfsops; 499 fscp->fs_consttype = CFS_FS_CONST_STRICT; 500 } 501 502 out: 503 mutex_exit(&fscp->fs_fslock); 504 (void) fscache_info_sync(fscp); 505 return (error); 506 } 507 508 /* 509 * Compares fscache state with new mount options 510 * to make sure compatable. 511 * Returns ESRCH if not compatable or 0 for success. 512 */ 513 int 514 fscache_compare_options(fscache_t *fscp, struct cachefsoptions *optp) 515 { 516 if ((fscp->fs_info.fi_popsize == optp->opt_popsize) && 517 (fscp->fs_info.fi_fgsize == optp->opt_fgsize)) { 518 return (0); 519 } else { 520 return (ESRCH); 521 } 522 } 523 524 /* 525 * ------------------------------------------------------------------ 526 * 527 * fscache_sync 528 * 529 * Description: 530 * Syncs any data for this fscache to the front file system. 531 * Arguments: 532 * fscp fscache to sync 533 * Returns: 534 * Preconditions: 535 * precond(fscp) 536 */ 537 538 void 539 fscache_sync(struct fscache *fscp) 540 { 541 struct filegrp *fgp; 542 int xx; 543 544 (void) fscache_info_sync(fscp); 545 546 /* sync the cnodes */ 547 cachefs_cnode_traverse(fscp, cachefs_cnode_sync); 548 549 mutex_enter(&fscp->fs_fslock); 550 551 /* sync the attrcache files */ 552 for (xx = 0; xx < CFS_FS_FGP_BUCKET_SIZE; xx++) { 553 for (fgp = fscp->fs_filegrp[xx]; fgp != NULL; 554 fgp = fgp->fg_next) { 555 (void) filegrp_sync(fgp); 556 } 557 } 558 559 /* garbage collect any unused file groups */ 560 filegrp_list_gc(fscp); 561 562 mutex_exit(&fscp->fs_fslock); 563 } 564 565 /* 566 * ------------------------------------------------------------------ 567 * 568 * fscache_acset 569 * 570 * Description: 571 * Sets the ac timeout values for the fscache. 572 * Arguments: 573 * fscp fscache object 574 * Returns: 575 * Preconditions: 576 * precond(fscp) 577 */ 578 579 void 580 fscache_acset(fscache_t *fscp, 581 uint_t acregmin, uint_t acregmax, uint_t acdirmin, uint_t acdirmax) 582 { 583 mutex_enter(&fscp->fs_fslock); 584 if (acregmin > acregmax) 585 acregmin = acregmax; 586 if (acdirmin > acdirmax) 587 acdirmin = acdirmax; 588 if (acregmin != 0) 589 fscp->fs_acregmin = acregmin; 590 if (acregmax != 0) 591 fscp->fs_acregmax = acregmax; 592 if (acdirmin != 0) 593 fscp->fs_acdirmin = acdirmin; 594 if (acdirmax != 0) 595 fscp->fs_acdirmax = acdirmax; 596 mutex_exit(&fscp->fs_fslock); 597 } 598 599 /* 600 * ------------------------------------------------------------------ 601 * 602 * fscache_list_find 603 * 604 * Description: 605 * Finds the desired fscache structure on a cache's 606 * file system list. 607 * Arguments: 608 * cachep holds the list of fscache objects to search 609 * fsid the numeric identifier of the fscache 610 * Returns: 611 * Returns an fscache object on success or NULL on failure. 612 * Preconditions: 613 * precond(cachep) 614 * precond(the fslistlock must be held) 615 */ 616 617 fscache_t * 618 fscache_list_find(cachefscache_t *cachep, ino64_t fsid) 619 { 620 fscache_t *fscp = cachep->c_fslist; 621 622 ASSERT(MUTEX_HELD(&cachep->c_fslistlock)); 623 624 while (fscp != NULL) { 625 if (fscp->fs_cfsid == fsid) { 626 ASSERT(fscp->fs_cache == cachep); 627 break; 628 } 629 fscp = fscp->fs_next; 630 } 631 632 return (fscp); 633 } 634 635 /* 636 * ------------------------------------------------------------------ 637 * 638 * fscache_list_add 639 * 640 * Description: 641 * Adds the specified fscache object to the list on 642 * the specified cachep. 643 * Arguments: 644 * cachep holds the list of fscache objects 645 * fscp fscache object to add to list 646 * Returns: 647 * Preconditions: 648 * precond(cachep) 649 * precond(fscp) 650 * precond(fscp cannot already be on a list) 651 * precond(the fslistlock must be held) 652 */ 653 654 void 655 fscache_list_add(cachefscache_t *cachep, fscache_t *fscp) 656 { 657 ASSERT(MUTEX_HELD(&cachep->c_fslistlock)); 658 659 fscp->fs_next = cachep->c_fslist; 660 cachep->c_fslist = fscp; 661 cachep->c_refcnt++; 662 } 663 664 /* 665 * ------------------------------------------------------------------ 666 * 667 * fscache_list_remove 668 * 669 * Description: 670 * Removes the specified fscache object from the list 671 * on the specified cachep. 672 * Arguments: 673 * cachep holds the list of fscache objects 674 * fscp fscache object to remove from list 675 * Returns: 676 * Preconditions: 677 * precond(cachep) 678 * precond(fscp) 679 * precond(the fslistlock must be held) 680 */ 681 682 void 683 fscache_list_remove(cachefscache_t *cachep, fscache_t *fscp) 684 { 685 struct fscache **pfscp = &cachep->c_fslist; 686 687 ASSERT(MUTEX_HELD(&cachep->c_fslistlock)); 688 689 while (*pfscp != NULL) { 690 if (fscp == *pfscp) { 691 *pfscp = fscp->fs_next; 692 cachep->c_refcnt--; 693 break; 694 } 695 pfscp = &(*pfscp)->fs_next; 696 } 697 } 698 699 /* 700 * ------------------------------------------------------------------ 701 * 702 * fscache_list_gc 703 * 704 * Description: 705 * Traverses the list of fscache objects on the cachep 706 * list and destroys any that are not mounted and 707 * that are not referenced. 708 * Arguments: 709 * cachep holds the list of fscache objects 710 * Returns: 711 * Preconditions: 712 * precond(cachep) 713 * precond(the fslistlock must be held) 714 */ 715 716 void 717 fscache_list_gc(cachefscache_t *cachep) 718 { 719 struct fscache *next, *fscp; 720 721 ASSERT(MUTEX_HELD(&cachep->c_fslistlock)); 722 723 for (fscp = cachep->c_fslist; fscp != NULL; fscp = next) { 724 next = fscp->fs_next; 725 mutex_enter(&fscp->fs_fslock); 726 if (((fscp->fs_flags & CFS_FS_MOUNTED) == 0) && 727 (fscp->fs_ref == 0)) { 728 mutex_exit(&fscp->fs_fslock); 729 fscache_list_remove(cachep, fscp); 730 fscache_destroy(fscp); 731 } else { 732 mutex_exit(&fscp->fs_fslock); 733 } 734 } 735 } 736 737 /* 738 * ------------------------------------------------------------------ 739 * 740 * fscache_list_mounted 741 * 742 * Description: 743 * Returns the number of fscache objects that are mounted. 744 * Arguments: 745 * cachep holds the list of fscache objects 746 * Returns: 747 * Preconditions: 748 * precond(cachep) 749 * precond(the fslistlock must be held) 750 */ 751 752 int 753 fscache_list_mounted(cachefscache_t *cachep) 754 { 755 struct fscache *fscp; 756 int count; 757 758 ASSERT(MUTEX_HELD(&cachep->c_fslistlock)); 759 760 count = 0; 761 for (fscp = cachep->c_fslist; fscp != NULL; fscp = fscp->fs_next) { 762 mutex_enter(&fscp->fs_fslock); 763 if (fscp->fs_flags & CFS_FS_MOUNTED) 764 count++; 765 mutex_exit(&fscp->fs_fslock); 766 } 767 768 return (count); 769 } 770 771 /* 772 * Creates the fs cache directory. 773 * The directory name is the ascii version of the fsid. 774 * Also makes a symlink to the directory using the specified name. 775 */ 776 int 777 fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp) 778 { 779 int error; 780 vnode_t *fscdirvp = NULL; 781 vnode_t *infovp = NULL; 782 vnode_t *attrvp = NULL; 783 struct vattr *attrp = (struct vattr *)NULL; 784 char name[CFS_FRONTFILE_NAME_SIZE]; 785 int files; 786 int blocks = 0; 787 cfs_cid_t cid; 788 ino64_t fsid; 789 790 ASSERT(MUTEX_HELD(&cachep->c_fslistlock)); 791 ASSERT(fscp->fs_infovp == NULL); 792 ASSERT(fscp->fs_fscdirvp == NULL); 793 ASSERT(fscp->fs_fsattrdir == NULL); 794 795 /* directory, symlink and options file + attrcache dir */ 796 files = 0; 797 while (files < 4) { 798 error = cachefs_allocfile(cachep); 799 if (error) 800 goto out; 801 files++; 802 } 803 error = cachefs_allocblocks(cachep, 4, CACHEFS_RL_NONE); 804 if (error) 805 goto out; 806 blocks = 4; 807 808 attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP); 809 attrp->va_mode = S_IFDIR | 0777; 810 attrp->va_uid = 0; 811 attrp->va_gid = 0; 812 attrp->va_type = VDIR; 813 attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 814 error = VOP_MKDIR(cachep->c_dirvp, namep, attrp, &fscdirvp, kcred); 815 if (error) { 816 cmn_err(CE_WARN, "Can't create fs cache directory"); 817 goto out; 818 } 819 820 /* 821 * Created the directory. Get the fileno. That'll be the cachefs_fsid. 822 */ 823 attrp->va_mask = AT_NODEID; 824 error = VOP_GETATTR(fscdirvp, attrp, 0, kcred); 825 if (error) { 826 goto out; 827 } 828 fsid = attrp->va_nodeid; 829 attrp->va_mode = S_IFREG | 0666; 830 attrp->va_uid = 0; 831 attrp->va_gid = 0; 832 attrp->va_type = VREG; 833 attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 834 error = VOP_CREATE(fscdirvp, CACHEFS_FSINFO, attrp, EXCL, 835 0600, &infovp, kcred, 0); 836 if (error) { 837 cmn_err(CE_WARN, "Can't create fs option file"); 838 goto out; 839 } 840 attrp->va_size = MAXBSIZE; 841 attrp->va_mask = AT_SIZE; 842 error = VOP_SETATTR(infovp, attrp, 0, kcred, NULL); 843 if (error) { 844 cmn_err(CE_WARN, "Can't set size of fsinfo file"); 845 goto out; 846 } 847 848 /* write out the info file */ 849 fscp->fs_flags |= CFS_FS_DIRTYINFO; 850 error = fscache_info_sync(fscp); 851 if (error) 852 goto out; 853 854 /* 855 * Install the symlink from cachefs_fsid -> directory. 856 */ 857 cid.cid_flags = 0; 858 cid.cid_fileno = fsid; 859 make_ascii_name(&cid, name); 860 error = VOP_RENAME(cachep->c_dirvp, namep, cachep->c_dirvp, 861 name, kcred); 862 if (error) { 863 cmn_err(CE_WARN, "Can't rename cache directory"); 864 goto out; 865 } 866 attrp->va_mask = AT_MODE | AT_TYPE; 867 attrp->va_mode = 0777; 868 attrp->va_type = VLNK; 869 error = VOP_SYMLINK(cachep->c_dirvp, namep, attrp, name, kcred); 870 if (error) { 871 cmn_err(CE_WARN, "Can't create cache directory symlink"); 872 goto out; 873 } 874 875 /* 876 * Finally, make the attrcache directory 877 */ 878 attrp->va_mode = S_IFDIR | 0777; 879 attrp->va_uid = 0; 880 attrp->va_gid = 0; 881 attrp->va_type = VDIR; 882 attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 883 error = VOP_MKDIR(fscdirvp, ATTRCACHE_NAME, attrp, &attrvp, kcred); 884 if (error) { 885 cmn_err(CE_WARN, "Can't create attrcache dir for fscache"); 886 goto out; 887 } 888 889 mutex_enter(&fscp->fs_fslock); 890 fscp->fs_cfsid = fsid; 891 fscp->fs_fscdirvp = fscdirvp; 892 fscp->fs_fsattrdir = attrvp; 893 fscp->fs_infovp = infovp; 894 mutex_exit(&fscp->fs_fslock); 895 896 out: 897 898 if (error) { 899 while (files-- > 0) 900 cachefs_freefile(cachep); 901 if (fscdirvp) 902 VN_RELE(fscdirvp); 903 if (blocks) 904 cachefs_freeblocks(cachep, blocks, CACHEFS_RL_NONE); 905 if (attrvp) 906 VN_RELE(attrvp); 907 if (infovp) 908 VN_RELE(infovp); 909 } 910 if (attrp) 911 cachefs_kmem_free(attrp, sizeof (struct vattr)); 912 return (error); 913 } 914 915 /* 916 * Tries to find the fscache directory indicated by fsid. 917 */ 918 int 919 fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp) 920 { 921 int error; 922 vnode_t *infovp = NULL; 923 vnode_t *fscdirvp = NULL; 924 vnode_t *attrvp = NULL; 925 char dirname[CFS_FRONTFILE_NAME_SIZE]; 926 cfs_cid_t cid; 927 cachefs_fsinfo_t fsinfo; 928 caddr_t addr; 929 930 ASSERT(MUTEX_HELD(&cachep->c_fslistlock)); 931 ASSERT(fscp->fs_infovp == NULL); 932 ASSERT(fscp->fs_fscdirvp == NULL); 933 ASSERT(fscp->fs_fsattrdir == NULL); 934 935 /* convert the fsid value to the name of the directory */ 936 cid.cid_flags = 0; 937 cid.cid_fileno = fsid; 938 make_ascii_name(&cid, dirname); 939 940 /* try to find the directory */ 941 error = VOP_LOOKUP(cachep->c_dirvp, dirname, &fscdirvp, NULL, 942 0, NULL, kcred); 943 if (error) 944 goto out; 945 946 /* this better be a directory or we are hosed */ 947 if (fscdirvp->v_type != VDIR) { 948 cmn_err(CE_WARN, "cachefs: fscdir_find_a: cache corruption" 949 " run fsck, %s", dirname); 950 error = ENOTDIR; 951 goto out; 952 } 953 954 /* try to find the info file */ 955 error = VOP_LOOKUP(fscdirvp, CACHEFS_FSINFO, &infovp, 956 NULL, 0, NULL, kcred); 957 if (error) { 958 cmn_err(CE_WARN, "cachefs: fscdir_find_b: cache corruption" 959 " run fsck, %s", dirname); 960 goto out; 961 } 962 963 /* read in info struct */ 964 addr = segmap_getmapflt(segkmap, infovp, (offset_t)0, 965 MAXBSIZE, 1, S_READ); 966 967 /*LINTED alignment okay*/ 968 fsinfo = *(cachefs_fsinfo_t *)addr; 969 error = segmap_release(segkmap, addr, 0); 970 if (error) { 971 cmn_err(CE_WARN, "cachefs: fscdir_find_c: cache corruption" 972 " run fsck, %s", dirname); 973 goto out; 974 } 975 976 /* try to find the attrcache directory */ 977 error = VOP_LOOKUP(fscdirvp, ATTRCACHE_NAME, 978 &attrvp, NULL, 0, NULL, kcred); 979 if (error) { 980 cmn_err(CE_WARN, "cachefs: fscdir_find_d: cache corruption" 981 " run fsck, %s", dirname); 982 goto out; 983 } 984 985 mutex_enter(&fscp->fs_fslock); 986 fscp->fs_info = fsinfo; 987 fscp->fs_cfsid = fsid; 988 fscp->fs_fscdirvp = fscdirvp; 989 fscp->fs_fsattrdir = attrvp; 990 fscp->fs_infovp = infovp; 991 mutex_exit(&fscp->fs_fslock); 992 993 out: 994 if (error) { 995 if (infovp) 996 VN_RELE(infovp); 997 if (fscdirvp) 998 VN_RELE(fscdirvp); 999 } 1000 return (error); 1001 } 1002 1003 /* 1004 * fscache_info_sync 1005 * Writes out the fs_info data if necessary. 1006 */ 1007 static int 1008 fscache_info_sync(fscache_t *fscp) 1009 { 1010 caddr_t addr; 1011 int error = 0; 1012 1013 mutex_enter(&fscp->fs_fslock); 1014 1015 if (fscp->fs_cache->c_flags & CACHE_NOFILL) { 1016 error = EROFS; 1017 goto out; 1018 } 1019 1020 /* if the data is dirty and we have the file vnode */ 1021 if ((fscp->fs_flags & CFS_FS_DIRTYINFO) && fscp->fs_infovp) { 1022 addr = segmap_getmapflt(segkmap, fscp->fs_infovp, 0, 1023 MAXBSIZE, 1, S_WRITE); 1024 1025 /*LINTED alignment okay*/ 1026 *(cachefs_fsinfo_t *)addr = fscp->fs_info; 1027 error = segmap_release(segkmap, addr, SM_WRITE); 1028 1029 if (error) { 1030 cmn_err(CE_WARN, 1031 "cachefs: Can not write to info file."); 1032 } else { 1033 fscp->fs_flags &= ~CFS_FS_DIRTYINFO; 1034 } 1035 } 1036 1037 out: 1038 1039 mutex_exit(&fscp->fs_fslock); 1040 1041 return (error); 1042 } 1043 1044 /* 1045 * ------------------------------------------------------------------ 1046 * 1047 * fscache_name_to_fsid 1048 * 1049 * Description: 1050 * Takes the name of a cache and determines it corresponding 1051 * fsid. 1052 * Arguments: 1053 * cachep cache object to find name of fs cache in 1054 * namep the name of the fs cache 1055 * fsidp set to the fsid if found 1056 * Returns: 1057 * Returns 0 on success, !0 on error. 1058 * Preconditions: 1059 * precond(cachep) 1060 * precond(namep) 1061 * precond(fsidp) 1062 */ 1063 1064 int 1065 fscache_name_to_fsid(cachefscache_t *cachep, char *namep, ino64_t *fsidp) 1066 { 1067 int error; 1068 char dirname[CFS_FRONTFILE_NAME_SIZE]; 1069 vnode_t *linkvp = NULL; 1070 struct uio uio; 1071 struct iovec iov; 1072 ino64_t nodeid; 1073 char *pd; 1074 int xx; 1075 int c; 1076 1077 /* get the vnode of the name */ 1078 error = VOP_LOOKUP(cachep->c_dirvp, namep, &linkvp, NULL, 0, NULL, 1079 kcred); 1080 if (error) 1081 goto out; 1082 1083 /* the vnode had better be a link */ 1084 if (linkvp->v_type != VLNK) { 1085 error = EINVAL; 1086 goto out; 1087 } 1088 1089 /* read the contents of the link */ 1090 iov.iov_len = CFS_FRONTFILE_NAME_SIZE; 1091 iov.iov_base = dirname; 1092 uio.uio_iov = &iov; 1093 uio.uio_iovcnt = 1; 1094 uio.uio_resid = iov.iov_len; 1095 uio.uio_segflg = UIO_SYSSPACE; 1096 uio.uio_loffset = 0; 1097 uio.uio_fmode = 0; 1098 uio.uio_extflg = UIO_COPY_CACHED; 1099 error = VOP_READLINK(linkvp, &uio, kcred); 1100 if (error) { 1101 cmn_err(CE_WARN, "cachefs: Can't read filesystem cache link"); 1102 goto out; 1103 } 1104 1105 /* convert the contents of the link to a ino64_t */ 1106 nodeid = 0; 1107 pd = dirname; 1108 for (xx = 0; xx < (CFS_FRONTFILE_NAME_SIZE - 2); xx++) { 1109 nodeid <<= 4; 1110 c = *pd++; 1111 if (c <= '9') 1112 c -= '0'; 1113 else if (c <= 'F') 1114 c = c - 'A' + 10; 1115 else 1116 c = c - 'a' + 10; 1117 nodeid += c; 1118 } 1119 *fsidp = nodeid; 1120 out: 1121 if (linkvp) 1122 VN_RELE(linkvp); 1123 1124 return (error); 1125 } 1126 1127 1128 /* 1129 * Suspends the thread until access to the cache is granted. 1130 * If !SOFT then 1131 * waitconnected == 1 means wait until connected 1132 * waitconnected == 0 means wait until connected or disconnected 1133 * else then 1134 * wait until connected or disconnected 1135 * writing is set to 1 if writing, 0 if reading 1136 * Returns 0, EINTR, or ETIMEDOUT. 1137 */ 1138 int 1139 cachefs_cd_access(fscache_t *fscp, int waitconnected, int writing) 1140 { 1141 int nosig; 1142 int error = 0; 1143 cachefscache_t *cachep; 1144 int waithappens = 0; 1145 pid_t pid; 1146 1147 mutex_enter(&fscp->fs_cdlock); 1148 1149 #ifdef CFS_CD_DEBUG 1150 ASSERT((curthread->t_flag & T_CD_HELD) == 0); 1151 #endif 1152 1153 for (;;) { 1154 /* if we have to wait */ 1155 if (waithappens || 1156 (waitconnected && 1157 (fscp->fs_cdconnected != CFS_CD_CONNECTED))) { 1158 1159 /* do not make soft mounts wait until connected */ 1160 if ((waithappens == 0) && CFS_ISFS_SOFT(fscp)) { 1161 error = ETIMEDOUT; 1162 break; 1163 } 1164 1165 /* wait for a wakeup or a signal */ 1166 nosig = cv_wait_sig(&fscp->fs_cdwaitcv, 1167 &fscp->fs_cdlock); 1168 1169 /* if we got a signal */ 1170 if (nosig == 0) { 1171 error = EINTR; 1172 break; 1173 } 1174 1175 if (waitconnected && 1176 (fscp->fs_cdconnected == CFS_CD_CONNECTED)) 1177 waitconnected = 0; 1178 1179 /* try again to get access */ 1180 waithappens = 0; 1181 continue; 1182 } 1183 1184 /* if transitioning modes */ 1185 if (fscp->fs_cdtransition) { 1186 waithappens = 1; 1187 continue; 1188 } 1189 1190 /* if rolling the log */ 1191 if (fscp->fs_cdconnected == CFS_CD_RECONNECTING) { 1192 pid = ttoproc(curthread)->p_pid; 1193 cachep = fscp->fs_cache; 1194 1195 /* if writing or not the cachefsd */ 1196 if (writing || 1197 ((fscp->fs_cddaemonid != pid) && 1198 (cachep->c_rootdaemonid != pid))) { 1199 waithappens = 1; 1200 continue; 1201 } 1202 } 1203 1204 /* if the daemon is not running */ 1205 if (fscp->fs_cddaemonid == 0) { 1206 /* if writing and not connected */ 1207 if (writing && 1208 (fscp->fs_cdconnected != CFS_CD_CONNECTED)) { 1209 waithappens = 1; 1210 continue; 1211 } 1212 } 1213 1214 /* 1215 * Verify don't set wait for NFSv4 (doesn't support 1216 * disconnected behavior). 1217 */ 1218 ASSERT(!CFS_ISFS_BACKFS_NFSV4(fscp) || 1219 (waithappens == 0 && waitconnected == 0)); 1220 1221 ASSERT(fscp->fs_cdrefcnt >= 0); 1222 fscp->fs_cdrefcnt++; 1223 #ifdef CFS_CD_DEBUG 1224 curthread->t_flag |= T_CD_HELD; 1225 #endif 1226 break; 1227 } 1228 mutex_exit(&fscp->fs_cdlock); 1229 1230 return (error); 1231 } 1232 1233 /* 1234 * Call to check if can have access after a cache miss has occurred. 1235 * Only read access is allowed, do not call this routine if want 1236 * to write. 1237 * Returns 1 if yes, 0 if no. 1238 */ 1239 int 1240 cachefs_cd_access_miss(fscache_t *fscp) 1241 { 1242 cachefscache_t *cachep; 1243 pid_t pid; 1244 1245 #ifdef CFS_CD_DEBUG 1246 ASSERT(curthread->t_flag & T_CD_HELD); 1247 #endif 1248 1249 /* should not get called if connected */ 1250 ASSERT(fscp->fs_cdconnected != CFS_CD_CONNECTED); 1251 1252 /* if no back file system, then no */ 1253 if (fscp->fs_backvfsp == NULL) 1254 return (0); 1255 1256 /* if daemon is not running, then yes */ 1257 if (fscp->fs_cddaemonid == 0) { 1258 return (1); 1259 } 1260 1261 pid = ttoproc(curthread)->p_pid; 1262 cachep = fscp->fs_cache; 1263 1264 /* if daemon is running, only daemon is allowed to have access */ 1265 if ((fscp->fs_cddaemonid != pid) && 1266 (cachep->c_rootdaemonid != pid)) { 1267 return (0); 1268 } 1269 1270 return (1); 1271 } 1272 1273 /* 1274 * Releases an access to the file system. 1275 */ 1276 void 1277 cachefs_cd_release(fscache_t *fscp) 1278 { 1279 mutex_enter(&fscp->fs_cdlock); 1280 1281 #ifdef CFS_CD_DEBUG 1282 ASSERT(curthread->t_flag & T_CD_HELD); 1283 curthread->t_flag &= ~T_CD_HELD; 1284 #endif 1285 /* decriment hold on file system */ 1286 fscp->fs_cdrefcnt--; 1287 ASSERT(fscp->fs_cdrefcnt >= 0); 1288 1289 /* Verify no connected state transitions for NFSv4 */ 1290 ASSERT(!CFS_ISFS_BACKFS_NFSV4(fscp) || fscp->fs_cdtransition == 0); 1291 1292 /* wake up cachefsd */ 1293 if ((fscp->fs_cdrefcnt == 0) && fscp->fs_cdtransition) 1294 cv_broadcast(&fscp->fs_cdwaitcv); 1295 1296 mutex_exit(&fscp->fs_cdlock); 1297 } 1298 1299 /* 1300 * Called when a network timeout error has occurred. 1301 * If connected, switches state to disconnected. 1302 */ 1303 void 1304 cachefs_cd_timedout(fscache_t *fscp) 1305 { 1306 int state; 1307 1308 /* nothing to do if not snr or not connected */ 1309 if (!CFS_ISFS_SNR(fscp) || (fscp->fs_cdconnected != CFS_CD_CONNECTED)) 1310 return; 1311 1312 #ifdef CFS_CD_DEBUG 1313 ASSERT((curthread->t_flag & T_CD_HELD) == 0); 1314 #endif 1315 1316 /* Verify no state changes done for NFSv4 */ 1317 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1318 1319 state = CFS_FS_DISCONNECTED; 1320 (void) cachefs_io_stateset(fscp->fs_rootvp, &state, NULL); 1321 } 1322