Print this page
3995 Memory leak of compressed buffers in l2arc_write_done
3997 ZFS L2ARC default behavior should allow reading while writing

*** 292,302 **** kstat_named_t arcstat_l2_read_bytes; kstat_named_t arcstat_l2_write_bytes; kstat_named_t arcstat_l2_writes_sent; kstat_named_t arcstat_l2_writes_done; kstat_named_t arcstat_l2_writes_error; - kstat_named_t arcstat_l2_writes_hdr_miss; kstat_named_t arcstat_l2_evict_lock_retry; kstat_named_t arcstat_l2_evict_reading; kstat_named_t arcstat_l2_free_on_write; kstat_named_t arcstat_l2_abort_lowmem; kstat_named_t arcstat_l2_cksum_bad; --- 292,301 ----
*** 358,368 **** { "l2_read_bytes", KSTAT_DATA_UINT64 }, { "l2_write_bytes", KSTAT_DATA_UINT64 }, { "l2_writes_sent", KSTAT_DATA_UINT64 }, { "l2_writes_done", KSTAT_DATA_UINT64 }, { "l2_writes_error", KSTAT_DATA_UINT64 }, - { "l2_writes_hdr_miss", KSTAT_DATA_UINT64 }, { "l2_evict_lock_retry", KSTAT_DATA_UINT64 }, { "l2_evict_reading", KSTAT_DATA_UINT64 }, { "l2_free_on_write", KSTAT_DATA_UINT64 }, { "l2_abort_lowmem", KSTAT_DATA_UINT64 }, { "l2_cksum_bad", KSTAT_DATA_UINT64 }, --- 357,366 ----
*** 620,630 **** uint64_t l2arc_headroom_boost = L2ARC_HEADROOM_BOOST; uint64_t l2arc_feed_secs = L2ARC_FEED_SECS; /* interval seconds */ uint64_t l2arc_feed_min_ms = L2ARC_FEED_MIN_MS; /* min interval milliseconds */ boolean_t l2arc_noprefetch = B_TRUE; /* don't cache prefetch bufs */ boolean_t l2arc_feed_again = B_TRUE; /* turbo warmup */ ! boolean_t l2arc_norw = B_TRUE; /* no reads during writes */ /* * L2ARC Internals */ typedef struct l2arc_dev { --- 618,628 ---- uint64_t l2arc_headroom_boost = L2ARC_HEADROOM_BOOST; uint64_t l2arc_feed_secs = L2ARC_FEED_SECS; /* interval seconds */ uint64_t l2arc_feed_min_ms = L2ARC_FEED_MIN_MS; /* min interval milliseconds */ boolean_t l2arc_noprefetch = B_TRUE; /* don't cache prefetch bufs */ boolean_t l2arc_feed_again = B_TRUE; /* turbo warmup */ ! boolean_t l2arc_norw = B_FALSE; /* no reads during writes */ /* * L2ARC Internals */ typedef struct l2arc_dev {
*** 4146,4156 **** { l2arc_write_callback_t *cb; l2arc_dev_t *dev; list_t *buflist; arc_buf_hdr_t *head, *ab, *ab_prev; ! l2arc_buf_hdr_t *abl2; kmutex_t *hash_lock; cb = zio->io_private; ASSERT(cb != NULL); dev = cb->l2wcb_dev; --- 4144,4154 ---- { l2arc_write_callback_t *cb; l2arc_dev_t *dev; list_t *buflist; arc_buf_hdr_t *head, *ab, *ab_prev; ! l2arc_buf_hdr_t *l2hdr; kmutex_t *hash_lock; cb = zio->io_private; ASSERT(cb != NULL); dev = cb->l2wcb_dev;
*** 4168,4207 **** mutex_enter(&l2arc_buflist_mtx); /* * All writes completed, or an error was hit. */ for (ab = list_prev(buflist, head); ab; ab = ab_prev) { ab_prev = list_prev(buflist, ab); hash_lock = HDR_LOCK(ab); ! if (!mutex_tryenter(hash_lock)) { ! /* ! * This buffer misses out. It may be in a stage ! * of eviction. Its ARC_L2_WRITING flag will be ! * left set, denying reads to this buffer. ! */ ! ARCSTAT_BUMP(arcstat_l2_writes_hdr_miss); ! continue; ! } ! abl2 = ab->b_l2hdr; /* * Release the temporary compressed buffer as soon as possible. */ ! if (abl2->b_compress != ZIO_COMPRESS_OFF) l2arc_release_cdata_buf(ab); if (zio->io_error != 0) { /* * Error - drop L2ARC entry. */ list_remove(buflist, ab); ! ARCSTAT_INCR(arcstat_l2_asize, -abl2->b_asize); ab->b_l2hdr = NULL; ! kmem_free(abl2, sizeof (l2arc_buf_hdr_t)); ARCSTAT_INCR(arcstat_l2_size, -ab->b_size); } /* * Allow ARC to begin reads to this L2ARC entry. --- 4166,4198 ---- mutex_enter(&l2arc_buflist_mtx); /* * All writes completed, or an error was hit. */ + dev->l2ad_writing = B_FALSE; for (ab = list_prev(buflist, head); ab; ab = ab_prev) { ab_prev = list_prev(buflist, ab); hash_lock = HDR_LOCK(ab); ! mutex_enter(hash_lock); ! l2hdr = ab->b_l2hdr; /* * Release the temporary compressed buffer as soon as possible. */ ! if (l2hdr->b_compress != ZIO_COMPRESS_OFF) l2arc_release_cdata_buf(ab); if (zio->io_error != 0) { /* * Error - drop L2ARC entry. */ list_remove(buflist, ab); ! ARCSTAT_INCR(arcstat_l2_asize, -l2hdr->b_asize); ab->b_l2hdr = NULL; ! kmem_free(l2hdr, sizeof (l2arc_buf_hdr_t)); ARCSTAT_INCR(arcstat_l2_size, -ab->b_size); } /* * Allow ARC to begin reads to this L2ARC entry.
*** 4348,4358 **** */ static void l2arc_evict(l2arc_dev_t *dev, uint64_t distance, boolean_t all) { list_t *buflist; ! l2arc_buf_hdr_t *abl2; arc_buf_hdr_t *ab, *ab_prev; kmutex_t *hash_lock; uint64_t taddr; buflist = dev->l2ad_buflist; --- 4339,4349 ---- */ static void l2arc_evict(l2arc_dev_t *dev, uint64_t distance, boolean_t all) { list_t *buflist; ! l2arc_buf_hdr_t *l2hdr; arc_buf_hdr_t *ab, *ab_prev; kmutex_t *hash_lock; uint64_t taddr; buflist = dev->l2ad_buflist;
*** 4448,4461 **** /* * Tell ARC this no longer exists in L2ARC. */ if (ab->b_l2hdr != NULL) { ! abl2 = ab->b_l2hdr; ! ARCSTAT_INCR(arcstat_l2_asize, -abl2->b_asize); ab->b_l2hdr = NULL; ! kmem_free(abl2, sizeof (l2arc_buf_hdr_t)); ARCSTAT_INCR(arcstat_l2_size, -ab->b_size); } list_remove(buflist, ab); /* --- 4439,4452 ---- /* * Tell ARC this no longer exists in L2ARC. */ if (ab->b_l2hdr != NULL) { ! l2hdr = ab->b_l2hdr; ! ARCSTAT_INCR(arcstat_l2_asize, -l2hdr->b_asize); ab->b_l2hdr = NULL; ! kmem_free(l2hdr, sizeof (l2arc_buf_hdr_t)); ARCSTAT_INCR(arcstat_l2_size, -ab->b_size); } list_remove(buflist, ab); /*
*** 4723,4735 **** dev->l2ad_hand = dev->l2ad_start; dev->l2ad_evict = dev->l2ad_start; dev->l2ad_first = B_FALSE; } dev->l2ad_writing = B_TRUE; (void) zio_wait(pio); ! dev->l2ad_writing = B_FALSE; return (write_asize); } /* --- 4714,4727 ---- dev->l2ad_hand = dev->l2ad_start; dev->l2ad_evict = dev->l2ad_start; dev->l2ad_first = B_FALSE; } + /* dev->l2ad_writing will be lowered in the zio done callback */ dev->l2ad_writing = B_TRUE; (void) zio_wait(pio); ! ASSERT(dev->l2ad_writing == B_FALSE); return (write_asize); } /*