Skip to content

Commit 99ad035

Browse files
committed
Some cosmetic prefetcher changes requested by mahrens.
Signed-off-by: Alexander Motin <[email protected]>
1 parent a9e69ec commit 99ad035

File tree

4 files changed

+47
-21
lines changed

4 files changed

+47
-21
lines changed

include/sys/dmu_zfetch.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ typedef struct zstream {
6565
zfetch_t *zs_fetch; /* parent fetch */
6666
boolean_t zs_missed; /* stream saw cache misses */
6767
zfs_refcount_t zs_callers; /* number of pending callers */
68-
zfs_refcount_t zs_blocks; /* number of pending blocks in the stream */
68+
/*
69+
* Number of stream references: dnode, callers and pending blocks.
70+
* The stream memory is freed when the number returns to zero.
71+
*/
72+
zfs_refcount_t zs_refs;
6973
} zstream_t;
7074

7175
void zfetch_init(void);

module/zfs/dbuf.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1662,7 +1662,8 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
16621662
*/
16631663
if (!err && prefetch) {
16641664
dmu_zfetch(&dn->dn_zfetch, db->db_blkid, 1, B_TRUE,
1665-
B_TRUE, flags & DB_RF_HAVESTRUCT);
1665+
db->db_state != DB_CACHED,
1666+
flags & DB_RF_HAVESTRUCT);
16661667
}
16671668

16681669
DB_DNODE_EXIT(db);

module/zfs/dmu.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,11 @@ dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length,
540540
blkid = dbuf_whichblock(dn, 0, offset);
541541
if ((flags & DMU_READ_NO_PREFETCH) == 0 &&
542542
DNODE_META_IS_CACHEABLE(dn) && length <= zfetch_array_rd_sz) {
543+
/*
544+
* Prepare the zfetch before initiating the demand reads, so
545+
* that if multiple threads block on same indirect block, we
546+
* base predictions on the original less racy request order.
547+
*/
543548
zs = dmu_zfetch_prepare(&dn->dn_zfetch, blkid, nblks,
544549
read && DNODE_IS_CACHEABLE(dn), B_TRUE);
545550
}
@@ -555,7 +560,14 @@ dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length,
555560
return (SET_ERROR(EIO));
556561
}
557562

558-
/* initiate async i/o */
563+
/*
564+
* Initiate async demand data read.
565+
* We check the db_state after calling dbuf_read() because
566+
* (1) dbuf_read() may change the state to CACHED due to a
567+
* hit in the ARC, and (2) on a cache miss, a child will
568+
* have been added to "zio" but not yet completed, so the
569+
* state will not yet be CACHED.
570+
*/
559571
if (read) {
560572
(void) dbuf_read(db, zio, dbuf_flags);
561573
if (db->db_state != DB_CACHED)

module/zfs/dmu_zfetch.c

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ dmu_zfetch_stream_remove(zfetch_t *zf, zstream_t *zs)
138138
ASSERT(MUTEX_HELD(&zf->zf_lock));
139139
list_remove(&zf->zf_stream, zs);
140140
zf->zf_numstreams--;
141-
if (zfs_refcount_remove(&zs->zs_blocks, NULL) == 0)
141+
if (zfs_refcount_remove(&zs->zs_refs, NULL) == 0)
142142
dmu_zfetch_stream_fini(zs);
143143
}
144144

@@ -184,7 +184,7 @@ dmu_zfetch_stream_create(zfetch_t *zf, uint64_t blkid)
184184
/*
185185
* Skip if still active. 1 -- zf_stream reference.
186186
*/
187-
if (zfs_refcount_count(&zs->zs_blocks) != 1)
187+
if (zfs_refcount_count(&zs->zs_refs) != 1)
188188
continue;
189189
if (((now - zs->zs_atime) / NANOSEC) >
190190
zfetch_min_sec_reap)
@@ -217,9 +217,9 @@ dmu_zfetch_stream_create(zfetch_t *zf, uint64_t blkid)
217217
zs->zs_fetch = zf;
218218
zs->zs_missed = B_FALSE;
219219
zfs_refcount_create(&zs->zs_callers);
220-
zfs_refcount_create(&zs->zs_blocks);
220+
zfs_refcount_create(&zs->zs_refs);
221221
/* One reference for zf_stream. */
222-
zfs_refcount_add(&zs->zs_blocks, NULL);
222+
zfs_refcount_add(&zs->zs_refs, NULL);
223223
zf->zf_numstreams++;
224224
list_insert_head(&zf->zf_stream, zs);
225225
}
@@ -239,14 +239,18 @@ dmu_zfetch_stream_done(void *arg, boolean_t io_issued)
239239
ZFETCHSTAT_SET(zfetchstat_max_completion_us, delta);
240240
}
241241

242-
if (zfs_refcount_remove(&zs->zs_blocks, NULL) == 0)
242+
if (zfs_refcount_remove(&zs->zs_refs, NULL) == 0)
243243
dmu_zfetch_stream_fini(zs);
244244
}
245245

