diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2022-11-13 18:59:01 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-01-06 19:47:58 -0500 |
commit | 03c4adb50c8a5889a3912648ae4085c594a1664c (patch) | |
tree | c15a03453e249ddaf87d5c8ca2d749a8a6a3a7c2 | |
parent | 298725d535227003dbad25f2674c279b220e0b73 (diff) |
bcachefs: Unwritten extents support
- bch2_extent_merge checks unwritten bit
- read path returns 0s for unwritten extents without actually reading
- reflink path skips over unwritten extents
- bch2_bkey_ptrs_invalid() checks for extents with both written and
unwritten extents, and non-normal extents (stripes, btree ptrs) with
unwritten ptrs
- fiemap checks for unwritten extents and returns
FIEMAP_EXTENT_UNWRITTEN
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/bcachefs_format.h | 4 | ||||
-rw-r--r-- | fs/bcachefs/extents.c | 34 | ||||
-rw-r--r-- | fs/bcachefs/extents.h | 17 | ||||
-rw-r--r-- | fs/bcachefs/fs-io.c | 14 | ||||
-rw-r--r-- | fs/bcachefs/fs.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/fsck.c | 4 | ||||
-rw-r--r-- | fs/bcachefs/io.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/reflink.c | 3 |
8 files changed, 67 insertions, 15 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index e22775938b94..f97399ad49e7 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -578,7 +578,7 @@ struct bch_extent_ptr { __u64 type:1, cached:1, unused:1, - reservation:1, + unwritten:1, offset:44, /* 8 petabytes */ dev:8, gen:8; @@ -586,7 +586,7 @@ struct bch_extent_ptr { __u64 gen:8, dev:8, offset:44, - reservation:1, + unwritten:1, unused:1, cached:1, type:1; diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c index 940af86c728c..07f91877d854 100644 --- a/fs/bcachefs/extents.c +++ b/fs/bcachefs/extents.c @@ -117,6 +117,13 @@ int bch2_bkey_pick_read_device(struct bch_fs *c, struct bkey_s_c k, return -EIO; bkey_for_each_ptr_decode(k.k, ptrs, p, entry) { + /* + * Unwritten extent: no need to actually read, treat it as a + * hole and return 0s: + */ + if (p.ptr.unwritten) + return 0; + ca = bch_dev_bkey_exists(c, p.ptr.dev); /* @@ -270,6 +277,7 @@ bool bch2_extent_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_c r) rp.ptr.offset + rp.crc.offset || lp.ptr.dev != rp.ptr.dev || lp.ptr.gen != rp.ptr.gen || + lp.ptr.unwritten != rp.ptr.unwritten || lp.has_ec != rp.has_ec) return false; @@ -928,6 +936,9 @@ bool bch2_extents_match(struct bkey_s_c k1, struct bkey_s_c k2) const union bch_extent_entry *entry1, *entry2; struct extent_ptr_decoded p1, p2; + if (bkey_extent_is_unwritten(k1) != bkey_extent_is_unwritten(k2)) + return false; + bkey_for_each_ptr_decode(k1.k, ptrs1, p1, entry1) bkey_for_each_ptr_decode(k2.k, ptrs2, p2, entry2) if (p1.ptr.dev == p2.ptr.dev && @@ -1005,10 +1016,12 @@ void bch2_bkey_ptrs_to_text(struct printbuf *out, struct bch_fs *c, u32 offset; u64 b = sector_to_bucket_and_offset(ca, ptr->offset, &offset); - prt_printf(out, "ptr: %u:%llu:%u gen %u%s", ptr->dev, - b, offset, ptr->gen, - ptr->cached ? " cached" : ""); - + prt_printf(out, "ptr: %u:%llu:%u gen %u", + ptr->dev, b, offset, ptr->gen); + if (ptr->cached) + prt_str(out, " cached"); + if (ptr->unwritten) + prt_str(out, " unwritten"); if (ca && ptr_stale(ca, ptr)) prt_printf(out, " stale"); } @@ -1097,6 +1110,7 @@ int bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k, unsigned size_ondisk = k.k->size; unsigned nonce = UINT_MAX; unsigned nr_ptrs = 0; + bool unwritten = false; int ret; if (bkey_is_btree_ptr(k.k)) @@ -1121,6 +1135,18 @@ int bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k, false, err); if (ret) return ret; + + if (nr_ptrs && unwritten != entry->ptr.unwritten) { + prt_printf(err, "extent with unwritten and written ptrs"); + return -EINVAL; + } + + if (k.k->type != KEY_TYPE_extent && entry->ptr.unwritten) { + prt_printf(err, "has unwritten ptrs"); + return -EINVAL; + } + + unwritten = entry->ptr.unwritten; nr_ptrs++; break; case BCH_EXTENT_ENTRY_crc32: diff --git a/fs/bcachefs/extents.h b/fs/bcachefs/extents.h index 224df17206cb..661c5e4c0943 100644 --- a/fs/bcachefs/extents.h +++ b/fs/bcachefs/extents.h @@ -510,6 +510,23 @@ static inline bool bkey_extent_is_allocation(const struct bkey *k) } } +static inline bool bkey_extent_is_unwritten(struct bkey_s_c k) +{ + struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k); + const struct bch_extent_ptr *ptr; + + bkey_for_each_ptr(ptrs, ptr) + if (ptr->unwritten) + return true; + return false; +} + +static inline bool bkey_extent_is_reservation(struct bkey_s_c k) +{ + return k.k->type == KEY_TYPE_reservation || + bkey_extent_is_unwritten(k); +} + static inline struct bch_devs_list bch2_bkey_devs(struct bkey_s_c k) { struct bch_devs_list ret = (struct bch_devs_list) { 0 }; diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c index 96b06b0a06b0..13f694193fe4 100644 --- a/fs/bcachefs/fs-io.c +++ b/fs/bcachefs/fs-io.c @@ -341,11 +341,11 @@ static struct bch_page_state *bch2_page_state_create(struct page *page, return bch2_page_state(page) ?: __bch2_page_state_create(page, gfp); } -static unsigned bkey_to_sector_state(const struct bkey *k) +static unsigned bkey_to_sector_state(struct bkey_s_c k) { - if (k->type == KEY_TYPE_reservation) + if (bkey_extent_is_reservation(k)) return SECTOR_RESERVED; - if (bkey_extent_is_allocation(k)) + if (bkey_extent_is_allocation(k.k)) return SECTOR_ALLOCATED; return SECTOR_UNALLOCATED; } @@ -396,7 +396,7 @@ retry: SPOS(inum.inum, offset, snapshot), BTREE_ITER_SLOTS, k, ret) { unsigned nr_ptrs = bch2_bkey_nr_ptrs_fully_allocated(k); - unsigned state = bkey_to_sector_state(k.k); + unsigned state = bkey_to_sector_state(k); while (pg_idx < nr_pages) { struct page *page = pages[pg_idx]; @@ -436,7 +436,7 @@ static void bch2_bio_page_state_set(struct bio *bio, struct bkey_s_c k) struct bio_vec bv; unsigned nr_ptrs = k.k->type == KEY_TYPE_reflink_v ? 0 : bch2_bkey_nr_ptrs_fully_allocated(k); - unsigned state = bkey_to_sector_state(k.k); + unsigned state = bkey_to_sector_state(k); bio_for_each_segment(bv, bio, iter) __bch2_page_state_set(bv.bv_page, bv.bv_offset >> 9, @@ -3074,8 +3074,8 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode, goto bkey_err; /* already reserved */ - if (k.k->type == KEY_TYPE_reservation && - bkey_s_c_to_reservation(k).v->nr_replicas >= opts.data_replicas) { + if (bkey_extent_is_reservation(k) && + bch2_bkey_nr_ptrs_fully_allocated(k) >= opts.data_replicas) { bch2_btree_iter_advance(&iter); continue; } diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index 786c39be7445..b1822f36cca8 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -811,6 +811,9 @@ static int bch2_fill_extent(struct bch_fs *c, int flags2 = 0; u64 offset = p.ptr.offset; + if (p.ptr.unwritten) + flags2 |= FIEMAP_EXTENT_UNWRITTEN; + if (p.crc.compression_type) flags2 |= FIEMAP_EXTENT_ENCODED; else diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index f4f0e0cec85d..ffc2671cece6 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -1257,8 +1257,8 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, continue; if (fsck_err_on(!(i->inode.bi_flags & BCH_INODE_I_SIZE_DIRTY) && - k.k->type != KEY_TYPE_reservation && - k.k->p.offset > round_up(i->inode.bi_size, block_bytes(c)) >> 9, c, + k.k->p.offset > round_up(i->inode.bi_size, block_bytes(c)) >> 9 && + !bkey_extent_is_reservation(k), c, "extent type past end of inode %llu:%u, i_size %llu\n %s", i->inode.bi_inum, i->snapshot, i->inode.bi_size, (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { diff --git a/fs/bcachefs/io.c b/fs/bcachefs/io.c index 82c37e7654c0..57c5fd351c15 100644 --- a/fs/bcachefs/io.c +++ b/fs/bcachefs/io.c @@ -1428,6 +1428,9 @@ static inline bool should_promote(struct bch_fs *c, struct bkey_s_c k, if (bch2_bkey_has_target(c, k, opts.promote_target)) return false; + if (bkey_extent_is_unwritten(k)) + return false; + if (bch2_target_congested(c, opts.promote_target)) { /* XXX trace this */ return false; diff --git a/fs/bcachefs/reflink.c b/fs/bcachefs/reflink.c index 0d4c004d7f9d..94f2b3059766 100644 --- a/fs/bcachefs/reflink.c +++ b/fs/bcachefs/reflink.c @@ -255,6 +255,9 @@ static struct bkey_s_c get_next_src(struct btree_iter *iter, struct bpos end) if (bkey_cmp(iter->pos, end) >= 0) break; + if (bkey_extent_is_unwritten(k)) + continue; + if (bkey_extent_is_data(k.k)) return k; } |