summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_zone_gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_zone_gc.c')
-rw-r--r--fs/xfs/xfs_zone_gc.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/fs/xfs/xfs_zone_gc.c b/fs/xfs/xfs_zone_gc.c
index f76a09130852..54b70ed2922f 100644
--- a/fs/xfs/xfs_zone_gc.c
+++ b/fs/xfs/xfs_zone_gc.c
@@ -46,7 +46,7 @@
* before remapping.
*
* Once a zone does not contain any valid data, be that through GC or user
- * block removal, it is queued for for a zone reset. The reset operation
+ * block removal, it is queued for a zone reset. The reset operation
* carefully ensures that the RT device cache is flushed and all transactions
* referencing the rmap have been committed to disk.
*/
@@ -103,6 +103,7 @@ struct xfs_gc_bio {
/* Open Zone being written to */
struct xfs_open_zone *oz;
+ /* Realtime group currently being reclaimed */
struct xfs_rtgroup *victim_rtg;
/* Bio used for reads and writes, including the bvec used by it */
@@ -130,6 +131,9 @@ struct xfs_zone_gc_data {
/* bioset used to allocate the gc_bios */
struct bio_set bio_set;
+ /* bioset used when writes need to be split to hardware limits */
+ struct bio_set split_bio_set;
+
/*
* Scratchpad to buffer GC data, organized as a ring buffer over
* discontiguous folios. scratch_head is where the buffer is filled,
@@ -221,6 +225,9 @@ xfs_zone_gc_data_alloc(
if (bioset_init(&data->bio_set, 16, offsetof(struct xfs_gc_bio, bio),
BIOSET_NEED_BVECS))
goto out_free_recs;
+ if (bioset_init(&data->split_bio_set, 16,
+ offsetof(struct xfs_gc_bio, bio), 0))
+ goto out_exit_bio_set;
for (i = 0; i < XFS_GC_NR_BUFS; i++) {
data->scratch_folios[i] =
folio_alloc(GFP_KERNEL, get_order(XFS_GC_BUF_SIZE));
@@ -238,6 +245,8 @@ xfs_zone_gc_data_alloc(
out_free_scratch:
while (--i >= 0)
folio_put(data->scratch_folios[i]);
+ bioset_exit(&data->split_bio_set);
+out_exit_bio_set:
bioset_exit(&data->bio_set);
out_free_recs:
kfree(data->iter.recs);
@@ -254,6 +263,7 @@ xfs_zone_gc_data_free(
for (i = 0; i < XFS_GC_NR_BUFS; i++)
folio_put(data->scratch_folios[i]);
+ bioset_exit(&data->split_bio_set);
bioset_exit(&data->bio_set);
kfree(data->iter.recs);
kfree(data);
@@ -802,7 +812,7 @@ xfs_zone_gc_split_write(
split_sectors = bio_split_rw_at(&chunk->bio, lim, &nsegs,
lim->max_zone_append_sectors << SECTOR_SHIFT);
- if (!split_sectors)
+ if (split_sectors <= 0)
return NULL;
/* ensure the split chunk is still block size aligned */
@@ -810,7 +820,8 @@ xfs_zone_gc_split_write(
data->mp->m_sb.sb_blocksize) >> SECTOR_SHIFT;
split_len = split_sectors << SECTOR_SHIFT;
- split = bio_split(&chunk->bio, split_sectors, GFP_NOFS, &data->bio_set);
+ split = bio_split(&chunk->bio, split_sectors, GFP_NOFS,
+ &data->split_bio_set);
split_chunk = container_of(split, struct xfs_gc_bio, bio);
split_chunk->data = data;
ihold(VFS_I(chunk->ip));
@@ -858,6 +869,11 @@ xfs_zone_gc_write_chunk(
WRITE_ONCE(chunk->state, XFS_GC_BIO_NEW);
list_move_tail(&chunk->entry, &data->writing);
+ /*
+ * If we run on top of stacked block device, the read I/O might have
+ * reset bi_bdev, restore it to the one we want.
+ */
+ bio_set_dev(&chunk->bio, mp->m_rtdev_targp->bt_bdev);
bio_reuse(&chunk->bio, REQ_OP_WRITE);
while ((split_chunk = xfs_zone_gc_split_write(data, chunk)))
xfs_zone_gc_submit_write(data, split_chunk);