246246
/*
247-
* This is the predictive prefetch entry point. It associates dnode access
248-
* specified with blkid and nblks arguments with prefetch stream, predicts
249-
* further accesses based on that stats and initiates speculative prefetch.
247+
* This is the predictive prefetch entry point. dmu_zfetch_prepare()
248+
* associates dnode access specified with blkid and nblks arguments with
249+
* prefetch stream, predicts further accesses based on that stats and returns
250+
* the stream pointer on success. That pointer must later be passed to
251+
* dmu_zfetch_run() to initiate the speculative prefetch for the stream and
252+
* release it. dmu_zfetch() is a wrapper for simple cases when window between
253+
* prediction and prefetch initiation is not needed.
250254
* fetch_data argument specifies whether actual data blocks should be fetched:
251255
* FALSE -- prefetch only indirect blocks for predicted data blocks;
252256
* TRUE -- prefetch predicted data blocks plus following indirect blocks.
@@ -257,9 +261,9 @@ dmu_zfetch_prepare(zfetch_t *zf, uint64_t blkid, uint64_t nblks,
257261
{
258262
zstream_t *zs;
259263
int64_t pf_start, ipf_start;
260-
int64_t pf_ahead_blks, max_blks, maxblkid;
264+
int64_t pf_ahead_blks, max_blks;
261265
int max_dist_blks, pf_nblks, ipf_nblks;
262-
uint64_t end_of_access_blkid;
266+
uint64_t end_of_access_blkid, maxblkid;
263267
end_of_access_blkid = blkid + nblks;
264268
spa_t *spa = zf->zf_dnode->dn_objset->os_spa;
265269

@@ -289,7 +293,8 @@ dmu_zfetch_prepare(zfetch_t *zf, uint64_t blkid, uint64_t nblks,
289293
* A fast path for small files for which no prefetch will
290294
* happen.
291295
*/
292-
if ((maxblkid = zf->zf_dnode->dn_maxblkid) < 2) {
296+
maxblkid = zf->zf_dnode->dn_maxblkid;
297+
if (maxblkid < 2) {
293298
if (!have_lock)
294299
rw_exit(&zf->zf_dnode->dn_struct_rwlock);
295300
return (NULL);
@@ -319,15 +324,19 @@ dmu_zfetch_prepare(zfetch_t *zf, uint64_t blkid, uint64_t nblks,
319324
if (end_of_access_blkid >= maxblkid) {
320325
if (zs != NULL)
321326
dmu_zfetch_stream_remove(zf, zs);
322-
done:
323327
mutex_exit(&zf->zf_lock);
324328
if (!have_lock)
325329
rw_exit(&zf->zf_dnode->dn_struct_rwlock);
326330
return (NULL);
327331
}
328332

329-
if (nblks == 0)
330-
goto done; /* Already prefetched this before. */
333+
/* Exit if we already prefetched this block before. */
334+
if (nblks == 0) {
335+
mutex_exit(&zf->zf_lock);
336+
if (!have_lock)
337+
rw_exit(&zf->zf_dnode->dn_struct_rwlock);
338+
return (NULL);
339+
}
331340

332341
if (zs == NULL) {
333342
/*
@@ -401,7 +410,7 @@ dmu_zfetch_prepare(zfetch_t *zf, uint64_t blkid, uint64_t nblks,
401410

402411
zs->zs_atime = gethrtime();
403412
/* Protect the stream from reclamation. 2 -- zf_stream + us. */
404-
if (zfs_refcount_add(&zs->zs_blocks, NULL) == 2)
413+
if (zfs_refcount_add(&zs->zs_refs, NULL) == 2)
405414
zs->zs_start_time = zs->zs_atime;
406415
/* Count concurrent callers. */
407416
zfs_refcount_add(&zs->zs_callers, NULL);
@@ -432,7 +441,7 @@ dmu_zfetch_run(zstream_t *zs, boolean_t missed, boolean_t have_lock)
432441
*/
433442
if (zfs_refcount_remove(&zs->zs_callers, NULL) != 0) {
434443
/* Drop reference taken in dmu_zfetch_prepare(). */
435-
if (zfs_refcount_remove(&zs->zs_blocks, NULL) == 0)
444+
if (zfs_refcount_remove(&zs->zs_refs, NULL) == 0)
436445
dmu_zfetch_stream_fini(zs);
437446
return;
438447
}
@@ -454,10 +463,10 @@ dmu_zfetch_run(zstream_t *zs, boolean_t missed, boolean_t have_lock)
454463
issued = pf_end - pf_start + ipf_end - ipf_start;
455464
if (issued > 1) {
456465
/* More references on top of taken in dmu_zfetch_prepare(). */
457-
zfs_refcount_add_many(&zs->zs_blocks, issued - 1, NULL);
466+
zfs_refcount_add_many(&zs->zs_refs, issued - 1, NULL);
458467
} else if (issued == 0) {
459468
/* Some other thread has done our work, so drop the ref. */
460-
if (zfs_refcount_remove(&zs->zs_blocks, NULL) == 0)
469+
if (zfs_refcount_remove(&zs->zs_refs, NULL) == 0)
461470
dmu_zfetch_stream_fini(zs);
462471
return;
463472
}

0 commit comments

Comments
 (0)