Skip to content

Commit 59c376d

Browse files
committed
Merge tag 'iomap-6.6-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull iomap fixes from Darrick Wong: - Return EIO on bad inputs to iomap_to_bh instead of BUGging, to deal less poorly with block device io racing with block device resizing - Fix a stale page data exposure bug introduced in 6.6-rc1 when unsharing a file range that is not in the page cache * tag 'iomap-6.6-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: iomap: convert iomap_unshare_iter to use large folios iomap: don't skip reading in !uptodate folios when unsharing a range iomap: handle error conditions more gracefully in iomap_to_bh
2 parents d90b027 + a5f31a5 commit 59c376d

File tree

2 files changed

+32
-23
lines changed

2 files changed

+32
-23
lines changed

fs/buffer.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,7 +2011,7 @@ void folio_zero_new_buffers(struct folio *folio, size_t from, size_t to)
20112011
}
20122012
EXPORT_SYMBOL(folio_zero_new_buffers);
20132013

2014-
static void
2014+
static int
20152015
iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
20162016
const struct iomap *iomap)
20172017
{
@@ -2025,7 +2025,8 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
20252025
* current block, then do not map the buffer and let the caller
20262026
* handle it.
20272027
*/
2028-
BUG_ON(offset >= iomap->offset + iomap->length);
2028+
if (offset >= iomap->offset + iomap->length)
2029+
return -EIO;
20292030

20302031
switch (iomap->type) {
20312032
case IOMAP_HOLE:
@@ -2037,15 +2038,15 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
20372038
if (!buffer_uptodate(bh) ||
20382039
(offset >= i_size_read(inode)))
20392040
set_buffer_new(bh);
2040-
break;
2041+
return 0;
20412042
case IOMAP_DELALLOC:
20422043
if (!buffer_uptodate(bh) ||
20432044
(offset >= i_size_read(inode)))
20442045
set_buffer_new(bh);
20452046
set_buffer_uptodate(bh);
20462047
set_buffer_mapped(bh);
20472048
set_buffer_delay(bh);
2048-
break;
2049+
return 0;
20492050
case IOMAP_UNWRITTEN:
20502051
/*
20512052
* For unwritten regions, we always need to ensure that regions
@@ -2062,7 +2063,10 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
20622063
bh->b_blocknr = (iomap->addr + offset - iomap->offset) >>
20632064
inode->i_blkbits;
20642065
set_buffer_mapped(bh);
2065-
break;
2066+
return 0;
2067+
default:
2068+
WARN_ON_ONCE(1);
2069+
return -EIO;
20662070
}
20672071
}
20682072

@@ -2103,13 +2107,12 @@ int __block_write_begin_int(struct folio *folio, loff_t pos, unsigned len,
21032107
clear_buffer_new(bh);
21042108
if (!buffer_mapped(bh)) {
21052109
WARN_ON(bh->b_size != blocksize);
2106-
if (get_block) {
2110+
if (get_block)
21072111
err = get_block(inode, block, bh, 1);
2108-
if (err)
2109-
break;
2110-
} else {
2111-
iomap_to_bh(inode, block, bh, iomap);
2112-
}
2112+
else
2113+
err = iomap_to_bh(inode, block, bh, iomap);
2114+
if (err)
2115+
break;
21132116

21142117
if (buffer_new(bh)) {
21152118
clean_bdev_bh_alias(bh);

fs/iomap/buffered-io.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -640,11 +640,13 @@ static int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
640640
size_t poff, plen;
641641

642642
/*
643-
* If the write completely overlaps the current folio, then
643+
* If the write or zeroing completely overlaps the current folio, then
644644
* entire folio will be dirtied so there is no need for
645645
* per-block state tracking structures to be attached to this folio.
646+
* For the unshare case, we must read in the ondisk contents because we
647+
* are not changing pagecache contents.
646648
*/
647-
if (pos <= folio_pos(folio) &&
649+
if (!(iter->flags & IOMAP_UNSHARE) && pos <= folio_pos(folio) &&
648650
pos + len >= folio_pos(folio) + folio_size(folio))
649651
return 0;
650652

@@ -1261,7 +1263,6 @@ static loff_t iomap_unshare_iter(struct iomap_iter *iter)
12611263
const struct iomap *srcmap = iomap_iter_srcmap(iter);
12621264
loff_t pos = iter->pos;
12631265
loff_t length = iomap_length(iter);
1264-
long status = 0;
12651266
loff_t written = 0;
12661267

12671268
/* don't bother with blocks that are not shared to start with */
@@ -1272,28 +1273,33 @@ static loff_t iomap_unshare_iter(struct iomap_iter *iter)
12721273
return length;
12731274

12741275
do {
1275-
unsigned long offset = offset_in_page(pos);
1276-
unsigned long bytes = min_t(loff_t, PAGE_SIZE - offset, length);
12771276
struct folio *folio;
1277+
int status;
1278+
size_t offset;
1279+
size_t bytes = min_t(u64, SIZE_MAX, length);
12781280

12791281
status = iomap_write_begin(iter, pos, bytes, &folio);
12801282
if (unlikely(status))
12811283
return status;
1282-
if (iter->iomap.flags & IOMAP_F_STALE)
1284+
if (iomap->flags & IOMAP_F_STALE)
12831285
break;
12841286

1285-
status = iomap_write_end(iter, pos, bytes, bytes, folio);
1286-
if (WARN_ON_ONCE(status == 0))
1287+
offset = offset_in_folio(folio, pos);
1288+
if (bytes > folio_size(folio) - offset)
1289+
bytes = folio_size(folio) - offset;
1290+
1291+
bytes = iomap_write_end(iter, pos, bytes, bytes, folio);
1292+
if (WARN_ON_ONCE(bytes == 0))
12871293
return -EIO;
12881294

12891295
cond_resched();
12901296

1291-
pos += status;
1292-
written += status;
1293-
length -= status;
1297+
pos += bytes;
1298+
written += bytes;
1299+
length -= bytes;
12941300

12951301
balance_dirty_pages_ratelimited(iter->inode->i_mapping);
1296-
} while (length);
1302+
} while (length > 0);
12971303

12981304
return written;
12991305
}

0 commit comments

Comments
 (0)