diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2022-10-23 22:01:50 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:09:45 -0400 |
commit | 353448f3ea42e5deec298d6d2c577ade7028b7fd (patch) | |
tree | b9e153d091b5a0cce6f644181855bdf8905eed89 /fs/bcachefs/fs-io.c | |
parent | c167f9e54100179a009051ad6eac1dfb0bcd21f6 (diff) | |
download | linux-stable-353448f3ea42e5deec298d6d2c577ade7028b7fd.tar.gz linux-stable-353448f3ea42e5deec298d6d2c577ade7028b7fd.tar.bz2 linux-stable-353448f3ea42e5deec298d6d2c577ade7028b7fd.zip |
bcachefs: Fix buffered write path for generic/275
Per fstests generic/275, on -ENOSPC we're supposed write until the
filesystem is full - i.e. do a partial write instead of failing the full
write.
This is a partial fix for the buffered write path: we'll still fail on a
page boundary.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/fs-io.c')
-rw-r--r-- | fs/bcachefs/fs-io.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c index b1d53290f6ba..49b0fb6522e7 100644 --- a/fs/bcachefs/fs-io.c +++ b/fs/bcachefs/fs-io.c @@ -1656,10 +1656,21 @@ static int __bch2_buffered_write(struct bch_inode_info *inode, goto out; } + /* + * 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_page_reservation_get(c, inode, page, &res, pg_offset, pg_len); - if (ret) - goto out; + if (unlikely(ret)) { + if (!reserved) + goto out; + break; + } reserved += pg_len; } @@ -1668,10 +1679,10 @@ static int __bch2_buffered_write(struct bch_inode_info *inode, for (i = 0; i < nr_pages; i++) flush_dcache_page(pages[i]); - while (copied < len) { + while (copied < reserved) { struct page *page = pages[(offset + copied) >> PAGE_SHIFT]; unsigned pg_offset = (offset + copied) & (PAGE_SIZE - 1); - unsigned pg_len = min_t(unsigned, len - copied, + unsigned pg_len = min_t(unsigned, reserved - copied, PAGE_SIZE - pg_offset); unsigned pg_copied = copy_page_from_iter_atomic(page, pg_offset, pg_len, iter); |