1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/types.h> 28 #include <sys/systm.h> 29 #include <sys/cred.h> 30 #include <sys/proc.h> 31 #include <sys/user.h> 32 #include <sys/vfs.h> 33 #include <sys/vnode.h> 34 #include <sys/pathname.h> 35 #include <sys/uio.h> 36 #include <sys/tiuser.h> 37 #include <sys/sysmacros.h> 38 #include <sys/kmem.h> 39 #include <sys/mount.h> 40 #include <sys/ioctl.h> 41 #include <sys/statvfs.h> 42 #include <sys/errno.h> 43 #include <sys/debug.h> 44 #include <sys/cmn_err.h> 45 #include <sys/utsname.h> 46 #include <sys/modctl.h> 47 #include <sys/file.h> 48 #include <sys/stat.h> 49 #include <sys/fcntl.h> 50 #include <sys/fbuf.h> 51 #include <sys/dnlc.h> 52 #include <sys/callb.h> 53 #include <sys/kobj.h> 54 #include <sys/rwlock.h> 55 56 #include <sys/vmsystm.h> 57 #include <vm/hat.h> 58 #include <vm/as.h> 59 #include <vm/page.h> 60 #include <vm/pvn.h> 61 #include <vm/seg.h> 62 #include <vm/seg_map.h> 63 #include <vm/seg_vn.h> 64 #include <vm/rm.h> 65 #include <sys/fs/cachefs_fs.h> 66 #include <sys/fs/cachefs_log.h> 67 #include <sys/fs/cachefs_dir.h> 68 69 extern struct seg *segkmap; 70 caddr_t segmap_getmap(); 71 int segmap_release(); 72 73 extern struct cnode *cachefs_freeback; 74 extern struct cnode *cachefs_freefront; 75 extern cachefscache_t *cachefs_cachelist; 76 77 #ifdef CFSDEBUG 78 int cachefsdebug = 0; 79 #endif 80 81 int cachefs_max_threads = CFS_MAX_THREADS; 82 ino64_t cachefs_check_fileno = 0; 83 struct kmem_cache *cachefs_cache_kmcache = NULL; 84 struct kmem_cache *cachefs_req_cache = NULL; 85 86 static int 87 cachefs_async_populate_reg(struct cachefs_populate_req *, cred_t *, 88 vnode_t *, vnode_t *); 89 90 /* 91 * Cache routines 92 */ 93 94 /* 95 * ------------------------------------------------------------------ 96 * 97 * cachefs_cache_create 98 * 99 * Description: 100 * Creates a cachefscache_t object and initializes it to 101 * be NOCACHE and NOFILL mode. 102 * Arguments: 103 * Returns: 104 * Returns a pointer to the created object or NULL if 105 * threads could not be created. 106 * Preconditions: 107 */ 108 109 cachefscache_t * 110 cachefs_cache_create(void) 111 { 112 cachefscache_t *cachep; 113 struct cachefs_req *rp; 114 115 /* allocate zeroed memory for the object */ 116 cachep = kmem_cache_alloc(cachefs_cache_kmcache, KM_SLEEP); 117 118 bzero(cachep, sizeof (*cachep)); 119 120 cv_init(&cachep->c_cwcv, NULL, CV_DEFAULT, NULL); 121 cv_init(&cachep->c_cwhaltcv, NULL, CV_DEFAULT, NULL); 122 mutex_init(&cachep->c_contentslock, NULL, MUTEX_DEFAULT, NULL); 123 mutex_init(&cachep->c_fslistlock, NULL, MUTEX_DEFAULT, NULL); 124 mutex_init(&cachep->c_log_mutex, NULL, MUTEX_DEFAULT, NULL); 125 126 /* set up the work queue and get the sync thread created */ 127 cachefs_workq_init(&cachep->c_workq); 128 cachep->c_workq.wq_keepone = 1; 129 cachep->c_workq.wq_cachep = cachep; 130 rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP); 131 rp->cfs_cmd = CFS_NOOP; 132 rp->cfs_cr = kcred; 133 rp->cfs_req_u.cu_fs_sync.cf_cachep = cachep; 134 crhold(rp->cfs_cr); 135 cachefs_addqueue(rp, &cachep->c_workq); 136 cachep->c_flags |= CACHE_NOCACHE | CACHE_NOFILL | CACHE_ALLOC_PENDING; 137 138 return (cachep); 139 } 140 141 /* 142 * ------------------------------------------------------------------ 143 * 144 * cachefs_cache_destroy 145 * 146 * Description: 147 * Destroys the cachefscache_t object. 148 * Arguments: 149 * cachep the cachefscache_t object to destroy 150 * Returns: 151 * Preconditions: 152 * precond(cachep) 153 */ 154 155 void 156 cachefs_cache_destroy(cachefscache_t *cachep) 157 { 158 int error = 0; 159 #ifdef CFSRLDEBUG 160 uint_t index; 161 #endif /* CFSRLDEBUG */ 162 clock_t wakeup = (60 * hz); 163 164 /* stop async threads */ 165 while (cachep->c_workq.wq_thread_count > 0) 166 (void) cachefs_async_halt(&cachep->c_workq, 1); 167 168 /* kill off the cachep worker thread */ 169 mutex_enter(&cachep->c_contentslock); 170 while (cachep->c_flags & CACHE_CACHEW_THREADRUN) { 171 cachep->c_flags |= CACHE_CACHEW_THREADEXIT; 172 cv_signal(&cachep->c_cwcv); 173 (void) cv_reltimedwait(&cachep->c_cwhaltcv, 174 &cachep->c_contentslock, wakeup, TR_CLOCK_TICK); 175 } 176 177 if ((cachep->c_flags & CACHE_ALLOC_PENDING) == 0) { 178 cachep->c_usage.cu_flags &= ~CUSAGE_ACTIVE; 179 (void) cachefs_cache_rssync(cachep); 180 } 181 mutex_exit(&cachep->c_contentslock); 182 183 /* if there is a cache */ 184 if ((cachep->c_flags & CACHE_NOCACHE) == 0) { 185 if ((cachep->c_flags & CACHE_NOFILL) == 0) { 186 #ifdef CFSRLDEBUG 187 /* blow away dangling rl debugging info */ 188 mutex_enter(&cachep->c_contentslock); 189 for (index = 0; 190 index <= cachep->c_rlinfo.rl_entries; 191 index++) { 192 rl_entry_t *rlent; 193 194 error = cachefs_rl_entry_get(cachep, index, 195 rlent); 196 /* 197 * Since we are destroying the cache, 198 * better to ignore and proceed 199 */ 200 if (error) 201 break; 202 cachefs_rl_debug_destroy(rlent); 203 } 204 mutex_exit(&cachep->c_contentslock); 205 #endif /* CFSRLDEBUG */ 206 207 /* sync the cache */ 208 if (!error) 209 cachefs_cache_sync(cachep); 210 } else { 211 /* get rid of any unused fscache objects */ 212 mutex_enter(&cachep->c_fslistlock); 213 fscache_list_gc(cachep); 214 mutex_exit(&cachep->c_fslistlock); 215 } 216 ASSERT(cachep->c_fslist == NULL); 217 218 VN_RELE(cachep->c_resfilevp); 219 VN_RELE(cachep->c_dirvp); 220 VN_RELE(cachep->c_lockvp); 221 VN_RELE(cachep->c_lostfoundvp); 222 } 223 224 if (cachep->c_log_ctl != NULL) 225 cachefs_kmem_free(cachep->c_log_ctl, 226 sizeof (cachefs_log_control_t)); 227 if (cachep->c_log != NULL) 228 cachefs_log_destroy_cookie(cachep->c_log); 229 230 cv_destroy(&cachep->c_cwcv); 231 cv_destroy(&cachep->c_cwhaltcv); 232 mutex_destroy(&cachep->c_contentslock); 233 mutex_destroy(&cachep->c_fslistlock); 234 mutex_destroy(&cachep->c_log_mutex); 235 236 kmem_cache_free(cachefs_cache_kmcache, cachep); 237 } 238 239 /* 240 * ------------------------------------------------------------------ 241 * 242 * cachefs_cache_active_ro 243 * 244 * Description: 245 * Activates the cachefscache_t object for a read-only file system. 246 * Arguments: 247 * cachep the cachefscache_t object to activate 248 * cdvp the vnode of the cache directory 249 * Returns: 250 * Returns 0 for success, !0 if there is a problem with the cache. 251 * Preconditions: 252 * precond(cachep) 253 * precond(cdvp) 254 * precond(cachep->c_flags & CACHE_NOCACHE) 255 */ 256 257 int 258 cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp) 259 { 260 cachefs_log_control_t *lc; 261 vnode_t *labelvp = NULL; 262 vnode_t *rifvp = NULL; 263 vnode_t *lockvp = NULL; 264 vnode_t *statevp = NULL; 265 vnode_t *lostfoundvp = NULL; 266 struct vattr *attrp = NULL; 267 int error; 268 269 ASSERT(cachep->c_flags & CACHE_NOCACHE); 270 mutex_enter(&cachep->c_contentslock); 271 272 attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP); 273 274 /* get the mode bits of the cache directory */ 275 attrp->va_mask = AT_ALL; 276 error = VOP_GETATTR(cdvp, attrp, 0, kcred, NULL); 277 if (error) 278 goto out; 279 280 /* ensure the mode bits are 000 to keep out casual users */ 281 if (attrp->va_mode & S_IAMB) { 282 cmn_err(CE_WARN, "cachefs: Cache Directory Mode must be 000\n"); 283 error = EPERM; 284 goto out; 285 } 286 287 /* Get the lock file */ 288 error = VOP_LOOKUP(cdvp, CACHEFS_LOCK_FILE, &lockvp, NULL, 0, NULL, 289 kcred, NULL, NULL, NULL); 290 if (error) { 291 cmn_err(CE_WARN, "cachefs: activate_a: cache corruption" 292 " run fsck.\n"); 293 goto out; 294 } 295 296 /* Get the label file */ 297 error = VOP_LOOKUP(cdvp, CACHELABEL_NAME, &labelvp, NULL, 0, NULL, 298 kcred, NULL, NULL, NULL); 299 if (error) { 300 cmn_err(CE_WARN, "cachefs: activate_b: cache corruption" 301 " run fsck.\n"); 302 goto out; 303 } 304 305 /* read in the label */ 306 error = vn_rdwr(UIO_READ, labelvp, (caddr_t)&cachep->c_label, 307 sizeof (struct cache_label), 0LL, UIO_SYSSPACE, 308 0, (rlim64_t)0, kcred, NULL); 309 if (error) { 310 cmn_err(CE_WARN, "cachefs: activate_c: cache corruption" 311 " run fsck.\n"); 312 goto out; 313 } 314 315 /* Verify that we can handle the version this cache was created under */ 316 if (cachep->c_label.cl_cfsversion != CFSVERSION) { 317 cmn_err(CE_WARN, "cachefs: Invalid Cache Version, run fsck\n"); 318 error = EINVAL; 319 goto out; 320 } 321 322 /* Open the resource file */ 323 error = VOP_LOOKUP(cdvp, RESOURCE_NAME, &rifvp, NULL, 0, NULL, kcred, 324 NULL, NULL, NULL); 325 if (error) { 326 cmn_err(CE_WARN, "cachefs: activate_d: cache corruption" 327 " run fsck.\n"); 328 goto out; 329 } 330 331 /* Read the usage struct for this cache */ 332 error = vn_rdwr(UIO_READ, rifvp, (caddr_t)&cachep->c_usage, 333 sizeof (struct cache_usage), 0LL, UIO_SYSSPACE, 0, 334 (rlim64_t)0, kcred, NULL); 335 if (error) { 336 cmn_err(CE_WARN, "cachefs: activate_e: cache corruption" 337 " run fsck.\n"); 338 goto out; 339 } 340 341 if (cachep->c_usage.cu_flags & CUSAGE_ACTIVE) { 342 cmn_err(CE_WARN, "cachefs: cache not clean. Run fsck\n"); 343 /* ENOSPC is what UFS uses for clean flag check */ 344 error = ENOSPC; 345 goto out; 346 } 347 348 /* Read the rlinfo for this cache */ 349 error = vn_rdwr(UIO_READ, rifvp, (caddr_t)&cachep->c_rlinfo, 350 sizeof (cachefs_rl_info_t), (offset_t)sizeof (struct cache_usage), 351 UIO_SYSSPACE, 0, 0, kcred, NULL); 352 if (error) { 353 cmn_err(CE_WARN, "cachefs: activate_f: cache corruption" 354 " run fsck.\n"); 355 goto out; 356 } 357 358 /* Open the lost+found directory */ 359 error = VOP_LOOKUP(cdvp, CACHEFS_LOSTFOUND_NAME, &lostfoundvp, 360 NULL, 0, NULL, kcred, NULL, NULL, NULL); 361 if (error) { 362 cmn_err(CE_WARN, "cachefs: activate_g: cache corruption" 363 " run fsck.\n"); 364 goto out; 365 } 366 367 VN_HOLD(rifvp); 368 VN_HOLD(cdvp); 369 VN_HOLD(lockvp); 370 VN_HOLD(lostfoundvp); 371 cachep->c_resfilevp = rifvp; 372 cachep->c_dirvp = cdvp; 373 cachep->c_lockvp = lockvp; 374 cachep->c_lostfoundvp = lostfoundvp; 375 376 /* get the cachep worker thread created */ 377 cachep->c_flags |= CACHE_CACHEW_THREADRUN; 378 (void) thread_create(NULL, 0, cachefs_cachep_worker_thread, 379 cachep, 0, &p0, TS_RUN, minclsyspri); 380 381 /* allocate the `logging control' field */ 382 mutex_enter(&cachep->c_log_mutex); 383 cachep->c_log_ctl = 384 cachefs_kmem_zalloc(sizeof (cachefs_log_control_t), KM_SLEEP); 385 lc = (cachefs_log_control_t *)cachep->c_log_ctl; 386 387 /* if the LOG_STATUS_NAME file exists, read it in and set up logging */ 388 error = VOP_LOOKUP(cachep->c_dirvp, LOG_STATUS_NAME, &statevp, 389 NULL, 0, NULL, kcred, NULL, NULL, NULL); 390 if (error == 0) { 391 int vnrw_error; 392 393 vnrw_error = vn_rdwr(UIO_READ, statevp, (caddr_t)lc, 394 sizeof (*lc), 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY, 395 kcred, NULL); 396 VN_RELE(statevp); 397 398 if (vnrw_error == 0) { 399 if ((cachep->c_log = cachefs_log_create_cookie(lc)) 400 == NULL) 401 cachefs_log_error(cachep, ENOMEM, 0); 402 else if ((lc->lc_magic != CACHEFS_LOG_MAGIC) || 403 (lc->lc_path[0] != '/') || 404 (cachefs_log_logfile_open(cachep, 405 lc->lc_path) != 0)) 406 cachefs_log_error(cachep, EINVAL, 0); 407 } 408 } else { 409 error = 0; 410 } 411 lc->lc_magic = CACHEFS_LOG_MAGIC; 412 lc->lc_cachep = (uint64_t)(uintptr_t)cachep; 413 mutex_exit(&cachep->c_log_mutex); 414 415 out: 416 if (error == 0) { 417 cachep->c_flags &= ~(CACHE_NOCACHE | CACHE_ALLOC_PENDING); 418 } 419 if (attrp) 420 cachefs_kmem_free(attrp, sizeof (struct vattr)); 421 if (labelvp != NULL) 422 VN_RELE(labelvp); 423 if (rifvp != NULL) 424 VN_RELE(rifvp); 425 if (lockvp) 426 VN_RELE(lockvp); 427 if (lostfoundvp) 428 VN_RELE(lostfoundvp); 429 430 mutex_exit(&cachep->c_contentslock); 431 return (error); 432 } 433 434 int 435 cachefs_stop_cache(cnode_t *cp) 436 { 437 fscache_t *fscp = C_TO_FSCACHE(cp); 438 cachefscache_t *cachep = fscp->fs_cache; 439 filegrp_t *fgp; 440 int i; 441 int error = 0; 442 clock_t wakeup = (60 * hz); 443 444 /* XXX verify lock-ordering for this function */ 445 446 mutex_enter(&cachep->c_contentslock); 447 448 /* 449 * no work if we're already in nocache mode. hopefully this 450 * will be the usual case. 451 */ 452 453 if (cachep->c_flags & CACHE_NOCACHE) { 454 mutex_exit(&cachep->c_contentslock); 455 return (0); 456 } 457 458 if ((cachep->c_flags & CACHE_NOFILL) == 0) { 459 mutex_exit(&cachep->c_contentslock); 460 return (EINVAL); 461 } 462 463 mutex_exit(&cachep->c_contentslock); 464 465 /* We are already not caching if nfsv4 */ 466 if (CFS_ISFS_BACKFS_NFSV4(fscp)) { 467 return (0); 468 } 469 470 #ifdef CFSDEBUG 471 mutex_enter(&cachep->c_fslistlock); 472 ASSERT(fscp == cachep->c_fslist); 473 ASSERT(fscp->fs_next == NULL); 474 mutex_exit(&cachep->c_fslistlock); 475 476 printf("cachefs_stop_cache: resetting CACHE_NOCACHE\n"); 477 #endif 478 479 /* XXX should i worry about disconnected during boot? */ 480 error = cachefs_cd_access(fscp, 1, 1); 481 if (error) 482 goto out; 483 484 error = cachefs_async_halt(&fscp->fs_workq, 1); 485 ASSERT(error == 0); 486 error = cachefs_async_halt(&cachep->c_workq, 1); 487 ASSERT(error == 0); 488 /* sigh -- best to keep going if async_halt failed. */ 489 error = 0; 490 491 /* XXX current order: cnode, fgp, fscp, cache. okay? */ 492 493 cachefs_cnode_traverse(fscp, cachefs_cnode_disable_caching); 494 495 for (i = 0; i < CFS_FS_FGP_BUCKET_SIZE; i++) { 496 for (fgp = fscp->fs_filegrp[i]; fgp != NULL; 497 fgp = fgp->fg_next) { 498 mutex_enter(&fgp->fg_mutex); 499 500 ASSERT((fgp->fg_flags & 501 (CFS_FG_WRITE | CFS_FG_UPDATED)) == 0); 502 fgp->fg_flags |= 503 CFS_FG_ALLOC_FILE | 504 CFS_FG_ALLOC_ATTR; 505 fgp->fg_flags &= ~CFS_FG_READ; 506 507 if (fgp->fg_dirvp) { 508 fgp->fg_flags |= CFS_FG_ALLOC_FILE; 509 VN_RELE(fgp->fg_dirvp); 510 fgp->fg_dirvp = NULL; 511 } 512 if (fgp->fg_attrvp) { 513 fgp->fg_flags |= CFS_FG_ALLOC_ATTR; 514 VN_RELE(fgp->fg_attrvp); 515 fgp->fg_attrvp = NULL; 516 } 517 518 mutex_exit(&fgp->fg_mutex); 519 } 520 } 521 522 mutex_enter(&fscp->fs_fslock); 523 ASSERT((fscp->fs_flags & (CFS_FS_WRITE)) == 0); 524 fscp->fs_flags &= ~(CFS_FS_READ | CFS_FS_DIRTYINFO); 525 526 if (fscp->fs_fscdirvp) { 527 VN_RELE(fscp->fs_fscdirvp); 528 fscp->fs_fscdirvp = NULL; 529 } 530 if (fscp->fs_fsattrdir) { 531 VN_RELE(fscp->fs_fsattrdir); 532 fscp->fs_fsattrdir = NULL; 533 } 534 if (fscp->fs_infovp) { 535 VN_RELE(fscp->fs_infovp); 536 fscp->fs_infovp = NULL; 537 } 538 /* XXX dlog stuff? */ 539 540 mutex_exit(&fscp->fs_fslock); 541 542 /* 543 * release resources grabbed in cachefs_cache_activate_ro 544 */ 545 546 mutex_enter(&cachep->c_contentslock); 547 548 /* kill off the cachep worker thread */ 549 while (cachep->c_flags & CACHE_CACHEW_THREADRUN) { 550 cachep->c_flags |= CACHE_CACHEW_THREADEXIT; 551 cv_signal(&cachep->c_cwcv); 552 (void) cv_reltimedwait(&cachep->c_cwhaltcv, 553 &cachep->c_contentslock, wakeup, TR_CLOCK_TICK); 554 } 555 556 if (cachep->c_resfilevp) { 557 VN_RELE(cachep->c_resfilevp); 558 cachep->c_resfilevp = NULL; 559 } 560 if (cachep->c_dirvp) { 561 VN_RELE(cachep->c_dirvp); 562 cachep->c_dirvp = NULL; 563 } 564 if (cachep->c_lockvp) { 565 VN_RELE(cachep->c_lockvp); 566 cachep->c_lockvp = NULL; 567 } 568 if (cachep->c_lostfoundvp) { 569 VN_RELE(cachep->c_lostfoundvp); 570 cachep->c_lostfoundvp = NULL; 571 } 572 573 mutex_enter(&cachep->c_log_mutex); 574 if (cachep->c_log_ctl) { 575 cachefs_kmem_free(cachep->c_log_ctl, 576 sizeof (cachefs_log_control_t)); 577 cachep->c_log_ctl = NULL; 578 } 579 if (cachep->c_log) { 580 cachefs_log_destroy_cookie(cachep->c_log); 581 cachep->c_log = NULL; 582 } 583 mutex_exit(&cachep->c_log_mutex); 584 585 /* XXX do what mountroot_init does when ! foundcache */ 586 587 cachep->c_flags |= CACHE_NOCACHE; 588 mutex_exit(&cachep->c_contentslock); 589 590 /* XXX should i release this here? */ 591 cachefs_cd_release(fscp); 592 593 out: 594 595 return (error); 596 } 597 598 /* 599 * ------------------------------------------------------------------ 600 * 601 * cachefs_cache_active_rw 602 * 603 * Description: 604 * Activates the cachefscache_t object for a read-write file system. 605 * Arguments: 606 * cachep the cachefscache_t object to activate 607 * Returns: 608 * Preconditions: 609 * precond(cachep) 610 * precond((cachep->c_flags & CACHE_NOCACHE) == 0) 611 * precond(cachep->c_flags & CACHE_NOFILL) 612 */ 613 614 void 615 cachefs_cache_activate_rw(cachefscache_t *cachep) 616 { 617 cachefs_rl_listhead_t *lhp; 618 619 ASSERT((cachep->c_flags & CACHE_NOCACHE) == 0); 620 ASSERT(cachep->c_flags & CACHE_NOFILL); 621 622 mutex_enter(&cachep->c_contentslock); 623 cachep->c_flags &= ~CACHE_NOFILL; 624 625 /* move the active list to the rl list */ 626 cachefs_rl_cleanup(cachep); 627 628 lhp = &cachep->c_rlinfo.rl_items[ 629 CACHEFS_RL_INDEX(CACHEFS_RL_PACKED_PENDING)]; 630 if (lhp->rli_itemcnt != 0) 631 cachep->c_flags |= CACHE_PACKED_PENDING; 632 cachefs_cache_dirty(cachep, 0); 633 mutex_exit(&cachep->c_contentslock); 634 } 635 636 /* 637 * ------------------------------------------------------------------ 638 * 639 * cachefs_cache_dirty 640 * 641 * Description: 642 * Marks the cache as dirty (active). 643 * Arguments: 644 * cachep the cachefscache_t to mark as dirty 645 * lockit 1 means grab contents lock, 0 means caller grabbed it 646 * Returns: 647 * Preconditions: 648 * precond(cachep) 649 * precond(cache is in rw mode) 650 */ 651 652 void 653 cachefs_cache_dirty(struct cachefscache *cachep, int lockit) 654 { 655 int error; 656 657 ASSERT((cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL)) == 0); 658 659 if (lockit) { 660 mutex_enter(&cachep->c_contentslock); 661 } else { 662 ASSERT(MUTEX_HELD(&cachep->c_contentslock)); 663 } 664 if (cachep->c_flags & CACHE_DIRTY) { 665 ASSERT(cachep->c_usage.cu_flags & CUSAGE_ACTIVE); 666 } else { 667 /* 668 * turn on the "cache active" (dirty) flag and write it 669 * synchronously to disk 670 */ 671 cachep->c_flags |= CACHE_DIRTY; 672 cachep->c_usage.cu_flags |= CUSAGE_ACTIVE; 673 if (error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp, 674 (caddr_t)&cachep->c_usage, sizeof (struct cache_usage), 675 0LL, UIO_SYSSPACE, FSYNC, (rlim64_t)RLIM_INFINITY, 676 kcred, NULL)) { 677 cmn_err(CE_WARN, 678 "cachefs: clean flag write error: %d\n", error); 679 } 680 } 681 682 if (lockit) 683 mutex_exit(&cachep->c_contentslock); 684 } 685 686 /* 687 * ------------------------------------------------------------------ 688 * 689 * cachefs_cache_rssync 690 * 691 * Description: 692 * Syncs out the resource file for the cachefscache_t object. 693 * Arguments: 694 * cachep the cachefscache_t object to operate on 695 * Returns: 696 * Returns 0 for success, !0 on an error writing data. 697 * Preconditions: 698 * precond(cachep) 699 * precond(cache is in rw mode) 700 */ 701 702 int 703 cachefs_cache_rssync(struct cachefscache *cachep) 704 { 705 int error; 706 707 ASSERT((cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL | 708 CACHE_ALLOC_PENDING)) == 0); 709 710 if (cachep->c_rl_entries != NULL) { 711 error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp, 712 (caddr_t)cachep->c_rl_entries, MAXBSIZE, 713 (offset_t)((cachep->c_rl_window + 1) * MAXBSIZE), 714 UIO_SYSSPACE, FSYNC, RLIM_INFINITY, kcred, NULL); 715 if (error) 716 cmn_err(CE_WARN, 717 "cachefs: Can't Write rl entries Info\n"); 718 cachefs_kmem_free(cachep->c_rl_entries, MAXBSIZE); 719 cachep->c_rl_entries = NULL; 720 } 721 722 /* write the usage struct for this cache */ 723 error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp, 724 (caddr_t)&cachep->c_usage, sizeof (struct cache_usage), 725 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY, kcred, NULL); 726 if (error) { 727 cmn_err(CE_WARN, "cachefs: Can't Write Cache Usage Info\n"); 728 } 729 730 /* write the rlinfo for this cache */ 731 error = vn_rdwr(UIO_WRITE, cachep->c_resfilevp, 732 (caddr_t)&cachep->c_rlinfo, sizeof (cachefs_rl_info_t), 733 (offset_t)sizeof (struct cache_usage), UIO_SYSSPACE, 734 0, (rlim64_t)RLIM_INFINITY, kcred, NULL); 735 if (error) { 736 cmn_err(CE_WARN, "cachefs: Can't Write Cache RL Info\n"); 737 } 738 error = VOP_FSYNC(cachep->c_resfilevp, FSYNC, kcred, NULL); 739 return (error); 740 } 741 742 /* 743 * ------------------------------------------------------------------ 744 * 745 * cachefs_cache_sync 746 * 747 * Description: 748 * Sync a cache which includes all of its fscaches. 749 * Arguments: 750 * cachep the cachefscache_t object to sync 751 * Returns: 752 * Preconditions: 753 * precond(cachep) 754 * precond(cache is in rw mode) 755 */ 756 757 void 758 cachefs_cache_sync(struct cachefscache *cachep) 759 { 760 struct fscache *fscp; 761 struct fscache **syncfsc; 762 int nfscs, fscidx; 763 int try; 764 int done; 765 766 if (cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL)) 767 return; 768 769 done = 0; 770 for (try = 0; (try < 2) && !done; try++) { 771 772 nfscs = 0; 773 774 /* 775 * here we turn off the cache-wide DIRTY flag. If it's still 776 * off when the sync completes we can write the clean flag to 777 * disk telling fsck it has no work to do. 778 */ 779 #ifdef CFSCLEANFLAG 780 mutex_enter(&cachep->c_contentslock); 781 cachep->c_flags &= ~CACHE_DIRTY; 782 mutex_exit(&cachep->c_contentslock); 783 #endif /* CFSCLEANFLAG */ 784 785 cachefs_log_process_queue(cachep, 1); 786 787 mutex_enter(&cachep->c_fslistlock); 788 syncfsc = cachefs_kmem_alloc( 789 cachep->c_refcnt * sizeof (struct fscache *), KM_SLEEP); 790 for (fscp = cachep->c_fslist; fscp; fscp = fscp->fs_next) { 791 fscache_hold(fscp); 792 ASSERT(nfscs < cachep->c_refcnt); 793 syncfsc[nfscs++] = fscp; 794 } 795 ASSERT(nfscs == cachep->c_refcnt); 796 mutex_exit(&cachep->c_fslistlock); 797 for (fscidx = 0; fscidx < nfscs; fscidx++) { 798 fscp = syncfsc[fscidx]; 799 fscache_sync(fscp); 800 fscache_rele(fscp); 801 } 802 803 /* get rid of any unused fscache objects */ 804 mutex_enter(&cachep->c_fslistlock); 805 fscache_list_gc(cachep); 806 mutex_exit(&cachep->c_fslistlock); 807 808 /* 809 * here we check the cache-wide DIRTY flag. 810 * If it's off, 811 * we can write the clean flag to disk. 812 */ 813 #ifdef CFSCLEANFLAG 814 mutex_enter(&cachep->c_contentslock); 815 if ((cachep->c_flags & CACHE_DIRTY) == 0) { 816 if (cachep->c_usage.cu_flags & CUSAGE_ACTIVE) { 817 cachep->c_usage.cu_flags &= ~CUSAGE_ACTIVE; 818 if (cachefs_cache_rssync(cachep) == 0) { 819 done = 1; 820 } else { 821 cachep->c_usage.cu_flags |= 822 CUSAGE_ACTIVE; 823 } 824 } else { 825 done = 1; 826 } 827 } 828 mutex_exit(&cachep->c_contentslock); 829 #else /* CFSCLEANFLAG */ 830 mutex_enter(&cachep->c_contentslock); 831 (void) cachefs_cache_rssync(cachep); 832 mutex_exit(&cachep->c_contentslock); 833 done = 1; 834 #endif /* CFSCLEANFLAG */ 835 cachefs_kmem_free(syncfsc, nfscs * sizeof (struct fscache *)); 836 } 837 } 838 839 /* 840 * ------------------------------------------------------------------ 841 * 842 * cachefs_cache_unique 843 * 844 * Description: 845 * Arguments: 846 * Returns: 847 * Returns a unique number. 848 * Preconditions: 849 * precond(cachep) 850 */ 851 852 uint_t 853 cachefs_cache_unique(cachefscache_t *cachep) 854 { 855 uint_t unique = 0; 856 int error = 0; 857 858 mutex_enter(&cachep->c_contentslock); 859 if (cachep->c_usage.cu_flags & CUSAGE_NEED_ADJUST || 860 ++(cachep->c_unique) == 0) { 861 cachep->c_usage.cu_unique++; 862 863 if (cachep->c_unique == 0) 864 cachep->c_unique = 1; 865 cachep->c_flags &= ~CUSAGE_NEED_ADJUST; 866 error = cachefs_cache_rssync(cachep); 867 } 868 if (error == 0) 869 unique = (cachep->c_usage.cu_unique << 16) + cachep->c_unique; 870 mutex_exit(&cachep->c_contentslock); 871 return (unique); 872 } 873 874 /* 875 * Called from c_getfrontfile. Shouldn't be called from anywhere else ! 876 */ 877 static int 878 cachefs_createfrontfile(cnode_t *cp, struct filegrp *fgp) 879 { 880 char name[CFS_FRONTFILE_NAME_SIZE]; 881 struct vattr *attrp = NULL; 882 int error = 0; 883 int mode; 884 int alloc = 0; 885 int freefile = 0; 886 int ffrele = 0; 887 int rlfree = 0; 888 rl_entry_t rl_ent; 889 890 #ifdef CFSDEBUG 891 CFS_DEBUG(CFSDEBUG_FRONT) 892 printf("c_createfrontfile: ENTER cp %p fgp %p\n", 893 (void *)cp, (void *)fgp); 894 #endif 895 896 ASSERT(cp->c_frontvp == NULL); 897 ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0); 898 899 /* quit if we cannot write to the filegrp */ 900 if ((fgp->fg_flags & CFS_FG_WRITE) == 0) { 901 error = ENOENT; 902 goto out; 903 } 904 905 /* find or create the filegrp attrcache file if necessary */ 906 if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) { 907 error = filegrp_allocattr(fgp); 908 if (error) 909 goto out; 910 } 911 912 make_ascii_name(&cp->c_id, name); 913 914 /* set up attributes for the front file we want to create */ 915 attrp = cachefs_kmem_zalloc(sizeof (struct vattr), KM_SLEEP); 916 alloc++; 917 attrp->va_mode = S_IFREG | 0666; 918 mode = 0666; 919 attrp->va_uid = 0; 920 attrp->va_gid = 0; 921 attrp->va_type = VREG; 922 attrp->va_size = 0; 923 attrp->va_mask = AT_SIZE | AT_TYPE | AT_MODE | AT_UID | AT_GID; 924 925 /* get a file from the resource counts */ 926 error = cachefs_allocfile(fgp->fg_fscp->fs_cache); 927 if (error) { 928 error = EINVAL; 929 goto out; 930 } 931 freefile++; 932 933 /* create the metadata slot if necessary */ 934 if (cp->c_flags & CN_ALLOC_PENDING) { 935 error = filegrp_create_metadata(fgp, &cp->c_metadata, 936 &cp->c_id); 937 if (error) { 938 error = EINVAL; 939 goto out; 940 } 941 cp->c_flags &= ~CN_ALLOC_PENDING; 942 cp->c_flags |= CN_UPDATED; 943 } 944 945 /* get an rl entry if necessary */ 946 if (cp->c_metadata.md_rlno == 0) { 947 rl_ent.rl_fileno = cp->c_id.cid_fileno; 948 rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0; 949 rl_ent.rl_fsid = fgp->fg_fscp->fs_cfsid; 950 rl_ent.rl_attrc = 0; 951 error = cachefs_rl_alloc(fgp->fg_fscp->fs_cache, &rl_ent, 952 &cp->c_metadata.md_rlno); 953 if (error) 954 goto out; 955 cachefs_rlent_moveto(fgp->fg_fscp->fs_cache, 956 CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno, 957 cp->c_metadata.md_frontblks); 958 cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE; 959 rlfree++; 960 cp->c_flags |= CN_UPDATED; /* XXX sam: do we need this? */ 961 962 /* increment number of front files */ 963 error = filegrp_ffhold(fgp); 964 if (error) { 965 error = EINVAL; 966 goto out; 967 } 968 ffrele++; 969 } 970 971 if (cp->c_flags & CN_ASYNC_POP_WORKING) { 972 /* lookup the already created front file */ 973 error = VOP_LOOKUP(fgp->fg_dirvp, name, &cp->c_frontvp, 974 NULL, 0, NULL, kcred, NULL, NULL, NULL); 975 } else { 976 /* create the front file */ 977 error = VOP_CREATE(fgp->fg_dirvp, name, attrp, EXCL, mode, 978 &cp->c_frontvp, kcred, 0, NULL, NULL); 979 } 980 if (error) { 981 #ifdef CFSDEBUG 982 CFS_DEBUG(CFSDEBUG_FRONT) 983 printf("c_createfrontfile: Can't create cached object" 984 " error %u, fileno %llx\n", error, 985 (u_longlong_t)cp->c_id.cid_fileno); 986 #endif 987 goto out; 988 } 989 990 /* get a copy of the fid of the front file */ 991 cp->c_metadata.md_fid.fid_len = MAXFIDSZ; 992 error = VOP_FID(cp->c_frontvp, &cp->c_metadata.md_fid, NULL); 993 if (error) { 994 /* 995 * If we get back ENOSPC then the fid we passed in was too 996 * small. For now we don't do anything and map to EINVAL. 997 */ 998 if (error == ENOSPC) { 999 error = EINVAL; 1000 } 1001 goto out; 1002 } 1003 1004 dnlc_purge_vp(cp->c_frontvp); 1005 1006 cp->c_metadata.md_flags |= MD_FILE; 1007 cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC; 1008 1009 out: 1010 if (error) { 1011 if (cp->c_frontvp) { 1012 VN_RELE(cp->c_frontvp); 1013 (void) VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0); 1014 cp->c_frontvp = NULL; 1015 } 1016 if (ffrele) 1017 filegrp_ffrele(fgp); 1018 if (freefile) 1019 cachefs_freefile(fgp->fg_fscp->fs_cache); 1020 if (rlfree) { 1021 #ifdef CFSDEBUG 1022 cachefs_rlent_verify(fgp->fg_fscp->fs_cache, 1023 CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno); 1024 #endif /* CFSDEBUG */ 1025 cachefs_rlent_moveto(fgp->fg_fscp->fs_cache, 1026 CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0); 1027 cp->c_metadata.md_rlno = 0; 1028 cp->c_metadata.md_rltype = CACHEFS_RL_NONE; 1029 } 1030 cachefs_nocache(cp); 1031 } 1032 if (alloc) 1033 cachefs_kmem_free(attrp, sizeof (struct vattr)); 1034 #ifdef CFSDEBUG 1035 CFS_DEBUG(CFSDEBUG_FRONT) 1036 printf("c_createfrontfile: EXIT error = %d name %s\n", error, 1037 name); 1038 #endif 1039 return (error); 1040 } 1041 1042 /* 1043 * Releases resources associated with the front file. 1044 * Only call this routine if a ffhold has been done. 1045 * Its okay to call this routine if the front file does not exist. 1046 * Note: this routine is used even if there is no front file. 1047 */ 1048 void 1049 cachefs_removefrontfile(cachefs_metadata_t *mdp, cfs_cid_t *cidp, 1050 filegrp_t *fgp) 1051 { 1052 int error, enoent; 1053 char name[CFS_FRONTFILE_NAME_SIZE + 2]; 1054 1055 ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0); 1056 1057 enoent = 0; 1058 if (mdp->md_flags & MD_FILE) { 1059 if (fgp->fg_dirvp == NULL) { 1060 cmn_err(CE_WARN, "cachefs: remove error, run fsck\n"); 1061 return; 1062 } 1063 make_ascii_name(cidp, name); 1064 error = VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0); 1065 if (error == ENOENT) 1066 enoent = 1; 1067 if ((error) && (error != ENOENT)) { 1068 cmn_err(CE_WARN, "UFS remove error %s %d, run fsck\n", 1069 name, error); 1070 } 1071 if (mdp->md_flags & MD_ACLDIR) { 1072 (void) strcat(name, ".d"); 1073 error = VOP_RMDIR(fgp->fg_dirvp, name, fgp->fg_dirvp, 1074 kcred, NULL, 0); 1075 if ((error) && (error != ENOENT)) { 1076 cmn_err(CE_WARN, "frontfs rmdir error %s %d" 1077 "; run fsck\n", name, error); 1078 } 1079 } 1080 mdp->md_flags &= ~(MD_FILE | MD_POPULATED | MD_ACL | MD_ACLDIR); 1081 bzero(&mdp->md_allocinfo, mdp->md_allocents * 1082 sizeof (struct cachefs_allocmap)); 1083 cachefs_freefile(fgp->fg_fscp->fs_cache); 1084 } 1085 1086 /* 1087 * Clear packed bit, fastsymlinks and special files 1088 * do not have a front file. 1089 */ 1090 mdp->md_flags &= ~MD_PACKED; 1091 1092 /* XXX either rename routine or move this to caller */ 1093 if (enoent == 0) 1094 filegrp_ffrele(fgp); 1095 1096 if (mdp->md_frontblks) { 1097 cachefs_freeblocks(fgp->fg_fscp->fs_cache, mdp->md_frontblks, 1098 mdp->md_rltype); 1099 mdp->md_frontblks = 0; 1100 } 1101 } 1102 1103 /* 1104 * This is the interface to the rest of CFS. This takes a cnode, and returns 1105 * the frontvp (stuffs it in the cnode). This creates an attrcache slot and 1106 * and frontfile if necessary. 1107 */ 1108 1109 int 1110 cachefs_getfrontfile(cnode_t *cp) 1111 { 1112 struct filegrp *fgp = cp->c_filegrp; 1113 int error; 1114 struct vattr va; 1115 1116 #ifdef CFSDEBUG 1117 CFS_DEBUG(CFSDEBUG_SUBR) 1118 printf("c_getfrontfile: ENTER cp %p\n", (void *)cp); 1119 #endif 1120 1121 ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0); 1122 ASSERT(MUTEX_HELD(&cp->c_statelock)); 1123 1124 /* 1125 * Now we check to see if there is a front file for this entry. 1126 * If there is, we get the vnode for it and stick it in the cnode. 1127 * Otherwise, we create a front file, get the vnode for it and stick 1128 * it in the cnode. 1129 */ 1130 if (cp->c_flags & CN_STALE) { 1131 cp->c_flags |= CN_NOCACHE; 1132 error = ESTALE; 1133 goto out; 1134 } 1135 1136 /* 1137 * If the cnode is being populated, and we're not the populating 1138 * thread, then block until the pop thread completes. If we are the 1139 * pop thread, then we may come in here, but not to nuke the directory 1140 * cnode at a critical juncture. If we return from a cv_wait and the 1141 * cnode is now stale, don't bother trying to get the front file. 1142 */ 1143 while ((cp->c_flags & CN_ASYNC_POP_WORKING) && 1144 (cp->c_popthrp != curthread)) { 1145 cv_wait(&cp->c_popcv, &cp->c_statelock); 1146 if (cp->c_flags & CN_STALE) { 1147 cp->c_flags |= CN_NOCACHE; 1148 error = ESTALE; 1149 goto out; 1150 } 1151 } 1152 1153 if ((cp->c_metadata.md_flags & MD_FILE) == 0) { 1154 #ifdef CFSDEBUG 1155 if (cp->c_frontvp != NULL) 1156 CFS_DEBUG(CFSDEBUG_FRONT) 1157 printf("c_getfrontfile: !MD_FILE and frontvp " 1158 "not null cp %p\n", (void *)cp); 1159 #endif 1160 if (CTOV(cp)->v_type == VDIR) 1161 ASSERT((cp->c_metadata.md_flags & MD_POPULATED) == 0); 1162 error = cachefs_createfrontfile(cp, fgp); 1163 if (error) 1164 goto out; 1165 } else { 1166 /* 1167 * A front file exists, all we need to do is to grab the fid, 1168 * do a VFS_VGET() on the fid, stuff the vnode in the cnode, 1169 * and return. 1170 */ 1171 if (fgp->fg_dirvp == NULL) { 1172 cmn_err(CE_WARN, "cachefs: gff0: corrupted file system" 1173 " run fsck\n"); 1174 cachefs_inval_object(cp); 1175 cp->c_flags |= CN_NOCACHE; 1176 error = ESTALE; 1177 goto out; 1178 } 1179 error = VFS_VGET(fgp->fg_dirvp->v_vfsp, &cp->c_frontvp, 1180 &cp->c_metadata.md_fid); 1181 if (error || (cp->c_frontvp == NULL)) { 1182 #ifdef CFSDEBUG 1183 CFS_DEBUG(CFSDEBUG_FRONT) 1184 printf("cachefs: " 1185 "gff1: front file system error %d\n", 1186 error); 1187 #endif /* CFSDEBUG */ 1188 cachefs_inval_object(cp); 1189 cp->c_flags |= CN_NOCACHE; 1190 error = ESTALE; 1191 goto out; 1192 } 1193 1194 /* don't need to check timestamps if need_front_sync is set */ 1195 if (cp->c_flags & CN_NEED_FRONT_SYNC) { 1196 error = 0; 1197 goto out; 1198 } 1199 1200 /* don't need to check empty directories */ 1201 if (CTOV(cp)->v_type == VDIR && 1202 ((cp->c_metadata.md_flags & MD_POPULATED) == 0)) { 1203 error = 0; 1204 goto out; 1205 } 1206 1207 /* get modify time of the front file */ 1208 va.va_mask = AT_MTIME; 1209 error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred, NULL); 1210 if (error) { 1211 cmn_err(CE_WARN, "cachefs: gff2: front file" 1212 " system error %d", error); 1213 cachefs_inval_object(cp); 1214 error = (cp->c_flags & CN_NOCACHE) ? ESTALE : 0; 1215 goto out; 1216 } 1217 1218 /* compare with modify time stored in metadata */ 1219 if (bcmp(&va.va_mtime, &cp->c_metadata.md_timestamp, 1220 sizeof (timestruc_t)) != 0) { 1221 #ifdef CFSDEBUG 1222 CFS_DEBUG(CFSDEBUG_GENERAL | CFSDEBUG_INVALIDATE) { 1223 long sec, nsec; 1224 sec = cp->c_metadata.md_timestamp.tv_sec; 1225 nsec = cp->c_metadata.md_timestamp.tv_nsec; 1226 printf("c_getfrontfile: timestamps don't" 1227 " match fileno %lld va %lx %lx" 1228 " meta %lx %lx\n", 1229 (u_longlong_t)cp->c_id.cid_fileno, 1230 va.va_mtime.tv_sec, 1231 va.va_mtime.tv_nsec, sec, nsec); 1232 } 1233 #endif 1234 cachefs_inval_object(cp); 1235 error = (cp->c_flags & CN_NOCACHE) ? ESTALE : 0; 1236 } 1237 } 1238 out: 1239 #ifdef CFSDEBUG 1240 CFS_DEBUG(CFSDEBUG_FRONT) 1241 printf("c_getfrontfile: EXIT error = %d\n", error); 1242 #endif 1243 return (error); 1244 } 1245 1246 void 1247 cachefs_inval_object(cnode_t *cp) 1248 { 1249 cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache; 1250 struct filegrp *fgp = cp->c_filegrp; 1251 int error; 1252 1253 ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0); 1254 ASSERT(MUTEX_HELD(&cp->c_statelock)); 1255 ASSERT((cp->c_flags & CN_ASYNC_POP_WORKING) == 0 || 1256 cp->c_popthrp == curthread); 1257 #if 0 1258 CFS_DEBUG(CFSDEBUG_SUBR) 1259 printf("c_inval_object: ENTER cp %p\n", (void *)cp); 1260 if (cp->c_flags & (CN_ASYNC_POPULATE | CN_ASYNC_POP_WORKING)) 1261 debug_enter("inval object during async pop"); 1262 #endif 1263 cp->c_flags |= CN_NOCACHE; 1264 1265 /* if we cannot modify the cache */ 1266 if (C_TO_FSCACHE(cp)->fs_cache->c_flags & 1267 (CACHE_NOFILL | CACHE_NOCACHE)) { 1268 goto out; 1269 } 1270 1271 /* if there is a front file */ 1272 if (cp->c_metadata.md_flags & MD_FILE) { 1273 if (fgp->fg_dirvp == NULL) 1274 goto out; 1275 1276 /* get the front file vp if necessary */ 1277 if (cp->c_frontvp == NULL) { 1278 1279 error = VFS_VGET(fgp->fg_dirvp->v_vfsp, &cp->c_frontvp, 1280 &cp->c_metadata.md_fid); 1281 if (error || (cp->c_frontvp == NULL)) { 1282 #ifdef CFSDEBUG 1283 CFS_DEBUG(CFSDEBUG_FRONT) 1284 printf("cachefs: " 1285 "io: front file error %d\n", error); 1286 #endif /* CFSDEBUG */ 1287 goto out; 1288 } 1289 } 1290 1291 /* truncate the file to zero size */ 1292 error = cachefs_frontfile_size(cp, 0); 1293 if (error) 1294 goto out; 1295 cp->c_flags &= ~CN_NOCACHE; 1296 1297 /* if a directory, v_type is zero if called from initcnode */ 1298 if (cp->c_attr.va_type == VDIR) { 1299 if (cp->c_usage < CFS_DIRCACHE_COST) { 1300 cp->c_invals++; 1301 if (cp->c_invals > CFS_DIRCACHE_INVAL) { 1302 cp->c_invals = 0; 1303 } 1304 } else 1305 cp->c_invals = 0; 1306 cp->c_usage = 0; 1307 } 1308 } else { 1309 cp->c_flags &= ~CN_NOCACHE; 1310 } 1311 1312 out: 1313 if ((cp->c_metadata.md_flags & MD_PACKED) && 1314 (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) && 1315 ((cachep->c_flags & CACHE_NOFILL) == 0)) { 1316 ASSERT(cp->c_metadata.md_rlno != 0); 1317 if (cp->c_metadata.md_rltype != CACHEFS_RL_PACKED_PENDING) { 1318 cachefs_rlent_moveto(cachep, 1319 CACHEFS_RL_PACKED_PENDING, 1320 cp->c_metadata.md_rlno, 1321 cp->c_metadata.md_frontblks); 1322 cp->c_metadata.md_rltype = CACHEFS_RL_PACKED_PENDING; 1323 /* unconditionally set CN_UPDATED below */ 1324 } 1325 } 1326 1327 cachefs_purgeacl(cp); 1328 1329 if (cp->c_flags & CN_ASYNC_POP_WORKING) 1330 cp->c_flags |= CN_NOCACHE; 1331 cp->c_metadata.md_flags &= ~(MD_POPULATED | MD_INVALREADDIR | 1332 MD_FASTSYMLNK); 1333 cp->c_flags &= ~CN_NEED_FRONT_SYNC; 1334 cp->c_flags |= CN_UPDATED; 1335 1336 /* 1337 * If the object invalidated is a directory, the dnlc should be purged 1338 * to elide all references to this (directory) vnode. 1339 */ 1340 if (CTOV(cp)->v_type == VDIR) 1341 dnlc_purge_vp(CTOV(cp)); 1342 1343 #ifdef CFSDEBUG 1344 CFS_DEBUG(CFSDEBUG_SUBR) 1345 printf("c_inval_object: EXIT\n"); 1346 #endif 1347 } 1348 1349 void 1350 make_ascii_name(cfs_cid_t *cidp, char *strp) 1351 { 1352 int i = sizeof (uint_t) * 4; 1353 u_longlong_t index; 1354 ino64_t name; 1355 1356 if (cidp->cid_flags & CFS_CID_LOCAL) 1357 *strp++ = 'L'; 1358 name = (ino64_t)cidp->cid_fileno; 1359 do { 1360 index = (((u_longlong_t)name) & 0xf000000000000000) >> 60; 1361 index &= (u_longlong_t)0xf; 1362 ASSERT(index < (u_longlong_t)16); 1363 *strp++ = "0123456789abcdef"[index]; 1364 name <<= 4; 1365 } while (--i); 1366 *strp = '\0'; 1367 } 1368 1369 void 1370 cachefs_nocache(cnode_t *cp) 1371 { 1372 fscache_t *fscp = C_TO_FSCACHE(cp); 1373 cachefscache_t *cachep = fscp->fs_cache; 1374 1375 #ifdef CFSDEBUG 1376 CFS_DEBUG(CFSDEBUG_SUBR) 1377 printf("c_nocache: ENTER cp %p\n", (void *)cp); 1378 #endif 1379 1380 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1381 ASSERT(MUTEX_HELD(&cp->c_statelock)); 1382 if ((cp->c_flags & CN_NOCACHE) == 0) { 1383 #ifdef CFSDEBUG 1384 CFS_DEBUG(CFSDEBUG_INVALIDATE) 1385 printf("cachefs_nocache: invalidating %llu\n", 1386 (u_longlong_t)cp->c_id.cid_fileno); 1387 #endif 1388 /* 1389 * Here we are waiting until inactive time to do 1390 * the inval_object. In case we don't get to inactive 1391 * (because of a crash, say) we set up a timestamp mismatch 1392 * such that getfrontfile will blow the front file away 1393 * next time we try to use it. 1394 */ 1395 cp->c_metadata.md_timestamp.tv_sec = 0; 1396 cp->c_metadata.md_timestamp.tv_nsec = 0; 1397 cp->c_metadata.md_flags &= ~(MD_POPULATED | MD_INVALREADDIR | 1398 MD_FASTSYMLNK); 1399 cp->c_flags &= ~CN_NEED_FRONT_SYNC; 1400 1401 cachefs_purgeacl(cp); 1402 1403 /* 1404 * It is possible we can nocache while disconnected. 1405 * A directory could be nocached by running out of space. 1406 * A regular file should only be nocached if an I/O error 1407 * occurs to the front fs. 1408 * We count on the item staying on the modified list 1409 * so we do not loose the cid to fid mapping for directories. 1410 */ 1411 1412 if ((cp->c_metadata.md_flags & MD_PACKED) && 1413 (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) && 1414 ((cachep->c_flags & CACHE_NOFILL) == 0)) { 1415 ASSERT(cp->c_metadata.md_rlno != 0); 1416 if (cp->c_metadata.md_rltype != 1417 CACHEFS_RL_PACKED_PENDING) { 1418 cachefs_rlent_moveto(cachep, 1419 CACHEFS_RL_PACKED_PENDING, 1420 cp->c_metadata.md_rlno, 1421 cp->c_metadata.md_frontblks); 1422 cp->c_metadata.md_rltype = 1423 CACHEFS_RL_PACKED_PENDING; 1424 /* unconditionally set CN_UPDATED below */ 1425 } 1426 } 1427 1428 if (CTOV(cp)->v_type == VDIR) 1429 dnlc_purge_vp(CTOV(cp)); 1430 cp->c_flags |= (CN_NOCACHE | CN_UPDATED); 1431 } 1432 1433 if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_NOCACHE)) 1434 cachefs_log_nocache(cachep, 0, fscp->fs_cfsvfsp, 1435 &cp->c_metadata.md_cookie, cp->c_id.cid_fileno); 1436 1437 #ifdef CFSDEBUG 1438 CFS_DEBUG(CFSDEBUG_SUBR) 1439 printf("c_nocache: EXIT cp %p\n", (void *)cp); 1440 #endif 1441 } 1442 1443 /* 1444 * Checks to see if the page is in the disk cache, by checking the allocmap. 1445 */ 1446 int 1447 cachefs_check_allocmap(cnode_t *cp, u_offset_t off) 1448 { 1449 int i; 1450 size_t dbl_size_to_look = cp->c_attr.va_size - off; 1451 uint_t size_to_look; 1452 1453 if (dbl_size_to_look > (u_offset_t)PAGESIZE) 1454 size_to_look = (uint_t)PAGESIZE; 1455 else 1456 /*LINTED alignment okay*/ 1457 size_to_look = (uint_t)dbl_size_to_look; 1458 1459 for (i = 0; i < cp->c_metadata.md_allocents; i++) { 1460 struct cachefs_allocmap *allocp = 1461 cp->c_metadata.md_allocinfo + i; 1462 1463 if (off >= allocp->am_start_off) { 1464 if ((off + size_to_look) <= 1465 (allocp->am_start_off + allocp->am_size)) { 1466 struct fscache *fscp = C_TO_FSCACHE(cp); 1467 cachefscache_t *cachep = fscp->fs_cache; 1468 1469 if (CACHEFS_LOG_LOGGING(cachep, 1470 CACHEFS_LOG_CALLOC)) 1471 cachefs_log_calloc(cachep, 0, 1472 fscp->fs_cfsvfsp, 1473 &cp->c_metadata.md_cookie, 1474 cp->c_id.cid_fileno, 1475 off, size_to_look); 1476 /* 1477 * Found the page in the CFS disk cache. 1478 */ 1479 return (1); 1480 } 1481 } else { 1482 return (0); 1483 } 1484 } 1485 return (0); 1486 } 1487 1488 /* 1489 * Merges adjacent allocmap entries together where possible, e.g. 1490 * offset=0x0, size=0x40000 1491 * offset=0x40000, size=0x20000 becomes just offset=0x0, size-0x90000 1492 * offset=0x60000, size=0x30000 1493 */ 1494 1495 1496 void 1497 cachefs_coalesce_allocmap(struct cachefs_metadata *cmd) 1498 { 1499 int i, reduced = 0; 1500 struct cachefs_allocmap *allocp, *nallocp; 1501 1502 nallocp = allocp = cmd->md_allocinfo; 1503 allocp++; 1504 for (i = 1; i < cmd->md_allocents; i++, allocp++) { 1505 if (nallocp->am_start_off + nallocp->am_size == 1506 allocp->am_start_off) { 1507 nallocp->am_size += allocp->am_size; 1508 reduced++; 1509 } else { 1510 nallocp++; 1511 nallocp->am_start_off = allocp->am_start_off; 1512 nallocp->am_size = allocp->am_size; 1513 } 1514 } 1515 cmd->md_allocents -= reduced; 1516 } 1517 1518 /* 1519 * Updates the allocmap to reflect a new chunk of data that has been 1520 * populated. 1521 */ 1522 void 1523 cachefs_update_allocmap(cnode_t *cp, u_offset_t off, size_t size) 1524 { 1525 int i; 1526 struct cachefs_allocmap *allocp; 1527 struct fscache *fscp = C_TO_FSCACHE(cp); 1528 cachefscache_t *cachep = fscp->fs_cache; 1529 u_offset_t saveoff; 1530 u_offset_t savesize; 1531 u_offset_t logoff = off; 1532 size_t logsize = size; 1533 u_offset_t endoff; 1534 u_offset_t tmpendoff; 1535 1536 /* 1537 * We try to see if we can coalesce the current block into an existing 1538 * allocation and mark it as such. 1539 * If we can't do that then we make a new entry in the allocmap. 1540 * when we run out of allocmaps, put the cnode in NOCACHE mode. 1541 */ 1542 again: 1543 allocp = cp->c_metadata.md_allocinfo; 1544 for (i = 0; i < cp->c_metadata.md_allocents; i++, allocp++) { 1545 1546 if (off <= (allocp->am_start_off)) { 1547 endoff = off + size; 1548 if (endoff >= allocp->am_start_off) { 1549 tmpendoff = allocp->am_start_off + 1550 allocp->am_size; 1551 if (endoff < tmpendoff) 1552 endoff = tmpendoff; 1553 allocp->am_size = endoff - off; 1554 allocp->am_start_off = off; 1555 cachefs_coalesce_allocmap(&cp->c_metadata); 1556 allocp = cp->c_metadata.md_allocinfo; 1557 if (allocp->am_size >= cp->c_size) 1558 cp->c_metadata.md_flags |= MD_POPULATED; 1559 return; 1560 } else { 1561 saveoff = off; 1562 savesize = size; 1563 off = allocp->am_start_off; 1564 size = allocp->am_size; 1565 allocp->am_size = savesize; 1566 allocp->am_start_off = saveoff; 1567 goto again; 1568 } 1569 } else { 1570 endoff = allocp->am_start_off + allocp->am_size; 1571 if (off < endoff) { 1572 tmpendoff = off + size; 1573 if (endoff < tmpendoff) 1574 endoff = tmpendoff; 1575 allocp->am_size = endoff - allocp->am_start_off; 1576 cachefs_coalesce_allocmap(&cp->c_metadata); 1577 allocp = cp->c_metadata.md_allocinfo; 1578 if (allocp->am_size >= cp->c_size) 1579 cp->c_metadata.md_flags |= MD_POPULATED; 1580 return; 1581 } 1582 if (off == (allocp->am_start_off + allocp->am_size)) { 1583 allocp->am_size += size; 1584 cachefs_coalesce_allocmap(&cp->c_metadata); 1585 allocp = cp->c_metadata.md_allocinfo; 1586 if (allocp->am_size >= cp->c_size) 1587 cp->c_metadata.md_flags |= MD_POPULATED; 1588 return; 1589 } 1590 } 1591 } 1592 if (i == C_MAX_ALLOCINFO_SLOTS) { 1593 #ifdef CFSDEBUG 1594 CFS_DEBUG(CFSDEBUG_ALLOCMAP) 1595 printf("c_update_alloc_map: " 1596 "Too many allinfo entries cp %p fileno %llu %p\n", 1597 (void *)cp, (u_longlong_t)cp->c_id.cid_fileno, 1598 (void *)cp->c_metadata.md_allocinfo); 1599 #endif 1600 cachefs_nocache(cp); 1601 return; 1602 } 1603 allocp->am_start_off = off; 1604 allocp->am_size = (u_offset_t)size; 1605 if (allocp->am_size >= cp->c_size) 1606 cp->c_metadata.md_flags |= MD_POPULATED; 1607 cp->c_metadata.md_allocents++; 1608 1609 if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UALLOC)) 1610 cachefs_log_ualloc(cachep, 0, fscp->fs_cfsvfsp, 1611 &cp->c_metadata.md_cookie, cp->c_id.cid_fileno, 1612 logoff, logsize); 1613 } 1614 1615 /* 1616 * CFS population function 1617 * 1618 * before async population, this function used to turn on the cnode 1619 * flags CN_UPDATED, CN_NEED_FRONT_SYNC, and CN_POPULATION_PENDING. 1620 * now, however, it's the responsibility of the caller to do this if 1621 * this function returns 0 (no error). 1622 */ 1623 1624 int 1625 cachefs_populate(cnode_t *cp, u_offset_t off, size_t popsize, vnode_t *frontvp, 1626 vnode_t *backvp, u_offset_t cpsize, cred_t *cr) 1627 { 1628 int error = 0; 1629 caddr_t addr; 1630 u_offset_t upto; 1631 uint_t size; 1632 u_offset_t from = off; 1633 cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache; 1634 ssize_t resid; 1635 struct fbuf *fbp; 1636 caddr_t buf = kmem_alloc(MAXBSIZE, KM_SLEEP); 1637 1638 #ifdef CFSDEBUG 1639 CFS_DEBUG(CFSDEBUG_VOPS) 1640 printf("cachefs_populate: ENTER cp %p off %lld\n", 1641 (void *)cp, off); 1642 #endif 1643 1644 upto = MIN((off + popsize), cpsize); 1645 1646 while (from < upto) { 1647 u_offset_t blkoff = (from & (offset_t)MAXBMASK); 1648 uint_t n = from - blkoff; 1649 1650 size = upto - from; 1651 if (upto > (blkoff + MAXBSIZE)) 1652 size = MAXBSIZE - n; 1653 1654 error = fbread(backvp, (offset_t)blkoff, n + size, 1655 S_OTHER, &fbp); 1656 if (CFS_TIMEOUT(C_TO_FSCACHE(cp), error)) 1657 goto out; 1658 else if (error) { 1659 #ifdef CFSDEBUG 1660 CFS_DEBUG(CFSDEBUG_BACK) 1661 printf("cachefs_populate: fbread error %d\n", 1662 error); 1663 #endif 1664 goto out; 1665 } 1666 1667 addr = fbp->fb_addr; 1668 ASSERT(addr != NULL); 1669 ASSERT(n + size <= MAXBSIZE); 1670 bcopy(addr, buf, n + size); 1671 fbrelse(fbp, S_OTHER); 1672 1673 if (n == 0 || cachefs_check_allocmap(cp, blkoff) == 0) { 1674 if (error = cachefs_allocblocks(cachep, 1, 1675 cp->c_metadata.md_rltype)) 1676 goto out; 1677 cp->c_metadata.md_frontblks++; 1678 } 1679 resid = 0; 1680 error = vn_rdwr(UIO_WRITE, frontvp, buf + n, size, 1681 (offset_t)from, UIO_SYSSPACE, 0, 1682 (rlim64_t)RLIM64_INFINITY, cr, &resid); 1683 if (error) { 1684 #ifdef CFSDEBUG 1685 CFS_DEBUG(CFSDEBUG_FRONT) 1686 printf("cachefs_populate: " 1687 "Got error = %d from vn_rdwr\n", error); 1688 #endif 1689 goto out; 1690 } 1691 #ifdef CFSDEBUG 1692 if (resid) 1693 CFS_DEBUG(CFSDEBUG_FRONT) 1694 printf("cachefs_populate: non-zero resid %ld\n", 1695 resid); 1696 #endif 1697 from += size; 1698 } 1699 (void) cachefs_update_allocmap(cp, off, upto - off); 1700 out: 1701 if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_POPULATE)) 1702 cachefs_log_populate(cachep, error, 1703 C_TO_FSCACHE(cp)->fs_cfsvfsp, 1704 &cp->c_metadata.md_cookie, cp->c_id.cid_fileno, off, 1705 popsize); 1706 1707 #ifdef CFSDEBUG 1708 CFS_DEBUG(CFSDEBUG_VOPS) 1709 printf("cachefs_populate: EXIT cp %p error %d\n", 1710 (void *)cp, error); 1711 #endif 1712 kmem_free(buf, MAXBSIZE); 1713 1714 return (error); 1715 } 1716 1717 /* 1718 * due to compiler error we shifted cnode to the last argument slot. 1719 * occurred during large files project - XXX. 1720 */ 1721 void 1722 cachefs_cluster_allocmap(u_offset_t off, u_offset_t *popoffp, size_t *popsizep, 1723 size_t size, struct cnode *cp) 1724 { 1725 int i; 1726 u_offset_t lastoff = 0; 1727 u_offset_t forward_diff = 0; 1728 u_offset_t backward_diff = 0; 1729 1730 ASSERT(size <= C_TO_FSCACHE(cp)->fs_info.fi_popsize); 1731 1732 #ifdef CFSDEBUG 1733 CFS_DEBUG(CFSDEBUG_SUBR) 1734 printf("cachefs_cluster_allocmap: off %llx, size %llx, " 1735 "c_size %llx\n", off, size, (longlong_t)cp->c_size); 1736 #endif /* CFSDEBUG */ 1737 for (i = 0; i < cp->c_metadata.md_allocents; i++) { 1738 struct cachefs_allocmap *allocp = 1739 cp->c_metadata.md_allocinfo + i; 1740 1741 if (allocp->am_start_off > off) { 1742 if ((off + size) > allocp->am_start_off) { 1743 forward_diff = allocp->am_start_off - off; 1744 backward_diff = size - forward_diff; 1745 if (backward_diff > off) 1746 backward_diff = off; 1747 if (lastoff > (off - backward_diff)) 1748 backward_diff = off - lastoff; 1749 } else { 1750 forward_diff = size; 1751 } 1752 *popoffp = (off - backward_diff) & (offset_t)PAGEMASK; 1753 *popsizep = ((off + forward_diff) - *popoffp) & 1754 (offset_t)PAGEMASK; 1755 return; 1756 } else { 1757 lastoff = allocp->am_start_off + allocp->am_size; 1758 } 1759 } 1760 if ((lastoff + size) > off) { 1761 *popoffp = (lastoff & (offset_t)PAGEMASK); 1762 } else { 1763 *popoffp = off & (offset_t)PAGEMASK; 1764 } 1765 1766 /* 1767 * 64bit project: popsize is the chunk size used to populate the 1768 * cache (default 64K). As such, 32 bit should suffice. 1769 */ 1770 if ((*popoffp + size) > cp->c_size) 1771 *popsizep = (cp->c_size - *popoffp + PAGEOFFSET) & 1772 (offset_t)PAGEMASK; 1773 else if (size < PAGESIZE) 1774 *popsizep = (size + PAGEOFFSET) & (offset_t)PAGEMASK; 1775 else 1776 *popsizep = size & (offset_t)PAGEMASK; 1777 1778 #ifdef CFSDEBUG 1779 CFS_DEBUG(CFSDEBUG_SUBR) 1780 printf("cachefs_cluster_allocmap: popoff %llx, popsize %llx\n", 1781 (u_longlong_t)(*popoffp), (u_longlong_t)(*popsizep)); 1782 #endif /* CFSDEBUG */ 1783 } 1784 1785 /* 1786 * "populate" a symlink in the cache 1787 */ 1788 int 1789 cachefs_stuffsymlink(cnode_t *cp, caddr_t buf, int buflen) 1790 { 1791 int error = 0; 1792 struct fscache *fscp = C_TO_FSCACHE(cp); 1793 cachefscache_t *cachep = fscp->fs_cache; 1794 struct cachefs_metadata *mdp = &cp->c_metadata; 1795 1796 ASSERT(RW_WRITE_HELD(&cp->c_rwlock)); 1797 ASSERT(MUTEX_HELD(&cp->c_statelock)); 1798 1799 if (CFS_ISFS_BACKFS_NFSV4(fscp)) 1800 goto out; 1801 1802 if (cp->c_flags & CN_NOCACHE) 1803 return (ENOENT); 1804 1805 cp->c_size = (u_offset_t)buflen; 1806 1807 /* if can create a fast sym link */ 1808 if (buflen <= C_FSL_SIZE) { 1809 /* give up the front file resources */ 1810 if (mdp->md_rlno) { 1811 cachefs_removefrontfile(mdp, &cp->c_id, cp->c_filegrp); 1812 cachefs_rlent_moveto(cachep, CACHEFS_RL_FREE, 1813 mdp->md_rlno, 0); 1814 mdp->md_rlno = 0; 1815 mdp->md_rltype = CACHEFS_RL_NONE; 1816 } 1817 /* put sym link contents in allocinfo in metadata */ 1818 bzero(mdp->md_allocinfo, C_FSL_SIZE); 1819 bcopy(buf, mdp->md_allocinfo, buflen); 1820 1821 mdp->md_flags |= MD_FASTSYMLNK; 1822 cp->c_flags &= ~CN_NEED_FRONT_SYNC; 1823 cp->c_flags |= CN_UPDATED; 1824 goto out; 1825 } 1826 1827 /* else create a sym link in a front file */ 1828 if (cp->c_frontvp == NULL) 1829 error = cachefs_getfrontfile(cp); 1830 if (error) 1831 goto out; 1832 1833 /* truncate front file */ 1834 error = cachefs_frontfile_size(cp, 0); 1835 mdp->md_flags &= ~(MD_FASTSYMLNK | MD_POPULATED); 1836 if (error) 1837 goto out; 1838 1839 /* get space for the sym link */ 1840 error = cachefs_allocblocks(cachep, 1, cp->c_metadata.md_rltype); 1841 if (error) 1842 goto out; 1843 1844 /* write the sym link to the front file */ 1845 error = vn_rdwr(UIO_WRITE, cp->c_frontvp, buf, buflen, 0, 1846 UIO_SYSSPACE, 0, RLIM_INFINITY, kcred, NULL); 1847 if (error) { 1848 cachefs_freeblocks(cachep, 1, cp->c_metadata.md_rltype); 1849 goto out; 1850 } 1851 1852 cp->c_metadata.md_flags |= MD_POPULATED; 1853 cp->c_flags |= CN_NEED_FRONT_SYNC; 1854 cp->c_flags |= CN_UPDATED; 1855 1856 out: 1857 if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_CSYMLINK)) 1858 cachefs_log_csymlink(cachep, error, fscp->fs_cfsvfsp, 1859 &cp->c_metadata.md_cookie, cp->c_id.cid_fileno, buflen); 1860 1861 return (error); 1862 } 1863 1864 /* 1865 * Reads the full contents of the symbolic link from the back file system. 1866 * *bufp is set to a MAXPATHLEN buffer that must be freed when done 1867 * *buflenp is the length of the link 1868 */ 1869 int 1870 cachefs_readlink_back(cnode_t *cp, cred_t *cr, caddr_t *bufp, int *buflenp) 1871 { 1872 int error; 1873 struct uio uio; 1874 struct iovec iov; 1875 caddr_t buf; 1876 fscache_t *fscp = C_TO_FSCACHE(cp); 1877 1878 ASSERT(MUTEX_HELD(&cp->c_statelock)); 1879 1880 *bufp = NULL; 1881 1882 /* get back vnode */ 1883 if (cp->c_backvp == NULL) { 1884 error = cachefs_getbackvp(fscp, cp); 1885 if (error) 1886 return (error); 1887 } 1888 1889 /* set up for the readlink */ 1890 bzero(&uio, sizeof (struct uio)); 1891 bzero(&iov, sizeof (struct iovec)); 1892 buf = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP); 1893 iov.iov_base = buf; 1894 iov.iov_len = MAXPATHLEN; 1895 uio.uio_iov = &iov; 1896 uio.uio_iovcnt = 1; 1897 uio.uio_resid = MAXPATHLEN; 1898 uio.uio_segflg = UIO_SYSSPACE; 1899 uio.uio_loffset = 0; 1900 uio.uio_fmode = 0; 1901 uio.uio_extflg = UIO_COPY_CACHED; 1902 uio.uio_llimit = MAXOFFSET_T; 1903 1904 /* get the link data */ 1905 CFS_DPRINT_BACKFS_NFSV4(fscp, 1906 ("cachefs_readlink (nfsv4): cnode %p, backvp %p\n", 1907 cp, cp->c_backvp)); 1908 error = VOP_READLINK(cp->c_backvp, &uio, cr, NULL); 1909 if (error) { 1910 cachefs_kmem_free(buf, MAXPATHLEN); 1911 } else { 1912 *bufp = buf; 1913 /*LINTED alignment okay*/ 1914 *buflenp = MAXPATHLEN - (int)uio.uio_resid; 1915 } 1916 1917 return (error); 1918 } 1919 1920 int 1921 cachefs_getbackvp(struct fscache *fscp, struct cnode *cp) 1922 { 1923 int error = 0; 1924 int flag; 1925 1926 #ifdef CFSDEBUG 1927 CFS_DEBUG(CFSDEBUG_CHEAT | CFSDEBUG_BACK) 1928 printf("cachefs_getbackvp: ENTER fscp %p cp %p\n", 1929 (void *)fscp, (void *)cp); 1930 #endif 1931 ASSERT(cp != NULL); 1932 ASSERT(MUTEX_HELD(&cp->c_statelock)); 1933 ASSERT(cp->c_backvp == NULL); 1934 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 1935 1936 /* 1937 * If destroy is set then the last link to a file has been 1938 * removed. Oddly enough NFS will still return a vnode 1939 * for the file if the timeout has not expired. 1940 * This causes headaches for cachefs_push because the 1941 * vnode is really stale. 1942 * So we just short circuit the problem here. 1943 */ 1944 if (cp->c_flags & CN_DESTROY) 1945 return (ESTALE); 1946 1947 ASSERT(fscp->fs_backvfsp); 1948 if (fscp->fs_backvfsp == NULL) 1949 return (ETIMEDOUT); 1950 error = VFS_VGET(fscp->fs_backvfsp, &cp->c_backvp, 1951 (struct fid *)&cp->c_cookie); 1952 if (cp->c_backvp && cp->c_cred && 1953 ((cp->c_flags & CN_NEEDOPEN) || (cp->c_attr.va_type == VREG))) { 1954 /* 1955 * XXX bob: really should pass in the correct flag, 1956 * fortunately nobody pays attention to it 1957 */ 1958 flag = 0; 1959 /* 1960 * If NEEDOOPEN is set, then this file was opened VOP_OPEN'd 1961 * but the backvp was not. So, for the sake of the vnode 1962 * open counts used by delegation, we need to OPEN the backvp 1963 * with the same flags that were used for this cnode. That way 1964 * when the file is VOP_CLOSE'd the counts won't go negative. 1965 */ 1966 if (cp->c_flags & CN_NEEDOPEN) { 1967 cp->c_flags &= ~CN_NEEDOPEN; 1968 if (cp->c_rdcnt > 0) { 1969 cp->c_rdcnt--; 1970 flag |= FREAD; 1971 } 1972 if (cp->c_wrcnt > 0) { 1973 cp->c_wrcnt--; 1974 flag |= FWRITE; 1975 } 1976 } 1977 error = VOP_OPEN(&cp->c_backvp, flag, cp->c_cred, NULL); 1978 if (error) { 1979 VN_RELE(cp->c_backvp); 1980 cp->c_backvp = NULL; 1981 } 1982 } 1983 1984 #ifdef CFSDEBUG 1985 CFS_DEBUG(CFSDEBUG_GENERAL | CFSDEBUG_BACK) { 1986 if (error || cp->c_backvp == NULL) { 1987 printf("Stale cookie cp %p fileno %llu type %d \n", 1988 (void *)cp, (u_longlong_t)cp->c_id.cid_fileno, 1989 CTOV(cp)->v_type); 1990 } 1991 } 1992 #endif 1993 1994 #ifdef CFSDEBUG 1995 CFS_DEBUG(CFSDEBUG_CHEAT | CFSDEBUG_BACK) 1996 printf("cachefs_getbackvp: EXIT error = %d\n", error); 1997 #endif 1998 return (error); 1999 } 2000 2001 int 2002 cachefs_getcookie( 2003 vnode_t *vp, 2004 struct fid *cookiep, 2005 struct vattr *attrp, 2006 cred_t *cr, 2007 uint32_t valid_fid) 2008 { 2009 int error = 0; 2010 2011 #ifdef CFSDEBUG 2012 CFS_DEBUG(CFSDEBUG_CHEAT) 2013 printf("cachefs_getcookie: ENTER vp %p\n", (void *)vp); 2014 #endif 2015 /* 2016 * Get the FID only if the caller has indicated it is valid, 2017 * otherwise, zero the cookie. 2018 */ 2019 if (valid_fid) { 2020 /* 2021 * This assumes that the cookie is a full size fid, if we go to 2022 * variable length fids we will need to change this. 2023 */ 2024 cookiep->fid_len = MAXFIDSZ; 2025 error = VOP_FID(vp, cookiep, NULL); 2026 } else { 2027 bzero(cookiep, sizeof (*cookiep)); 2028 } 2029 2030 if (!error) { 2031 if (attrp) { 2032 ASSERT(attrp != NULL); 2033 attrp->va_mask = AT_ALL; 2034 error = VOP_GETATTR(vp, attrp, 0, cr, NULL); 2035 } 2036 } else { 2037 if (error == ENOSPC) { 2038 /* 2039 * This is an indication that the underlying filesystem 2040 * needs a bigger fid. For now just map to EINVAL. 2041 */ 2042 error = EINVAL; 2043 } 2044 } 2045 #ifdef CFSDEBUG 2046 CFS_DEBUG(CFSDEBUG_CHEAT) 2047 printf("cachefs_getcookie: EXIT error = %d\n", error); 2048 #endif 2049 return (error); 2050 } 2051 2052 void 2053 cachefs_workq_init(struct cachefs_workq *qp) 2054 { 2055 qp->wq_head = qp->wq_tail = NULL; 2056 qp->wq_length = 2057 qp->wq_thread_count = 2058 qp->wq_max_len = 2059 qp->wq_halt_request = 0; 2060 qp->wq_keepone = 0; 2061 cv_init(&qp->wq_req_cv, NULL, CV_DEFAULT, NULL); 2062 cv_init(&qp->wq_halt_cv, NULL, CV_DEFAULT, NULL); 2063 mutex_init(&qp->wq_queue_lock, NULL, MUTEX_DEFAULT, NULL); 2064 } 2065 2066 /* 2067 * return non-zero if it's `okay' to queue more requests (policy) 2068 */ 2069 2070 static int cachefs_async_max = 512; 2071 static int cachefs_async_count = 0; 2072 kmutex_t cachefs_async_lock; 2073 2074 int 2075 cachefs_async_okay(void) 2076 { 2077 /* 2078 * a value of -1 for max means to ignore freemem 2079 */ 2080 2081 if (cachefs_async_max == -1) 2082 return (1); 2083 2084 if (freemem < minfree) 2085 return (0); 2086 2087 /* 2088 * a value of 0 for max means no arbitrary limit (only `freemen') 2089 */ 2090 2091 if (cachefs_async_max == 0) 2092 return (1); 2093 2094 ASSERT(cachefs_async_max > 0); 2095 2096 /* 2097 * check the global count against the max. 2098 * 2099 * we don't need to grab cachefs_async_lock -- we're just 2100 * looking, and a little bit of `fuzz' is okay. 2101 */ 2102 2103 if (cachefs_async_count >= cachefs_async_max) 2104 return (0); 2105 2106 return (1); 2107 } 2108 2109 void 2110 cachefs_async_start(struct cachefs_workq *qp) 2111 { 2112 struct cachefs_req *rp; 2113 int left; 2114 callb_cpr_t cprinfo; 2115 2116 CALLB_CPR_INIT(&cprinfo, &qp->wq_queue_lock, callb_generic_cpr, "cas"); 2117 mutex_enter(&qp->wq_queue_lock); 2118 left = 1; 2119 for (;;) { 2120 /* if there are no pending requests */ 2121 if ((qp->wq_head == NULL) && (qp->wq_logwork == 0)) { 2122 /* see if thread should exit */ 2123 if (qp->wq_halt_request || (left == -1)) { 2124 if ((qp->wq_thread_count > 1) || 2125 (qp->wq_keepone == 0)) 2126 break; 2127 } 2128 2129 /* wake up thread in async_halt if necessary */ 2130 if (qp->wq_halt_request) 2131 cv_broadcast(&qp->wq_halt_cv); 2132 2133 CALLB_CPR_SAFE_BEGIN(&cprinfo); 2134 /* sleep until there is something to do */ 2135 left = cv_reltimedwait(&qp->wq_req_cv, 2136 &qp->wq_queue_lock, CFS_ASYNC_TIMEOUT, 2137 TR_CLOCK_TICK); 2138 CALLB_CPR_SAFE_END(&cprinfo, &qp->wq_queue_lock); 2139 if ((qp->wq_head == NULL) && (qp->wq_logwork == 0)) 2140 continue; 2141 } 2142 left = 1; 2143 2144 if (qp->wq_logwork) { 2145 qp->wq_logwork = 0; 2146 mutex_exit(&qp->wq_queue_lock); 2147 cachefs_log_process_queue(qp->wq_cachep, 1); 2148 mutex_enter(&qp->wq_queue_lock); 2149 continue; 2150 } 2151 2152 /* remove request from the list */ 2153 rp = qp->wq_head; 2154 qp->wq_head = rp->cfs_next; 2155 if (rp->cfs_next == NULL) 2156 qp->wq_tail = NULL; 2157 2158 /* do the request */ 2159 mutex_exit(&qp->wq_queue_lock); 2160 cachefs_do_req(rp); 2161 mutex_enter(&qp->wq_queue_lock); 2162 2163 /* decrement count of requests */ 2164 qp->wq_length--; 2165 mutex_enter(&cachefs_async_lock); 2166 --cachefs_async_count; 2167 mutex_exit(&cachefs_async_lock); 2168 } 2169 ASSERT(qp->wq_head == NULL); 2170 qp->wq_thread_count--; 2171 if (qp->wq_halt_request && qp->wq_thread_count == 0) 2172 cv_broadcast(&qp->wq_halt_cv); 2173 CALLB_CPR_EXIT(&cprinfo); 2174 thread_exit(); 2175 /*NOTREACHED*/ 2176 } 2177 2178 /* 2179 * attempt to halt all the async threads associated with a given workq 2180 */ 2181 int 2182 cachefs_async_halt(struct cachefs_workq *qp, int force) 2183 { 2184 int error = 0; 2185 2186 mutex_enter(&qp->wq_queue_lock); 2187 if (force) 2188 qp->wq_keepone = 0; 2189 2190 if (qp->wq_thread_count > 0) { 2191 qp->wq_halt_request++; 2192 cv_broadcast(&qp->wq_req_cv); 2193 (void) cv_reltimedwait(&qp->wq_halt_cv, 2194 &qp->wq_queue_lock, (60 * hz), TR_CLOCK_TICK); 2195 qp->wq_halt_request--; 2196 if (qp->wq_thread_count > 0) { 2197 if ((qp->wq_thread_count == 1) && 2198 (qp->wq_length == 0) && qp->wq_keepone) 2199 error = EAGAIN; 2200 else 2201 error = EBUSY; 2202 } else { 2203 ASSERT(qp->wq_length == 0 && qp->wq_head == NULL); 2204 } 2205 } 2206 mutex_exit(&qp->wq_queue_lock); 2207 return (error); 2208 } 2209 2210 void 2211 cachefs_addqueue(struct cachefs_req *rp, struct cachefs_workq *qp) 2212 { 2213 mutex_enter(&qp->wq_queue_lock); 2214 if (qp->wq_thread_count < cachefs_max_threads) { 2215 if (qp->wq_thread_count == 0 || 2216 (qp->wq_length >= (qp->wq_thread_count * 2))) { 2217 (void) thread_create(NULL, 0, cachefs_async_start, 2218 qp, 0, &p0, TS_RUN, minclsyspri); 2219 qp->wq_thread_count++; 2220 } 2221 } 2222 mutex_enter(&rp->cfs_req_lock); 2223 if (qp->wq_tail) 2224 qp->wq_tail->cfs_next = rp; 2225 else 2226 qp->wq_head = rp; 2227 qp->wq_tail = rp; 2228 rp->cfs_next = NULL; 2229 qp->wq_length++; 2230 if (qp->wq_length > qp->wq_max_len) 2231 qp->wq_max_len = qp->wq_length; 2232 mutex_enter(&cachefs_async_lock); 2233 ++cachefs_async_count; 2234 mutex_exit(&cachefs_async_lock); 2235 2236 cv_signal(&qp->wq_req_cv); 2237 mutex_exit(&rp->cfs_req_lock); 2238 mutex_exit(&qp->wq_queue_lock); 2239 } 2240 2241 void 2242 cachefs_async_putpage(struct cachefs_putpage_req *prp, cred_t *cr) 2243 { 2244 struct cnode *cp = VTOC(prp->cp_vp); 2245 2246 ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0); 2247 2248 (void) VOP_PUTPAGE(prp->cp_vp, prp->cp_off, prp->cp_len, 2249 prp->cp_flags, cr, NULL); 2250 2251 mutex_enter(&cp->c_iomutex); 2252 if (--cp->c_nio == 0) 2253 cv_broadcast(&cp->c_iocv); 2254 if (prp->cp_off == 0 && prp->cp_len == 0 && 2255 (cp->c_ioflags & CIO_PUTPAGES)) { 2256 cp->c_ioflags &= ~CIO_PUTPAGES; 2257 } 2258 mutex_exit(&cp->c_iomutex); 2259 } 2260 2261 void 2262 cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr) 2263 { 2264 struct cnode *cp = VTOC(pop->cpop_vp); 2265 struct fscache *fscp = C_TO_FSCACHE(cp); 2266 struct filegrp *fgp = cp->c_filegrp; 2267 int error = 0; /* not returned -- used as a place-holder */ 2268 vnode_t *frontvp = NULL, *backvp = NULL; 2269 int havelock = 0; 2270 vattr_t va; 2271 2272 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0); 2273 2274 if (((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) || 2275 (fscp->fs_cdconnected != CFS_CD_CONNECTED)) { 2276 mutex_enter(&cp->c_statelock); 2277 cp->c_flags &= ~CN_ASYNC_POPULATE; 2278 mutex_exit(&cp->c_statelock); 2279 return; /* goto out */ 2280 } 2281 2282 error = cachefs_cd_access(fscp, 0, 0); 2283 if (error) { 2284 #ifdef CFSDEBUG 2285 CFS_DEBUG(CFSDEBUG_ASYNCPOP) 2286 printf("async_pop: cd_access: err %d con %d\n", 2287 error, fscp->fs_cdconnected); 2288 #endif /* CFSDEBUG */ 2289 mutex_enter(&cp->c_statelock); 2290 cp->c_flags &= ~CN_ASYNC_POPULATE; 2291 mutex_exit(&cp->c_statelock); 2292 return; /* goto out */ 2293 } 2294 2295 /* 2296 * grab the statelock for some minimal things 2297 */ 2298 2299 rw_enter(&cp->c_rwlock, RW_WRITER); 2300 mutex_enter(&cp->c_statelock); 2301 havelock = 1; 2302 2303 if ((cp->c_flags & CN_ASYNC_POPULATE) == 0) 2304 goto out; 2305 2306 /* there can be only one */ 2307 ASSERT((cp->c_flags & CN_ASYNC_POP_WORKING) == 0); 2308 cp->c_flags |= CN_ASYNC_POP_WORKING; 2309 cp->c_popthrp = curthread; 2310 2311 if (cp->c_metadata.md_flags & MD_POPULATED) 2312 goto out; 2313 2314 if (cp->c_flags & CN_NOCACHE) { 2315 #ifdef CFSDEBUG 2316 CFS_DEBUG(CFSDEBUG_ASYNCPOP) 2317 printf("cachefs_async_populate: nocache bit on\n"); 2318 #endif /* CFSDEBUG */ 2319 error = EINVAL; 2320 goto out; 2321 } 2322 2323 if (cp->c_frontvp == NULL) { 2324 if ((cp->c_metadata.md_flags & MD_FILE) == 0) { 2325 struct cfs_cid cid = cp->c_id; 2326 2327 mutex_exit(&cp->c_statelock); 2328 havelock = 0; 2329 2330 /* 2331 * if frontfile doesn't exist, drop the lock 2332 * to do some of the file creation stuff. 2333 */ 2334 2335 if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) { 2336 error = filegrp_allocattr(fgp); 2337 if (error != 0) 2338 goto out; 2339 } 2340 if (fgp->fg_flags & CFS_FG_ALLOC_FILE) { 2341 mutex_enter(&fgp->fg_mutex); 2342 if (fgp->fg_flags & CFS_FG_ALLOC_FILE) { 2343 if (fgp->fg_header->ach_nffs == 0) 2344 error = filegrpdir_create(fgp); 2345 else 2346 error = filegrpdir_find(fgp); 2347 if (error != 0) { 2348 mutex_exit(&fgp->fg_mutex); 2349 goto out; 2350 } 2351 } 2352 mutex_exit(&fgp->fg_mutex); 2353 } 2354 2355 if (fgp->fg_dirvp != NULL) { 2356 char name[CFS_FRONTFILE_NAME_SIZE]; 2357 struct vattr *attrp; 2358 2359 attrp = cachefs_kmem_zalloc( 2360 sizeof (struct vattr), KM_SLEEP); 2361 attrp->va_mode = S_IFREG | 0666; 2362 attrp->va_uid = 0; 2363 attrp->va_gid = 0; 2364 attrp->va_type = VREG; 2365 attrp->va_size = 0; 2366 attrp->va_mask = 2367 AT_SIZE | AT_TYPE | AT_MODE | 2368 AT_UID | AT_GID; 2369 2370 make_ascii_name(&cid, name); 2371 2372 (void) VOP_CREATE(fgp->fg_dirvp, name, attrp, 2373 EXCL, 0666, &frontvp, kcred, 0, NULL, NULL); 2374 2375 cachefs_kmem_free(attrp, 2376 sizeof (struct vattr)); 2377 } 2378 2379 mutex_enter(&cp->c_statelock); 2380 havelock = 1; 2381 } 2382 error = cachefs_getfrontfile(cp); 2383 ASSERT((error != 0) || 2384 (frontvp == NULL) || 2385 (frontvp == cp->c_frontvp)); 2386 } 2387 if ((error != 0) || (cp->c_frontvp == NULL)) 2388 goto out; 2389 2390 if (frontvp != NULL) 2391 VN_RELE(frontvp); 2392 2393 frontvp = cp->c_frontvp; 2394 VN_HOLD(frontvp); 2395 2396 if (cp->c_backvp == NULL) { 2397 error = cachefs_getbackvp(fscp, cp); 2398 if ((error != 0) || (cp->c_backvp == NULL)) 2399 goto out; 2400 } 2401 backvp = cp->c_backvp; 2402 VN_HOLD(backvp); 2403 2404 switch (pop->cpop_vp->v_type) { 2405 case VREG: 2406 mutex_exit(&cp->c_statelock); 2407 havelock = 0; 2408 error = cachefs_async_populate_reg(pop, cr, backvp, frontvp); 2409 break; 2410 case VDIR: 2411 error = cachefs_async_populate_dir(pop, cr, backvp, frontvp); 2412 mutex_exit(&cp->c_statelock); 2413 havelock = 0; 2414 break; 2415 default: 2416 #ifdef CFSDEBUG 2417 printf("cachefs_async_populate: warning: vnode type = %d\n", 2418 pop->cpop_vp->v_type); 2419 ASSERT(0); 2420 #endif /* CFSDEBUG */ 2421 error = EINVAL; 2422 break; 2423 } 2424 2425 if (error != 0) 2426 goto out; 2427 2428 error = VOP_FSYNC(frontvp, FSYNC, cr, NULL); 2429 if (error != 0) { 2430 #ifdef CFSDEBUG 2431 CFS_DEBUG(CFSDEBUG_ASYNCPOP) 2432 printf("cachefs_async_populate: fsync\n"); 2433 #endif /* CFSDEBUG */ 2434 goto out; 2435 } 2436 2437 /* grab the lock and finish up */ 2438 mutex_enter(&cp->c_statelock); 2439 havelock = 1; 2440 2441 /* if went nocache while lock was dropped, get out */ 2442 if ((cp->c_flags & CN_NOCACHE) || (cp->c_frontvp == NULL)) { 2443 error = EINVAL; 2444 goto out; 2445 } 2446 2447 va.va_mask = AT_MTIME; 2448 error = VOP_GETATTR(cp->c_frontvp, &va, 0, cr, NULL); 2449 if (error) { 2450 #ifdef CFSDEBUG 2451 CFS_DEBUG(CFSDEBUG_ASYNCPOP) 2452 printf("cachefs_async_populate: getattr\n"); 2453 #endif /* CFSDEBUG */ 2454 goto out; 2455 } 2456 cp->c_metadata.md_timestamp = va.va_mtime; 2457 cp->c_metadata.md_flags |= MD_POPULATED; 2458 cp->c_metadata.md_flags &= ~MD_INVALREADDIR; 2459 cp->c_flags |= CN_UPDATED; 2460 2461 out: 2462 if (! havelock) 2463 mutex_enter(&cp->c_statelock); 2464 2465 /* see if an error happened behind our backs */ 2466 if ((error == 0) && (cp->c_flags & CN_NOCACHE)) { 2467 #ifdef CFSDEBUG 2468 CFS_DEBUG(CFSDEBUG_ASYNCPOP) 2469 printf("cachefs_async_populate: " 2470 "nocache behind our backs\n"); 2471 #endif /* CFSDEBUG */ 2472 error = EINVAL; 2473 } 2474 2475 cp->c_flags &= ~(CN_NEED_FRONT_SYNC | CN_POPULATION_PENDING | 2476 CN_ASYNC_POPULATE | CN_ASYNC_POP_WORKING); 2477 cp->c_popthrp = NULL; 2478 2479 if (error != 0) 2480 cachefs_nocache(cp); 2481 2482 /* unblock any threads waiting for populate to finish */ 2483 cv_broadcast(&cp->c_popcv); 2484 mutex_exit(&cp->c_statelock); 2485 rw_exit(&cp->c_rwlock); 2486 cachefs_cd_release(fscp); 2487 2488 if (backvp != NULL) { 2489 VN_RELE(backvp); 2490 } 2491 if (frontvp != NULL) { 2492 VN_RELE(frontvp); 2493 } 2494 } 2495 2496 /* 2497 * only to be called from cachefs_async_populate 2498 */ 2499 2500 static int 2501 cachefs_async_populate_reg(struct cachefs_populate_req *pop, cred_t *cr, 2502 vnode_t *backvp, vnode_t *frontvp) 2503 { 2504 struct cnode *cp = VTOC(pop->cpop_vp); 2505 int error = 0; 2506 u_offset_t popoff; 2507 size_t popsize; 2508 2509 cachefs_cluster_allocmap(pop->cpop_off, &popoff, 2510 &popsize, pop->cpop_size, cp); 2511 if (popsize == 0) { 2512 #ifdef CFSDEBUG 2513 CFS_DEBUG(CFSDEBUG_ASYNCPOP) 2514 printf("cachefs_async_populate: popsize == 0\n"); 2515 #endif /* CFSDEBUG */ 2516 goto out; 2517 } 2518 2519 error = cachefs_populate(cp, popoff, popsize, frontvp, backvp, 2520 cp->c_size, cr); 2521 if (error != 0) { 2522 #ifdef CFSDEBUG 2523 CFS_DEBUG(CFSDEBUG_ASYNCPOP) 2524 printf("cachefs_async_populate: cachefs_populate\n"); 2525 #endif /* CFSDEBUG */ 2526 goto out; 2527 } 2528 2529 out: 2530 return (error); 2531 } 2532 2533 void 2534 cachefs_do_req(struct cachefs_req *rp) 2535 { 2536 struct cachefscache *cachep; 2537 2538 mutex_enter(&rp->cfs_req_lock); 2539 switch (rp->cfs_cmd) { 2540 case CFS_INVALID: 2541 panic("cachefs_do_req: CFS_INVALID operation on queue"); 2542 /*NOTREACHED*/ 2543 case CFS_CACHE_SYNC: 2544 cachep = rp->cfs_req_u.cu_fs_sync.cf_cachep; 2545 cachefs_cache_sync(cachep); 2546 break; 2547 case CFS_IDLE: 2548 cachefs_cnode_idle(rp->cfs_req_u.cu_idle.ci_vp, rp->cfs_cr); 2549 break; 2550 case CFS_PUTPAGE: 2551 cachefs_async_putpage(&rp->cfs_req_u.cu_putpage, rp->cfs_cr); 2552 VN_RELE(rp->cfs_req_u.cu_putpage.cp_vp); 2553 break; 2554 case CFS_POPULATE: 2555 cachefs_async_populate(&rp->cfs_req_u.cu_populate, rp->cfs_cr); 2556 VN_RELE(rp->cfs_req_u.cu_populate.cpop_vp); 2557 break; 2558 case CFS_NOOP: 2559 break; 2560 default: 2561 panic("c_do_req: Invalid CFS async operation"); 2562 } 2563 crfree(rp->cfs_cr); 2564 rp->cfs_cmd = CFS_INVALID; 2565 mutex_exit(&rp->cfs_req_lock); 2566 kmem_cache_free(cachefs_req_cache, rp); 2567 } 2568 2569 2570 2571 2572 ssize_t cachefs_mem_usage = 0; 2573 2574 struct km_wrap { 2575 size_t kw_size; 2576 struct km_wrap *kw_other; 2577 }; 2578 2579 kmutex_t cachefs_kmem_lock; 2580 2581 void * 2582 cachefs_kmem_alloc(size_t size, int flag) 2583 { 2584 #ifdef DEBUG 2585 caddr_t mp = NULL; 2586 struct km_wrap *kwp; 2587 size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7; 2588 2589 ASSERT(n >= (size + 8)); 2590 mp = kmem_alloc(n, flag); 2591 if (mp == NULL) { 2592 return (NULL); 2593 } 2594 /*LINTED alignment okay*/ 2595 kwp = (struct km_wrap *)mp; 2596 kwp->kw_size = n; 2597 /*LINTED alignment okay*/ 2598 kwp->kw_other = (struct km_wrap *)(mp + n - sizeof (struct km_wrap)); 2599 kwp = (struct km_wrap *)kwp->kw_other; 2600 kwp->kw_size = n; 2601 /*LINTED alignment okay*/ 2602 kwp->kw_other = (struct km_wrap *)mp; 2603 2604 mutex_enter(&cachefs_kmem_lock); 2605 ASSERT(cachefs_mem_usage >= 0); 2606 cachefs_mem_usage += n; 2607 mutex_exit(&cachefs_kmem_lock); 2608 2609 return (mp + sizeof (struct km_wrap)); 2610 #else /* DEBUG */ 2611 return (kmem_alloc(size, flag)); 2612 #endif /* DEBUG */ 2613 } 2614 2615 void * 2616 cachefs_kmem_zalloc(size_t size, int flag) 2617 { 2618 #ifdef DEBUG 2619 caddr_t mp = NULL; 2620 struct km_wrap *kwp; 2621 size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7; 2622 2623 ASSERT(n >= (size + 8)); 2624 mp = kmem_zalloc(n, flag); 2625 if (mp == NULL) { 2626 return (NULL); 2627 } 2628 /*LINTED alignment okay*/ 2629 kwp = (struct km_wrap *)mp; 2630 kwp->kw_size = n; 2631 /*LINTED alignment okay*/ 2632 kwp->kw_other = (struct km_wrap *)(mp + n - sizeof (struct km_wrap)); 2633 kwp = (struct km_wrap *)kwp->kw_other; 2634 kwp->kw_size = n; 2635 /*LINTED alignment okay*/ 2636 kwp->kw_other = (struct km_wrap *)mp; 2637 2638 mutex_enter(&cachefs_kmem_lock); 2639 ASSERT(cachefs_mem_usage >= 0); 2640 cachefs_mem_usage += n; 2641 mutex_exit(&cachefs_kmem_lock); 2642 2643 return (mp + sizeof (struct km_wrap)); 2644 #else /* DEBUG */ 2645 return (kmem_zalloc(size, flag)); 2646 #endif /* DEBUG */ 2647 } 2648 2649 void 2650 cachefs_kmem_free(void *mp, size_t size) 2651 { 2652 #ifdef DEBUG 2653 struct km_wrap *front_kwp; 2654 struct km_wrap *back_kwp; 2655 size_t n = (size + (2 * sizeof (struct km_wrap)) + 7) & ~7; 2656 void *p; 2657 2658 ASSERT(n >= (size + 8)); 2659 front_kwp = (struct km_wrap *)((uintptr_t)mp - sizeof (struct km_wrap)); 2660 back_kwp = (struct km_wrap *) 2661 ((uintptr_t)front_kwp + n - sizeof (struct km_wrap)); 2662 2663 ASSERT(front_kwp->kw_other == back_kwp); 2664 ASSERT(front_kwp->kw_size == n); 2665 ASSERT(back_kwp->kw_other == front_kwp); 2666 ASSERT(back_kwp->kw_size == n); 2667 2668 mutex_enter(&cachefs_kmem_lock); 2669 cachefs_mem_usage -= n; 2670 ASSERT(cachefs_mem_usage >= 0); 2671 mutex_exit(&cachefs_kmem_lock); 2672 2673 p = front_kwp; 2674 front_kwp->kw_size = back_kwp->kw_size = 0; 2675 front_kwp->kw_other = back_kwp->kw_other = NULL; 2676 kmem_free(p, n); 2677 #else /* DEBUG */ 2678 kmem_free(mp, size); 2679 #endif /* DEBUG */ 2680 } 2681 2682 char * 2683 cachefs_strdup(char *s) 2684 { 2685 char *rc; 2686 2687 ASSERT(s != NULL); 2688 2689 rc = cachefs_kmem_alloc(strlen(s) + 1, KM_SLEEP); 2690 (void) strcpy(rc, s); 2691 2692 return (rc); 2693 } 2694 2695 int 2696 cachefs_stats_kstat_snapshot(kstat_t *ksp, void *buf, int rw) 2697 { 2698 struct fscache *fscp = (struct fscache *)ksp->ks_data; 2699 cachefscache_t *cachep = fscp->fs_cache; 2700 int error = 0; 2701 2702 if (rw == KSTAT_WRITE) { 2703 bcopy(buf, &fscp->fs_stats, sizeof (fscp->fs_stats)); 2704 cachep->c_gc_count = fscp->fs_stats.st_gc_count; 2705 CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_time, 2706 cachep->c_gc_time); 2707 CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_before_atime, 2708 cachep->c_gc_before); 2709 CACHEFS_CFS_TIME_TO_TIME_COPY(fscp->fs_stats.st_gc_after_atime, 2710 cachep->c_gc_after); 2711 return (error); 2712 } 2713 2714 fscp->fs_stats.st_gc_count = cachep->c_gc_count; 2715 CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_time, 2716 fscp->fs_stats.st_gc_time, error); 2717 CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_before, 2718 fscp->fs_stats.st_gc_before_atime, error); 2719 CACHEFS_TIME_TO_CFS_TIME_COPY(cachep->c_gc_after, 2720 fscp->fs_stats.st_gc_after_atime, error); 2721 bcopy(&fscp->fs_stats, buf, sizeof (fscp->fs_stats)); 2722 2723 return (error); 2724 } 2725 2726 #ifdef DEBUG 2727 cachefs_debug_info_t * 2728 cachefs_debug_save(cachefs_debug_info_t *oldcdb, int chain, 2729 char *message, uint_t flags, int number, void *pointer, 2730 cachefscache_t *cachep, struct fscache *fscp, struct cnode *cp) 2731 { 2732 cachefs_debug_info_t *cdb; 2733 2734 if ((chain) || (oldcdb == NULL)) 2735 cdb = cachefs_kmem_zalloc(sizeof (*cdb), KM_SLEEP); 2736 else 2737 cdb = oldcdb; 2738 if (chain) 2739 cdb->cdb_next = oldcdb; 2740 2741 if (message != NULL) { 2742 if (cdb->cdb_message != NULL) 2743 cachefs_kmem_free(cdb->cdb_message, 2744 strlen(cdb->cdb_message) + 1); 2745 cdb->cdb_message = cachefs_kmem_alloc(strlen(message) + 1, 2746 KM_SLEEP); 2747 (void) strcpy(cdb->cdb_message, message); 2748 } 2749 cdb->cdb_flags = flags; 2750 cdb->cdb_int = number; 2751 cdb->cdb_pointer = pointer; 2752 2753 cdb->cdb_count++; 2754 2755 cdb->cdb_cnode = cp; 2756 if (cp != NULL) { 2757 cdb->cdb_frontvp = cp->c_frontvp; 2758 cdb->cdb_backvp = cp->c_backvp; 2759 } 2760 if (fscp != NULL) 2761 cdb->cdb_fscp = fscp; 2762 else if (cp != NULL) 2763 cdb->cdb_fscp = C_TO_FSCACHE(cp); 2764 if (cachep != NULL) 2765 cdb->cdb_cachep = cachep; 2766 else if (cdb->cdb_fscp != NULL) 2767 cdb->cdb_cachep = cdb->cdb_fscp->fs_cache; 2768 2769 cdb->cdb_thread = curthread; 2770 cdb->cdb_timestamp = gethrtime(); 2771 cdb->cdb_depth = getpcstack(cdb->cdb_stack, CACHEFS_DEBUG_DEPTH); 2772 2773 return (cdb); 2774 } 2775 2776 void 2777 cachefs_debug_show(cachefs_debug_info_t *cdb) 2778 { 2779 hrtime_t now = gethrtime(); 2780 timestruc_t ts; 2781 int i; 2782 2783 while (cdb != NULL) { 2784 hrt2ts(now - cdb->cdb_timestamp, &ts); 2785 printf("cdb: %p count: %d timelapse: %ld.%9ld\n", 2786 (void *)cdb, cdb->cdb_count, ts.tv_sec, ts.tv_nsec); 2787 if (cdb->cdb_message != NULL) 2788 printf("message: %s", cdb->cdb_message); 2789 printf("flags: %x int: %d pointer: %p\n", 2790 cdb->cdb_flags, cdb->cdb_int, (void *)cdb->cdb_pointer); 2791 2792 printf("cnode: %p fscp: %p cachep: %p\n", 2793 (void *)cdb->cdb_cnode, 2794 (void *)cdb->cdb_fscp, (void *)cdb->cdb_cachep); 2795 printf("frontvp: %p backvp: %p\n", 2796 (void *)cdb->cdb_frontvp, (void *)cdb->cdb_backvp); 2797 2798 printf("thread: %p stack...\n", (void *)cdb->cdb_thread); 2799 for (i = 0; i < cdb->cdb_depth; i++) { 2800 ulong_t off; 2801 char *sym; 2802 2803 sym = kobj_getsymname(cdb->cdb_stack[i], &off); 2804 printf("%s+%lx\n", sym ? sym : "?", off); 2805 } 2806 delay(2*hz); 2807 cdb = cdb->cdb_next; 2808 } 2809 debug_enter(NULL); 2810 } 2811 #endif /* DEBUG */ 2812 2813 /* 2814 * Changes the size of the front file. 2815 * Returns 0 for success or error if cannot set file size. 2816 * NOCACHE bit is ignored. 2817 * c_size is ignored. 2818 * statelock must be held, frontvp must be set. 2819 * File must be populated if setting to a size other than zero. 2820 */ 2821 int 2822 cachefs_frontfile_size(cnode_t *cp, u_offset_t length) 2823 { 2824 cachefscache_t *cachep = C_TO_FSCACHE(cp)->fs_cache; 2825 vattr_t va; 2826 size_t nblks, blkdelta; 2827 int error = 0; 2828 int alloc = 0; 2829 struct cachefs_allocmap *allocp; 2830 2831 ASSERT(MUTEX_HELD(&cp->c_statelock)); 2832 ASSERT(cp->c_frontvp); 2833 2834 /* if growing the file, allocate space first, we charge for holes */ 2835 if (length) { 2836 ASSERT(cp->c_metadata.md_flags & MD_POPULATED); 2837 2838 nblks = (length + MAXBSIZE - 1) / MAXBSIZE; 2839 if (nblks > cp->c_metadata.md_frontblks) { 2840 blkdelta = nblks - cp->c_metadata.md_frontblks; 2841 error = cachefs_allocblocks(cachep, blkdelta, 2842 cp->c_metadata.md_rltype); 2843 if (error) 2844 goto out; 2845 alloc = 1; 2846 } 2847 } 2848 2849 /* change the size of the front file */ 2850 va.va_mask = AT_SIZE; 2851 va.va_size = length; 2852 error = VOP_SETATTR(cp->c_frontvp, &va, 0, kcred, NULL); 2853 if (error) 2854 goto out; 2855 2856 /* zero out the alloc map */ 2857 bzero(&cp->c_metadata.md_allocinfo, 2858 cp->c_metadata.md_allocents * sizeof (struct cachefs_allocmap)); 2859 cp->c_metadata.md_allocents = 0; 2860 2861 if (length == 0) { 2862 /* free up blocks */ 2863 if (cp->c_metadata.md_frontblks) { 2864 cachefs_freeblocks(cachep, cp->c_metadata.md_frontblks, 2865 cp->c_metadata.md_rltype); 2866 cp->c_metadata.md_frontblks = 0; 2867 } 2868 } else { 2869 /* update number of blocks if shrinking file */ 2870 nblks = (length + MAXBSIZE - 1) / MAXBSIZE; 2871 if (nblks < cp->c_metadata.md_frontblks) { 2872 blkdelta = cp->c_metadata.md_frontblks - nblks; 2873 cachefs_freeblocks(cachep, blkdelta, 2874 cp->c_metadata.md_rltype); 2875 cp->c_metadata.md_frontblks = (uint_t)nblks; 2876 } 2877 2878 /* fix up alloc map to reflect new size */ 2879 allocp = cp->c_metadata.md_allocinfo; 2880 allocp->am_start_off = 0; 2881 allocp->am_size = length; 2882 cp->c_metadata.md_allocents = 1; 2883 } 2884 cp->c_flags |= CN_UPDATED | CN_NEED_FRONT_SYNC; 2885 2886 out: 2887 if (error && alloc) 2888 cachefs_freeblocks(cachep, blkdelta, cp->c_metadata.md_rltype); 2889 return (error); 2890 } 2891 2892 /*ARGSUSED*/ 2893 int 2894 cachefs_req_create(void *voidp, void *cdrarg, int kmflags) 2895 { 2896 struct cachefs_req *rp = (struct cachefs_req *)voidp; 2897 2898 /* 2899 * XXX don't do this! if you need this, you can't use this 2900 * constructor. 2901 */ 2902 2903 bzero(rp, sizeof (struct cachefs_req)); 2904 2905 mutex_init(&rp->cfs_req_lock, NULL, MUTEX_DEFAULT, NULL); 2906 return (0); 2907 } 2908 2909 /*ARGSUSED*/ 2910 void 2911 cachefs_req_destroy(void *voidp, void *cdrarg) 2912 { 2913 struct cachefs_req *rp = (struct cachefs_req *)voidp; 2914 2915 mutex_destroy(&rp->cfs_req_lock); 2916 }