mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Merge patch series "iomap: trivial fixes for ext4 conversion"
Zhang Yi <yi.zhang@huaweicloud.com> says: This patch series contains a few trivial iomap-related fixes in preparation for converting ext4 buffered I/O to use iomap. The first three patches are taken from my ext4 conversion series [1], as suggested by Christoph. The fourth patch fixes a bug originally reported by Sashiko during review of my series; although unrelated to the ext4 conversion, it is worth fixing on its own. Please see the following patches for detail. The fifth patch add comments for ifs_clear/set_range_dirty(), and the last patch avoids merging ioends that have different private data. [1] https://lore.kernel.org/linux-ext4/20260511072344.191271-1-yi.zhang@huaweicloud.com/ * patches from https://patch.msgid.link/20260714082325.325163-1-yi.zhang@huaweicloud.com: iomap: add comments for ifs_clear/set_range_dirty() iomap: fix out-of-bounds bitmap_set() with zero-length range iomap: fix incorrect did_zero setting in iomap_zero_iter() iomap: support invalidating partial folios iomap: correct the range of a partial dirty clear Link: https://patch.msgid.link/20260714082325.325163-1-yi.zhang@huaweicloud.com Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
commit
1c9cb1826b
|
|
@ -68,11 +68,13 @@ static bool ifs_set_range_uptodate(struct folio *folio,
|
|||
struct iomap_folio_state *ifs, size_t off, size_t len)
|
||||
{
|
||||
struct inode *inode = folio->mapping->host;
|
||||
unsigned int first_blk = off >> inode->i_blkbits;
|
||||
unsigned int last_blk = (off + len - 1) >> inode->i_blkbits;
|
||||
unsigned int nr_blks = last_blk - first_blk + 1;
|
||||
unsigned int first_blk, last_blk;
|
||||
|
||||
bitmap_set(ifs->state, first_blk, nr_blks);
|
||||
if (len) {
|
||||
first_blk = off >> inode->i_blkbits;
|
||||
last_blk = (off + len - 1) >> inode->i_blkbits;
|
||||
bitmap_set(ifs->state, first_blk, last_blk - first_blk + 1);
|
||||
}
|
||||
return ifs_is_fully_uptodate(folio, ifs);
|
||||
}
|
||||
|
||||
|
|
@ -172,18 +174,29 @@ static unsigned iomap_find_dirty_range(struct folio *folio, u64 *range_start,
|
|||
return range_end - *range_start;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the per-block dirty bits for the range [@off, @off + @len) within a
|
||||
* folio. The range is rounded inwards so that only blocks fully covered by
|
||||
* the range are cleared. This is required for operations like folio
|
||||
* invalidation, where we must ensure a block is fully clean before discarding
|
||||
* it.
|
||||
*/
|
||||
static void ifs_clear_range_dirty(struct folio *folio,
|
||||
struct iomap_folio_state *ifs, size_t off, size_t len)
|
||||
{
|
||||
struct inode *inode = folio->mapping->host;
|
||||
unsigned int blks_per_folio = i_blocks_per_folio(inode, folio);
|
||||
unsigned int first_blk = (off >> inode->i_blkbits);
|
||||
unsigned int last_blk = (off + len - 1) >> inode->i_blkbits;
|
||||
unsigned int nr_blks = last_blk - first_blk + 1;
|
||||
unsigned int first_blk = round_up(off, i_blocksize(inode)) >>
|
||||
inode->i_blkbits;
|
||||
unsigned int last_blk = (off + len) >> inode->i_blkbits;
|
||||
unsigned long flags;
|
||||
|
||||
if (first_blk >= last_blk)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&ifs->state_lock, flags);
|
||||
bitmap_clear(ifs->state, first_blk + blks_per_folio, nr_blks);
|
||||
bitmap_clear(ifs->state, first_blk + blks_per_folio,
|
||||
last_blk - first_blk);
|
||||
spin_unlock_irqrestore(&ifs->state_lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -195,18 +208,29 @@ static void iomap_clear_range_dirty(struct folio *folio, size_t off, size_t len)
|
|||
ifs_clear_range_dirty(folio, ifs, off, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the per-block dirty bits for the range [@off, @off + @len) within a
|
||||
* folio. The range is rounded outwards so that any block partially touched
|
||||
* by the range is marked dirty. This ensures blocks containing even a
|
||||
* single dirty byte will be included in subsequent writeback, preventing
|
||||
* data loss when partial blocks are written.
|
||||
*/
|
||||
static void ifs_set_range_dirty(struct folio *folio,
|
||||
struct iomap_folio_state *ifs, size_t off, size_t len)
|
||||
{
|
||||
struct inode *inode = folio->mapping->host;
|
||||
unsigned int blks_per_folio = i_blocks_per_folio(inode, folio);
|
||||
unsigned int first_blk = (off >> inode->i_blkbits);
|
||||
unsigned int last_blk = (off + len - 1) >> inode->i_blkbits;
|
||||
unsigned int nr_blks = last_blk - first_blk + 1;
|
||||
unsigned int first_blk, last_blk;
|
||||
unsigned long flags;
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
first_blk = off >> inode->i_blkbits;
|
||||
last_blk = (off + len - 1) >> inode->i_blkbits;
|
||||
spin_lock_irqsave(&ifs->state_lock, flags);
|
||||
bitmap_set(ifs->state, first_blk + blks_per_folio, nr_blks);
|
||||
bitmap_set(ifs->state, first_blk + blks_per_folio,
|
||||
last_blk - first_blk + 1);
|
||||
spin_unlock_irqrestore(&ifs->state_lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -811,6 +835,8 @@ void iomap_invalidate_folio(struct folio *folio, size_t offset, size_t len)
|
|||
WARN_ON_ONCE(folio_test_writeback(folio));
|
||||
folio_cancel_dirty(folio);
|
||||
ifs_free(folio);
|
||||
} else {
|
||||
iomap_clear_range_dirty(folio, offset, len);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iomap_invalidate_folio);
|
||||
|
|
@ -1619,6 +1645,7 @@ static int iomap_zero_iter(struct iomap_iter *iter, bool *did_zero,
|
|||
const struct iomap_write_ops *write_ops)
|
||||
{
|
||||
u64 bytes = iomap_length(iter);
|
||||
bool zeroed = false;
|
||||
int status;
|
||||
|
||||
do {
|
||||
|
|
@ -1639,6 +1666,8 @@ static int iomap_zero_iter(struct iomap_iter *iter, bool *did_zero,
|
|||
/* a NULL folio means we're done with a folio batch */
|
||||
if (!folio) {
|
||||
status = iomap_iter_advance_full(iter);
|
||||
if (status)
|
||||
return status;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1649,6 +1678,7 @@ static int iomap_zero_iter(struct iomap_iter *iter, bool *did_zero,
|
|||
bytes);
|
||||
|
||||
folio_zero_range(folio, offset, bytes);
|
||||
zeroed = true;
|
||||
folio_mark_accessed(folio);
|
||||
|
||||
ret = iomap_write_end(iter, bytes, bytes, folio);
|
||||
|
|
@ -1658,10 +1688,10 @@ static int iomap_zero_iter(struct iomap_iter *iter, bool *did_zero,
|
|||
|
||||
status = iomap_iter_advance(iter, bytes);
|
||||
if (status)
|
||||
break;
|
||||
return status;
|
||||
} while ((bytes = iomap_length(iter)) > 0);
|
||||
|
||||
if (did_zero)
|
||||
if (did_zero && zeroed)
|
||||
*did_zero = true;
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user