]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Fix the L2ARC write size calculating logic (2)
authorGeorge Amanakis <gamanakis@gmail.com>
Sat, 10 Jun 2023 00:05:47 +0000 (02:05 +0200)
committerGitHub <noreply@github.com>
Sat, 10 Jun 2023 00:05:47 +0000 (17:05 -0700)
While commit bcd5321 adjusts the write size based on the size of the log
block, this happens after comparing the unadjusted write size to the
evicted (target) size.

In this case l2ad_hand will exceed l2ad_evict and violate an assertion
at the end of l2arc_write_buffers().

Fix this by adding the max log block size to the allocated size of the
buffer to be committed before comparing the result to the target
size.

Also reset the l2arc_trim_ahead ZFS module variable when the adjusted
write size exceeds the size of the L2ARC device.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: George Amanakis <gamanakis@gmail.com>
Closes #14936
Closes #14954

module/zfs/arc.c

index 3dbaaa76b4a520537a8b944d981030a7ddce04b7..a23715309f2bd67b66b728b134eab2f2a0e4405a 100644 (file)
@@ -8206,7 +8206,7 @@ l2arc_write_size(l2arc_dev_t *dev)
         * device. This is important in l2arc_evict(), otherwise infinite
         * iteration can occur.
         */
-       if (size >= dev->l2ad_end - dev->l2ad_start) {
+       if (size > dev->l2ad_end - dev->l2ad_start) {
                cmn_err(CE_NOTE, "l2arc_write_max or l2arc_write_boost "
                    "plus the overhead of log blocks (persistent L2ARC, "
                    "%llu bytes) exceeds the size of the cache device "
@@ -8216,6 +8216,11 @@ l2arc_write_size(l2arc_dev_t *dev)
 
                size = l2arc_write_max = l2arc_write_boost = L2ARC_WRITE_SIZE;
 
+               if (l2arc_trim_ahead > 1) {
+                       cmn_err(CE_NOTE, "l2arc_trim_ahead set to 1");
+                       l2arc_trim_ahead = 1;
+               }
+
                if (arc_warm == B_FALSE)
                        size += l2arc_write_boost;
 
@@ -8842,7 +8847,7 @@ l2arc_evict(l2arc_dev_t *dev, uint64_t distance, boolean_t all)
 
 top:
        rerun = B_FALSE;
-       if (dev->l2ad_hand >= (dev->l2ad_end - distance)) {
+       if (dev->l2ad_hand + distance > dev->l2ad_end) {
                /*
                 * When there is no space to accommodate upcoming writes,
                 * evict to the end. Then bump the write and evict hands
@@ -9036,7 +9041,7 @@ out:
                 */
                ASSERT3U(dev->l2ad_hand + distance, <, dev->l2ad_end);
                if (!dev->l2ad_first)
-                       ASSERT3U(dev->l2ad_hand, <, dev->l2ad_evict);
+                       ASSERT3U(dev->l2ad_hand, <=, dev->l2ad_evict);
        }
 }
 
@@ -9296,7 +9301,13 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
                        uint64_t asize = vdev_psize_to_asize(dev->l2ad_vdev,
                            psize);
 
-                       if ((write_asize + asize) > target_sz) {
+                       /*
+                        * If the allocated size of this buffer plus the max
+                        * size for the pending log block exceeds the evicted
+                        * target size, terminate writing buffers for this run.
+                        */
+                       if (write_asize + asize +
+                           sizeof (l2arc_log_blk_phys_t) > target_sz) {
                                full = B_TRUE;
                                mutex_exit(hash_lock);
                                break;
@@ -9412,7 +9423,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
                         */
                        if (l2arc_log_blk_insert(dev, hdr)) {
                                /*
-                                * l2ad_hand has been accounted for in
+                                * l2ad_hand will be adjusted in
                                 * l2arc_log_blk_commit().
                                 */
                                write_asize +=