From: Kent Overstreet Date: Fri, 7 Jul 2023 08:24:54 +0000 (-0400) Subject: Update bcachefs sources to 25de2b00dc bcachefs: Change check for invalid key types X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=c99a444c5cc242a89845be83236aacd7db628ef5;hp=619c99de4be8f0618e7c4cb65039de2aa1e2536c;p=bcachefs-tools-debian Update bcachefs sources to 25de2b00dc bcachefs: Change check for invalid key types Signed-off-by: Kent Overstreet --- diff --git a/.bcachefs_revision b/.bcachefs_revision index 08e43b2..e6dc62b 100644 --- a/.bcachefs_revision +++ b/.bcachefs_revision @@ -1 +1 @@ -84f132d5696138bb038d2dc8f1162d2fab5ac832 +25de2b00dcca9bd801d37efd5e08c15dbf151825 diff --git a/cmd_dump.c b/cmd_dump.c index 76b44c5..59d73c3 100644 --- a/cmd_dump.c +++ b/cmd_dump.c @@ -84,7 +84,7 @@ static void dump_one_device(struct bch_fs *c, struct bch_dev *ca, int fd, if (ret) die("error %s walking btree nodes", bch2_err_str(ret)); - b = c->btree_roots[i].b; + b = bch2_btree_id_root(c, i)->b; if (!btree_node_fake(b)) { ptrs = bch2_bkey_ptrs_c(bkey_i_to_s_c(&b->key)); diff --git a/include/linux/bio.h b/include/linux/bio.h index 0ad5a87..1f8acca 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -234,7 +234,7 @@ enum { }; struct bio *bio_alloc_bioset(struct block_device *, unsigned, - unsigned, gfp_t, struct bio_set *); + blk_opf_t, gfp_t, struct bio_set *); extern void bio_put(struct bio *); int bio_add_page(struct bio *, struct page *, unsigned, unsigned); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index f78621d..9e02077 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -9,6 +9,7 @@ #define BIO_MAX_VECS 256U typedef unsigned fmode_t; +typedef __u32 __bitwise blk_opf_t; struct bio; struct user_namespace; diff --git a/libbcachefs/acl.c b/libbcachefs/acl.c index ce7a460..b1a4888 100644 --- a/libbcachefs/acl.c +++ b/libbcachefs/acl.c @@ -225,6 +225,7 @@ struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap, struct bch_inode_info *inode = to_bch_ei(dentry->d_inode); struct bch_fs *c = inode->v.i_sb->s_fs_info; struct bch_hash_info hash = bch2_hash_info_init(c, &inode->ei_inode); + struct xattr_search_key search = X_SEARCH(acl_to_xattr_type(type), "", 0); struct btree_trans trans; struct btree_iter iter = { NULL }; struct bkey_s_c_xattr xattr; @@ -237,9 +238,7 @@ retry: bch2_trans_begin(&trans); ret = bch2_hash_lookup(&trans, &iter, bch2_xattr_hash_desc, - &hash, inode_inum(inode), - &X_SEARCH(acl_to_xattr_type(type), "", 0), - 0); + &hash, inode_inum(inode), &search, 0); if (ret) { if (!bch2_err_matches(ret, ENOENT)) acl = ERR_PTR(ret); @@ -364,6 +363,7 @@ int bch2_acl_chmod(struct btree_trans *trans, subvol_inum inum, struct posix_acl **new_acl) { struct bch_hash_info hash_info = bch2_hash_info_init(trans->c, inode); + struct xattr_search_key search = X_SEARCH(KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS, "", 0); struct btree_iter iter; struct bkey_s_c_xattr xattr; struct bkey_i_xattr *new; @@ -372,9 +372,7 @@ int bch2_acl_chmod(struct btree_trans *trans, subvol_inum inum, int ret; ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc, - &hash_info, inum, - &X_SEARCH(KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS, "", 0), - BTREE_ITER_INTENT); + &hash_info, inum, &search, BTREE_ITER_INTENT); if (ret) return bch2_err_matches(ret, ENOENT) ? 0 : ret; diff --git a/libbcachefs/alloc_background.c b/libbcachefs/alloc_background.c index 9f83111..c59629b 100644 --- a/libbcachefs/alloc_background.c +++ b/libbcachefs/alloc_background.c @@ -223,7 +223,8 @@ static unsigned bch_alloc_v1_val_u64s(const struct bch_alloc *a) } int bch2_alloc_v1_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_s_c_alloc a = bkey_s_c_to_alloc(k); @@ -238,7 +239,8 @@ int bch2_alloc_v1_invalid(const struct bch_fs *c, struct bkey_s_c k, } int bch2_alloc_v2_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_alloc_unpacked u; @@ -251,7 +253,8 @@ int bch2_alloc_v2_invalid(const struct bch_fs *c, struct bkey_s_c k, } int bch2_alloc_v3_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_alloc_unpacked u; @@ -282,7 +285,7 @@ int bch2_alloc_v4_invalid(const struct bch_fs *c, struct bkey_s_c k, } if (rw == WRITE && - !(flags & BKEY_INVALID_FROM_JOURNAL) && + !(flags & BKEY_INVALID_JOURNAL) && test_bit(BCH_FS_CHECK_BACKPOINTERS_DONE, &c->flags)) { unsigned i, bp_len = 0; @@ -605,7 +608,8 @@ static unsigned alloc_gen(struct bkey_s_c k, unsigned offset) } int bch2_bucket_gens_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { if (bkey_val_bytes(k.k) != sizeof(struct bch_bucket_gens)) { prt_printf(err, "bad val size (%lu != %zu)", @@ -929,7 +933,7 @@ int bch2_trans_mark_alloc(struct btree_trans *trans, * This synthesizes deleted extents for holes, similar to BTREE_ITER_SLOTS for * extents style btrees, but works on non-extents btrees: */ -struct bkey_s_c bch2_get_key_or_hole(struct btree_iter *iter, struct bpos end, struct bkey *hole) +static struct bkey_s_c bch2_get_key_or_hole(struct btree_iter *iter, struct bpos end, struct bkey *hole) { struct bkey_s_c k = bch2_btree_iter_peek_slot(iter); @@ -1000,7 +1004,7 @@ static bool next_bucket(struct bch_fs *c, struct bpos *bucket) return ca != NULL; } -struct bkey_s_c bch2_get_key_or_real_bucket_hole(struct btree_iter *iter, struct bkey *hole) +static struct bkey_s_c bch2_get_key_or_real_bucket_hole(struct btree_iter *iter, struct bkey *hole) { struct bch_fs *c = iter->trans->c; struct bkey_s_c k; @@ -1719,7 +1723,8 @@ static int bch2_discard_one_bucket(struct btree_trans *trans, write: ret = bch2_trans_update(trans, &iter, &a->k_i, 0) ?: bch2_trans_commit(trans, NULL, NULL, - BTREE_INSERT_USE_RESERVE|BTREE_INSERT_NOFAIL); + BCH_WATERMARK_btree| + BTREE_INSERT_NOFAIL); if (ret) goto out; @@ -1827,7 +1832,8 @@ static int invalidate_one_bucket(struct btree_trans *trans, ret = bch2_trans_update(trans, &alloc_iter, &a->k_i, BTREE_TRIGGER_BUCKET_INVALIDATE) ?: bch2_trans_commit(trans, NULL, NULL, - BTREE_INSERT_USE_RESERVE|BTREE_INSERT_NOFAIL); + BCH_WATERMARK_btree| + BTREE_INSERT_NOFAIL); if (ret) goto out; diff --git a/libbcachefs/alloc_background.h b/libbcachefs/alloc_background.h index 3c4d6d4..d1bf45a 100644 --- a/libbcachefs/alloc_background.h +++ b/libbcachefs/alloc_background.h @@ -8,6 +8,8 @@ #include "debug.h" #include "super.h" +enum bkey_invalid_flags; + /* How out of date a pointer gen is allowed to be: */ #define BUCKET_GC_GEN_MAX 96U @@ -147,10 +149,14 @@ struct bkey_i_alloc_v4 *bch2_alloc_to_v4_mut(struct btree_trans *, struct bkey_s int bch2_bucket_io_time_reset(struct btree_trans *, unsigned, size_t, int); -int bch2_alloc_v1_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); -int bch2_alloc_v2_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); -int bch2_alloc_v3_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); -int bch2_alloc_v4_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); +int bch2_alloc_v1_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); +int bch2_alloc_v2_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); +int bch2_alloc_v3_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); +int bch2_alloc_v4_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); void bch2_alloc_v4_swab(struct bkey_s); void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); @@ -187,7 +193,8 @@ void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); .min_val_size = 48, \ }) -int bch2_bucket_gens_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); +int bch2_bucket_gens_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_ops_bucket_gens ((struct bkey_ops) { \ diff --git a/libbcachefs/alloc_foreground.c b/libbcachefs/alloc_foreground.c index c7db89b..6650c00 100644 --- a/libbcachefs/alloc_foreground.c +++ b/libbcachefs/alloc_foreground.c @@ -191,11 +191,12 @@ long bch2_bucket_alloc_new_fs(struct bch_dev *ca) static inline unsigned open_buckets_reserved(enum bch_watermark watermark) { switch (watermark) { + case BCH_WATERMARK_reclaim: case BCH_WATERMARK_btree: case BCH_WATERMARK_btree_copygc: - return 0; - case BCH_WATERMARK_copygc: return OPEN_BUCKETS_COUNT / 4; + case BCH_WATERMARK_copygc: + return OPEN_BUCKETS_COUNT / 3; default: return OPEN_BUCKETS_COUNT / 2; } diff --git a/libbcachefs/alloc_types.h b/libbcachefs/alloc_types.h index a01fddf..c33a299 100644 --- a/libbcachefs/alloc_types.h +++ b/libbcachefs/alloc_types.h @@ -17,11 +17,12 @@ struct bucket_alloc_state { }; #define BCH_WATERMARKS() \ - x(btree_copygc) \ - x(btree) \ - x(copygc) \ + x(stripe) \ x(normal) \ - x(stripe) + x(copygc) \ + x(btree) \ + x(btree_copygc) \ + x(reclaim) enum bch_watermark { #define x(name) BCH_WATERMARK_##name, @@ -30,6 +31,9 @@ enum bch_watermark { BCH_WATERMARK_NR, }; +#define BCH_WATERMARK_BITS 3 +#define BCH_WATERMARK_MASK ~(~0 << BCH_WATERMARK_BITS) + #define OPEN_BUCKETS_COUNT 1024 #define WRITE_POINT_HASH_NR 32 diff --git a/libbcachefs/backpointers.c b/libbcachefs/backpointers.c index a270ff9..f5ce9c9 100644 --- a/libbcachefs/backpointers.c +++ b/libbcachefs/backpointers.c @@ -38,7 +38,8 @@ static bool extent_matches_bp(struct bch_fs *c, } int bch2_backpointer_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k); struct bpos bucket = bp_pos_to_bucket(c, bp.k->p); @@ -272,6 +273,7 @@ struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *trans, unsigned iter_flags) { struct bch_fs *c = trans->c; + struct btree_root *r = bch2_btree_id_root(c, bp.btree_id); struct bpos bucket = bp_pos_to_bucket(c, bp_pos); struct bkey_s_c k; @@ -279,7 +281,7 @@ struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *trans, bp.btree_id, bp.pos, 0, - min(bp.level, c->btree_roots[bp.btree_id].level), + min(bp.level, r->level), iter_flags); k = bch2_btree_iter_peek_slot(iter); if (bkey_err(k)) { @@ -287,8 +289,8 @@ struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *trans, return k; } - if (bp.level == c->btree_roots[bp.btree_id].level + 1) - k = bkey_i_to_s_c(&c->btree_roots[bp.btree_id].key); + if (bp.level == r->level + 1) + k = bkey_i_to_s_c(&r->key); if (k.k && extent_matches_bp(c, bp.btree_id, bp.level, k, bucket, bp)) return k; @@ -531,6 +533,7 @@ static int check_btree_root_to_backpointers(struct btree_trans *trans, struct bpos_level *last_flushed) { struct bch_fs *c = trans->c; + struct btree_root *r = bch2_btree_id_root(c, btree_id); struct btree_iter iter; struct btree *b; struct bkey_s_c k; @@ -539,8 +542,7 @@ static int check_btree_root_to_backpointers(struct btree_trans *trans, const union bch_extent_entry *entry; int ret; - bch2_trans_node_iter_init(trans, &iter, btree_id, POS_MIN, 0, - c->btree_roots[btree_id].level, 0); + bch2_trans_node_iter_init(trans, &iter, btree_id, POS_MIN, 0, r->level, 0); b = bch2_btree_iter_peek_node(&iter); ret = PTR_ERR_OR_ZERO(b); if (ret) @@ -589,10 +591,10 @@ static size_t btree_nodes_fit_in_ram(struct bch_fs *c) return div_u64(mem_bytes >> 1, btree_bytes(c)); } -int bch2_get_btree_in_memory_pos(struct btree_trans *trans, - unsigned btree_leaf_mask, - unsigned btree_interior_mask, - struct bbpos start, struct bbpos *end) +static int bch2_get_btree_in_memory_pos(struct btree_trans *trans, + unsigned btree_leaf_mask, + unsigned btree_interior_mask, + struct bbpos start, struct bbpos *end) { struct btree_iter iter; struct bkey_s_c k; @@ -640,14 +642,18 @@ static int bch2_check_extents_to_backpointers_pass(struct btree_trans *trans, struct bpos bucket_start, struct bpos bucket_end) { + struct bch_fs *c = trans->c; struct btree_iter iter; enum btree_id btree_id; struct bpos_level last_flushed = { UINT_MAX }; int ret = 0; - for (btree_id = 0; btree_id < BTREE_ID_NR; btree_id++) { + for (btree_id = 0; btree_id < btree_id_nr_alive(c); btree_id++) { unsigned depth = btree_type_has_ptrs(btree_id) ? 0 : 1; + if (!bch2_btree_id_root(c, btree_id)->alive) + continue; + bch2_trans_node_iter_init(trans, &iter, btree_id, POS_MIN, 0, depth, BTREE_ITER_ALL_LEVELS| @@ -689,8 +695,8 @@ static struct bpos bucket_pos_to_bp_safe(const struct bch_fs *c, : bucket; } -int bch2_get_alloc_in_memory_pos(struct btree_trans *trans, - struct bpos start, struct bpos *end) +static int bch2_get_alloc_in_memory_pos(struct btree_trans *trans, + struct bpos start, struct bpos *end) { struct btree_iter alloc_iter; struct btree_iter bp_iter; diff --git a/libbcachefs/backpointers.h b/libbcachefs/backpointers.h index c52954e..778b677 100644 --- a/libbcachefs/backpointers.h +++ b/libbcachefs/backpointers.h @@ -8,7 +8,7 @@ #include "super.h" int bch2_backpointer_invalid(const struct bch_fs *, struct bkey_s_c k, - unsigned, struct printbuf *); + enum bkey_invalid_flags, struct printbuf *); void bch2_backpointer_to_text(struct printbuf *, const struct bch_backpointer *); void bch2_backpointer_k_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_backpointer_swab(struct bkey_s); diff --git a/libbcachefs/bcachefs.h b/libbcachefs/bcachefs.h index b8d50fe..a8488d4 100644 --- a/libbcachefs/bcachefs.h +++ b/libbcachefs/bcachefs.h @@ -749,7 +749,8 @@ struct bch_fs { struct bio_set btree_bio; struct workqueue_struct *io_complete_wq; - struct btree_root btree_roots[BTREE_ID_NR]; + struct btree_root btree_roots_known[BTREE_ID_NR]; + DARRAY(struct btree_root) btree_roots_extra; struct mutex btree_root_lock; struct btree_cache btree_cache; diff --git a/libbcachefs/bcachefs_format.h b/libbcachefs/bcachefs_format.h index ad87cdf..49b86bf 100644 --- a/libbcachefs/bcachefs_format.h +++ b/libbcachefs/bcachefs_format.h @@ -488,8 +488,9 @@ struct bch_csum { x(crc32, 1) \ x(crc64, 2) \ x(crc128, 3) \ - x(stripe_ptr, 4) -#define BCH_EXTENT_ENTRY_MAX 5 + x(stripe_ptr, 4) \ + x(rebalance, 5) +#define BCH_EXTENT_ENTRY_MAX 6 enum bch_extent_entry_type { #define x(f, n) BCH_EXTENT_ENTRY_##f = n, @@ -624,6 +625,20 @@ struct bch_extent_reservation { #endif }; +struct bch_extent_rebalance { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u64 type:7, + unused:33, + compression:8, + target:16; +#elif defined (__BIG_ENDIAN_BITFIELD) + __u64 target:16, + compression:8, + unused:33, + type:7; +#endif +}; + union bch_extent_entry { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || __BITS_PER_LONG == 64 unsigned long type; @@ -1356,19 +1371,19 @@ static inline bool data_type_is_hidden(enum bch_data_type type) struct bch_replicas_entry_v0 { __u8 data_type; __u8 nr_devs; - __u8 devs[]; + __u8 devs[0]; } __packed; struct bch_sb_field_replicas_v0 { struct bch_sb_field field; - struct bch_replicas_entry_v0 entries[]; + struct bch_replicas_entry_v0 entries[0]; } __packed __aligned(8); struct bch_replicas_entry { __u8 data_type; __u8 nr_devs; __u8 nr_required; - __u8 devs[]; + __u8 devs[0]; } __packed; #define replicas_entry_bytes(_i) \ @@ -1376,7 +1391,7 @@ struct bch_replicas_entry { struct bch_sb_field_replicas { struct bch_sb_field field; - struct bch_replicas_entry entries[]; + struct bch_replicas_entry entries[0]; } __packed __aligned(8); /* BCH_SB_FIELD_quota: */ @@ -1559,8 +1574,6 @@ struct bch_sb_field_journal_seq_blacklist { * One common version number for all on disk data structures - superblock, btree * nodes, journal entries */ -#define BCH_JSET_VERSION_OLD 2 -#define BCH_BSET_VERSION_OLD 3 #define BCH_METADATA_VERSIONS() \ x(bkey_renumber, 10) \ @@ -2195,13 +2208,25 @@ struct btree_node { }; } __packed __aligned(8); -LE64_BITMASK(BTREE_NODE_ID, struct btree_node, flags, 0, 4); +LE64_BITMASK(BTREE_NODE_ID_LO, struct btree_node, flags, 0, 4); LE64_BITMASK(BTREE_NODE_LEVEL, struct btree_node, flags, 4, 8); LE64_BITMASK(BTREE_NODE_NEW_EXTENT_OVERWRITE, struct btree_node, flags, 8, 9); -/* 9-32 unused */ +LE64_BITMASK(BTREE_NODE_ID_HI, struct btree_node, flags, 9, 25); +/* 25-32 unused */ LE64_BITMASK(BTREE_NODE_SEQ, struct btree_node, flags, 32, 64); +static inline __u64 BTREE_NODE_ID(struct btree_node *n) +{ + return BTREE_NODE_ID_LO(n) | (BTREE_NODE_ID_HI(n) << 4); +} + +static inline void SET_BTREE_NODE_ID(struct btree_node *n, u64 v) +{ + SET_BTREE_NODE_ID_LO(n, v); + SET_BTREE_NODE_ID_HI(n, v >> 4); +} + struct btree_node_entry { struct bch_csum csum; @@ -2211,7 +2236,6 @@ struct btree_node_entry { __u8 pad[22]; __le16 u64s; __u64 _data[0]; - }; }; } __packed __aligned(8); diff --git a/libbcachefs/bkey_methods.c b/libbcachefs/bkey_methods.c index 79f3fbe..1381166 100644 --- a/libbcachefs/bkey_methods.c +++ b/libbcachefs/bkey_methods.c @@ -118,17 +118,15 @@ const struct bkey_ops bch2_bkey_ops[] = { #undef x }; +const struct bkey_ops bch2_bkey_null_ops = { + .min_val_size = U8_MAX, +}; + int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { - const struct bkey_ops *ops; - - if (k.k->type >= KEY_TYPE_MAX) { - prt_printf(err, "invalid type (%u >= %u)", k.k->type, KEY_TYPE_MAX); - return -BCH_ERR_invalid_bkey; - } - - ops = &bch2_bkey_ops[k.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type); if (bkey_val_bytes(k.k) < ops->min_val_size) { prt_printf(err, "bad val size (%zu < %u)", @@ -136,6 +134,9 @@ int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k, return -BCH_ERR_invalid_bkey; } + if (!ops->key_invalid) + return 0; + return ops->key_invalid(c, k, flags, err); } @@ -215,14 +216,16 @@ static unsigned bch2_key_types_allowed[] = { int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k, enum btree_node_type type, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { if (k.k->u64s < BKEY_U64s) { prt_printf(err, "u64s too small (%u < %zu)", k.k->u64s, BKEY_U64s); return -BCH_ERR_invalid_bkey; } - if (!(bch2_key_types_allowed[type] & (1U << k.k->type))) { + if (flags & BKEY_INVALID_COMMIT && + !(bch2_key_types_allowed[type] & (1U << k.k->type))) { prt_printf(err, "invalid key type for btree %s (%s)", bch2_btree_ids[type], bch2_bkey_types[k.k->type]); return -BCH_ERR_invalid_bkey; @@ -246,24 +249,23 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k, } } - if (type != BKEY_TYPE_btree && - !btree_type_has_snapshots(type) && - k.k->p.snapshot) { - prt_printf(err, "nonzero snapshot"); - return -BCH_ERR_invalid_bkey; - } + if (type != BKEY_TYPE_btree) { + if (!btree_type_has_snapshots((enum btree_id) type) && + k.k->p.snapshot) { + prt_printf(err, "nonzero snapshot"); + return -BCH_ERR_invalid_bkey; + } - if (type != BKEY_TYPE_btree && - btree_type_has_snapshots(type) && - !k.k->p.snapshot) { - prt_printf(err, "snapshot == 0"); - return -BCH_ERR_invalid_bkey; - } + if (btree_type_has_snapshots((enum btree_id) type) && + !k.k->p.snapshot) { + prt_printf(err, "snapshot == 0"); + return -BCH_ERR_invalid_bkey; + } - if (type != BKEY_TYPE_btree && - bkey_eq(k.k->p, POS_MAX)) { - prt_printf(err, "key at POS_MAX"); - return -BCH_ERR_invalid_bkey; + if (bkey_eq(k.k->p, POS_MAX)) { + prt_printf(err, "key at POS_MAX"); + return -BCH_ERR_invalid_bkey; + } } return 0; @@ -271,7 +273,8 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k, int bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k, enum btree_node_type type, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { return __bch2_bkey_invalid(c, k, type, flags, err) ?: bch2_bkey_val_invalid(c, k, flags, err); @@ -340,14 +343,10 @@ void bch2_bkey_to_text(struct printbuf *out, const struct bkey *k) void bch2_val_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k) { - if (k.k->type < KEY_TYPE_MAX) { - const struct bkey_ops *ops = &bch2_bkey_ops[k.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type); - if (likely(ops->val_to_text)) - ops->val_to_text(out, c, k); - } else { - prt_printf(out, "(invalid type %u)", k.k->type); - } + if (likely(ops->val_to_text)) + ops->val_to_text(out, c, k); } void bch2_bkey_val_to_text(struct printbuf *out, struct bch_fs *c, @@ -363,7 +362,7 @@ void bch2_bkey_val_to_text(struct printbuf *out, struct bch_fs *c, void bch2_bkey_swab_val(struct bkey_s k) { - const struct bkey_ops *ops = &bch2_bkey_ops[k.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type); if (ops->swab) ops->swab(k); @@ -371,7 +370,7 @@ void bch2_bkey_swab_val(struct bkey_s k) bool bch2_bkey_normalize(struct bch_fs *c, struct bkey_s k) { - const struct bkey_ops *ops = &bch2_bkey_ops[k.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type); return ops->key_normalize ? ops->key_normalize(c, k) @@ -380,11 +379,11 @@ bool bch2_bkey_normalize(struct bch_fs *c, struct bkey_s k) bool bch2_bkey_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_c r) { - const struct bkey_ops *ops = &bch2_bkey_ops[l.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(l.k->type); - return bch2_bkey_maybe_mergable(l.k, r.k) && + return ops->key_merge && + bch2_bkey_maybe_mergable(l.k, r.k) && (u64) l.k->size + r.k->size <= KEY_SIZE_MAX && - bch2_bkey_ops[l.k->type].key_merge && !bch2_key_merging_disabled && ops->key_merge(c, l, r); } @@ -484,7 +483,7 @@ void __bch2_bkey_compat(unsigned level, enum btree_id btree_id, u->k.p.snapshot = write ? 0 : U32_MAX; } else { - u64 min_packed = f->field_offset[BKEY_FIELD_SNAPSHOT]; + u64 min_packed = le64_to_cpu(f->field_offset[BKEY_FIELD_SNAPSHOT]); u64 max_packed = min_packed + ~(~0ULL << f->bits_per_field[BKEY_FIELD_SNAPSHOT]); @@ -509,7 +508,7 @@ void __bch2_bkey_compat(unsigned level, enum btree_id btree_id, if (big_endian != CPU_BIG_ENDIAN) bch2_bkey_swab_val(u); - ops = &bch2_bkey_ops[k->type]; + ops = bch2_bkey_type_ops(k->type); if (ops->compat) ops->compat(btree_id, version, big_endian, write, u); diff --git a/libbcachefs/bkey_methods.h b/libbcachefs/bkey_methods.h index c2bd72f..36a08e3 100644 --- a/libbcachefs/bkey_methods.h +++ b/libbcachefs/bkey_methods.h @@ -11,6 +11,13 @@ struct bkey; enum btree_node_type; extern const char * const bch2_bkey_types[]; +extern const struct bkey_ops bch2_bkey_null_ops; + +enum bkey_invalid_flags { + BKEY_INVALID_WRITE = (1U << 0), + BKEY_INVALID_COMMIT = (1U << 1), + BKEY_INVALID_JOURNAL = (1U << 2), +}; /* * key_invalid: checks validity of @k, returns 0 if good or -EINVAL if bad. If @@ -21,7 +28,7 @@ extern const char * const bch2_bkey_types[]; */ struct bkey_ops { int (*key_invalid)(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err); + enum bkey_invalid_flags flags, struct printbuf *err); void (*val_to_text)(struct printbuf *, struct bch_fs *, struct bkey_s_c); void (*swab)(struct bkey_s); @@ -41,7 +48,12 @@ struct bkey_ops { extern const struct bkey_ops bch2_bkey_ops[]; -#define BKEY_INVALID_FROM_JOURNAL (1 << 1) +static inline const struct bkey_ops *bch2_bkey_type_ops(enum bch_bkey_type type) +{ + return likely(type < KEY_TYPE_MAX) + ? &bch2_bkey_ops[type] + : &bch2_bkey_null_ops; +} int bch2_bkey_val_invalid(struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); int __bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, @@ -75,7 +87,7 @@ static inline int bch2_mark_key(struct btree_trans *trans, struct bkey_s_c old, struct bkey_s_c new, unsigned flags) { - const struct bkey_ops *ops = &bch2_bkey_ops[old.k->type ?: new.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(old.k->type ?: new.k->type); return ops->atomic_trigger ? ops->atomic_trigger(trans, btree, level, old, new, flags) @@ -115,7 +127,7 @@ static inline int bch2_trans_mark_key(struct btree_trans *trans, struct bkey_s_c old, struct bkey_i *new, unsigned flags) { - const struct bkey_ops *ops = &bch2_bkey_ops[old.k->type ?: new->k.type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(old.k->type ?: new->k.type); return ops->trans_trigger ? ops->trans_trigger(trans, btree_id, level, old, new, flags) diff --git a/libbcachefs/bset.c b/libbcachefs/bset.c index 4d55011..bcdf28f 100644 --- a/libbcachefs/bset.c +++ b/libbcachefs/bset.c @@ -599,11 +599,10 @@ static inline unsigned bkey_mantissa(const struct bkey_packed *k, return (u16) v; } -__always_inline -static inline void make_bfloat(struct btree *b, struct bset_tree *t, - unsigned j, - struct bkey_packed *min_key, - struct bkey_packed *max_key) +static __always_inline void make_bfloat(struct btree *b, struct bset_tree *t, + unsigned j, + struct bkey_packed *min_key, + struct bkey_packed *max_key) { struct bkey_float *f = bkey_float(b, t, j); struct bkey_packed *m = tree_to_bkey(b, t, j); diff --git a/libbcachefs/btree_cache.c b/libbcachefs/btree_cache.c index 5ffd8db..191d6c1 100644 --- a/libbcachefs/btree_cache.c +++ b/libbcachefs/btree_cache.c @@ -32,13 +32,15 @@ void bch2_recalc_btree_reserve(struct bch_fs *c) { unsigned i, reserve = 16; - if (!c->btree_roots[0].b) + if (!c->btree_roots_known[0].b) reserve += 8; - for (i = 0; i < BTREE_ID_NR; i++) - if (c->btree_roots[i].b) - reserve += min_t(unsigned, 1, - c->btree_roots[i].b->c.level) * 8; + for (i = 0; i < btree_id_nr_alive(c); i++) { + struct btree_root *r = bch2_btree_id_root(c, i); + + if (r->b) + reserve += min_t(unsigned, 1, r->b->c.level) * 8; + } c->btree_cache.reserve = reserve; } @@ -457,9 +459,12 @@ void bch2_fs_btree_cache_exit(struct bch_fs *c) kvpfree(c->verify_ondisk, btree_bytes(c)); - for (i = 0; i < BTREE_ID_NR; i++) - if (c->btree_roots[i].b) - list_add(&c->btree_roots[i].b->list, &bc->live); + for (i = 0; i < btree_id_nr_alive(c); i++) { + struct btree_root *r = bch2_btree_id_root(c, i); + + if (r->b) + list_add(&r->b->list, &bc->live); + } list_splice(&bc->freeable, &bc->live); diff --git a/libbcachefs/btree_cache.h b/libbcachefs/btree_cache.h index 4900ed4..00c9b92 100644 --- a/libbcachefs/btree_cache.h +++ b/libbcachefs/btree_cache.h @@ -45,7 +45,11 @@ static inline u64 btree_ptr_hash_val(const struct bkey_i *k) case KEY_TYPE_btree_ptr: return *((u64 *) bkey_i_to_btree_ptr_c(k)->v.start); case KEY_TYPE_btree_ptr_v2: - return bkey_i_to_btree_ptr_v2_c(k)->v.seq; + /* + * The cast/deref is only necessary to avoid sparse endianness + * warnings: + */ + return *((u64 *) &bkey_i_to_btree_ptr_v2_c(k)->v.seq); default: return 0; } @@ -97,7 +101,27 @@ static inline unsigned btree_blocks(struct bch_fs *c) (BTREE_FOREGROUND_MERGE_THRESHOLD(c) + \ (BTREE_FOREGROUND_MERGE_THRESHOLD(c) >> 2)) -#define btree_node_root(_c, _b) ((_c)->btree_roots[(_b)->c.btree_id].b) +static inline unsigned btree_id_nr_alive(struct bch_fs *c) +{ + return BTREE_ID_NR + c->btree_roots_extra.nr; +} + +static inline struct btree_root *bch2_btree_id_root(struct bch_fs *c, unsigned id) +{ + if (likely(id < BTREE_ID_NR)) { + return &c->btree_roots_known[id]; + } else { + unsigned idx = id - BTREE_ID_NR; + + EBUG_ON(idx >= c->btree_roots_extra.nr); + return &c->btree_roots_extra.data[idx]; + } +} + +static inline struct btree *btree_node_root(struct bch_fs *c, struct btree *b) +{ + return bch2_btree_id_root(c, b->c.btree_id)->b; +} void bch2_btree_node_to_text(struct printbuf *, struct bch_fs *, const struct btree *); diff --git a/libbcachefs/btree_gc.c b/libbcachefs/btree_gc.c index 529613f..1fc3867 100644 --- a/libbcachefs/btree_gc.c +++ b/libbcachefs/btree_gc.c @@ -529,8 +529,13 @@ static int bch2_repair_topology(struct bch_fs *c) bch2_trans_init(&trans, c, 0, 0); - for (i = 0; i < BTREE_ID_NR && !ret; i++) { - b = c->btree_roots[i].b; + for (i = 0; i < btree_id_nr_alive(c)&& !ret; i++) { + struct btree_root *r = bch2_btree_id_root(c, i); + + if (!r->alive) + continue; + + b = r->b; if (btree_node_fake(b)) continue; @@ -883,7 +888,7 @@ static int bch2_gc_btree(struct btree_trans *trans, enum btree_id btree_id, return ret; mutex_lock(&c->btree_root_lock); - b = c->btree_roots[btree_id].b; + b = bch2_btree_id_root(c, btree_id)->b; if (!btree_node_fake(b)) { struct bkey_s_c k = bkey_i_to_s_c(&b->key); @@ -1006,7 +1011,7 @@ static int bch2_gc_btree_init(struct btree_trans *trans, struct printbuf buf = PRINTBUF; int ret = 0; - b = c->btree_roots[btree_id].b; + b = bch2_btree_id_root(c, btree_id)->b; if (btree_node_fake(b)) return 0; @@ -1075,6 +1080,15 @@ static int bch2_gc_btrees(struct bch_fs *c, bool initial, bool metadata_only) ? bch2_gc_btree_init(&trans, ids[i], metadata_only) : bch2_gc_btree(&trans, ids[i], initial, metadata_only); + for (i = BTREE_ID_NR; i < btree_id_nr_alive(c) && !ret; i++) { + if (!bch2_btree_id_root(c, i)->alive) + continue; + + ret = initial + ? bch2_gc_btree_init(&trans, i, metadata_only) + : bch2_gc_btree(&trans, i, initial, metadata_only); + } + if (ret < 0) bch_err_fn(c, ret); @@ -1218,7 +1232,7 @@ static int bch2_gc_done(struct bch_fs *c, for_each_member_device(ca, c, dev) { struct bch_dev_usage *dst = ca->usage_base; struct bch_dev_usage *src = (void *) - bch2_acc_percpu_u64s((void *) ca->usage_gc, + bch2_acc_percpu_u64s((u64 __percpu *) ca->usage_gc, dev_usage_u64s()); copy_dev_field(buckets_ec, "buckets_ec"); @@ -1234,7 +1248,7 @@ static int bch2_gc_done(struct bch_fs *c, unsigned nr = fs_usage_u64s(c); struct bch_fs_usage *dst = c->usage_base; struct bch_fs_usage *src = (void *) - bch2_acc_percpu_u64s((void *) c->usage_gc, nr); + bch2_acc_percpu_u64s((u64 __percpu *) c->usage_gc, nr); copy_fs_field(hidden, "hidden"); copy_fs_field(btree, "btree"); diff --git a/libbcachefs/btree_io.c b/libbcachefs/btree_io.c index 27a2a7b..a8197c5 100644 --- a/libbcachefs/btree_io.c +++ b/libbcachefs/btree_io.c @@ -517,7 +517,7 @@ static void btree_pos_to_text(struct printbuf *out, struct bch_fs *c, prt_printf(out, "%s level %u/%u\n ", bch2_btree_ids[b->c.btree_id], b->c.level, - c->btree_roots[b->c.btree_id].level); + bch2_btree_id_root(c, b->c.btree_id)->level); bch2_bkey_val_to_text(out, c, bkey_i_to_s_c(&b->key)); } @@ -699,11 +699,9 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca, struct printbuf buf2 = PRINTBUF; int ret = 0; - btree_err_on((version != BCH_BSET_VERSION_OLD && - version < bcachefs_metadata_version_min) || - version >= bcachefs_metadata_version_max, + btree_err_on(!bch2_version_compatible(version), BTREE_ERR_INCOMPATIBLE, c, ca, b, i, - "unsupported bset version"); + "unsupported bset version %u", version); if (btree_err_on(version < c->sb.version_min, BTREE_ERR_FIXABLE, c, NULL, b, i, @@ -1283,7 +1281,7 @@ struct btree_node_read_all { unsigned nr; void *buf[BCH_REPLICAS_MAX]; struct bio *bio[BCH_REPLICAS_MAX]; - int err[BCH_REPLICAS_MAX]; + blk_status_t err[BCH_REPLICAS_MAX]; }; static unsigned btree_node_sectors_written(struct bch_fs *c, void *data) @@ -1766,7 +1764,11 @@ static void btree_node_write_work(struct work_struct *work) } else { ret = bch2_trans_do(c, NULL, NULL, 0, bch2_btree_node_update_key_get_iter(&trans, b, &wbio->key, - !wbio->wbio.failed.nr)); + BCH_WATERMARK_reclaim| + BTREE_INSERT_JOURNAL_RECLAIM| + BTREE_INSERT_NOFAIL| + BTREE_INSERT_NOCHECK_RW, + !wbio->wbio.failed.nr)); if (ret) goto err; } @@ -1777,7 +1779,7 @@ out: err: set_btree_node_noevict(b); if (!bch2_err_matches(ret, EROFS)) - bch2_fs_fatal_error(c, "fatal error writing btree node"); + bch2_fs_fatal_error(c, "fatal error writing btree node: %s", bch2_err_str(ret)); goto out; } @@ -2015,9 +2017,7 @@ do_write: BUG_ON(BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN); BUG_ON(i->seq != b->data->keys.seq); - i->version = c->sb.version < bcachefs_metadata_version_bkey_renumber - ? cpu_to_le16(BCH_BSET_VERSION_OLD) - : cpu_to_le16(c->sb.version); + i->version = cpu_to_le16(c->sb.version); SET_BSET_OFFSET(i, b->written); SET_BSET_CSUM_TYPE(i, bch2_meta_checksum_type(c)); @@ -2230,7 +2230,7 @@ bool bch2_btree_flush_all_writes(struct bch_fs *c) return __bch2_btree_flush_all(c, BTREE_NODE_write_in_flight); } -const char * const bch2_btree_write_types[] = { +static const char * const bch2_btree_write_types[] = { #define x(t, n) [n] = #t, BCH_BTREE_WRITE_TYPES() NULL diff --git a/libbcachefs/btree_io.h b/libbcachefs/btree_io.h index c43fb60..0cadf65 100644 --- a/libbcachefs/btree_io.h +++ b/libbcachefs/btree_io.h @@ -178,7 +178,7 @@ static inline void compat_bformat(unsigned level, enum btree_id btree_id, f->field_offset[BKEY_FIELD_SNAPSHOT] = write ? 0 - : U32_MAX - max_packed; + : cpu_to_le64(U32_MAX - max_packed); } } @@ -200,7 +200,7 @@ static inline void compat_btree_node(unsigned level, enum btree_id btree_id, struct btree_node *bn) { if (version < bcachefs_metadata_version_inode_btree_change && - btree_node_type_is_extents(btree_id) && + btree_id_is_extents(btree_id) && !bpos_eq(bn->min_key, POS_MIN) && write) bn->min_key = bpos_nosnap_predecessor(bn->min_key); @@ -217,7 +217,7 @@ static inline void compat_btree_node(unsigned level, enum btree_id btree_id, bn->max_key.snapshot = U32_MAX; if (version < bcachefs_metadata_version_inode_btree_change && - btree_node_type_is_extents(btree_id) && + btree_id_is_extents(btree_id) && !bpos_eq(bn->min_key, POS_MIN) && !write) bn->min_key = bpos_nosnap_successor(bn->min_key); diff --git a/libbcachefs/btree_iter.c b/libbcachefs/btree_iter.c index 3c6ea6a..e292c5a 100644 --- a/libbcachefs/btree_iter.c +++ b/libbcachefs/btree_iter.c @@ -238,7 +238,7 @@ static void bch2_btree_path_verify(struct btree_trans *trans, for (i = 0; i < (!path->cached ? BTREE_MAX_DEPTH : 1); i++) { if (!path->l[i].b) { BUG_ON(!path->cached && - c->btree_roots[path->btree_id].b->c.level > i); + bch2_btree_id_root(c, path->btree_id)->b->c.level > i); break; } @@ -700,8 +700,8 @@ void bch2_trans_node_add(struct btree_trans *trans, struct btree *b) if (t != BTREE_NODE_UNLOCKED) { btree_node_unlock(trans, path, b->c.level); - six_lock_increment(&b->c.lock, t); - mark_btree_node_locked(trans, path, b->c.level, t); + six_lock_increment(&b->c.lock, (enum six_lock_type) t); + mark_btree_node_locked(trans, path, b->c.level, (enum six_lock_type) t); } bch2_btree_path_level_init(trans, path, b); @@ -732,7 +732,7 @@ static inline int btree_path_lock_root(struct btree_trans *trans, unsigned long trace_ip) { struct bch_fs *c = trans->c; - struct btree *b, **rootp = &c->btree_roots[path->btree_id].b; + struct btree *b, **rootp = &bch2_btree_id_root(c, path->btree_id)->b; enum six_lock_type lock_type; unsigned i; int ret; @@ -1438,7 +1438,7 @@ void bch2_btree_path_to_text(struct printbuf *out, struct btree_path *path) prt_newline(out); } -noinline __cold +static noinline __cold void __bch2_trans_paths_to_text(struct printbuf *out, struct btree_trans *trans, bool nosort) { @@ -1458,7 +1458,7 @@ void bch2_trans_paths_to_text(struct printbuf *out, struct btree_trans *trans) __bch2_trans_paths_to_text(out, trans, false); } -noinline __cold +static noinline __cold void __bch2_dump_trans_paths_updates(struct btree_trans *trans, bool nosort) { struct printbuf buf = PRINTBUF; @@ -1867,9 +1867,9 @@ static inline struct bkey_i *btree_trans_peek_updates(struct btree_iter *iter) : NULL; } -struct bkey_i *bch2_btree_journal_peek(struct btree_trans *trans, - struct btree_iter *iter, - struct bpos end_pos) +static struct bkey_i *bch2_btree_journal_peek(struct btree_trans *trans, + struct btree_iter *iter, + struct bpos end_pos) { struct bkey_i *k; diff --git a/libbcachefs/btree_iter.h b/libbcachefs/btree_iter.h index 13d4e9a..0e9c1cb 100644 --- a/libbcachefs/btree_iter.h +++ b/libbcachefs/btree_iter.h @@ -283,7 +283,7 @@ static inline void bch2_trans_verify_not_in_restart(struct btree_trans *trans) } __always_inline -static inline int btree_trans_restart_nounlock(struct btree_trans *trans, int err) +static int btree_trans_restart_nounlock(struct btree_trans *trans, int err) { BUG_ON(err <= 0); BUG_ON(!bch2_err_matches(-err, BCH_ERR_transaction_restart)); @@ -294,7 +294,7 @@ static inline int btree_trans_restart_nounlock(struct btree_trans *trans, int er } __always_inline -static inline int btree_trans_restart(struct btree_trans *trans, int err) +static int btree_trans_restart(struct btree_trans *trans, int err) { btree_trans_restart_nounlock(trans, err); return -err; diff --git a/libbcachefs/btree_key_cache.c b/libbcachefs/btree_key_cache.c index 9627b94..a71db7a 100644 --- a/libbcachefs/btree_key_cache.c +++ b/libbcachefs/btree_key_cache.c @@ -651,9 +651,8 @@ static int btree_key_cache_flush_pos(struct btree_trans *trans, bch2_trans_commit(trans, NULL, NULL, BTREE_INSERT_NOCHECK_RW| BTREE_INSERT_NOFAIL| - BTREE_INSERT_USE_RESERVE| (ck->journal.seq == journal_last_seq(j) - ? JOURNAL_WATERMARK_reserved + ? BCH_WATERMARK_reclaim : 0)| commit_flags); diff --git a/libbcachefs/btree_locking.c b/libbcachefs/btree_locking.c index 70d25ce..d7fd871 100644 --- a/libbcachefs/btree_locking.c +++ b/libbcachefs/btree_locking.c @@ -597,13 +597,6 @@ int __bch2_btree_path_relock(struct btree_trans *trans, return 0; } -__flatten -bool bch2_btree_path_upgrade_norestart(struct btree_trans *trans, - struct btree_path *path, unsigned long trace_ip) -{ - return btree_path_get_locks(trans, path, true); -} - bool bch2_btree_path_upgrade_noupgrade_sibs(struct btree_trans *trans, struct btree_path *path, unsigned new_locks_want) diff --git a/libbcachefs/btree_locking.h b/libbcachefs/btree_locking.h index 0ad8fd4..f3e58aa 100644 --- a/libbcachefs/btree_locking.h +++ b/libbcachefs/btree_locking.h @@ -94,7 +94,7 @@ static inline void mark_btree_node_locked(struct btree_trans *trans, unsigned level, enum six_lock_type type) { - mark_btree_node_locked_noreset(path, level, type); + mark_btree_node_locked_noreset(path, level, (enum btree_node_locked_type) type); #ifdef CONFIG_BCACHEFS_LOCK_TIME_STATS path->l[level].lock_taken_time = local_clock(); #endif @@ -247,7 +247,7 @@ static inline bool btree_node_lock_increment(struct btree_trans *trans, trans_for_each_path(trans, path) if (&path->l[level].b->c == b && btree_node_locked_type(path, level) >= want) { - six_lock_increment(&b->lock, want); + six_lock_increment(&b->lock, (enum six_lock_type) want); return true; } @@ -267,7 +267,7 @@ static inline int btree_node_lock(struct btree_trans *trans, EBUG_ON(!(trans->paths_allocated & (1ULL << path->idx))); if (likely(six_trylock_type(&b->lock, type)) || - btree_node_lock_increment(trans, b, level, type) || + btree_node_lock_increment(trans, b, level, (enum btree_node_locked_type) type) || !(ret = btree_node_lock_nopath(trans, b, type, btree_path_ip_allocated(path)))) { #ifdef CONFIG_BCACHEFS_LOCK_TIME_STATS path->l[b->level].lock_taken_time = local_clock(); diff --git a/libbcachefs/btree_types.h b/libbcachefs/btree_types.h index d4ff721..4efc694 100644 --- a/libbcachefs/btree_types.h +++ b/libbcachefs/btree_types.h @@ -688,6 +688,11 @@ static inline bool btree_node_type_is_extents(enum btree_node_type type) return (1U << type) & BTREE_ID_IS_EXTENTS; } +static inline bool btree_id_is_extents(enum btree_id btree) +{ + return btree_node_type_is_extents((enum btree_node_type) btree); +} + #define BTREE_ID_HAS_SNAPSHOTS \ ((1U << BTREE_ID_extents)| \ (1U << BTREE_ID_inodes)| \ diff --git a/libbcachefs/btree_update.h b/libbcachefs/btree_update.h index dbb0ae1..93d2e54 100644 --- a/libbcachefs/btree_update.h +++ b/libbcachefs/btree_update.h @@ -23,11 +23,10 @@ void bch2_btree_insert_key_leaf(struct btree_trans *, struct btree_path *, struct bkey_i *, u64); enum btree_insert_flags { - /* First two bits for journal watermark: */ - __BTREE_INSERT_NOFAIL = 2, + /* First bits for bch_watermark: */ + __BTREE_INSERT_NOFAIL = BCH_WATERMARK_BITS, __BTREE_INSERT_NOCHECK_RW, __BTREE_INSERT_LAZY_RW, - __BTREE_INSERT_USE_RESERVE, __BTREE_INSERT_JOURNAL_REPLAY, __BTREE_INSERT_JOURNAL_RECLAIM, __BTREE_INSERT_NOWAIT, @@ -37,26 +36,23 @@ enum btree_insert_flags { }; /* Don't check for -ENOSPC: */ -#define BTREE_INSERT_NOFAIL (1 << __BTREE_INSERT_NOFAIL) +#define BTREE_INSERT_NOFAIL BIT(__BTREE_INSERT_NOFAIL) -#define BTREE_INSERT_NOCHECK_RW (1 << __BTREE_INSERT_NOCHECK_RW) -#define BTREE_INSERT_LAZY_RW (1 << __BTREE_INSERT_LAZY_RW) - -/* for copygc, or when merging btree nodes */ -#define BTREE_INSERT_USE_RESERVE (1 << __BTREE_INSERT_USE_RESERVE) +#define BTREE_INSERT_NOCHECK_RW BIT(__BTREE_INSERT_NOCHECK_RW) +#define BTREE_INSERT_LAZY_RW BIT(__BTREE_INSERT_LAZY_RW) /* Insert is for journal replay - don't get journal reservations: */ -#define BTREE_INSERT_JOURNAL_REPLAY (1 << __BTREE_INSERT_JOURNAL_REPLAY) +#define BTREE_INSERT_JOURNAL_REPLAY BIT(__BTREE_INSERT_JOURNAL_REPLAY) /* Insert is being called from journal reclaim path: */ -#define BTREE_INSERT_JOURNAL_RECLAIM (1 << __BTREE_INSERT_JOURNAL_RECLAIM) +#define BTREE_INSERT_JOURNAL_RECLAIM BIT(__BTREE_INSERT_JOURNAL_RECLAIM) /* Don't block on allocation failure (for new btree nodes: */ -#define BTREE_INSERT_NOWAIT (1 << __BTREE_INSERT_NOWAIT) -#define BTREE_INSERT_GC_LOCK_HELD (1 << __BTREE_INSERT_GC_LOCK_HELD) +#define BTREE_INSERT_NOWAIT BIT(__BTREE_INSERT_NOWAIT) +#define BTREE_INSERT_GC_LOCK_HELD BIT(__BTREE_INSERT_GC_LOCK_HELD) -#define BCH_HASH_SET_MUST_CREATE (1 << __BCH_HASH_SET_MUST_CREATE) -#define BCH_HASH_SET_MUST_REPLACE (1 << __BCH_HASH_SET_MUST_REPLACE) +#define BCH_HASH_SET_MUST_CREATE BIT(__BCH_HASH_SET_MUST_CREATE) +#define BCH_HASH_SET_MUST_REPLACE BIT(__BCH_HASH_SET_MUST_REPLACE) int bch2_btree_delete_extent_at(struct btree_trans *, struct btree_iter *, unsigned, unsigned); @@ -80,9 +76,10 @@ int bch2_btree_node_rewrite(struct btree_trans *, struct btree_iter *, struct btree *, unsigned); void bch2_btree_node_rewrite_async(struct bch_fs *, struct btree *); int bch2_btree_node_update_key(struct btree_trans *, struct btree_iter *, - struct btree *, struct bkey_i *, bool); -int bch2_btree_node_update_key_get_iter(struct btree_trans *, - struct btree *, struct bkey_i *, bool); + struct btree *, struct bkey_i *, + unsigned, bool); +int bch2_btree_node_update_key_get_iter(struct btree_trans *, struct btree *, + struct bkey_i *, unsigned, bool); int __bch2_insert_snapshot_whiteouts(struct btree_trans *, enum btree_id, struct bpos, struct bpos); diff --git a/libbcachefs/btree_update_interior.c b/libbcachefs/btree_update_interior.c index eb3319f..5592fef 100644 --- a/libbcachefs/btree_update_interior.c +++ b/libbcachefs/btree_update_interior.c @@ -246,18 +246,12 @@ static struct btree *__bch2_btree_node_alloc(struct btree_trans *trans, BKEY_PADDED_ONSTACK(k, BKEY_BTREE_PTR_VAL_U64s_MAX) tmp; struct open_buckets ob = { .nr = 0 }; struct bch_devs_list devs_have = (struct bch_devs_list) { 0 }; - unsigned nr_reserve; - enum bch_watermark alloc_reserve; + enum bch_watermark watermark = flags & BCH_WATERMARK_MASK; + unsigned nr_reserve = watermark > BCH_WATERMARK_reclaim + ? BTREE_NODE_RESERVE + : 0; int ret; - if (flags & BTREE_INSERT_USE_RESERVE) { - nr_reserve = 0; - alloc_reserve = BCH_WATERMARK_btree_copygc; - } else { - nr_reserve = BTREE_NODE_RESERVE; - alloc_reserve = BCH_WATERMARK_btree; - } - mutex_lock(&c->btree_reserve_cache_lock); if (c->btree_reserve_cache_nr > nr_reserve) { struct btree_alloc *a = @@ -279,7 +273,7 @@ retry: &devs_have, res->nr_replicas, c->opts.metadata_replicas_required, - alloc_reserve, 0, cl, &wp); + watermark, 0, cl, &wp); if (unlikely(ret)) return ERR_PTR(ret); @@ -647,11 +641,10 @@ static void btree_update_nodes_written(struct btree_update *as) * which may require allocations as well. */ ret = commit_do(&trans, &as->disk_res, &journal_seq, + BCH_WATERMARK_reclaim| BTREE_INSERT_NOFAIL| BTREE_INSERT_NOCHECK_RW| - BTREE_INSERT_USE_RESERVE| - BTREE_INSERT_JOURNAL_RECLAIM| - JOURNAL_WATERMARK_reserved, + BTREE_INSERT_JOURNAL_RECLAIM, btree_update_nodes_written_trans(&trans, as)); bch2_trans_unlock(&trans); @@ -1049,14 +1042,24 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path, ? BCH_DISK_RESERVATION_NOFAIL : 0; unsigned nr_nodes[2] = { 0, 0 }; unsigned update_level = level; - int journal_flags = flags & JOURNAL_WATERMARK_MASK; + enum bch_watermark watermark = flags & BCH_WATERMARK_MASK; + unsigned journal_flags = 0; int ret = 0; u32 restart_count = trans->restart_count; BUG_ON(!path->should_be_locked); + if (watermark == BCH_WATERMARK_copygc) + watermark = BCH_WATERMARK_btree_copygc; + if (watermark < BCH_WATERMARK_btree) + watermark = BCH_WATERMARK_btree; + + flags &= ~BCH_WATERMARK_MASK; + flags |= watermark; + if (flags & BTREE_INSERT_JOURNAL_RECLAIM) journal_flags |= JOURNAL_RES_GET_NONBLOCK; + journal_flags |= watermark; while (1) { nr_nodes[!!update_level] += 1 + split; @@ -1196,7 +1199,7 @@ static void bch2_btree_set_root_inmem(struct bch_fs *c, struct btree *b) (b->c.level < btree_node_root(c, b)->c.level || !btree_node_dying(btree_node_root(c, b)))); - btree_node_root(c, b) = b; + bch2_btree_id_root(c, b->c.btree_id)->b = b; mutex_unlock(&c->btree_root_lock); bch2_recalc_btree_reserve(c); @@ -1845,9 +1848,7 @@ int __bch2_foreground_maybe_merge(struct btree_trans *trans, parent = btree_node_parent(path, b); as = bch2_btree_update_start(trans, path, level, false, - BTREE_INSERT_NOFAIL| - BTREE_INSERT_USE_RESERVE| - flags); + BTREE_INSERT_NOFAIL|flags); ret = PTR_ERR_OR_ZERO(as); if (ret) goto err; @@ -2035,7 +2036,7 @@ out: return ret; } -void async_btree_node_rewrite_work(struct work_struct *work) +static void async_btree_node_rewrite_work(struct work_struct *work) { struct async_btree_rewrite *a = container_of(work, struct async_btree_rewrite, work); @@ -2127,6 +2128,7 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans, struct btree_iter *iter, struct btree *b, struct btree *new_hash, struct bkey_i *new_key, + unsigned commit_flags, bool skip_triggers) { struct bch_fs *c = trans->c; @@ -2187,12 +2189,7 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans, trans->extra_journal_entries.nr += jset_u64s(new_key->k.u64s); } - ret = bch2_trans_commit(trans, NULL, NULL, - BTREE_INSERT_NOFAIL| - BTREE_INSERT_NOCHECK_RW| - BTREE_INSERT_USE_RESERVE| - BTREE_INSERT_JOURNAL_RECLAIM| - JOURNAL_WATERMARK_reserved); + ret = bch2_trans_commit(trans, NULL, NULL, commit_flags); if (ret) goto err; @@ -2226,7 +2223,7 @@ err: int bch2_btree_node_update_key(struct btree_trans *trans, struct btree_iter *iter, struct btree *b, struct bkey_i *new_key, - bool skip_triggers) + unsigned commit_flags, bool skip_triggers) { struct bch_fs *c = trans->c; struct btree *new_hash = NULL; @@ -2256,8 +2253,8 @@ int bch2_btree_node_update_key(struct btree_trans *trans, struct btree_iter *ite } path->intent_ref++; - ret = __bch2_btree_node_update_key(trans, iter, b, new_hash, - new_key, skip_triggers); + ret = __bch2_btree_node_update_key(trans, iter, b, new_hash, new_key, + commit_flags, skip_triggers); --path->intent_ref; if (new_hash) { @@ -2275,7 +2272,7 @@ int bch2_btree_node_update_key(struct btree_trans *trans, struct btree_iter *ite int bch2_btree_node_update_key_get_iter(struct btree_trans *trans, struct btree *b, struct bkey_i *new_key, - bool skip_triggers) + unsigned commit_flags, bool skip_triggers) { struct btree_iter iter; int ret; @@ -2296,7 +2293,8 @@ int bch2_btree_node_update_key_get_iter(struct btree_trans *trans, BUG_ON(!btree_node_hashed(b)); - ret = bch2_btree_node_update_key(trans, &iter, b, new_key, skip_triggers); + ret = bch2_btree_node_update_key(trans, &iter, b, new_key, + commit_flags, skip_triggers); out: bch2_trans_iter_exit(trans, &iter); return ret; @@ -2404,7 +2402,7 @@ bool bch2_btree_interior_updates_flush(struct bch_fs *c) void bch2_journal_entry_to_btree_root(struct bch_fs *c, struct jset_entry *entry) { - struct btree_root *r = &c->btree_roots[entry->btree_id]; + struct btree_root *r = bch2_btree_id_root(c, entry->btree_id); mutex_lock(&c->btree_root_lock); @@ -2430,15 +2428,15 @@ bch2_btree_roots_to_journal_entries(struct bch_fs *c, mutex_lock(&c->btree_root_lock); - for (i = 0; i < BTREE_ID_NR; i++) - if (c->btree_roots[i].alive && !test_bit(i, &have)) { - journal_entry_set(end, - BCH_JSET_ENTRY_btree_root, - i, c->btree_roots[i].level, - &c->btree_roots[i].key, - c->btree_roots[i].key.k.u64s); + for (i = 0; i < btree_id_nr_alive(c); i++) { + struct btree_root *r = bch2_btree_id_root(c, i); + + if (r->alive && !test_bit(i, &have)) { + journal_entry_set(end, BCH_JSET_ENTRY_btree_root, + i, r->level, &r->key, r->key.k.u64s); end = vstruct_next(end); } + } mutex_unlock(&c->btree_root_lock); @@ -2452,7 +2450,7 @@ void bch2_fs_btree_interior_update_exit(struct bch_fs *c) mempool_exit(&c->btree_interior_update_pool); } -int bch2_fs_btree_interior_update_init(struct bch_fs *c) +void bch2_fs_btree_interior_update_init_early(struct bch_fs *c) { mutex_init(&c->btree_reserve_cache_lock); INIT_LIST_HEAD(&c->btree_interior_update_list); @@ -2462,7 +2460,10 @@ int bch2_fs_btree_interior_update_init(struct bch_fs *c) INIT_LIST_HEAD(&c->pending_node_rewrites); mutex_init(&c->pending_node_rewrites_lock); +} +int bch2_fs_btree_interior_update_init(struct bch_fs *c) +{ c->btree_interior_update_worker = alloc_workqueue("btree_update", WQ_UNBOUND|WQ_MEM_RECLAIM, 1); if (!c->btree_interior_update_worker) diff --git a/libbcachefs/btree_update_interior.h b/libbcachefs/btree_update_interior.h index dcfd7ce..221b7ad 100644 --- a/libbcachefs/btree_update_interior.h +++ b/libbcachefs/btree_update_interior.h @@ -322,6 +322,7 @@ void bch2_do_pending_node_rewrites(struct bch_fs *); void bch2_free_pending_node_rewrites(struct bch_fs *); void bch2_fs_btree_interior_update_exit(struct bch_fs *); +void bch2_fs_btree_interior_update_init_early(struct bch_fs *); int bch2_fs_btree_interior_update_init(struct bch_fs *); #endif /* _BCACHEFS_BTREE_UPDATE_INTERIOR_H */ diff --git a/libbcachefs/btree_update_leaf.c b/libbcachefs/btree_update_leaf.c index 8976a21..f7ffd68 100644 --- a/libbcachefs/btree_update_leaf.c +++ b/libbcachefs/btree_update_leaf.c @@ -29,7 +29,7 @@ * bch2_btree_path_peek_slot() for a cached iterator might return a key in a * different snapshot: */ -struct bkey_s_c bch2_btree_path_peek_slot_exact(struct btree_path *path, struct bkey *u) +static struct bkey_s_c bch2_btree_path_peek_slot_exact(struct btree_path *path, struct bkey *u) { struct bkey_s_c k = bch2_btree_path_peek_slot(path, u); @@ -320,7 +320,7 @@ bch2_trans_journal_preres_get_cold(struct btree_trans *trans, unsigned flags, bch2_journal_preres_get(&trans->c->journal, &trans->journal_preres, trans->journal_preres_u64s, - (flags & JOURNAL_WATERMARK_MASK))); + (flags & BCH_WATERMARK_MASK))); } static __always_inline int bch2_trans_journal_res_get(struct btree_trans *trans, @@ -407,6 +407,8 @@ static int run_one_mem_trigger(struct btree_trans *trans, { struct bkey_s_c old = { &i->old_k, i->old_v }; struct bkey_i *new = i->k; + const struct bkey_ops *old_ops = bch2_bkey_type_ops(old.k->type); + const struct bkey_ops *new_ops = bch2_bkey_type_ops(i->k->k.type); int ret; verify_update_old_key(trans, i); @@ -417,8 +419,7 @@ static int run_one_mem_trigger(struct btree_trans *trans, if (!btree_node_type_needs_gc(i->btree_id)) return 0; - if (bch2_bkey_ops[old.k->type].atomic_trigger == - bch2_bkey_ops[i->k->k.type].atomic_trigger) { + if (old_ops->atomic_trigger == new_ops->atomic_trigger) { ret = bch2_mark_key(trans, i->btree_id, i->level, old, bkey_i_to_s_c(new), BTREE_TRIGGER_INSERT|BTREE_TRIGGER_OVERWRITE|flags); @@ -449,6 +450,8 @@ static int run_one_trans_trigger(struct btree_trans *trans, struct btree_insert_ */ struct bkey old_k = i->old_k; struct bkey_s_c old = { &old_k, i->old_v }; + const struct bkey_ops *old_ops = bch2_bkey_type_ops(old.k->type); + const struct bkey_ops *new_ops = bch2_bkey_type_ops(i->k->k.type); verify_update_old_key(trans, i); @@ -458,8 +461,7 @@ static int run_one_trans_trigger(struct btree_trans *trans, struct btree_insert_ if (!i->insert_trigger_run && !i->overwrite_trigger_run && - bch2_bkey_ops[old.k->type].trans_trigger == - bch2_bkey_ops[i->k->k.type].trans_trigger) { + old_ops->trans_trigger == new_ops->trans_trigger) { i->overwrite_trigger_run = true; i->insert_trigger_run = true; return bch2_trans_mark_key(trans, i->btree_id, i->level, old, i->k, @@ -634,7 +636,7 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, unsigned flags, */ if (likely(!(flags & BTREE_INSERT_JOURNAL_REPLAY))) { ret = bch2_trans_journal_res_get(trans, - (flags & JOURNAL_WATERMARK_MASK)| + (flags & BCH_WATERMARK_MASK)| JOURNAL_RES_GET_NONBLOCK); if (ret) return ret; @@ -852,10 +854,13 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans, unsigned flags struct printbuf buf = PRINTBUF; trans_for_each_update(trans, i) { - int rw = (flags & BTREE_INSERT_JOURNAL_REPLAY) ? READ : WRITE; + enum bkey_invalid_flags invalid_flags = 0; + + if (!(flags & BTREE_INSERT_JOURNAL_REPLAY)) + invalid_flags |= BKEY_INVALID_WRITE|BKEY_INVALID_COMMIT; if (unlikely(bch2_bkey_invalid(c, bkey_i_to_s_c(i->k), - i->bkey_type, rw, &buf))) + i->bkey_type, invalid_flags, &buf))) return bch2_trans_commit_bkey_invalid(trans, flags, i, &buf); btree_insert_entry_checks(trans, i); } @@ -883,7 +888,7 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans, unsigned flags ret = bch2_journal_preres_get(&c->journal, &trans->journal_preres, trans->journal_preres_u64s, - (flags & JOURNAL_WATERMARK_MASK)|JOURNAL_RES_GET_NONBLOCK); + (flags & BCH_WATERMARK_MASK)|JOURNAL_RES_GET_NONBLOCK); if (unlikely(ret == -BCH_ERR_journal_preres_get_blocked)) ret = bch2_trans_journal_preres_get_cold(trans, flags, trace_ip); if (unlikely(ret)) @@ -950,14 +955,14 @@ int bch2_trans_commit_error(struct btree_trans *trans, unsigned flags, break; case -BCH_ERR_journal_res_get_blocked: if ((flags & BTREE_INSERT_JOURNAL_RECLAIM) && - !(flags & JOURNAL_WATERMARK_reserved)) { + (flags & BCH_WATERMARK_MASK) != BCH_WATERMARK_reclaim) { ret = -BCH_ERR_journal_reclaim_would_deadlock; break; } ret = drop_locks_do(trans, bch2_trans_journal_res_get(trans, - (flags & JOURNAL_WATERMARK_MASK)| + (flags & BCH_WATERMARK_MASK)| JOURNAL_RES_GET_CHECK)); break; case -BCH_ERR_btree_insert_need_journal_reclaim: @@ -2044,7 +2049,7 @@ int bch2_journal_log_msg(struct bch_fs *c, const char *fmt, ...) int ret; va_start(args, fmt); - ret = __bch2_fs_log_msg(c, JOURNAL_WATERMARK_reserved, fmt, args); + ret = __bch2_fs_log_msg(c, BCH_WATERMARK_reclaim, fmt, args); va_end(args); return ret; } diff --git a/libbcachefs/btree_write_buffer.c b/libbcachefs/btree_write_buffer.c index 8b7fffb..3a3e36c 100644 --- a/libbcachefs/btree_write_buffer.c +++ b/libbcachefs/btree_write_buffer.c @@ -213,6 +213,9 @@ slowpath: btree_write_buffered_journal_cmp, NULL); + commit_flags &= ~BCH_WATERMARK_MASK; + commit_flags |= BCH_WATERMARK_reclaim; + for (i = keys; i < keys + nr; i++) { if (!i->journal_seq) continue; @@ -231,8 +234,7 @@ slowpath: ret = commit_do(trans, NULL, NULL, commit_flags| BTREE_INSERT_NOFAIL| - BTREE_INSERT_JOURNAL_RECLAIM| - JOURNAL_WATERMARK_reserved, + BTREE_INSERT_JOURNAL_RECLAIM, __bch2_btree_insert(trans, i->btree, &i->k, 0)); if (bch2_fs_fatal_err_on(ret, c, "%s: insert error %s", __func__, bch2_err_str(ret))) break; diff --git a/libbcachefs/buckets.c b/libbcachefs/buckets.c index ed86ad0..4aa0209 100644 --- a/libbcachefs/buckets.c +++ b/libbcachefs/buckets.c @@ -374,7 +374,7 @@ static inline int update_replicas(struct bch_fs *c, struct bkey_s_c k, struct bch_replicas_entry *r, s64 sectors, unsigned journal_seq, bool gc) { - struct bch_fs_usage __percpu *fs_usage; + struct bch_fs_usage *fs_usage; int idx, ret = 0; struct printbuf buf = PRINTBUF; @@ -1149,7 +1149,7 @@ int bch2_mark_inode(struct btree_trans *trans, unsigned flags) { struct bch_fs *c = trans->c; - struct bch_fs_usage __percpu *fs_usage; + struct bch_fs_usage *fs_usage; u64 journal_seq = trans->journal_res.seq; if (flags & BTREE_TRIGGER_INSERT) { @@ -1180,7 +1180,7 @@ static int __mark_reservation(struct btree_trans *trans, struct bkey_s_c k, unsigned flags) { struct bch_fs *c = trans->c; - struct bch_fs_usage __percpu *fs_usage; + struct bch_fs_usage *fs_usage; unsigned replicas = bkey_s_c_to_reservation(k).v->nr_replicas; s64 sectors = (s64) k.k->size; diff --git a/libbcachefs/buckets.h b/libbcachefs/buckets.h index ef4e100..400d105 100644 --- a/libbcachefs/buckets.h +++ b/libbcachefs/buckets.h @@ -170,6 +170,7 @@ static inline u64 bch2_dev_buckets_reserved(struct bch_dev *ca, enum bch_waterma reserved += ca->nr_btree_reserve; fallthrough; case BCH_WATERMARK_btree_copygc: + case BCH_WATERMARK_reclaim: break; } diff --git a/libbcachefs/counters.c b/libbcachefs/counters.c index e5587bc..442a9b8 100644 --- a/libbcachefs/counters.c +++ b/libbcachefs/counters.c @@ -5,7 +5,7 @@ /* BCH_SB_FIELD_counters */ -const char * const bch2_counter_names[] = { +static const char * const bch2_counter_names[] = { #define x(t, n, ...) (#t), BCH_PERSISTENT_COUNTERS() #undef x @@ -27,7 +27,7 @@ static int bch2_sb_counters_validate(struct bch_sb *sb, return 0; }; -void bch2_sb_counters_to_text(struct printbuf *out, struct bch_sb *sb, +static void bch2_sb_counters_to_text(struct printbuf *out, struct bch_sb *sb, struct bch_sb_field *f) { struct bch_sb_field_counters *ctrs = field_to_type(f, counters); diff --git a/libbcachefs/data_update.c b/libbcachefs/data_update.c index 053df0c..3c91836 100644 --- a/libbcachefs/data_update.c +++ b/libbcachefs/data_update.c @@ -381,7 +381,7 @@ void bch2_update_unwritten_extent(struct btree_trans *trans, &update->op.devs_have, update->op.nr_replicas, update->op.nr_replicas, - update->op.alloc_reserve, + update->op.watermark, 0, &cl, &wp); if (bch2_err_matches(ret, BCH_ERR_operation_blocked)) { bch2_trans_unlock(trans); @@ -458,8 +458,7 @@ int bch2_data_update_init(struct btree_trans *trans, m->op.compression_type = bch2_compression_opt_to_type[io_opts.background_compression ?: io_opts.compression]; - if (m->data_opts.btree_insert_flags & BTREE_INSERT_USE_RESERVE) - m->op.alloc_reserve = BCH_WATERMARK_copygc; + m->op.watermark = m->data_opts.btree_insert_flags & BCH_WATERMARK_MASK; bkey_for_each_ptr(ptrs, ptr) percpu_ref_get(&bch_dev_bkey_exists(c, ptr->dev)->ref); diff --git a/libbcachefs/dirent.c b/libbcachefs/dirent.c index 610dd74..065ea59 100644 --- a/libbcachefs/dirent.c +++ b/libbcachefs/dirent.c @@ -85,7 +85,8 @@ const struct bch_hash_desc bch2_dirent_hash_desc = { }; int bch2_dirent_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k); unsigned len; @@ -219,7 +220,7 @@ int bch2_dirent_read_target(struct btree_trans *trans, subvol_inum dir, int ret = 0; if (d.v->d_type == DT_SUBVOL && - d.v->d_parent_subvol != dir.subvol) + le32_to_cpu(d.v->d_parent_subvol) != dir.subvol) return 1; if (likely(d.v->d_type != DT_SUBVOL)) { diff --git a/libbcachefs/dirent.h b/libbcachefs/dirent.h index bf9ea2e..b42f4a1 100644 --- a/libbcachefs/dirent.h +++ b/libbcachefs/dirent.h @@ -4,9 +4,11 @@ #include "str_hash.h" +enum bkey_invalid_flags; extern const struct bch_hash_desc bch2_dirent_hash_desc; -int bch2_dirent_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); +int bch2_dirent_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); void bch2_dirent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_ops_dirent ((struct bkey_ops) { \ diff --git a/libbcachefs/ec.c b/libbcachefs/ec.c index 8d091c4..d35a59e 100644 --- a/libbcachefs/ec.c +++ b/libbcachefs/ec.c @@ -105,7 +105,8 @@ struct ec_bio { /* Stripes btree keys: */ int bch2_stripe_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { const struct bch_stripe *s = bkey_s_c_to_stripe(k).v; @@ -385,7 +386,7 @@ static void ec_block_endio(struct bio *bio) } static void ec_block_io(struct bch_fs *c, struct ec_stripe_buf *buf, - unsigned rw, unsigned idx, struct closure *cl) + blk_opf_t opf, unsigned idx, struct closure *cl) { struct bch_stripe *v = &buf->key.v; unsigned offset = 0, bytes = buf->size << 9; @@ -394,6 +395,7 @@ static void ec_block_io(struct bch_fs *c, struct ec_stripe_buf *buf, enum bch_data_type data_type = idx < buf->key.v.nr_blocks - buf->key.v.nr_redundant ? BCH_DATA_user : BCH_DATA_parity; + int rw = op_is_write(opf); if (ptr_stale(ca, ptr)) { bch_err_ratelimited(c, @@ -419,7 +421,7 @@ static void ec_block_io(struct bch_fs *c, struct ec_stripe_buf *buf, ec_bio = container_of(bio_alloc_bioset(ca->disk_sb.bdev, nr_iovecs, - rw, + opf, GFP_KERNEL, &c->ec_bioset), struct ec_bio, bio); @@ -1380,11 +1382,12 @@ void bch2_ec_stripe_head_put(struct bch_fs *c, struct ec_stripe_head *h) mutex_unlock(&h->lock); } -struct ec_stripe_head *__bch2_ec_stripe_head_get(struct btree_trans *trans, - unsigned target, - unsigned algo, - unsigned redundancy, - enum bch_watermark watermark) +static struct ec_stripe_head * +__bch2_ec_stripe_head_get(struct btree_trans *trans, + unsigned target, + unsigned algo, + unsigned redundancy, + enum bch_watermark watermark) { struct bch_fs *c = trans->c; struct ec_stripe_head *h; @@ -1570,7 +1573,7 @@ static int __bch2_ec_stripe_head_reuse(struct btree_trans *trans, struct ec_stri } BUG_ON(h->s->existing_stripe.size != h->blocksize); - BUG_ON(h->s->existing_stripe.size != h->s->existing_stripe.key.v.sectors); + BUG_ON(h->s->existing_stripe.size != le16_to_cpu(h->s->existing_stripe.key.v.sectors)); /* * Free buckets we initially allocated - they might conflict with diff --git a/libbcachefs/ec.h b/libbcachefs/ec.h index 64ca277..1b1848e 100644 --- a/libbcachefs/ec.h +++ b/libbcachefs/ec.h @@ -6,8 +6,10 @@ #include "buckets_types.h" #include "extents_types.h" +enum bkey_invalid_flags; + int bch2_stripe_invalid(const struct bch_fs *, struct bkey_s_c, - unsigned, struct printbuf *); + enum bkey_invalid_flags, struct printbuf *); void bch2_stripe_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); diff --git a/libbcachefs/extents.c b/libbcachefs/extents.c index 7e00550..c13e0af 100644 --- a/libbcachefs/extents.c +++ b/libbcachefs/extents.c @@ -163,7 +163,8 @@ int bch2_bkey_pick_read_device(struct bch_fs *c, struct bkey_s_c k, /* KEY_TYPE_btree_ptr: */ int bch2_btree_ptr_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { if (bkey_val_u64s(k.k) > BCH_REPLICAS_MAX) { prt_printf(err, "value too big (%zu > %u)", @@ -181,7 +182,8 @@ void bch2_btree_ptr_to_text(struct printbuf *out, struct bch_fs *c, } int bch2_btree_ptr_v2_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { if (bkey_val_u64s(k.k) > BKEY_BTREE_PTR_VAL_U64s_MAX) { prt_printf(err, "value too big (%zu > %zu)", @@ -216,7 +218,7 @@ void bch2_btree_ptr_v2_compat(enum btree_id btree_id, unsigned version, compat_bpos(0, btree_id, version, big_endian, write, &bp.v->min_key); if (version < bcachefs_metadata_version_inode_btree_change && - btree_node_type_is_extents(btree_id) && + btree_id_is_extents(btree_id) && !bkey_eq(bp.v->min_key, POS_MIN)) bp.v->min_key = write ? bpos_nosnap_predecessor(bp.v->min_key) @@ -371,7 +373,8 @@ bool bch2_extent_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_c r) /* KEY_TYPE_reservation: */ int bch2_reservation_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_s_c_reservation r = bkey_s_c_to_reservation(k); @@ -514,7 +517,7 @@ static void bch2_extent_crc_pack(union bch_extent_crc *dst, switch (type) { case BCH_EXTENT_ENTRY_crc32: set_common_fields(dst->crc32, src); - dst->crc32.csum = *((__le32 *) &src.csum.lo); + memcpy(&dst->crc32.csum, &src.csum.lo, sizeof(dst->crc32.csum)); break; case BCH_EXTENT_ENTRY_crc64: set_common_fields(dst->crc64, src); @@ -1103,7 +1106,8 @@ static int extent_ptr_invalid(const struct bch_fs *c, } int bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k); const union bch_extent_entry *entry; @@ -1202,6 +1206,8 @@ int bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k, } have_ec = true; break; + case BCH_EXTENT_ENTRY_rebalance: + break; } } @@ -1260,6 +1266,8 @@ void bch2_ptr_swab(struct bkey_s k) break; case BCH_EXTENT_ENTRY_stripe_ptr: break; + case BCH_EXTENT_ENTRY_rebalance: + break; } } } @@ -1310,6 +1318,8 @@ int bch2_cut_front_s(struct bpos where, struct bkey_s k) break; case BCH_EXTENT_ENTRY_stripe_ptr: break; + case BCH_EXTENT_ENTRY_rebalance: + break; } if (extent_entry_is_crc(entry)) diff --git a/libbcachefs/extents.h b/libbcachefs/extents.h index 3ba41e3..d359b3f 100644 --- a/libbcachefs/extents.h +++ b/libbcachefs/extents.h @@ -8,6 +8,7 @@ struct bch_fs; struct btree_trans; +enum bkey_invalid_flags; /* extent entries: */ @@ -154,11 +155,7 @@ bch2_extent_crc_unpack(const struct bkey *k, const union bch_extent_crc *crc) common_fields(crc->crc32), }; - *((__le32 *) &ret.csum.lo) = crc->crc32.csum; - - memcpy(&ret.csum.lo, &crc->crc32.csum, - sizeof(crc->crc32.csum)); - + memcpy(&ret.csum.lo, &crc->crc32.csum, sizeof(crc->crc32.csum)); return ret; } case BCH_EXTENT_ENTRY_crc64: { @@ -168,8 +165,8 @@ bch2_extent_crc_unpack(const struct bkey *k, const union bch_extent_crc *crc) .csum.lo = (__force __le64) crc->crc64.csum_lo, }; - *((__le16 *) &ret.csum.hi) = crc->crc64.csum_hi; - + u16 hi = crc->crc64.csum_hi; + memcpy(&ret.csum.hi, &hi, sizeof(hi)); return ret; } case BCH_EXTENT_ENTRY_crc128: { @@ -318,6 +315,9 @@ static inline struct bkey_ptrs bch2_bkey_ptrs(struct bkey_s k) (_ptr).ec = _entry->stripe_ptr; \ (_ptr).has_ec = true; \ break; \ + default: \ + /* nothing */ \ + break; \ } \ out: \ _entry < (_end); \ @@ -383,11 +383,13 @@ int bch2_bkey_pick_read_device(struct bch_fs *, struct bkey_s_c, /* KEY_TYPE_btree_ptr: */ -int bch2_btree_ptr_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); +int bch2_btree_ptr_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); -int bch2_btree_ptr_v2_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); +int bch2_btree_ptr_v2_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); void bch2_btree_ptr_v2_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned, int, struct bkey_s); @@ -427,7 +429,7 @@ bool bch2_extent_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); /* KEY_TYPE_reservation: */ int bch2_reservation_invalid(const struct bch_fs *, struct bkey_s_c, - unsigned, struct printbuf *); + enum bkey_invalid_flags, struct printbuf *); void bch2_reservation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); bool bch2_reservation_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); diff --git a/libbcachefs/fs-io.c b/libbcachefs/fs-io.c index 4585817..36e2886 100644 --- a/libbcachefs/fs-io.c +++ b/libbcachefs/fs-io.c @@ -458,7 +458,7 @@ enum bch_folio_sector_state { #undef x }; -const char * const bch2_folio_sector_states[] = { +static const char * const bch2_folio_sector_states[] = { #define x(n) #n, BCH_FOLIO_SECTOR_STATE() #undef x @@ -997,7 +997,7 @@ vm_fault_t bch2_page_fault(struct vm_fault *vmf) struct address_space *mapping = file->f_mapping; struct address_space *fdm = faults_disabled_mapping(); struct bch_inode_info *inode = file_bch_inode(file); - int ret; + vm_fault_t ret; if (fdm == mapping) return VM_FAULT_SIGBUS; @@ -1039,7 +1039,7 @@ vm_fault_t bch2_page_mkwrite(struct vm_fault *vmf) struct bch2_folio_reservation res; unsigned len; loff_t isize; - int ret; + vm_fault_t ret; bch2_folio_reservation_init(c, inode, &res); diff --git a/libbcachefs/fsck.c b/libbcachefs/fsck.c index 7af6503..98fde0b 100644 --- a/libbcachefs/fsck.c +++ b/libbcachefs/fsck.c @@ -1216,7 +1216,7 @@ static int check_overlapping_extents(struct btree_trans *trans, if (ret) break; - if (fsck_err(c, buf.buf)) { + if (fsck_err(c, "%s", buf.buf)) { struct bkey_i *update = bch2_trans_kmalloc(trans, bkey_bytes(k.k)); if ((ret = PTR_ERR_OR_ZERO(update))) goto err; @@ -1696,8 +1696,8 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, goto err; if (fsck_err_on(ret, c, - "dirent points to missing subvolume %llu", - le64_to_cpu(d.v->d_child_subvol))) { + "dirent points to missing subvolume %u", + le32_to_cpu(d.v->d_child_subvol))) { ret = __remove_dirent(trans, d.k->p); goto err; } @@ -2238,7 +2238,7 @@ static int check_nlinks_find_hardlinks(struct bch_fs *c, * Backpointer and directory structure checks are sufficient for * directories, since they can't have hardlinks: */ - if (S_ISDIR(le16_to_cpu(u.bi_mode))) + if (S_ISDIR(u.bi_mode)) continue; if (!u.bi_nlink) @@ -2324,7 +2324,7 @@ static int check_nlinks_update_inode(struct btree_trans *trans, struct btree_ite BUG_ON(bch2_inode_unpack(k, &u)); - if (S_ISDIR(le16_to_cpu(u.bi_mode))) + if (S_ISDIR(u.bi_mode)) return 0; if (!u.bi_nlink) diff --git a/libbcachefs/inode.c b/libbcachefs/inode.c index 64e8d1f..fa435d8 100644 --- a/libbcachefs/inode.c +++ b/libbcachefs/inode.c @@ -432,7 +432,8 @@ static int __bch2_inode_invalid(struct bkey_s_c k, struct printbuf *err) } int bch2_inode_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_s_c_inode inode = bkey_s_c_to_inode(k); @@ -446,7 +447,8 @@ int bch2_inode_invalid(const struct bch_fs *c, struct bkey_s_c k, } int bch2_inode_v2_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_s_c_inode_v2 inode = bkey_s_c_to_inode_v2(k); @@ -460,7 +462,8 @@ int bch2_inode_v2_invalid(const struct bch_fs *c, struct bkey_s_c k, } int bch2_inode_v3_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_s_c_inode_v3 inode = bkey_s_c_to_inode_v3(k); @@ -517,7 +520,8 @@ void bch2_inode_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c } int bch2_inode_generation_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { if (k.k->p.inode) { prt_printf(err, "nonzero k.p.inode"); diff --git a/libbcachefs/inode.h b/libbcachefs/inode.h index 0c3022d..8f9be5e 100644 --- a/libbcachefs/inode.h +++ b/libbcachefs/inode.h @@ -5,11 +5,15 @@ #include "bkey.h" #include "opts.h" +enum bkey_invalid_flags; extern const char * const bch2_inode_opts[]; -int bch2_inode_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); -int bch2_inode_v2_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); -int bch2_inode_v3_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); +int bch2_inode_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); +int bch2_inode_v2_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); +int bch2_inode_v3_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_ops_inode ((struct bkey_ops) { \ @@ -44,7 +48,7 @@ static inline bool bkey_is_inode(const struct bkey *k) } int bch2_inode_generation_invalid(const struct bch_fs *, struct bkey_s_c, - unsigned, struct printbuf *); + enum bkey_invalid_flags, struct printbuf *); void bch2_inode_generation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_ops_inode_generation ((struct bkey_ops) { \ diff --git a/libbcachefs/io.c b/libbcachefs/io.c index e87c0a7..0e9c23b 100644 --- a/libbcachefs/io.c +++ b/libbcachefs/io.c @@ -1696,7 +1696,7 @@ again: &op->devs_have, op->nr_replicas, op->nr_replicas_required, - op->alloc_reserve, + op->watermark, op->flags, (op->flags & (BCH_WRITE_ALLOC_NOWAIT| BCH_WRITE_ONLY_SPECIFIED_DEVS)) @@ -1878,7 +1878,7 @@ err: op->end_io(op); } -const char * const bch2_write_flags[] = { +static const char * const bch2_write_flags[] = { #define x(f) #f, BCH_WRITE_FLAGS() #undef x diff --git a/libbcachefs/io.h b/libbcachefs/io.h index 87e1305..7a243a5 100644 --- a/libbcachefs/io.h +++ b/libbcachefs/io.h @@ -59,7 +59,7 @@ enum bch_write_flags { static inline struct workqueue_struct *index_update_wq(struct bch_write_op *op) { - return op->alloc_reserve == BCH_WATERMARK_copygc + return op->watermark == BCH_WATERMARK_copygc ? op->c->copygc_wq : op->c->btree_update_wq; } @@ -89,7 +89,7 @@ static inline void bch2_write_op_init(struct bch_write_op *op, struct bch_fs *c, op->compression_type = bch2_compression_opt_to_type[opts.compression]; op->nr_replicas = 0; op->nr_replicas_required = c->opts.data_replicas_required; - op->alloc_reserve = BCH_WATERMARK_normal; + op->watermark = BCH_WATERMARK_normal; op->incompressible = 0; op->open_buckets.nr = 0; op->devs_have.nr = 0; diff --git a/libbcachefs/io_types.h b/libbcachefs/io_types.h index 4149291..0fbdfbf 100644 --- a/libbcachefs/io_types.h +++ b/libbcachefs/io_types.h @@ -119,7 +119,7 @@ struct bch_write_op { unsigned compression_type:4; unsigned nr_replicas:4; unsigned nr_replicas_required:4; - unsigned alloc_reserve:3; + unsigned watermark:3; unsigned incompressible:1; unsigned stripe_waited:1; diff --git a/libbcachefs/journal.c b/libbcachefs/journal.c index dc34aba..f33ab45 100644 --- a/libbcachefs/journal.c +++ b/libbcachefs/journal.c @@ -19,17 +19,12 @@ #include "journal_seq_blacklist.h" #include "trace.h" -#define x(n) #n, -static const char * const bch2_journal_watermarks[] = { - JOURNAL_WATERMARKS() - NULL -}; - static const char * const bch2_journal_errors[] = { +#define x(n) #n, JOURNAL_ERRORS() +#undef x NULL }; -#undef x static inline bool journal_seq_unwritten(struct journal *j, u64 seq) { @@ -96,7 +91,7 @@ journal_error_check_stuck(struct journal *j, int error, unsigned flags) if (!(error == JOURNAL_ERR_journal_full || error == JOURNAL_ERR_journal_pin_full) || nr_unwritten_journal_entries(j) || - (flags & JOURNAL_WATERMARK_MASK) != JOURNAL_WATERMARK_reserved) + (flags & BCH_WATERMARK_MASK) != BCH_WATERMARK_reclaim) return stuck; spin_lock(&j->lock); @@ -440,7 +435,7 @@ retry: return 0; } - if ((flags & JOURNAL_WATERMARK_MASK) < j->watermark) { + if ((flags & BCH_WATERMARK_MASK) < j->watermark) { /* * Don't want to close current journal entry, just need to * invoke reclaim: @@ -1292,7 +1287,7 @@ void __bch2_journal_debug_to_text(struct printbuf *out, struct journal *j) prt_printf(out, "last_seq_ondisk:\t%llu\n", j->last_seq_ondisk); prt_printf(out, "flushed_seq_ondisk:\t%llu\n", j->flushed_seq_ondisk); prt_printf(out, "prereserved:\t\t%u/%u\n", j->prereserved.reserved, j->prereserved.remaining); - prt_printf(out, "watermark:\t\t%s\n", bch2_journal_watermarks[j->watermark]); + prt_printf(out, "watermark:\t\t%s\n", bch2_watermarks[j->watermark]); prt_printf(out, "each entry reserved:\t%u\n", j->entry_u64s_reserved); prt_printf(out, "nr flush writes:\t%llu\n", j->nr_flush_writes); prt_printf(out, "nr noflush writes:\t%llu\n", j->nr_noflush_writes); diff --git a/libbcachefs/journal.h b/libbcachefs/journal.h index 024cea9..008a2e2 100644 --- a/libbcachefs/journal.h +++ b/libbcachefs/journal.h @@ -294,9 +294,14 @@ static inline void bch2_journal_res_put(struct journal *j, int bch2_journal_res_get_slowpath(struct journal *, struct journal_res *, unsigned); -/* First two bits for JOURNAL_WATERMARK: */ -#define JOURNAL_RES_GET_NONBLOCK (1 << 2) -#define JOURNAL_RES_GET_CHECK (1 << 3) +/* First bits for BCH_WATERMARK: */ +enum journal_res_flags { + __JOURNAL_RES_GET_NONBLOCK = BCH_WATERMARK_BITS, + __JOURNAL_RES_GET_CHECK, +}; + +#define JOURNAL_RES_GET_NONBLOCK (1 << __JOURNAL_RES_GET_NONBLOCK) +#define JOURNAL_RES_GET_CHECK (1 << __JOURNAL_RES_GET_CHECK) static inline int journal_res_get_fast(struct journal *j, struct journal_res *res, @@ -317,7 +322,7 @@ static inline int journal_res_get_fast(struct journal *j, EBUG_ON(!journal_state_count(new, new.idx)); - if ((flags & JOURNAL_WATERMARK_MASK) < j->watermark) + if ((flags & BCH_WATERMARK_MASK) < j->watermark) return 0; new.cur_entry_offset += res->u64s; @@ -373,17 +378,17 @@ out: static inline void journal_set_watermark(struct journal *j) { union journal_preres_state s = READ_ONCE(j->prereserved); - unsigned watermark = JOURNAL_WATERMARK_any; + unsigned watermark = BCH_WATERMARK_stripe; if (fifo_free(&j->pin) < j->pin.size / 4) - watermark = max_t(unsigned, watermark, JOURNAL_WATERMARK_copygc); + watermark = max_t(unsigned, watermark, BCH_WATERMARK_copygc); if (fifo_free(&j->pin) < j->pin.size / 8) - watermark = max_t(unsigned, watermark, JOURNAL_WATERMARK_reserved); + watermark = max_t(unsigned, watermark, BCH_WATERMARK_reclaim); if (s.reserved > s.remaining) - watermark = max_t(unsigned, watermark, JOURNAL_WATERMARK_copygc); + watermark = max_t(unsigned, watermark, BCH_WATERMARK_copygc); if (!s.remaining) - watermark = max_t(unsigned, watermark, JOURNAL_WATERMARK_reserved); + watermark = max_t(unsigned, watermark, BCH_WATERMARK_reclaim); if (watermark == j->watermark) return; @@ -426,13 +431,14 @@ static inline int bch2_journal_preres_get_fast(struct journal *j, int d = new_u64s - res->u64s; union journal_preres_state old, new; u64 v = atomic64_read(&j->prereserved.counter); + enum bch_watermark watermark = flags & BCH_WATERMARK_MASK; int ret; do { old.v = new.v = v; ret = 0; - if ((flags & JOURNAL_WATERMARK_reserved) || + if (watermark == BCH_WATERMARK_reclaim || new.reserved + d < new.remaining) { new.reserved += d; ret = 1; diff --git a/libbcachefs/journal_io.c b/libbcachefs/journal_io.c index 8dc3786..c7c2ae3 100644 --- a/libbcachefs/journal_io.c +++ b/libbcachefs/journal_io.c @@ -340,7 +340,8 @@ static int journal_entry_btree_keys_validate(struct bch_fs *c, int ret = journal_validate_key(c, jset, entry, entry->level, entry->btree_id, - k, version, big_endian, write|BKEY_INVALID_FROM_JOURNAL); + k, version, big_endian, + write|BKEY_INVALID_JOURNAL); if (ret == FSCK_DELETED_KEY) continue; @@ -745,14 +746,10 @@ static int jset_validate(struct bch_fs *c, return JOURNAL_ENTRY_NONE; version = le32_to_cpu(jset->version); - if (journal_entry_err_on((version != BCH_JSET_VERSION_OLD && - version < bcachefs_metadata_version_min) || - version >= bcachefs_metadata_version_max, - c, jset, NULL, - "%s sector %llu seq %llu: unknown journal entry version %u", + if (journal_entry_err_on(!bch2_version_compatible(version), c, jset, NULL, + "%s sector %llu seq %llu: incompatible journal entry version %u", ca ? ca->name : c->name, - sector, le64_to_cpu(jset->seq), - version)) { + sector, le64_to_cpu(jset->seq), version)) { /* don't try to continue: */ return -EINVAL; } @@ -796,14 +793,10 @@ static int jset_validate_early(struct bch_fs *c, return JOURNAL_ENTRY_NONE; version = le32_to_cpu(jset->version); - if (journal_entry_err_on((version != BCH_JSET_VERSION_OLD && - version < bcachefs_metadata_version_min) || - version >= bcachefs_metadata_version_max, - c, jset, NULL, + if (journal_entry_err_on(!bch2_version_compatible(version), c, jset, NULL, "%s sector %llu seq %llu: unknown journal entry version %u", ca ? ca->name : c->name, - sector, le64_to_cpu(jset->seq), - version)) { + sector, le64_to_cpu(jset->seq), version)) { /* don't try to continue: */ return -EINVAL; } @@ -1505,7 +1498,7 @@ static void journal_write_done(struct closure *cl) * Must come before signaling write completion, for * bch2_fs_journal_stop(): */ - if (j->watermark) + if (j->watermark != BCH_WATERMARK_stripe) journal_reclaim_kick(&c->journal); /* also must come before signalling write completion: */ @@ -1755,9 +1748,7 @@ void bch2_journal_write(struct closure *cl) } jset->magic = cpu_to_le64(jset_magic(c)); - jset->version = c->sb.version < bcachefs_metadata_version_bkey_renumber - ? cpu_to_le32(BCH_JSET_VERSION_OLD) - : cpu_to_le32(c->sb.version); + jset->version = cpu_to_le32(c->sb.version); SET_JSET_BIG_ENDIAN(jset, CPU_BIG_ENDIAN); SET_JSET_CSUM_TYPE(jset, bch2_meta_checksum_type(c)); diff --git a/libbcachefs/journal_reclaim.c b/libbcachefs/journal_reclaim.c index 2c7f8ac..72486f1 100644 --- a/libbcachefs/journal_reclaim.c +++ b/libbcachefs/journal_reclaim.c @@ -361,7 +361,7 @@ void bch2_journal_pin_drop(struct journal *j, spin_unlock(&j->lock); } -enum journal_pin_type journal_pin_type(journal_pin_flush_fn fn) +static enum journal_pin_type journal_pin_type(journal_pin_flush_fn fn) { if (fn == bch2_btree_node_flush0 || fn == bch2_btree_node_flush1) @@ -837,8 +837,20 @@ int bch2_journal_flush_device_pins(struct journal *j, int dev_idx) mutex_lock(&c->replicas_gc_lock); bch2_replicas_gc_start(c, 1 << BCH_DATA_journal); - seq = 0; + /* + * Now that we've populated replicas_gc, write to the journal to mark + * active journal devices. This handles the case where the journal might + * be empty. Otherwise we could clear all journal replicas and + * temporarily put the fs into an unrecoverable state. Journal recovery + * expects to find devices marked for journal data on unclean mount. + */ + ret = bch2_journal_meta(&c->journal); + if (ret) { + mutex_unlock(&c->replicas_gc_lock); + return ret; + } + seq = 0; spin_lock(&j->lock); while (!ret) { struct bch_replicas_padded replicas; diff --git a/libbcachefs/journal_sb.c b/libbcachefs/journal_sb.c index fcefbbe..cc41bff 100644 --- a/libbcachefs/journal_sb.c +++ b/libbcachefs/journal_sb.c @@ -201,16 +201,16 @@ int bch2_journal_buckets_to_sb(struct bch_fs *c, struct bch_dev *ca, bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal); - j->d[dst].start = le64_to_cpu(buckets[0]); - j->d[dst].nr = le64_to_cpu(1); + j->d[dst].start = cpu_to_le64(buckets[0]); + j->d[dst].nr = cpu_to_le64(1); for (i = 1; i < nr; i++) { if (buckets[i] == buckets[i - 1] + 1) { le64_add_cpu(&j->d[dst].nr, 1); } else { dst++; - j->d[dst].start = le64_to_cpu(buckets[i]); - j->d[dst].nr = le64_to_cpu(1); + j->d[dst].start = cpu_to_le64(buckets[i]); + j->d[dst].nr = cpu_to_le64(1); } } diff --git a/libbcachefs/journal_types.h b/libbcachefs/journal_types.h index 8d8c0b3..42504e1 100644 --- a/libbcachefs/journal_types.h +++ b/libbcachefs/journal_types.h @@ -154,19 +154,6 @@ enum journal_flags { JOURNAL_NEED_FLUSH_WRITE, }; -#define JOURNAL_WATERMARKS() \ - x(any) \ - x(copygc) \ - x(reserved) - -enum journal_watermark { -#define x(n) JOURNAL_WATERMARK_##n, - JOURNAL_WATERMARKS() -#undef x -}; - -#define JOURNAL_WATERMARK_MASK 3 - /* Reasons we may fail to get a journal reservation: */ #define JOURNAL_ERRORS() \ x(ok) \ @@ -191,7 +178,7 @@ struct journal { struct { union journal_res_state reservations; - enum journal_watermark watermark; + enum bch_watermark watermark; union journal_preres_state prereserved; diff --git a/libbcachefs/lru.c b/libbcachefs/lru.c index d324251..2387e08 100644 --- a/libbcachefs/lru.c +++ b/libbcachefs/lru.c @@ -11,7 +11,8 @@ /* KEY_TYPE_lru is obsolete: */ int bch2_lru_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { if (!lru_pos_time(k.k->p)) { prt_printf(err, "lru entry at time=0"); diff --git a/libbcachefs/lru.h b/libbcachefs/lru.h index adb9842..7a3be20 100644 --- a/libbcachefs/lru.h +++ b/libbcachefs/lru.h @@ -43,7 +43,8 @@ static inline enum bch_lru_type lru_type(struct bkey_s_c l) return BCH_LRU_read; } -int bch2_lru_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); +int bch2_lru_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); void bch2_lru_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_lru_pos_to_text(struct printbuf *, struct bpos); diff --git a/libbcachefs/migrate.c b/libbcachefs/migrate.c index 783e944..81c8cdb 100644 --- a/libbcachefs/migrate.c +++ b/libbcachefs/migrate.c @@ -141,7 +141,7 @@ retry: break; } - ret = bch2_btree_node_update_key(&trans, &iter, b, k.k, false); + ret = bch2_btree_node_update_key(&trans, &iter, b, k.k, 0, false); if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) { ret = 0; continue; diff --git a/libbcachefs/move.c b/libbcachefs/move.c index 37fb378..0527267 100644 --- a/libbcachefs/move.c +++ b/libbcachefs/move.c @@ -632,7 +632,7 @@ int bch2_move_data(struct bch_fs *c, bch2_moving_ctxt_init(&ctxt, c, rate, stats, wp, wait_on_copygc); for (id = start_btree_id; - id <= min_t(unsigned, end_btree_id, BTREE_ID_NR - 1); + id <= min_t(unsigned, end_btree_id, btree_id_nr_alive(c) - 1); id++) { stats->btree_id = id; @@ -640,6 +640,9 @@ int bch2_move_data(struct bch_fs *c, id != BTREE_ID_reflink) continue; + if (!bch2_btree_id_root(c, id)->b) + continue; + ret = __bch2_move_data(&ctxt, id == start_btree_id ? start_pos : POS_MIN, id == end_btree_id ? end_pos : POS_MAX, @@ -861,10 +864,13 @@ static int bch2_move_btree(struct bch_fs *c, stats->data_type = BCH_DATA_btree; for (id = start_btree_id; - id <= min_t(unsigned, end_btree_id, BTREE_ID_NR - 1); + id <= min_t(unsigned, end_btree_id, btree_id_nr_alive(c) - 1); id++) { stats->btree_id = id; + if (!bch2_btree_id_root(c, id)->b) + continue; + bch2_trans_node_iter_init(&trans, &iter, id, POS_MIN, 0, 0, BTREE_ITER_PREFETCH); retry: diff --git a/libbcachefs/movinggc.c b/libbcachefs/movinggc.c index 5ea5129..5242f20 100644 --- a/libbcachefs/movinggc.c +++ b/libbcachefs/movinggc.c @@ -202,7 +202,7 @@ static int bch2_copygc(struct btree_trans *trans, { struct bch_fs *c = trans->c; struct data_update_opts data_opts = { - .btree_insert_flags = BTREE_INSERT_USE_RESERVE|JOURNAL_WATERMARK_copygc, + .btree_insert_flags = BCH_WATERMARK_copygc, }; move_buckets buckets = { 0 }; struct move_bucket_in_flight *f; diff --git a/libbcachefs/opts.c b/libbcachefs/opts.c index 04e2989..a05c389 100644 --- a/libbcachefs/opts.c +++ b/libbcachefs/opts.c @@ -11,11 +11,6 @@ #define x(t, n) [n] = #t, -const char * const bch2_metadata_versions[] = { - BCH_METADATA_VERSIONS() - NULL -}; - const char * const bch2_error_actions[] = { BCH_ERROR_ACTIONS() NULL diff --git a/libbcachefs/opts.h b/libbcachefs/opts.h index 719693b..e7cf7e9 100644 --- a/libbcachefs/opts.h +++ b/libbcachefs/opts.h @@ -8,7 +8,6 @@ #include #include "bcachefs_format.h" -extern const char * const bch2_metadata_versions[]; extern const char * const bch2_error_actions[]; extern const char * const bch2_sb_features[]; extern const char * const bch2_sb_compat[]; diff --git a/libbcachefs/quota.c b/libbcachefs/quota.c index 7e1f182..d90db3f 100644 --- a/libbcachefs/quota.c +++ b/libbcachefs/quota.c @@ -60,7 +60,8 @@ const struct bch_sb_field_ops bch_sb_field_ops_quota = { }; int bch2_quota_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { if (k.k->p.inode >= QTYP_NR) { prt_printf(err, "invalid quota type (%llu >= %u)", @@ -480,13 +481,13 @@ static int __bch2_quota_set(struct bch_fs *c, struct bkey_s_c k, } if (qdq && qdq->d_fieldmask & QC_SPC_TIMER) - mq->c[Q_SPC].timer = cpu_to_le64(qdq->d_spc_timer); + mq->c[Q_SPC].timer = qdq->d_spc_timer; if (qdq && qdq->d_fieldmask & QC_SPC_WARNS) - mq->c[Q_SPC].warns = cpu_to_le64(qdq->d_spc_warns); + mq->c[Q_SPC].warns = qdq->d_spc_warns; if (qdq && qdq->d_fieldmask & QC_INO_TIMER) - mq->c[Q_INO].timer = cpu_to_le64(qdq->d_ino_timer); + mq->c[Q_INO].timer = qdq->d_ino_timer; if (qdq && qdq->d_fieldmask & QC_INO_WARNS) - mq->c[Q_INO].warns = cpu_to_le64(qdq->d_ino_warns); + mq->c[Q_INO].warns = qdq->d_ino_warns; mutex_unlock(&q->lock); } diff --git a/libbcachefs/quota.h b/libbcachefs/quota.h index b0f7d4e..2f46387 100644 --- a/libbcachefs/quota.h +++ b/libbcachefs/quota.h @@ -5,9 +5,11 @@ #include "inode.h" #include "quota_types.h" +enum bkey_invalid_flags; extern const struct bch_sb_field_ops bch_sb_field_ops_quota; -int bch2_quota_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); +int bch2_quota_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_ops_quota ((struct bkey_ops) { \ diff --git a/libbcachefs/recovery.c b/libbcachefs/recovery.c index 09c9d40..9b49a6b 100644 --- a/libbcachefs/recovery.c +++ b/libbcachefs/recovery.c @@ -308,7 +308,7 @@ static void bch2_journal_iter_advance(struct journal_iter *iter) } } -struct bkey_s_c bch2_journal_iter_peek(struct journal_iter *iter) +static struct bkey_s_c bch2_journal_iter_peek(struct journal_iter *iter) { struct journal_key *k = iter->keys->d + iter->idx; @@ -664,7 +664,7 @@ static int bch2_journal_replay(struct bch_fs *c, u64 start_seq, u64 end_seq) BTREE_INSERT_LAZY_RW| BTREE_INSERT_NOFAIL| (!k->allocated - ? BTREE_INSERT_JOURNAL_REPLAY|JOURNAL_WATERMARK_reserved + ? BTREE_INSERT_JOURNAL_REPLAY|BCH_WATERMARK_reclaim : 0), bch2_journal_replay_key(&trans, k)); if (ret) { @@ -702,13 +702,13 @@ static int journal_replay_entry_early(struct bch_fs *c, case BCH_JSET_ENTRY_btree_root: { struct btree_root *r; - if (entry->btree_id >= BTREE_ID_NR) { - bch_err(c, "filesystem has unknown btree type %u", - entry->btree_id); - return -EINVAL; + while (entry->btree_id >= c->btree_roots_extra.nr + BTREE_ID_NR) { + ret = darray_push(&c->btree_roots_extra, (struct btree_root) { NULL }); + if (ret) + return ret; } - r = &c->btree_roots[entry->btree_id]; + r = bch2_btree_id_root(c, entry->btree_id); if (entry->u64s) { r->level = entry->level; @@ -980,8 +980,8 @@ static int read_btree_roots(struct bch_fs *c) unsigned i; int ret = 0; - for (i = 0; i < BTREE_ID_NR; i++) { - struct btree_root *r = &c->btree_roots[i]; + for (i = 0; i < btree_id_nr_alive(c); i++) { + struct btree_root *r = bch2_btree_id_root(c, i); if (!r->alive) continue; @@ -1014,7 +1014,7 @@ static int read_btree_roots(struct bch_fs *c) } for (i = 0; i < BTREE_ID_NR; i++) { - struct btree_root *r = &c->btree_roots[i]; + struct btree_root *r = bch2_btree_id_root(c, i); if (!r->b) { r->alive = false; @@ -1042,7 +1042,7 @@ static int bch2_fs_initialize_subvolumes(struct bch_fs *c) root_snapshot.k.p.offset = U32_MAX; root_snapshot.v.flags = 0; root_snapshot.v.parent = 0; - root_snapshot.v.subvol = BCACHEFS_ROOT_SUBVOL; + root_snapshot.v.subvol = cpu_to_le32(BCACHEFS_ROOT_SUBVOL); root_snapshot.v.tree = cpu_to_le32(1); SET_BCH_SNAPSHOT_SUBVOL(&root_snapshot.v, true); @@ -1146,17 +1146,22 @@ int bch2_fs_recovery(struct bch_fs *c) goto err; } - if (!c->opts.nochanges) { - if (c->sb.version < bcachefs_metadata_required_upgrade_below) { - bch_info(c, "version %s (%u) prior to %s (%u), upgrade and fsck required", - bch2_metadata_versions[c->sb.version], - c->sb.version, - bch2_metadata_versions[bcachefs_metadata_required_upgrade_below], - bcachefs_metadata_required_upgrade_below); - c->opts.version_upgrade = true; - c->opts.fsck = true; - c->opts.fix_errors = FSCK_OPT_YES; - } + if (!c->opts.nochanges && + c->sb.version < bcachefs_metadata_required_upgrade_below) { + struct printbuf buf = PRINTBUF; + + prt_str(&buf, "version "); + bch2_version_to_text(&buf, c->sb.version); + prt_str(&buf, " prior to "); + bch2_version_to_text(&buf, bcachefs_metadata_required_upgrade_below); + prt_str(&buf, ", upgrade and fsck required"); + + bch_info(c, "%s", buf.buf); + printbuf_exit(&buf); + + c->opts.version_upgrade = true; + c->opts.fsck = true; + c->opts.fix_errors = FSCK_OPT_YES; } if (c->opts.fsck && c->opts.norecovery) { @@ -1463,7 +1468,7 @@ use_clean: if (!(c->sb.compat & (1ULL << BCH_COMPAT_extents_above_btree_updates_done)) || !(c->sb.compat & (1ULL << BCH_COMPAT_bformat_overflow_done)) || - le16_to_cpu(c->sb.version_min) < bcachefs_metadata_version_btree_ptr_sectors_written) { + c->sb.version_min < bcachefs_metadata_version_btree_ptr_sectors_written) { struct bch_move_stats stats; bch2_move_stats_init(&stats, "recovery"); diff --git a/libbcachefs/reflink.c b/libbcachefs/reflink.c index 537d84b..08a05cc 100644 --- a/libbcachefs/reflink.c +++ b/libbcachefs/reflink.c @@ -26,7 +26,8 @@ static inline unsigned bkey_type_to_indirect(const struct bkey *k) /* reflink pointers */ int bch2_reflink_p_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_s_c_reflink_p p = bkey_s_c_to_reflink_p(k); @@ -72,7 +73,8 @@ bool bch2_reflink_p_merge(struct bch_fs *c, struct bkey_s _l, struct bkey_s_c _r /* indirect extents */ int bch2_reflink_v_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { return bch2_bkey_ptrs_invalid(c, k, flags, err); } @@ -118,7 +120,8 @@ int bch2_trans_mark_reflink_v(struct btree_trans *trans, /* indirect inline data */ int bch2_indirect_inline_data_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { return 0; } diff --git a/libbcachefs/reflink.h b/libbcachefs/reflink.h index ba40018..fe52538 100644 --- a/libbcachefs/reflink.h +++ b/libbcachefs/reflink.h @@ -2,8 +2,10 @@ #ifndef _BCACHEFS_REFLINK_H #define _BCACHEFS_REFLINK_H +enum bkey_invalid_flags; + int bch2_reflink_p_invalid(const struct bch_fs *, struct bkey_s_c, - unsigned, struct printbuf *); + enum bkey_invalid_flags, struct printbuf *); void bch2_reflink_p_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); bool bch2_reflink_p_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); @@ -18,7 +20,7 @@ bool bch2_reflink_p_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); }) int bch2_reflink_v_invalid(const struct bch_fs *, struct bkey_s_c, - unsigned, struct printbuf *); + enum bkey_invalid_flags, struct printbuf *); void bch2_reflink_v_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); int bch2_trans_mark_reflink_v(struct btree_trans *, enum btree_id, unsigned, @@ -34,7 +36,7 @@ int bch2_trans_mark_reflink_v(struct btree_trans *, enum btree_id, unsigned, }) int bch2_indirect_inline_data_invalid(const struct bch_fs *, struct bkey_s_c, - unsigned, struct printbuf *); + enum bkey_invalid_flags, struct printbuf *); void bch2_indirect_inline_data_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); int bch2_trans_mark_indirect_inline_data(struct btree_trans *, diff --git a/libbcachefs/replicas.c b/libbcachefs/replicas.c index 76efbfc..d4c1d43 100644 --- a/libbcachefs/replicas.c +++ b/libbcachefs/replicas.c @@ -36,8 +36,8 @@ static void bch2_cpu_replicas_sort(struct bch_replicas_cpu *r) eytzinger0_sort(r->entries, r->nr, r->entry_size, memcmp, NULL); } -void bch2_replicas_entry_v0_to_text(struct printbuf *out, - struct bch_replicas_entry_v0 *e) +static void bch2_replicas_entry_v0_to_text(struct printbuf *out, + struct bch_replicas_entry_v0 *e) { unsigned i; @@ -272,7 +272,7 @@ static void __replicas_table_update_pcpu(struct bch_fs_usage __percpu *dst_p, { unsigned src_nr = sizeof(struct bch_fs_usage) / sizeof(u64) + src_r->nr; struct bch_fs_usage *dst, *src = (void *) - bch2_acc_percpu_u64s((void *) src_p, src_nr); + bch2_acc_percpu_u64s((u64 __percpu *) src_p, src_nr); preempt_disable(); dst = this_cpu_ptr(dst_p); diff --git a/libbcachefs/subvolume.c b/libbcachefs/subvolume.c index 89c7c83..f26397a 100644 --- a/libbcachefs/subvolume.c +++ b/libbcachefs/subvolume.c @@ -23,7 +23,8 @@ void bch2_snapshot_tree_to_text(struct printbuf *out, struct bch_fs *c, } int bch2_snapshot_tree_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { if (bkey_gt(k.k->p, POS(0, U32_MAX)) || bkey_lt(k.k->p, POS(0, 1))) { @@ -97,7 +98,8 @@ void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c, } int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { struct bkey_s_c_snapshot s; u32 i, id; @@ -825,7 +827,7 @@ static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) goto err; if (s.v->children[0]) { - s_t->v.root_snapshot = cpu_to_le32(s.v->children[0]); + s_t->v.root_snapshot = s.v->children[0]; } else { s_t->k.type = KEY_TYPE_deleted; set_bkey_val_u64s(&s_t->k, 0); @@ -1328,7 +1330,7 @@ static int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid) __bch2_subvolume_delete(trans, subvolid)); } -void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work) +static void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work) { struct bch_fs *c = container_of(work, struct bch_fs, snapshot_wait_for_pagecache_and_delete_work); @@ -1366,7 +1368,7 @@ struct subvolume_unlink_hook { u32 subvol; }; -int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans, +static int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans, struct btree_trans_commit_hook *_h) { struct subvolume_unlink_hook *h = container_of(_h, struct subvolume_unlink_hook, h); diff --git a/libbcachefs/subvolume.h b/libbcachefs/subvolume.h index 1a39f71..105410e 100644 --- a/libbcachefs/subvolume.h +++ b/libbcachefs/subvolume.h @@ -5,9 +5,11 @@ #include "darray.h" #include "subvolume_types.h" +enum bkey_invalid_flags; + void bch2_snapshot_tree_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); int bch2_snapshot_tree_invalid(const struct bch_fs *, struct bkey_s_c, - unsigned, struct printbuf *); + enum bkey_invalid_flags, struct printbuf *); #define bch2_bkey_ops_snapshot_tree ((struct bkey_ops) { \ .key_invalid = bch2_snapshot_tree_invalid, \ @@ -19,7 +21,7 @@ int bch2_snapshot_tree_lookup(struct btree_trans *, u32, struct bch_snapshot_tre void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); int bch2_snapshot_invalid(const struct bch_fs *, struct bkey_s_c, - unsigned, struct printbuf *); + enum bkey_invalid_flags, struct printbuf *); int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned, struct bkey_s_c, struct bkey_s_c, unsigned); diff --git a/libbcachefs/super-io.c b/libbcachefs/super-io.c index e5636c3..472f5b2 100644 --- a/libbcachefs/super-io.c +++ b/libbcachefs/super-io.c @@ -23,6 +23,21 @@ #include #include +static const char * const bch2_metadata_versions[] = { +#define x(t, n) [n] = #t, + BCH_METADATA_VERSIONS() +#undef x +}; + +void bch2_version_to_text(struct printbuf *out, unsigned v) +{ + const char *str = v < ARRAY_SIZE(bch2_metadata_versions) + ? bch2_metadata_versions[v] + : "(unknown version)"; + + prt_printf(out, "%u: %s", v, str); +} + const char * const bch2_sb_fields[] = { #define x(name, nr) #name, BCH_SB_FIELDS() @@ -250,40 +265,58 @@ static int validate_sb_layout(struct bch_sb_layout *layout, struct printbuf *out return 0; } -static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out, - int rw) +static int bch2_sb_compatible(struct bch_sb *sb, struct printbuf *out) { - struct bch_sb *sb = disk_sb->sb; - struct bch_sb_field *f; - struct bch_sb_field_members *mi; - enum bch_opt_id opt_id; - u32 version, version_min; - u16 block_size; - int ret; - - version = le16_to_cpu(sb->version); - version_min = version >= bcachefs_metadata_version_bkey_renumber - ? le16_to_cpu(sb->version_min) - : version; - - if (version >= bcachefs_metadata_version_max) { - prt_printf(out, "Unsupported superblock version %u (min %u, max %u)", - version, bcachefs_metadata_version_min, bcachefs_metadata_version_max); + u16 version = le16_to_cpu(sb->version); + u16 version_min = le16_to_cpu(sb->version_min); + + if (!bch2_version_compatible(version)) { + prt_str(out, "Unsupported superblock version "); + bch2_version_to_text(out, version); + prt_str(out, " (min "); + bch2_version_to_text(out, bcachefs_metadata_version_min); + prt_str(out, ", max "); + bch2_version_to_text(out, bcachefs_metadata_version_current); + prt_str(out, ")"); return -BCH_ERR_invalid_sb_version; } - if (version_min < bcachefs_metadata_version_min) { - prt_printf(out, "Unsupported superblock version %u (min %u, max %u)", - version_min, bcachefs_metadata_version_min, bcachefs_metadata_version_max); + if (!bch2_version_compatible(version_min)) { + prt_str(out, "Unsupported superblock version_min "); + bch2_version_to_text(out, version_min); + prt_str(out, " (min "); + bch2_version_to_text(out, bcachefs_metadata_version_min); + prt_str(out, ", max "); + bch2_version_to_text(out, bcachefs_metadata_version_current); + prt_str(out, ")"); return -BCH_ERR_invalid_sb_version; } if (version_min > version) { - prt_printf(out, "Bad minimum version %u, greater than version field %u", - version_min, version); + prt_str(out, "Bad minimum version "); + bch2_version_to_text(out, version_min); + prt_str(out, ", greater than version field "); + bch2_version_to_text(out, version); return -BCH_ERR_invalid_sb_version; } + return 0; +} + +static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out, + int rw) +{ + struct bch_sb *sb = disk_sb->sb; + struct bch_sb_field *f; + struct bch_sb_field_members *mi; + enum bch_opt_id opt_id; + u16 block_size; + int ret; + + ret = bch2_sb_compatible(sb, out); + if (ret) + return ret; + if (sb->features[1] || (le64_to_cpu(sb->features[0]) & (~0ULL << BCH_FEATURE_NR))) { prt_printf(out, "Filesystem has incompatible features"); @@ -331,7 +364,7 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out, if (rw == READ) { /* * Been seeing a bug where these are getting inexplicably - * zeroed, so we'r now validating them, but we have to be + * zeroed, so we're now validating them, but we have to be * careful not to preven people's filesystems from mounting: */ if (!BCH_SB_JOURNAL_FLUSH_DELAY(sb)) @@ -512,7 +545,6 @@ int bch2_sb_from_fs(struct bch_fs *c, struct bch_dev *ca) static int read_one_super(struct bch_sb_handle *sb, u64 offset, struct printbuf *err) { struct bch_csum csum; - u32 version, version_min; size_t bytes; int ret; reread: @@ -532,22 +564,9 @@ reread: return -BCH_ERR_invalid_sb_magic; } - version = le16_to_cpu(sb->sb->version); - version_min = version >= bcachefs_metadata_version_bkey_renumber - ? le16_to_cpu(sb->sb->version_min) - : version; - - if (version >= bcachefs_metadata_version_max) { - prt_printf(err, "Unsupported superblock version %u (min %u, max %u)", - version, bcachefs_metadata_version_min, bcachefs_metadata_version_max); - return -BCH_ERR_invalid_sb_version; - } - - if (version_min < bcachefs_metadata_version_min) { - prt_printf(err, "Unsupported superblock version %u (min %u, max %u)", - version_min, bcachefs_metadata_version_min, bcachefs_metadata_version_max); - return -BCH_ERR_invalid_sb_version; - } + ret = bch2_sb_compatible(sb->sb, err); + if (ret) + return ret; bytes = vstruct_bytes(sb->sb); @@ -1389,21 +1408,29 @@ static const struct bch_sb_field_ops *bch2_sb_field_ops[] = { #undef x }; +static const struct bch_sb_field_ops bch2_sb_field_null_ops = { + NULL +}; + +static const struct bch_sb_field_ops *bch2_sb_field_type_ops(unsigned type) +{ + return likely(type < ARRAY_SIZE(bch2_sb_field_ops)) + ? bch2_sb_field_ops[type] + : &bch2_sb_field_null_ops; +} + static int bch2_sb_field_validate(struct bch_sb *sb, struct bch_sb_field *f, struct printbuf *err) { unsigned type = le32_to_cpu(f->type); struct printbuf field_err = PRINTBUF; + const struct bch_sb_field_ops *ops = bch2_sb_field_type_ops(type); int ret; - if (type >= BCH_SB_FIELD_NR) - return 0; - - ret = bch2_sb_field_ops[type]->validate(sb, f, &field_err); + ret = ops->validate ? ops->validate(sb, f, &field_err) : 0; if (ret) { prt_printf(err, "Invalid superblock section %s: %s", - bch2_sb_fields[type], - field_err.buf); + bch2_sb_fields[type], field_err.buf); prt_newline(err); bch2_sb_field_to_text(err, sb, f); } @@ -1416,13 +1443,12 @@ void bch2_sb_field_to_text(struct printbuf *out, struct bch_sb *sb, struct bch_sb_field *f) { unsigned type = le32_to_cpu(f->type); - const struct bch_sb_field_ops *ops = type < BCH_SB_FIELD_NR - ? bch2_sb_field_ops[type] : NULL; + const struct bch_sb_field_ops *ops = bch2_sb_field_type_ops(type); if (!out->nr_tabstops) printbuf_tabstop_push(out, 32); - if (ops) + if (type < BCH_SB_FIELD_NR) prt_printf(out, "%s", bch2_sb_fields[type]); else prt_printf(out, "(unknown field %u)", type); @@ -1430,9 +1456,9 @@ void bch2_sb_field_to_text(struct printbuf *out, struct bch_sb *sb, prt_printf(out, " (size %zu):", vstruct_bytes(f)); prt_newline(out); - if (ops && ops->to_text) { + if (ops->to_text) { printbuf_indent_add(out, 2); - bch2_sb_field_ops[type]->to_text(out, sb, f); + ops->to_text(out, sb, f); printbuf_indent_sub(out, 2); } } @@ -1503,12 +1529,12 @@ void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb, prt_str(out, "Version:"); prt_tab(out); - prt_printf(out, "%s", bch2_metadata_versions[le16_to_cpu(sb->version)]); + bch2_version_to_text(out, le16_to_cpu(sb->version)); prt_newline(out); prt_printf(out, "Oldest version on disk:"); prt_tab(out); - prt_printf(out, "%s", bch2_metadata_versions[le16_to_cpu(sb->version_min)]); + bch2_version_to_text(out, le16_to_cpu(sb->version_min)); prt_newline(out); prt_printf(out, "Created:"); diff --git a/libbcachefs/super-io.h b/libbcachefs/super-io.h index ab0ad32..cda71ec 100644 --- a/libbcachefs/super-io.h +++ b/libbcachefs/super-io.h @@ -9,6 +9,14 @@ #include +static inline bool bch2_version_compatible(u16 version) +{ + return version <= bcachefs_metadata_version_current && + version >= bcachefs_metadata_version_min; +} + +void bch2_version_to_text(struct printbuf *, unsigned); + struct bch_sb_field *bch2_sb_field_get(struct bch_sb *, enum bch_sb_field_type); struct bch_sb_field *bch2_sb_field_resize(struct bch_sb_handle *, enum bch_sb_field_type, unsigned); diff --git a/libbcachefs/super.c b/libbcachefs/super.c index 99b7670..6fa805c 100644 --- a/libbcachefs/super.c +++ b/libbcachefs/super.c @@ -485,6 +485,7 @@ static void __bch2_fs_free(struct bch_fs *c) for_each_possible_cpu(cpu) kfree(per_cpu_ptr(c->btree_paths_bufs, cpu)->path); + darray_exit(&c->btree_roots_extra); free_percpu(c->btree_paths_bufs); free_percpu(c->pcpu); mempool_exit(&c->large_bkey_pool); @@ -560,9 +561,12 @@ void __bch2_fs_stop(struct bch_fs *c) cancel_work_sync(&c->read_only_work); - for (i = 0; i < c->sb.nr_devices; i++) - if (c->devs[i]) - bch2_free_super(&c->devs[i]->disk_sb); + for (i = 0; i < c->sb.nr_devices; i++) { + struct bch_dev *ca = rcu_dereference_protected(c->devs[i], true); + + if (ca) + bch2_free_super(&ca->disk_sb); + } } void bch2_fs_free(struct bch_fs *c) @@ -685,6 +689,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts) bch2_fs_copygc_init(c); bch2_fs_btree_key_cache_init_early(&c->btree_key_cache); + bch2_fs_btree_interior_update_init_early(c); bch2_fs_allocator_background_init(c); bch2_fs_allocator_foreground_init(c); bch2_fs_rebalance_init(c); @@ -751,11 +756,11 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts) goto err; /* Compat: */ - if (sb->version <= bcachefs_metadata_version_inode_v2 && + if (le16_to_cpu(sb->version) <= bcachefs_metadata_version_inode_v2 && !BCH_SB_JOURNAL_FLUSH_DELAY(sb)) SET_BCH_SB_JOURNAL_FLUSH_DELAY(sb, 1000); - if (sb->version <= bcachefs_metadata_version_inode_v2 && + if (le16_to_cpu(sb->version) <= bcachefs_metadata_version_inode_v2 && !BCH_SB_JOURNAL_RECLAIM_DELAY(sb)) SET_BCH_SB_JOURNAL_RECLAIM_DELAY(sb, 100); @@ -875,7 +880,8 @@ static void print_mount_opts(struct bch_fs *c) struct printbuf p = PRINTBUF; bool first = true; - prt_printf(&p, "mounted version=%s", bch2_metadata_versions[c->sb.version]); + prt_str(&p, "mounted version "); + bch2_version_to_text(&p, c->sb.version); if (c->opts.read_only) { prt_str(&p, " opts="); @@ -1520,6 +1526,17 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags) bch2_dev_free(ca); + /* + * At this point the device object has been removed in-core, but the + * on-disk journal might still refer to the device index via sb device + * usage entries. Recovery fails if it sees usage information for an + * invalid device. Flush journal pins to push the back of the journal + * past now invalid device index references before we update the + * superblock, but after the device object has been removed so any + * further journal writes elide usage info for the device. + */ + bch2_journal_flush_all_pins(&c->journal); + /* * Free this device's slot in the bch_member array - all pointers to * this device must be gone: @@ -1986,7 +2003,7 @@ err: BCH_DEBUG_PARAMS() #undef BCH_DEBUG_PARAM -unsigned bch2_metadata_version = bcachefs_metadata_version_current; +static unsigned bch2_metadata_version = bcachefs_metadata_version_current; module_param_named(version, bch2_metadata_version, uint, 0400); module_exit(bcachefs_exit); diff --git a/libbcachefs/sysfs.c b/libbcachefs/sysfs.c index 3145a0a..740305e 100644 --- a/libbcachefs/sysfs.c +++ b/libbcachefs/sysfs.c @@ -202,7 +202,7 @@ read_attribute(nocow_lock_table); #ifdef BCH_WRITE_REF_DEBUG read_attribute(write_refs); -const char * const bch2_write_refs[] = { +static const char * const bch2_write_refs[] = { #define x(n) #n, BCH_WRITE_REFS() #undef x diff --git a/libbcachefs/tests.c b/libbcachefs/tests.c index 50d69a5..cef23d2 100644 --- a/libbcachefs/tests.c +++ b/libbcachefs/tests.c @@ -444,7 +444,7 @@ static int test_peek_end_extents(struct bch_fs *c, u64 nr) /* extent unit tests */ -u64 test_version; +static u64 test_version; static int insert_test_extent(struct bch_fs *c, u64 start, u64 end) diff --git a/libbcachefs/varint.c b/libbcachefs/varint.c index 5143b60..ef030fc 100644 --- a/libbcachefs/varint.c +++ b/libbcachefs/varint.c @@ -22,12 +22,13 @@ int bch2_varint_encode(u8 *out, u64 v) { unsigned bits = fls64(v|1); unsigned bytes = DIV_ROUND_UP(bits, 7); + __le64 v_le; if (likely(bytes < 9)) { v <<= bytes; v |= ~(~0 << (bytes - 1)); - v = cpu_to_le64(v); - memcpy(out, &v, bytes); + v_le = cpu_to_le64(v); + memcpy(out, &v_le, bytes); } else { *out++ = 255; bytes = 9; @@ -57,9 +58,9 @@ int bch2_varint_decode(const u8 *in, const u8 *end, u64 *out) return -1; if (likely(bytes < 9)) { - v = 0; - memcpy(&v, in, bytes); - v = le64_to_cpu(v); + __le64 v_le = 0; + memcpy(&v_le, in, bytes); + v = le64_to_cpu(v_le); v >>= bytes; } else { v = get_unaligned_le64(++in); diff --git a/libbcachefs/xattr.c b/libbcachefs/xattr.c index 05c65d9..867cc68 100644 --- a/libbcachefs/xattr.c +++ b/libbcachefs/xattr.c @@ -70,7 +70,8 @@ const struct bch_hash_desc bch2_xattr_hash_desc = { }; int bch2_xattr_invalid(const struct bch_fs *c, struct bkey_s_c k, - unsigned flags, struct printbuf *err) + enum bkey_invalid_flags flags, + struct printbuf *err) { const struct xattr_handler *handler; struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr(k); @@ -135,15 +136,14 @@ static int bch2_xattr_get_trans(struct btree_trans *trans, struct bch_inode_info const char *name, void *buffer, size_t size, int type) { struct bch_hash_info hash = bch2_hash_info_init(trans->c, &inode->ei_inode); + struct xattr_search_key search = X_SEARCH(type, name, strlen(name)); struct btree_iter iter; struct bkey_s_c_xattr xattr; struct bkey_s_c k; int ret; ret = bch2_hash_lookup(trans, &iter, bch2_xattr_hash_desc, &hash, - inode_inum(inode), - &X_SEARCH(type, name, strlen(name)), - 0); + inode_inum(inode), &search, 0); if (ret) goto err1; diff --git a/libbcachefs/xattr.h b/libbcachefs/xattr.h index b3e1672..214cbba 100644 --- a/libbcachefs/xattr.h +++ b/libbcachefs/xattr.h @@ -6,7 +6,8 @@ extern const struct bch_hash_desc bch2_xattr_hash_desc; -int bch2_xattr_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); +int bch2_xattr_invalid(const struct bch_fs *, struct bkey_s_c, + enum bkey_invalid_flags, struct printbuf *); void bch2_xattr_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); #define bch2_bkey_ops_xattr ((struct bkey_ops) { \