Print this page
5219 l2arc_write_buffers() may write beyond target_sz
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Saso Kiselkov <skiselkov@gmail.com>
Reviewed by: George Wilson <george@delphix.com>
Reviewed by: Steven Hartland <steven.hartland@multiplay.co.uk>
Reviewed by: Justin Gibbs <gibbs@FreeBSD.org>
Approved by: Matthew Ahrens <mahrens@delphix.com>

*** 5842,5852 **** static uint64_t l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, boolean_t *headroom_boost) { arc_buf_hdr_t *hdr, *hdr_prev, *head; ! uint64_t write_asize, write_psize, write_sz, headroom, buf_compress_minsz; void *buf_data; boolean_t full; l2arc_write_callback_t *cb; zio_t *pio, *wzio; --- 5842,5852 ---- static uint64_t l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz, boolean_t *headroom_boost) { arc_buf_hdr_t *hdr, *hdr_prev, *head; ! uint64_t write_asize, write_sz, headroom, buf_compress_minsz; void *buf_data; boolean_t full; l2arc_write_callback_t *cb; zio_t *pio, *wzio;
*** 5857,5867 **** /* Lower the flag now, we might want to raise it again later. */ *headroom_boost = B_FALSE; pio = NULL; ! write_sz = write_asize = write_psize = 0; full = B_FALSE; head = kmem_cache_alloc(hdr_l2only_cache, KM_PUSHPAGE); head->b_flags |= ARC_FLAG_L2_WRITE_HEAD; head->b_flags |= ARC_FLAG_HAS_L2HDR; --- 5857,5867 ---- /* Lower the flag now, we might want to raise it again later. */ *headroom_boost = B_FALSE; pio = NULL; ! write_sz = write_asize = 0; full = B_FALSE; head = kmem_cache_alloc(hdr_l2only_cache, KM_PUSHPAGE); head->b_flags |= ARC_FLAG_L2_WRITE_HEAD; head->b_flags |= ARC_FLAG_HAS_L2HDR;
*** 5894,5903 **** --- 5894,5904 ---- headroom = (headroom * l2arc_headroom_boost) / 100; for (; hdr; hdr = hdr_prev) { kmutex_t *hash_lock; uint64_t buf_sz; + uint64_t buf_a_sz; if (arc_warm == B_FALSE) hdr_prev = multilist_sublist_next(mls, hdr); else hdr_prev = multilist_sublist_prev(mls, hdr);
*** 5922,5932 **** if (!l2arc_write_eligible(guid, hdr)) { mutex_exit(hash_lock); continue; } ! if ((write_sz + hdr->b_size) > target_sz) { full = B_TRUE; mutex_exit(hash_lock); break; } --- 5923,5941 ---- if (!l2arc_write_eligible(guid, hdr)) { mutex_exit(hash_lock); continue; } ! /* ! * Assume that the buffer is not going to be compressed ! * and could take more space on disk because of a larger ! * disk block size. ! */ ! buf_sz = hdr->b_size; ! buf_a_sz = vdev_psize_to_asize(dev->l2ad_vdev, buf_sz); ! ! if ((write_asize + buf_a_sz) > target_sz) { full = B_TRUE; mutex_exit(hash_lock); break; }
*** 5986,5996 **** * be holding the l2ad_mtx; which is why we're * using it to denote the header's state change. */ hdr->b_l2hdr.b_daddr = L2ARC_ADDR_UNSET; - buf_sz = hdr->b_size; hdr->b_flags |= ARC_FLAG_HAS_L2HDR; mutex_enter(&dev->l2ad_mtx); list_insert_head(&dev->l2ad_buflist, hdr); mutex_exit(&dev->l2ad_mtx); --- 5995,6004 ----
*** 6003,6012 **** --- 6011,6021 ---- arc_cksum_compute(hdr->b_l1hdr.b_buf, B_TRUE); mutex_exit(hash_lock); write_sz += buf_sz; + write_asize += buf_a_sz; } multilist_sublist_unlock(mls); if (full == B_TRUE)
*** 6022,6031 **** --- 6031,6053 ---- } mutex_enter(&dev->l2ad_mtx); /* + * Note that elsewhere in this file arcstat_l2_asize + * and the used space on l2ad_vdev are updated using b_asize, + * which is not necessarily rounded up to the device block size. + * Too keep accounting consistent we do the same here as well: + * stats_size accumulates the sum of b_asize of the written buffers, + * while write_asize accumulates the sum of b_asize rounded up + * to the device block size. + * The latter sum is used only to validate the corectness of the code. + */ + uint64_t stats_size = 0; + write_asize = 0; + + /* * Now start writing the buffers. We're starting at the write head * and work backwards, retracing the course of the buffer selector * loop above. */ for (hdr = list_prev(&dev->l2ad_buflist, head); hdr;
*** 6074,6084 **** */ (void) refcount_add_many(&dev->l2ad_alloc, buf_sz, hdr); /* Compression may have squashed the buffer to zero length. */ if (buf_sz != 0) { ! uint64_t buf_p_sz; wzio = zio_write_phys(pio, dev->l2ad_vdev, dev->l2ad_hand, buf_sz, buf_data, ZIO_CHECKSUM_OFF, NULL, NULL, ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_CANFAIL, B_FALSE); --- 6096,6106 ---- */ (void) refcount_add_many(&dev->l2ad_alloc, buf_sz, hdr); /* Compression may have squashed the buffer to zero length. */ if (buf_sz != 0) { ! uint64_t buf_a_sz; wzio = zio_write_phys(pio, dev->l2ad_vdev, dev->l2ad_hand, buf_sz, buf_data, ZIO_CHECKSUM_OFF, NULL, NULL, ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_CANFAIL, B_FALSE);
*** 6085,6113 **** DTRACE_PROBE2(l2arc__write, vdev_t *, dev->l2ad_vdev, zio_t *, wzio); (void) zio_nowait(wzio); ! write_asize += buf_sz; /* * Keep the clock hand suitably device-aligned. */ ! buf_p_sz = vdev_psize_to_asize(dev->l2ad_vdev, buf_sz); ! write_psize += buf_p_sz; ! dev->l2ad_hand += buf_p_sz; } } mutex_exit(&dev->l2ad_mtx); ASSERT3U(write_asize, <=, target_sz); ARCSTAT_BUMP(arcstat_l2_writes_sent); ARCSTAT_INCR(arcstat_l2_write_bytes, write_asize); ARCSTAT_INCR(arcstat_l2_size, write_sz); ! ARCSTAT_INCR(arcstat_l2_asize, write_asize); ! vdev_space_update(dev->l2ad_vdev, write_asize, 0, 0); /* * Bump device hand to the device start if it is approaching the end. * l2arc_evict() will already have evicted ahead for this case. */ --- 6107,6135 ---- DTRACE_PROBE2(l2arc__write, vdev_t *, dev->l2ad_vdev, zio_t *, wzio); (void) zio_nowait(wzio); ! stats_size += buf_sz; /* * Keep the clock hand suitably device-aligned. */ ! buf_a_sz = vdev_psize_to_asize(dev->l2ad_vdev, buf_sz); ! write_asize += buf_a_sz; ! dev->l2ad_hand += buf_a_sz; } } mutex_exit(&dev->l2ad_mtx); ASSERT3U(write_asize, <=, target_sz); ARCSTAT_BUMP(arcstat_l2_writes_sent); ARCSTAT_INCR(arcstat_l2_write_bytes, write_asize); ARCSTAT_INCR(arcstat_l2_size, write_sz); ! ARCSTAT_INCR(arcstat_l2_asize, stats_size); ! vdev_space_update(dev->l2ad_vdev, stats_size, 0, 0); /* * Bump device hand to the device start if it is approaching the end. * l2arc_evict() will already have evicted ahead for this case. */