Skip to content

Commit 7554a8b

Browse files
author
Kent Overstreet
committed
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>
1 parent 9592442 commit 7554a8b

3 files changed

Lines changed: 52 additions & 24 deletions

File tree

fs/bcachefs/fs-io-buffered.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -863,24 +863,26 @@ static int __bch2_buffered_write(struct bch_inode_info *inode,
863863
f_pos = pos;
864864
f_offset = pos - folio_pos(darray_first(fs));
865865
darray_for_each(fs, fi) {
866+
ssize_t f_reserved;
867+
866868
f = *fi;
867869
f_len = min(end, folio_end_pos(f)) - f_pos;
870+
f_reserved = bch2_folio_reservation_get_partial(c, inode, f, &res, f_offset, f_len);
871+
872+
if (unlikely(f_reserved != f_len)) {
873+
if (f_reserved < 0) {
874+
if (f == darray_first(fs)) {
875+
ret = f_reserved;
876+
goto out;
877+
}
878+
879+
folios_trunc(&fs, fi);
880+
end = min(end, folio_end_pos(darray_last(fs)));
881+
} else {
882+
folios_trunc(&fs, fi + 1);
883+
end = f_pos + f_reserved;
884+
}
868885

869-
/*
870-
* XXX: per POSIX and fstests generic/275, on -ENOSPC we're
871-
* supposed to write as much as we have disk space for.
872-
*
873-
* On failure here we should still write out a partial page if
874-
* we aren't completely out of disk space - we don't do that
875-
* yet:
876-
*/
877-
ret = bch2_folio_reservation_get(c, inode, f, &res, f_offset, f_len);
878-
if (unlikely(ret)) {
879-
folios_trunc(&fs, fi);
880-
if (!fs.nr)
881-
goto out;
882-
883-
end = min(end, folio_end_pos(darray_last(fs)));
884886
break;
885887
}
886888

fs/bcachefs/fs-io-pagecache.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ int bch2_folio_reservation_get(struct bch_fs *c,
423423
struct bch_inode_info *inode,
424424
struct folio *folio,
425425
struct bch2_folio_reservation *res,
426-
unsigned offset, unsigned len)
426+
size_t offset, size_t len)
427427
{
428428
struct bch_folio *s = bch2_folio_create(folio, 0);
429429
unsigned i, disk_sectors = 0, quota_sectors = 0;
@@ -437,8 +437,7 @@ int bch2_folio_reservation_get(struct bch_fs *c,
437437
for (i = round_down(offset, block_bytes(c)) >> 9;
438438
i < round_up(offset + len, block_bytes(c)) >> 9;
439439
i++) {
440-
disk_sectors += sectors_to_reserve(&s->s[i],
441-
res->disk.nr_replicas);
440+
disk_sectors += sectors_to_reserve(&s->s[i], res->disk.nr_replicas);
442441
quota_sectors += s->s[i].state == SECTOR_unallocated;
443442
}
444443

@@ -449,12 +448,9 @@ int bch2_folio_reservation_get(struct bch_fs *c,
449448
}
450449

451450
if (quota_sectors) {
452-
ret = bch2_quota_reservation_add(c, inode, &res->quota,
453-
quota_sectors, true);
451+
ret = bch2_quota_reservation_add(c, inode, &res->quota, quota_sectors, true);
454452
if (unlikely(ret)) {
455-
struct disk_reservation tmp = {
456-
.sectors = disk_sectors
457-
};
453+
struct disk_reservation tmp = { .sectors = disk_sectors };
458454

459455
bch2_disk_reservation_put(c, &tmp);
460456
res->disk.sectors -= disk_sectors;
@@ -465,6 +461,31 @@ int bch2_folio_reservation_get(struct bch_fs *c,
465461
return 0;
466462
}
467463

464+
ssize_t bch2_folio_reservation_get_partial(struct bch_fs *c,
465+
struct bch_inode_info *inode,
466+
struct folio *folio,
467+
struct bch2_folio_reservation *res,
468+
size_t offset, size_t len)
469+
{
470+
size_t l, reserved = 0;
471+
int ret;
472+
473+
while ((l = len - reserved)) {
474+
while ((ret = bch2_folio_reservation_get(c, inode, folio, res, offset, l))) {
475+
if ((offset & (block_bytes(c) - 1)) + l <= block_bytes(c))
476+
return reserved ?: ret;
477+
478+
len = reserved + l;
479+
l /= 2;
480+
}
481+
482+
offset += l;
483+
reserved += l;
484+
}
485+
486+
return reserved;
487+
}
488+
468489
static void bch2_clear_folio_bits(struct folio *folio)
469490
{
470491
struct bch_inode_info *inode = to_bch_ei(folio->mapping->host);

fs/bcachefs/fs-io-pagecache.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,12 @@ int bch2_folio_reservation_get(struct bch_fs *,
153153
struct bch_inode_info *,
154154
struct folio *,
155155
struct bch2_folio_reservation *,
156-
unsigned, unsigned);
156+
size_t, size_t);
157+
ssize_t bch2_folio_reservation_get_partial(struct bch_fs *,
158+
struct bch_inode_info *,
159+
struct folio *,
160+
struct bch2_folio_reservation *,
161+
size_t, size_t);
157162

158163
void bch2_set_folio_dirty(struct bch_fs *,
159164
struct bch_inode_info *,

0 commit comments

Comments
 (0)