Update bcachefs sources to 6c3c2a24c61d bcachefs: Fix possible corruption on repeated mmap writes

This commit is contained in:
Kent Overstreet 2025-12-02 23:06:44 -05:00
parent 800949c1ce
commit 858e41a71d
5 changed files with 80 additions and 20 deletions

View File

@ -1 +1 @@
682cbaf658f5fde86172e02ffdac0f65650f9fa1
6c3c2a24c61ddc23a6bbdf604b88262da0cd2d9c

View File

@ -598,6 +598,7 @@ static int __bch2_writepage(struct folio *folio,
do_io:
f_sectors = folio_sectors(folio);
s = bch2_folio(folio);
BUG_ON(!s);
if (f_sectors > w->tmp_sectors) {
kfree(w->tmp);
@ -829,7 +830,7 @@ int bch2_write_end(
struct bch_inode_info *inode = to_bch_ei(mapping->host);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
struct bch2_folio_reservation *res = fsdata;
unsigned offset = pos - folio_pos(folio);
size_t offset = pos - folio_pos(folio);
BUG_ON(offset + copied > folio_size(folio));
@ -886,8 +887,9 @@ static int __bch2_buffered_write(struct bch_fs *c,
struct bch2_folio_reservation res;
folios fs;
struct folio *f;
unsigned copied = 0, f_offset, f_copied;
u64 end = pos + len, f_pos, f_len;
unsigned copied = 0, f_copied;
size_t f_offset, f_len;
u64 end = pos + len, f_pos;
loff_t last_folio_pos = inode->v.i_size;
int ret = 0;

View File

@ -1498,7 +1498,7 @@ static const struct address_space_operations bch_address_space_operations = {
.read_folio = bch2_read_folio,
.writepages = bch2_writepages,
.readahead = bch2_readahead,
.dirty_folio = filemap_dirty_folio,
.dirty_folio = bch2_vfs_dirty_folio,
.write_begin = bch2_write_begin,
.write_end = bch2_write_end,
.invalidate_folio = bch2_invalidate_folio,

View File

@ -361,14 +361,14 @@ int bch2_get_folio_disk_reservation(struct bch_fs *c,
struct bch_inode_info *inode,
struct folio *folio, bool check_enospc)
{
struct bch_folio *s = bch2_folio_create(folio, 0);
struct bch_folio *s = bch2_folio(folio);
unsigned nr_replicas = inode_nr_replicas(c, inode);
struct disk_reservation disk_res = { 0 };
unsigned i, sectors = folio_sectors(folio), disk_res_sectors = 0;
int ret;
if (!s)
return -ENOMEM;
BUG_ON(!s);
EBUG_ON(!s->uptodate);
for (i = 0; i < sectors; i++)
disk_res_sectors += sectors_to_reserve(&s->s[i], nr_replicas);
@ -399,21 +399,19 @@ void bch2_folio_reservation_put(struct bch_fs *c,
bch2_quota_reservation_put(c, inode, &res->quota);
}
static int __bch2_folio_reservation_get(struct bch_fs *c,
static ssize_t __bch2_folio_reservation_get(struct bch_fs *c,
struct bch_inode_info *inode,
struct folio *folio,
struct bch2_folio_reservation *res,
size_t offset, size_t len,
bool partial)
{
struct bch_folio *s = bch2_folio_create(folio, 0);
struct bch_folio *s = bch2_folio(folio);
unsigned i, disk_sectors = 0, quota_sectors = 0;
size_t reserved = len;
int ret;
if (!s)
return -ENOMEM;
BUG_ON(!s);
BUG_ON(!s->uptodate);
for (i = round_down(offset, block_bytes(c)) >> 9;
@ -462,13 +460,54 @@ static int __bch2_folio_reservation_get(struct bch_fs *c,
return partial ? reserved : 0;
}
static int bch2_folio_reservation_get_nofail(struct bch_fs *c,
struct bch_inode_info *inode,
struct folio *folio,
struct bch2_folio_reservation *res,
size_t offset, size_t len)
{
struct bch_folio *s = bch2_folio(folio);
unsigned i, disk_sectors = 0, quota_sectors = 0;
struct disk_reservation disk_res = {};
int ret;
BUG_ON(!s);
BUG_ON(!s->uptodate);
for (i = round_down(offset, block_bytes(c)) >> 9;
i < round_up(offset + len, block_bytes(c)) >> 9;
i++) {
disk_sectors += sectors_to_reserve(&s->s[i], res->disk.nr_replicas);
quota_sectors += s->s[i].state == SECTOR_unallocated;
}
if (disk_sectors) {
ret = bch2_disk_reservation_add(c, &disk_res, disk_sectors,
BCH_DISK_RESERVATION_NOFAIL);
if (unlikely(ret))
return ret;
}
if (quota_sectors) {
/* FIXME: we'll need to make sure this won't fail with -ENOMEM */
ret = bch2_quota_reservation_add(c, inode, &res->quota, quota_sectors, false);
if (unlikely(ret)) {
bch2_disk_reservation_put(c, &disk_res);
return ret;
}
}
res->disk.sectors += disk_res.sectors;
return 0;
}
int bch2_folio_reservation_get(struct bch_fs *c,
struct bch_inode_info *inode,
struct folio *folio,
struct bch2_folio_reservation *res,
size_t offset, size_t len)
{
return __bch2_folio_reservation_get(c, inode, folio, res, offset, len, false);
return (int)__bch2_folio_reservation_get(c, inode, folio, res, offset, len, false);
}
ssize_t bch2_folio_reservation_get_partial(struct bch_fs *c,
@ -508,11 +547,26 @@ static void bch2_clear_folio_bits(struct folio *folio)
bch2_folio_release(folio);
}
void bch2_set_folio_dirty(struct bch_fs *c,
bool bch2_vfs_dirty_folio(struct address_space *mapping, struct folio *folio)
{
struct bch_inode_info *inode = to_bch_ei(mapping->host);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
struct bch2_folio_reservation res;
loff_t file_size = i_size_read(&inode->v);
size_t dirty_bytes = min_t(size_t, folio_size(folio),
round_up(file_size, block_bytes(c)) - folio_pos(folio));
bch2_folio_reservation_init(c, inode, &res);
BUG_ON(bch2_folio_reservation_get_nofail(c, inode, folio, &res, 0, dirty_bytes));
return bch2_set_folio_dirty(c, inode, folio, &res, 0, dirty_bytes);
}
bool bch2_set_folio_dirty(struct bch_fs *c,
struct bch_inode_info *inode,
struct folio *folio,
struct bch2_folio_reservation *res,
unsigned offset, unsigned len)
size_t offset, size_t len)
{
struct bch_folio *s = bch2_folio(folio);
unsigned i, dirty_sectors = 0;
@ -520,7 +574,9 @@ void bch2_set_folio_dirty(struct bch_fs *c,
WARN_ON((u64) folio_pos(folio) + offset + len >
round_up((u64) i_size_read(&inode->v), block_bytes(c)));
BUG_ON(!s);
BUG_ON(!s->uptodate);
EBUG_ON(round_up(offset + len, block_bytes(c)) >> 9 > UINT_MAX);
scoped_guard(spinlock, &s->lock)
for (i = round_down(offset, block_bytes(c)) >> 9;
@ -546,7 +602,8 @@ void bch2_set_folio_dirty(struct bch_fs *c,
bch2_i_sectors_acct(c, inode, &res->quota, dirty_sectors);
if (!folio_test_dirty(folio))
filemap_dirty_folio(inode->v.i_mapping, folio);
return filemap_dirty_folio(inode->v.i_mapping, folio);
return false;
}
vm_fault_t bch2_page_fault(struct vm_fault *vmf)
@ -598,7 +655,7 @@ vm_fault_t bch2_page_mkwrite(struct vm_fault *vmf)
vm_fault_t ret;
loff_t file_offset = round_down(vmf->pgoff << PAGE_SHIFT, block_bytes(c));
unsigned offset = file_offset - folio_pos(folio);
size_t offset = file_offset - folio_pos(folio);
unsigned len = max(PAGE_SIZE, block_bytes(c));
BUG_ON(offset + len > folio_size(folio));

View File

@ -153,11 +153,12 @@ ssize_t bch2_folio_reservation_get_partial(struct bch_fs *,
struct bch2_folio_reservation *,
size_t, size_t);
void bch2_set_folio_dirty(struct bch_fs *,
bool bch2_vfs_dirty_folio(struct address_space *mapping, struct folio *folio);
bool bch2_set_folio_dirty(struct bch_fs *,
struct bch_inode_info *,
struct folio *,
struct bch2_folio_reservation *,
unsigned, unsigned);
size_t, size_t);
vm_fault_t bch2_page_fault(struct vm_fault *);
vm_fault_t bch2_page_mkwrite(struct vm_fault *);