FreeBSD ZFS
The Zettabyte File System
|
00001 /* 00002 * CDDL HEADER START 00003 * 00004 * The contents of this file are subject to the terms of the 00005 * Common Development and Distribution License (the "License"). 00006 * You may not use this file except in compliance with the License. 00007 * 00008 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 00009 * or http://www.opensolaris.org/os/licensing. 00010 * See the License for the specific language governing permissions 00011 * and limitations under the License. 00012 * 00013 * When distributing Covered Code, include this CDDL HEADER in each 00014 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 00015 * If applicable, add the following below this CDDL HEADER, with the 00016 * fields enclosed by brackets "[]" replaced with your own identifying 00017 * information: Portions Copyright [yyyy] [name of copyright owner] 00018 * 00019 * CDDL HEADER END 00020 */ 00021 /* 00022 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 00023 * Use is subject to license terms. 00024 */ 00025 00026 #include <sys/zfs_context.h> 00027 #include <sys/dnode.h> 00028 #include <sys/dmu_objset.h> 00029 #include <sys/dmu_zfetch.h> 00030 #include <sys/dmu.h> 00031 #include <sys/dbuf.h> 00032 #include <sys/kstat.h> 00033 00034 /* 00035 * I'm against tune-ables, but these should probably exist as tweakable globals 00036 * until we can get this working the way we want it to. 00037 */ 00043 int zfs_prefetch_disable = 0; 00044 00046 uint32_t zfetch_max_streams = 8; 00048 uint32_t zfetch_min_sec_reap = 2; 00050 uint32_t zfetch_block_cap = 256; 00052 uint64_t zfetch_array_rd_sz = 1024 * 1024; 00053 /* \} */ 00054 00055 SYSCTL_DECL(_vfs_zfs); 00056 SYSCTL_INT(_vfs_zfs, OID_AUTO, prefetch_disable, CTLFLAG_RW, 00057 &zfs_prefetch_disable, 0, "Disable prefetch"); 00058 SYSCTL_NODE(_vfs_zfs, OID_AUTO, zfetch, CTLFLAG_RW, 0, "ZFS ZFETCH"); 00059 TUNABLE_INT("vfs.zfs.zfetch.max_streams", &zfetch_max_streams); 00060 SYSCTL_UINT(_vfs_zfs_zfetch, OID_AUTO, max_streams, CTLFLAG_RW, 00061 &zfetch_max_streams, 0, "Max # of streams per zfetch"); 00062 TUNABLE_INT("vfs.zfs.zfetch.min_sec_reap", &zfetch_min_sec_reap); 00063 SYSCTL_UINT(_vfs_zfs_zfetch, OID_AUTO, min_sec_reap, CTLFLAG_RDTUN, 00064 &zfetch_min_sec_reap, 0, "Min time before stream reclaim"); 00065 TUNABLE_INT("vfs.zfs.zfetch.block_cap", &zfetch_block_cap); 00066 SYSCTL_UINT(_vfs_zfs_zfetch, OID_AUTO, block_cap, CTLFLAG_RDTUN, 00067 &zfetch_block_cap, 0, "Max number of blocks to fetch at a time"); 00068 TUNABLE_QUAD("vfs.zfs.zfetch.array_rd_sz", &zfetch_array_rd_sz); 00069 SYSCTL_UQUAD(_vfs_zfs_zfetch, OID_AUTO, array_rd_sz, CTLFLAG_RDTUN, 00070 &zfetch_array_rd_sz, 0, 00071 "Number of bytes in a array_read at which we stop prefetching"); 00072 00073 /* forward decls for static routines */ 00074 static int dmu_zfetch_colinear(zfetch_t *, zstream_t *); 00075 static void dmu_zfetch_dofetch(zfetch_t *, zstream_t *); 00076 static uint64_t dmu_zfetch_fetch(dnode_t *, uint64_t, uint64_t); 00077 static uint64_t dmu_zfetch_fetchsz(dnode_t *, uint64_t, uint64_t); 00078 static int dmu_zfetch_find(zfetch_t *, zstream_t *, int); 00079 static int dmu_zfetch_stream_insert(zfetch_t *, zstream_t *); 00080 static zstream_t *dmu_zfetch_stream_reclaim(zfetch_t *); 00081 static void dmu_zfetch_stream_remove(zfetch_t *, zstream_t *); 00082 static int dmu_zfetch_streams_equal(zstream_t *, zstream_t *); 00083 00084 typedef struct zfetch_stats { 00085 kstat_named_t zfetchstat_hits; 00086 kstat_named_t zfetchstat_misses; 00087 kstat_named_t zfetchstat_colinear_hits; 00088 kstat_named_t zfetchstat_colinear_misses; 00089 kstat_named_t zfetchstat_stride_hits; 00090 kstat_named_t zfetchstat_stride_misses; 00091 kstat_named_t zfetchstat_reclaim_successes; 00092 kstat_named_t zfetchstat_reclaim_failures; 00093 kstat_named_t zfetchstat_stream_resets; 00094 kstat_named_t zfetchstat_stream_noresets; 00095 kstat_named_t zfetchstat_bogus_streams; 00096 } zfetch_stats_t; 00097 00098 static zfetch_stats_t zfetch_stats = { 00099 { "hits", KSTAT_DATA_UINT64 }, 00100 { "misses", KSTAT_DATA_UINT64 }, 00101 { "colinear_hits", KSTAT_DATA_UINT64 }, 00102 { "colinear_misses", KSTAT_DATA_UINT64 }, 00103 { "stride_hits", KSTAT_DATA_UINT64 }, 00104 { "stride_misses", KSTAT_DATA_UINT64 }, 00105 { "reclaim_successes", KSTAT_DATA_UINT64 }, 00106 { "reclaim_failures", KSTAT_DATA_UINT64 }, 00107 { "streams_resets", KSTAT_DATA_UINT64 }, 00108 { "streams_noresets", KSTAT_DATA_UINT64 }, 00109 { "bogus_streams", KSTAT_DATA_UINT64 }, 00110 }; 00111 00112 #define ZFETCHSTAT_INCR(stat, val) \ 00113 atomic_add_64(&zfetch_stats.stat.value.ui64, (val)); 00114 00115 #define ZFETCHSTAT_BUMP(stat) ZFETCHSTAT_INCR(stat, 1); 00116 00117 kstat_t *zfetch_ksp; 00118 00132 static int 00133 dmu_zfetch_colinear(zfetch_t *zf, zstream_t *zh) 00134 { 00135 zstream_t *z_walk; 00136 zstream_t *z_comp; 00137 00138 if (! rw_tryenter(&zf->zf_rwlock, RW_WRITER)) 00139 return (0); 00140 00141 if (zh == NULL) { 00142 rw_exit(&zf->zf_rwlock); 00143 return (0); 00144 } 00145 00146 for (z_walk = list_head(&zf->zf_stream); z_walk; 00147 z_walk = list_next(&zf->zf_stream, z_walk)) { 00148 for (z_comp = list_next(&zf->zf_stream, z_walk); z_comp; 00149 z_comp = list_next(&zf->zf_stream, z_comp)) { 00150 int64_t diff; 00151 00152 if (z_walk->zst_len != z_walk->zst_stride || 00153 z_comp->zst_len != z_comp->zst_stride) { 00154 continue; 00155 } 00156 00157 diff = z_comp->zst_offset - z_walk->zst_offset; 00158 if (z_comp->zst_offset + diff == zh->zst_offset) { 00159 z_walk->zst_offset = zh->zst_offset; 00160 z_walk->zst_direction = diff < 0 ? -1 : 1; 00161 z_walk->zst_stride = 00162 diff * z_walk->zst_direction; 00163 z_walk->zst_ph_offset = 00164 zh->zst_offset + z_walk->zst_stride; 00165 dmu_zfetch_stream_remove(zf, z_comp); 00166 mutex_destroy(&z_comp->zst_lock); 00167 kmem_free(z_comp, sizeof (zstream_t)); 00168 00169 dmu_zfetch_dofetch(zf, z_walk); 00170 00171 rw_exit(&zf->zf_rwlock); 00172 return (1); 00173 } 00174 00175 diff = z_walk->zst_offset - z_comp->zst_offset; 00176 if (z_walk->zst_offset + diff == zh->zst_offset) { 00177 z_walk->zst_offset = zh->zst_offset; 00178 z_walk->zst_direction = diff < 0 ? -1 : 1; 00179 z_walk->zst_stride = 00180 diff * z_walk->zst_direction; 00181 z_walk->zst_ph_offset = 00182 zh->zst_offset + z_walk->zst_stride; 00183 dmu_zfetch_stream_remove(zf, z_comp); 00184 mutex_destroy(&z_comp->zst_lock); 00185 kmem_free(z_comp, sizeof (zstream_t)); 00186 00187 dmu_zfetch_dofetch(zf, z_walk); 00188 00189 rw_exit(&zf->zf_rwlock); 00190 return (1); 00191 } 00192 } 00193 } 00194 00195 rw_exit(&zf->zf_rwlock); 00196 return (0); 00197 } 00198 00203 static void 00204 dmu_zfetch_dofetch(zfetch_t *zf, zstream_t *zs) 00205 { 00206 uint64_t prefetch_tail; 00207 uint64_t prefetch_limit; 00208 uint64_t prefetch_ofst; 00209 uint64_t prefetch_len; 00210 uint64_t blocks_fetched; 00211 00212 zs->zst_stride = MAX((int64_t)zs->zst_stride, zs->zst_len); 00213 zs->zst_cap = MIN(zfetch_block_cap, 2 * zs->zst_cap); 00214 00215 prefetch_tail = MAX((int64_t)zs->zst_ph_offset, 00216 (int64_t)(zs->zst_offset + zs->zst_stride)); 00217 /* 00218 * XXX: use a faster division method? 00219 */ 00220 prefetch_limit = zs->zst_offset + zs->zst_len + 00221 (zs->zst_cap * zs->zst_stride) / zs->zst_len; 00222 00223 while (prefetch_tail < prefetch_limit) { 00224 prefetch_ofst = zs->zst_offset + zs->zst_direction * 00225 (prefetch_tail - zs->zst_offset); 00226 00227 prefetch_len = zs->zst_len; 00228 00229 /* 00230 * Don't prefetch beyond the end of the file, if working 00231 * backwards. 00232 */ 00233 if ((zs->zst_direction == ZFETCH_BACKWARD) && 00234 (prefetch_ofst > prefetch_tail)) { 00235 prefetch_len += prefetch_ofst; 00236 prefetch_ofst = 0; 00237 } 00238 00239 /* don't prefetch more than we're supposed to */ 00240 if (prefetch_len > zs->zst_len) 00241 break; 00242 00243 blocks_fetched = dmu_zfetch_fetch(zf->zf_dnode, 00244 prefetch_ofst, zs->zst_len); 00245 00246 prefetch_tail += zs->zst_stride; 00247 /* stop if we've run out of stuff to prefetch */ 00248 if (blocks_fetched < zs->zst_len) 00249 break; 00250 } 00251 zs->zst_ph_offset = prefetch_tail; 00252 zs->zst_last = ddi_get_lbolt(); 00253 } 00254 00255 void 00256 zfetch_init(void) 00257 { 00258 00259 zfetch_ksp = kstat_create("zfs", 0, "zfetchstats", "misc", 00260 KSTAT_TYPE_NAMED, sizeof (zfetch_stats) / sizeof (kstat_named_t), 00261 KSTAT_FLAG_VIRTUAL); 00262 00263 if (zfetch_ksp != NULL) { 00264 zfetch_ksp->ks_data = &zfetch_stats; 00265 kstat_install(zfetch_ksp); 00266 } 00267 } 00268 00269 void 00270 zfetch_fini(void) 00271 { 00272 if (zfetch_ksp != NULL) { 00273 kstat_delete(zfetch_ksp); 00274 zfetch_ksp = NULL; 00275 } 00276 } 00277 00285 void 00286 dmu_zfetch_init(zfetch_t *zf, dnode_t *dno) 00287 { 00288 if (zf == NULL) { 00289 return; 00290 } 00291 00292 zf->zf_dnode = dno; 00293 zf->zf_stream_cnt = 0; 00294 zf->zf_alloc_fail = 0; 00295 00296 list_create(&zf->zf_stream, sizeof (zstream_t), 00297 offsetof(zstream_t, zst_node)); 00298 00299 rw_init(&zf->zf_rwlock, NULL, RW_DEFAULT, NULL); 00300 } 00301 00306 static uint64_t 00307 dmu_zfetch_fetch(dnode_t *dn, uint64_t blkid, uint64_t nblks) 00308 { 00309 uint64_t fetchsz; 00310 uint64_t i; 00311 00312 fetchsz = dmu_zfetch_fetchsz(dn, blkid, nblks); 00313 00314 for (i = 0; i < fetchsz; i++) { 00315 dbuf_prefetch(dn, blkid + i); 00316 } 00317 00318 return (fetchsz); 00319 } 00320 00328 static uint64_t 00329 dmu_zfetch_fetchsz(dnode_t *dn, uint64_t blkid, uint64_t nblks) 00330 { 00331 uint64_t fetchsz; 00332 00333 if (blkid > dn->dn_maxblkid) { 00334 return (0); 00335 } 00336 00337 /* compute fetch size */ 00338 if (blkid + nblks + 1 > dn->dn_maxblkid) { 00339 fetchsz = (dn->dn_maxblkid - blkid) + 1; 00340 ASSERT(blkid + fetchsz - 1 <= dn->dn_maxblkid); 00341 } else { 00342 fetchsz = nblks; 00343 } 00344 00345 00346 return (fetchsz); 00347 } 00348 00354 static int 00355 dmu_zfetch_find(zfetch_t *zf, zstream_t *zh, int prefetched) 00356 { 00357 zstream_t *zs; 00358 int64_t diff; 00359 int reset = !prefetched; 00360 int rc = 0; 00361 00362 if (zh == NULL) 00363 return (0); 00364 00365 /* 00366 * XXX: This locking strategy is a bit coarse; however, it's impact has 00367 * yet to be tested. If this turns out to be an issue, it can be 00368 * modified in a number of different ways. 00369 */ 00370 00371 rw_enter(&zf->zf_rwlock, RW_READER); 00372 top: 00373 00374 for (zs = list_head(&zf->zf_stream); zs; 00375 zs = list_next(&zf->zf_stream, zs)) { 00376 00377 /* 00378 * XXX - should this be an assert? 00379 */ 00380 if (zs->zst_len == 0) { 00381 /* bogus stream */ 00382 ZFETCHSTAT_BUMP(zfetchstat_bogus_streams); 00383 continue; 00384 } 00385 00386 /* 00387 * We hit this case when we are in a strided prefetch stream: 00388 * we will read "len" blocks before "striding". 00389 */ 00390 if (zh->zst_offset >= zs->zst_offset && 00391 zh->zst_offset < zs->zst_offset + zs->zst_len) { 00392 if (prefetched) { 00393 /* already fetched */ 00394 ZFETCHSTAT_BUMP(zfetchstat_stride_hits); 00395 rc = 1; 00396 goto out; 00397 } else { 00398 ZFETCHSTAT_BUMP(zfetchstat_stride_misses); 00399 } 00400 } 00401 00402 /* 00403 * This is the forward sequential read case: we increment 00404 * len by one each time we hit here, so we will enter this 00405 * case on every read. 00406 */ 00407 if (zh->zst_offset == zs->zst_offset + zs->zst_len) { 00408 00409 reset = !prefetched && zs->zst_len > 1; 00410 00411 if (mutex_tryenter(&zs->zst_lock) == 0) { 00412 rc = 1; 00413 goto out; 00414 } 00415 00416 if (zh->zst_offset != zs->zst_offset + zs->zst_len) { 00417 mutex_exit(&zs->zst_lock); 00418 goto top; 00419 } 00420 zs->zst_len += zh->zst_len; 00421 diff = zs->zst_len - zfetch_block_cap; 00422 if (diff > 0) { 00423 zs->zst_offset += diff; 00424 zs->zst_len = zs->zst_len > diff ? 00425 zs->zst_len - diff : 0; 00426 } 00427 zs->zst_direction = ZFETCH_FORWARD; 00428 00429 break; 00430 00431 /* 00432 * Same as above, but reading backwards through the file. 00433 */ 00434 } else if (zh->zst_offset == zs->zst_offset - zh->zst_len) { 00435 /* backwards sequential access */ 00436 00437 reset = !prefetched && zs->zst_len > 1; 00438 00439 if (mutex_tryenter(&zs->zst_lock) == 0) { 00440 rc = 1; 00441 goto out; 00442 } 00443 00444 if (zh->zst_offset != zs->zst_offset - zh->zst_len) { 00445 mutex_exit(&zs->zst_lock); 00446 goto top; 00447 } 00448 00449 zs->zst_offset = zs->zst_offset > zh->zst_len ? 00450 zs->zst_offset - zh->zst_len : 0; 00451 zs->zst_ph_offset = zs->zst_ph_offset > zh->zst_len ? 00452 zs->zst_ph_offset - zh->zst_len : 0; 00453 zs->zst_len += zh->zst_len; 00454 00455 diff = zs->zst_len - zfetch_block_cap; 00456 if (diff > 0) { 00457 zs->zst_ph_offset = zs->zst_ph_offset > diff ? 00458 zs->zst_ph_offset - diff : 0; 00459 zs->zst_len = zs->zst_len > diff ? 00460 zs->zst_len - diff : zs->zst_len; 00461 } 00462 zs->zst_direction = ZFETCH_BACKWARD; 00463 00464 break; 00465 00466 } else if ((zh->zst_offset - zs->zst_offset - zs->zst_stride < 00467 zs->zst_len) && (zs->zst_len != zs->zst_stride)) { 00468 /* strided forward access */ 00469 00470 if (mutex_tryenter(&zs->zst_lock) == 0) { 00471 rc = 1; 00472 goto out; 00473 } 00474 00475 if ((zh->zst_offset - zs->zst_offset - zs->zst_stride >= 00476 zs->zst_len) || (zs->zst_len == zs->zst_stride)) { 00477 mutex_exit(&zs->zst_lock); 00478 goto top; 00479 } 00480 00481 zs->zst_offset += zs->zst_stride; 00482 zs->zst_direction = ZFETCH_FORWARD; 00483 00484 break; 00485 00486 } else if ((zh->zst_offset - zs->zst_offset + zs->zst_stride < 00487 zs->zst_len) && (zs->zst_len != zs->zst_stride)) { 00488 /* strided reverse access */ 00489 00490 if (mutex_tryenter(&zs->zst_lock) == 0) { 00491 rc = 1; 00492 goto out; 00493 } 00494 00495 if ((zh->zst_offset - zs->zst_offset + zs->zst_stride >= 00496 zs->zst_len) || (zs->zst_len == zs->zst_stride)) { 00497 mutex_exit(&zs->zst_lock); 00498 goto top; 00499 } 00500 00501 zs->zst_offset = zs->zst_offset > zs->zst_stride ? 00502 zs->zst_offset - zs->zst_stride : 0; 00503 zs->zst_ph_offset = (zs->zst_ph_offset > 00504 (2 * zs->zst_stride)) ? 00505 (zs->zst_ph_offset - (2 * zs->zst_stride)) : 0; 00506 zs->zst_direction = ZFETCH_BACKWARD; 00507 00508 break; 00509 } 00510 } 00511 00512 if (zs) { 00513 if (reset) { 00514 zstream_t *remove = zs; 00515 00516 ZFETCHSTAT_BUMP(zfetchstat_stream_resets); 00517 rc = 0; 00518 mutex_exit(&zs->zst_lock); 00519 rw_exit(&zf->zf_rwlock); 00520 rw_enter(&zf->zf_rwlock, RW_WRITER); 00521 /* 00522 * Relocate the stream, in case someone removes 00523 * it while we were acquiring the WRITER lock. 00524 */ 00525 for (zs = list_head(&zf->zf_stream); zs; 00526 zs = list_next(&zf->zf_stream, zs)) { 00527 if (zs == remove) { 00528 dmu_zfetch_stream_remove(zf, zs); 00529 mutex_destroy(&zs->zst_lock); 00530 kmem_free(zs, sizeof (zstream_t)); 00531 break; 00532 } 00533 } 00534 } else { 00535 ZFETCHSTAT_BUMP(zfetchstat_stream_noresets); 00536 rc = 1; 00537 dmu_zfetch_dofetch(zf, zs); 00538 mutex_exit(&zs->zst_lock); 00539 } 00540 } 00541 out: 00542 rw_exit(&zf->zf_rwlock); 00543 return (rc); 00544 } 00545 00551 void 00552 dmu_zfetch_rele(zfetch_t *zf) 00553 { 00554 zstream_t *zs; 00555 zstream_t *zs_next; 00556 00557 ASSERT(!RW_LOCK_HELD(&zf->zf_rwlock)); 00558 00559 for (zs = list_head(&zf->zf_stream); zs; zs = zs_next) { 00560 zs_next = list_next(&zf->zf_stream, zs); 00561 00562 list_remove(&zf->zf_stream, zs); 00563 mutex_destroy(&zs->zst_lock); 00564 kmem_free(zs, sizeof (zstream_t)); 00565 } 00566 list_destroy(&zf->zf_stream); 00567 rw_destroy(&zf->zf_rwlock); 00568 00569 zf->zf_dnode = NULL; 00570 } 00571 00580 static int 00581 dmu_zfetch_stream_insert(zfetch_t *zf, zstream_t *zs) 00582 { 00583 zstream_t *zs_walk; 00584 zstream_t *zs_next; 00585 00586 ASSERT(RW_WRITE_HELD(&zf->zf_rwlock)); 00587 00588 for (zs_walk = list_head(&zf->zf_stream); zs_walk; zs_walk = zs_next) { 00589 zs_next = list_next(&zf->zf_stream, zs_walk); 00590 00591 if (dmu_zfetch_streams_equal(zs_walk, zs)) { 00592 return (0); 00593 } 00594 } 00595 00596 list_insert_head(&zf->zf_stream, zs); 00597 zf->zf_stream_cnt++; 00598 return (1); 00599 } 00600 00601 00606 static zstream_t * 00607 dmu_zfetch_stream_reclaim(zfetch_t *zf) 00608 { 00609 zstream_t *zs; 00610 00611 if (! rw_tryenter(&zf->zf_rwlock, RW_WRITER)) 00612 return (0); 00613 00614 for (zs = list_head(&zf->zf_stream); zs; 00615 zs = list_next(&zf->zf_stream, zs)) { 00616 00617 if (((ddi_get_lbolt() - zs->zst_last)/hz) > zfetch_min_sec_reap) 00618 break; 00619 } 00620 00621 if (zs) { 00622 dmu_zfetch_stream_remove(zf, zs); 00623 mutex_destroy(&zs->zst_lock); 00624 bzero(zs, sizeof (zstream_t)); 00625 } else { 00626 zf->zf_alloc_fail++; 00627 } 00628 rw_exit(&zf->zf_rwlock); 00629 00630 return (zs); 00631 } 00632 00637 static void 00638 dmu_zfetch_stream_remove(zfetch_t *zf, zstream_t *zs) 00639 { 00640 ASSERT(RW_WRITE_HELD(&zf->zf_rwlock)); 00641 00642 list_remove(&zf->zf_stream, zs); 00643 zf->zf_stream_cnt--; 00644 } 00645 00646 static int 00647 dmu_zfetch_streams_equal(zstream_t *zs1, zstream_t *zs2) 00648 { 00649 if (zs1->zst_offset != zs2->zst_offset) 00650 return (0); 00651 00652 if (zs1->zst_len != zs2->zst_len) 00653 return (0); 00654 00655 if (zs1->zst_stride != zs2->zst_stride) 00656 return (0); 00657 00658 if (zs1->zst_ph_offset != zs2->zst_ph_offset) 00659 return (0); 00660 00661 if (zs1->zst_cap != zs2->zst_cap) 00662 return (0); 00663 00664 if (zs1->zst_direction != zs2->zst_direction) 00665 return (0); 00666 00667 return (1); 00668 } 00669 00674 void 00675 dmu_zfetch(zfetch_t *zf, uint64_t offset, uint64_t size, int prefetched) 00676 { 00677 zstream_t zst; 00678 zstream_t *newstream; 00679 int fetched; 00680 int inserted; 00681 unsigned int blkshft; 00682 uint64_t blksz; 00683 00684 if (zfs_prefetch_disable) 00685 return; 00686 00687 /* files that aren't ln2 blocksz are only one block -- nothing to do */ 00688 if (!zf->zf_dnode->dn_datablkshift) 00689 return; 00690 00691 /* convert offset and size, into blockid and nblocks */ 00692 blkshft = zf->zf_dnode->dn_datablkshift; 00693 blksz = (1 << blkshft); 00694 00695 bzero(&zst, sizeof (zstream_t)); 00696 zst.zst_offset = offset >> blkshft; 00697 zst.zst_len = (P2ROUNDUP(offset + size, blksz) - 00698 P2ALIGN(offset, blksz)) >> blkshft; 00699 00700 fetched = dmu_zfetch_find(zf, &zst, prefetched); 00701 if (fetched) { 00702 ZFETCHSTAT_BUMP(zfetchstat_hits); 00703 } else { 00704 ZFETCHSTAT_BUMP(zfetchstat_misses); 00705 if (fetched = dmu_zfetch_colinear(zf, &zst)) { 00706 ZFETCHSTAT_BUMP(zfetchstat_colinear_hits); 00707 } else { 00708 ZFETCHSTAT_BUMP(zfetchstat_colinear_misses); 00709 } 00710 } 00711 00712 if (!fetched) { 00713 newstream = dmu_zfetch_stream_reclaim(zf); 00714 00715 /* 00716 * we still couldn't find a stream, drop the lock, and allocate 00717 * one if possible. Otherwise, give up and go home. 00718 */ 00719 if (newstream) { 00720 ZFETCHSTAT_BUMP(zfetchstat_reclaim_successes); 00721 } else { 00722 uint64_t maxblocks; 00723 uint32_t max_streams; 00724 uint32_t cur_streams; 00725 00726 ZFETCHSTAT_BUMP(zfetchstat_reclaim_failures); 00727 cur_streams = zf->zf_stream_cnt; 00728 maxblocks = zf->zf_dnode->dn_maxblkid; 00729 00730 max_streams = MIN(zfetch_max_streams, 00731 (maxblocks / zfetch_block_cap)); 00732 if (max_streams == 0) { 00733 max_streams++; 00734 } 00735 00736 if (cur_streams >= max_streams) { 00737 return; 00738 } 00739 newstream = kmem_zalloc(sizeof (zstream_t), KM_SLEEP); 00740 } 00741 00742 newstream->zst_offset = zst.zst_offset; 00743 newstream->zst_len = zst.zst_len; 00744 newstream->zst_stride = zst.zst_len; 00745 newstream->zst_ph_offset = zst.zst_len + zst.zst_offset; 00746 newstream->zst_cap = zst.zst_len; 00747 newstream->zst_direction = ZFETCH_FORWARD; 00748 newstream->zst_last = ddi_get_lbolt(); 00749 00750 mutex_init(&newstream->zst_lock, NULL, MUTEX_DEFAULT, NULL); 00751 00752 rw_enter(&zf->zf_rwlock, RW_WRITER); 00753 inserted = dmu_zfetch_stream_insert(zf, newstream); 00754 rw_exit(&zf->zf_rwlock); 00755 00756 if (!inserted) { 00757 mutex_destroy(&newstream->zst_lock); 00758 kmem_free(newstream, sizeof (zstream_t)); 00759 } 00760 } 00761 }