mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
bcachefs: Ensure buffered writes write as much as they can
This adds a new helper, bch2_folio_reservation_get_partial(), which reserves as many blocks as possible and may return partial success. __bch2_buffered_write() is switched to the new helper - this fixes fstests generic/275, the write until -ENOSPC test. generic/230 now fails: this appears to be a test bug, where xfs_io isn't looping after a partial write to get the error code. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
95924420b0
commit
7554a8bb6d
@ -863,24 +863,26 @@ static int __bch2_buffered_write(struct bch_inode_info *inode,
|
||||
f_pos = pos;
|
||||
f_offset = pos - folio_pos(darray_first(fs));
|
||||
darray_for_each(fs, fi) {
|
||||
ssize_t f_reserved;
|
||||
|
||||
f = *fi;
|
||||
f_len = min(end, folio_end_pos(f)) - f_pos;
|
||||
f_reserved = bch2_folio_reservation_get_partial(c, inode, f, &res, f_offset, f_len);
|
||||
|
||||
/*
|
||||
* XXX: per POSIX and fstests generic/275, on -ENOSPC we're
|
||||
* supposed to write as much as we have disk space for.
|
||||
*
|
||||
* On failure here we should still write out a partial page if
|
||||
* we aren't completely out of disk space - we don't do that
|
||||
* yet:
|
||||
*/
|
||||
ret = bch2_folio_reservation_get(c, inode, f, &res, f_offset, f_len);
|
||||
if (unlikely(ret)) {
|
||||
folios_trunc(&fs, fi);
|
||||
if (!fs.nr)
|
||||
goto out;
|
||||
if (unlikely(f_reserved != f_len)) {
|
||||
if (f_reserved < 0) {
|
||||
if (f == darray_first(fs)) {
|
||||
ret = f_reserved;
|
||||
goto out;
|
||||
}
|
||||
|
||||
folios_trunc(&fs, fi);
|
||||
end = min(end, folio_end_pos(darray_last(fs)));
|
||||
} else {
|
||||
folios_trunc(&fs, fi + 1);
|
||||
end = f_pos + f_reserved;
|
||||
}
|
||||
|
||||
end = min(end, folio_end_pos(darray_last(fs)));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -423,7 +423,7 @@ int bch2_folio_reservation_get(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_create(folio, 0);
|
||||
unsigned i, disk_sectors = 0, quota_sectors = 0;
|
||||
@ -437,8 +437,7 @@ int bch2_folio_reservation_get(struct bch_fs *c,
|
||||
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);
|
||||
disk_sectors += sectors_to_reserve(&s->s[i], res->disk.nr_replicas);
|
||||
quota_sectors += s->s[i].state == SECTOR_unallocated;
|
||||
}
|
||||
|
||||
@ -449,12 +448,9 @@ int bch2_folio_reservation_get(struct bch_fs *c,
|
||||
}
|
||||
|
||||
if (quota_sectors) {
|
||||
ret = bch2_quota_reservation_add(c, inode, &res->quota,
|
||||
quota_sectors, true);
|
||||
ret = bch2_quota_reservation_add(c, inode, &res->quota, quota_sectors, true);
|
||||
if (unlikely(ret)) {
|
||||
struct disk_reservation tmp = {
|
||||
.sectors = disk_sectors
|
||||
};
|
||||
struct disk_reservation tmp = { .sectors = disk_sectors };
|
||||
|
||||
bch2_disk_reservation_put(c, &tmp);
|
||||
res->disk.sectors -= disk_sectors;
|
||||
@ -465,6 +461,31 @@ int bch2_folio_reservation_get(struct bch_fs *c,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t bch2_folio_reservation_get_partial(struct bch_fs *c,
|
||||
struct bch_inode_info *inode,
|
||||
struct folio *folio,
|
||||
struct bch2_folio_reservation *res,
|
||||
size_t offset, size_t len)
|
||||
{
|
||||
size_t l, reserved = 0;
|
||||
int ret;
|
||||
|
||||
while ((l = len - reserved)) {
|
||||
while ((ret = bch2_folio_reservation_get(c, inode, folio, res, offset, l))) {
|
||||
if ((offset & (block_bytes(c) - 1)) + l <= block_bytes(c))
|
||||
return reserved ?: ret;
|
||||
|
||||
len = reserved + l;
|
||||
l /= 2;
|
||||
}
|
||||
|
||||
offset += l;
|
||||
reserved += l;
|
||||
}
|
||||
|
||||
return reserved;
|
||||
}
|
||||
|
||||
static void bch2_clear_folio_bits(struct folio *folio)
|
||||
{
|
||||
struct bch_inode_info *inode = to_bch_ei(folio->mapping->host);
|
||||
|
@ -153,7 +153,12 @@ int bch2_folio_reservation_get(struct bch_fs *,
|
||||
struct bch_inode_info *,
|
||||
struct folio *,
|
||||
struct bch2_folio_reservation *,
|
||||
unsigned, unsigned);
|
||||
size_t, size_t);
|
||||
ssize_t bch2_folio_reservation_get_partial(struct bch_fs *,
|
||||
struct bch_inode_info *,
|
||||
struct folio *,
|
||||
struct bch2_folio_reservation *,
|
||||
size_t, size_t);
|
||||
|
||||
void bch2_set_folio_dirty(struct bch_fs *,
|
||||
struct bch_inode_info *,
|
||||
|
Loading…
Reference in New Issue
Block a user