summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2019-11-13 19:55:58 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2019-11-16 16:35:38 -0500
commit75d4c8fd98acca81d7729a33dd7ca7db88ba28d0 (patch)
treed339436889a2fa29cc5663465dcece83ed831e07
parent98bc6e8ac8ee470ac349ed2b5f462b6ddfc81c18 (diff)
bcachefs: Shorten data len XXX
-rw-r--r--fs/bcachefs/io.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/fs/bcachefs/io.c b/fs/bcachefs/io.c
index a544ef7de31f..75fe7eb63d5e 100644
--- a/fs/bcachefs/io.c
+++ b/fs/bcachefs/io.c
@@ -1130,6 +1130,43 @@ flush_io:
goto again;
}
+static unsigned __data_len(void *p, unsigned len)
+{
+ while ((len & 7) && !*((u8 *) (p + len - 1)))
+ len -= 1;
+
+ while (len && !*((u64 *) (p + len - 8)))
+ len -= 8;
+
+ while (len && !*((u8 *) (p + len - 1)))
+ len -= 1;
+
+ return len;
+}
+
+static unsigned shorten_data_len(struct bio *bio, unsigned data_len)
+{
+ struct bio_vec bv;
+ struct bvec_iter iter;
+restart:
+ bio_for_each_segment(bv, bio, iter) {
+ unsigned done = bio->bi_iter.bi_size - iter.bi_size;
+
+ if (data_len <= done + bv.bv_len) {
+ void *p = kmap_atomic(bv.bv_page) + bv.bv_offset;
+ data_len = done + __data_len(p, bv.bv_len);
+ kunmap_atomic(p);
+
+ if (data_len && data_len == done)
+ goto restart;
+ else
+ return data_len;
+ }
+ }
+
+ BUG();
+}
+
static void bch2_write_data_inline(struct bch_write_op *op, unsigned data_len)
{
struct closure *cl = &op->cl;
@@ -1219,6 +1256,7 @@ void bch2_write(struct closure *cl)
data_len = min_t(u64, bio->bi_iter.bi_size,
op->new_i_size - (op->pos.offset << 9));
+ data_len = shorten_data_len(bio, data_len);
if (data_len <= min(block_bytes(c) / 2, 1024U)) {
bch2_write_data_inline(op, data_len);