]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xfs: refactor hint based zone allocation
authorHans Holmberg <Hans.Holmberg@wdc.com>
Mon, 1 Sep 2025 10:52:05 +0000 (10:52 +0000)
committerCarlos Maiolino <cem@kernel.org>
Tue, 16 Sep 2025 10:30:41 +0000 (12:30 +0200)
Replace the co-location code with a matrix that makes it more clear
on how the decisions are made.

The matrix contains scores for zone/file hint combinations. A "GOOD"
score for an open zone will result in immediate co-location while "OK"
combinations will only be picked if we cannot open a new zone.

Signed-off-by: Hans Holmberg <hans.holmberg@wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
fs/xfs/xfs_zone_alloc.c

index f28214c28ab5455670f7ef2a57e8317c73b5f204..ff24769b88702ef84db988f897c6134ca385bcb8 100644 (file)
@@ -493,64 +493,64 @@ xfs_try_open_zone(
        return oz;
 }
 
+enum xfs_zone_alloc_score {
+       /* Any open zone will do it, we're desperate */
+       XFS_ZONE_ALLOC_ANY      = 0,
+
+       /* It better fit somehow */
+       XFS_ZONE_ALLOC_OK       = 1,
+
+       /* Only reuse a zone if it fits really well. */
+       XFS_ZONE_ALLOC_GOOD     = 2,
+};
+
 /*
- * For data with short or medium lifetime, try to colocated it into an
- * already open zone with a matching temperature.
+ * Life time hint co-location matrix.  Fields not set default to 0
+ * aka XFS_ZONE_ALLOC_ANY.
  */
