summaryrefslogtreecommitdiffstats
path: root/fs/bcachefs/fs-io.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2022-10-23 22:01:50 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:45 -0400
commit353448f3ea42e5deec298d6d2c577ade7028b7fd (patch)
treeb9e153d091b5a0cce6f644181855bdf8905eed89 /fs/bcachefs/fs-io.c
parentc167f9e54100179a009051ad6eac1dfb0bcd21f6 (diff)
downloadlinux-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.c19
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);