return 0;
}
+static inline bool
+xfs_zone_is_conv(
+ struct xfs_rtgroup *rtg)
+{
+ return !bdev_zone_is_seq(rtg_mount(rtg)->m_rtdev_targp->bt_bdev,
+ xfs_gbno_to_daddr(rtg_group(rtg), 0));
+}
+
+static struct xfs_open_zone *
+xfs_find_fullest_conventional_open_zone(
+ struct xfs_mount *mp)
+{
+ struct xfs_zone_info *zi = mp->m_zone_info;
+ struct xfs_open_zone *found = NULL, *oz;
+
+ spin_lock(&zi->zi_open_zones_lock);
+ list_for_each_entry(oz, &zi->zi_open_zones, oz_entry) {
+ if (!xfs_zone_is_conv(oz->oz_rtg))
+ continue;
+ if (!found || oz->oz_allocated > found->oz_allocated)
+ found = oz;
+ }
+ spin_unlock(&zi->zi_open_zones_lock);
+
+ return found;
+}
+
+/*
+ * Find the fullest conventional zones and remove them from the open zone pool
+ * until we are at the open zone limit.
+ *
+ * We can end up with spurious "open" zones when the last blocks in a fully
+ * written zone were invalidate as there is no write pointer for conventional
+ * zones.
+ *
+ * If we are still over the limit when there is no conventional open zone left,
+ * the user overrode the max open zones limit using the max_open_zones mount
+ * option we should fail.
+ */
+static int
+xfs_finish_spurious_open_zones(
+ struct xfs_mount *mp,
+ struct xfs_init_zones *iz)
+{
+ struct xfs_zone_info *zi = mp->m_zone_info;
+
+ while (zi->zi_nr_open_zones > mp->m_max_open_zones) {
+ struct xfs_open_zone *oz;
+ xfs_filblks_t adjust;
+
+ oz = xfs_find_fullest_conventional_open_zone(mp);
+ if (!oz) {
+ xfs_err(mp,
+"too many open zones for max_open_zones limit (%u/%u)",
+ zi->zi_nr_open_zones, mp->m_max_open_zones);
+ return -EINVAL;
+ }
+
+ xfs_rtgroup_lock(oz->oz_rtg, XFS_RTGLOCK_RMAP);
+ adjust = rtg_blocks(oz->oz_rtg) - oz->oz_written;
+ trace_xfs_zone_spurious_open(oz, oz->oz_written, adjust);
+ oz->oz_written = rtg_blocks(oz->oz_rtg);
+ xfs_open_zone_mark_full(oz);
+ xfs_rtgroup_unlock(oz->oz_rtg, XFS_RTGLOCK_RMAP);
+ iz->available -= adjust;
+ iz->reclaimable += adjust;
+ }
+
+ return 0;
+}
+
int
xfs_mount_zones(
struct xfs_mount *mp)
if (error)
goto out_free_zone_info;
+ error = xfs_finish_spurious_open_zones(mp, &iz);
+ if (error)
+ goto out_free_zone_info;
+
xfs_set_freecounter(mp, XC_FREE_RTAVAILABLE, iz.available);
xfs_set_freecounter(mp, XC_FREE_RTEXTENTS,
iz.available + iz.reclaimable);