-static bool
-xfs_colocate_eagerly(
-       enum rw_hint            file_hint)
-{
-       switch (file_hint) {
-       case WRITE_LIFE_MEDIUM:
-       case WRITE_LIFE_SHORT:
-       case WRITE_LIFE_NONE:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static bool
-xfs_good_hint_match(
-       struct xfs_open_zone    *oz,
-       enum rw_hint            file_hint)
-{
-       switch (oz->oz_write_hint) {
-       case WRITE_LIFE_LONG:
-       case WRITE_LIFE_EXTREME:
-               /* colocate long and extreme */
-               if (file_hint == WRITE_LIFE_LONG ||
-                   file_hint == WRITE_LIFE_EXTREME)
-                       return true;
-               break;
-       case WRITE_LIFE_MEDIUM:
-               /* colocate medium with medium */
-               if (file_hint == WRITE_LIFE_MEDIUM)
-                       return true;
-               break;
-       case WRITE_LIFE_SHORT:
-       case WRITE_LIFE_NONE:
-       case WRITE_LIFE_NOT_SET:
-               /* colocate short and none */
-               if (file_hint <= WRITE_LIFE_SHORT)
-                       return true;
-               break;
-       }
-       return false;
-}
+static const unsigned int
+xfs_zoned_hint_score[WRITE_LIFE_HINT_NR][WRITE_LIFE_HINT_NR] = {
+       [WRITE_LIFE_NOT_SET]    = {
+               [WRITE_LIFE_NOT_SET]    = XFS_ZONE_ALLOC_OK,
+               [WRITE_LIFE_NONE]       = XFS_ZONE_ALLOC_OK,
+               [WRITE_LIFE_SHORT]      = XFS_ZONE_ALLOC_OK,
+       },
+       [WRITE_LIFE_NONE]       = {
+               [WRITE_LIFE_NOT_SET]    = XFS_ZONE_ALLOC_OK,
+               [WRITE_LIFE_NONE]       = XFS_ZONE_ALLOC_GOOD,
+               [WRITE_LIFE_SHORT]      = XFS_ZONE_ALLOC_GOOD,
+       },
+       [WRITE_LIFE_SHORT]      = {
+               [WRITE_LIFE_NOT_SET]    = XFS_ZONE_ALLOC_GOOD,
+               [WRITE_LIFE_NONE]       = XFS_ZONE_ALLOC_GOOD,
+               [WRITE_LIFE_SHORT]      = XFS_ZONE_ALLOC_GOOD,
+       },
+       [WRITE_LIFE_MEDIUM]     = {
+               [WRITE_LIFE_MEDIUM]     = XFS_ZONE_ALLOC_GOOD,
+       },
+       [WRITE_LIFE_LONG]       = {
+               [WRITE_LIFE_LONG]       = XFS_ZONE_ALLOC_OK,
+               [WRITE_LIFE_EXTREME]    = XFS_ZONE_ALLOC_OK,
+       },
+       [WRITE_LIFE_EXTREME]    = {
+               [WRITE_LIFE_LONG]       = XFS_ZONE_ALLOC_OK,
+               [WRITE_LIFE_EXTREME]    = XFS_ZONE_ALLOC_OK,
+       },
+};
 
 static bool
 xfs_try_use_zone(
        struct xfs_zone_info    *zi,
        enum rw_hint            file_hint,
        struct xfs_open_zone    *oz,
-       bool                    lowspace)
+       unsigned int            goodness)
 {
        if (oz->oz_allocated == rtg_blocks(oz->oz_rtg))
                return false;
-       if (!lowspace && !xfs_good_hint_match(oz, file_hint))
+
+       if (xfs_zoned_hint_score[oz->oz_write_hint][file_hint] < goodness)
                return false;
+
        if (!atomic_inc_not_zero(&oz->oz_ref))
                return false;
 
@@ -581,14 +581,14 @@ static struct xfs_open_zone *
 xfs_select_open_zone_lru(
        struct xfs_zone_info    *zi,
        enum rw_hint            file_hint,
-       bool                    lowspace)
+       unsigned int            goodness)
 {
        struct xfs_open_zone    *oz;
 
        lockdep_assert_held(&zi->zi_open_zones_lock);
 
        list_for_each_entry(oz, &zi->zi_open_zones, oz_entry)
-               if (xfs_try_use_zone(zi, file_hint, oz, lowspace))
+               if (xfs_try_use_zone(zi, file_hint, oz, goodness))
                        return oz;
 
        cond_resched_lock(&zi->zi_open_zones_lock);
@@ -651,9 +651,11 @@ xfs_select_zone_nowait(
         * data.
         */
        spin_lock(&zi->zi_open_zones_lock);
-       if (xfs_colocate_eagerly(write_hint))
-               oz = xfs_select_open_zone_lru(zi, write_hint, false);
-       else if (pack_tight)
+       oz = xfs_select_open_zone_lru(zi, write_hint, XFS_ZONE_ALLOC_GOOD);
+       if (oz)
+               goto out_unlock;
+
+       if (pack_tight)
                oz = xfs_select_open_zone_mru(zi, write_hint);
        if (oz)
                goto out_unlock;
@@ -667,16 +669,16 @@ xfs_select_zone_nowait(
                goto out_unlock;
 
        /*
-        * Try to colocate cold data with other cold data if we failed to open a
-        * new zone for it.
+        * Try to find an zone that is an ok match to colocate data with.
+        */
+       oz = xfs_select_open_zone_lru(zi, write_hint, XFS_ZONE_ALLOC_OK);
+       if (oz)
+               goto out_unlock;
+
+       /*
+        * Pick the least recently used zone, regardless of hint match
         */
-       if (write_hint != WRITE_LIFE_NOT_SET &&
-           !xfs_colocate_eagerly(write_hint))
-               oz = xfs_select_open_zone_lru(zi, write_hint, false);
-       if (!oz)
-               oz = xfs_select_open_zone_lru(zi, WRITE_LIFE_NOT_SET, false);
-       if (!oz)
-               oz = xfs_select_open_zone_lru(zi, WRITE_LIFE_NOT_SET, true);
+       oz = xfs_select_open_zone_lru(zi, write_hint, XFS_ZONE_ALLOC_ANY);
 out_unlock:
        spin_unlock(&zi->zi_open_zones_lock);
        return oz;