FreeBSD ZFS
The Zettabyte File System

dmu_zfetch.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines