diff options
-rw-r--r-- | .bcachefs_revision | 2 | ||||
-rw-r--r-- | bch_bindgen/build.rs | 1 | ||||
-rw-r--r-- | bch_bindgen/src/libbcachefs_wrapper.h | 1 | ||||
-rw-r--r-- | c_src/cmd_format.c | 3 | ||||
-rw-r--r-- | c_src/cmd_super.c | 93 | ||||
-rw-r--r-- | c_src/cmd_super.h | 8 | ||||
-rw-r--r-- | c_src/tools-util.c | 5 | ||||
-rw-r--r-- | libbcachefs/btree_cache.c | 2 | ||||
-rw-r--r-- | libbcachefs/btree_cache.h | 8 | ||||
-rw-r--r-- | libbcachefs/btree_gc.c | 38 | ||||
-rw-r--r-- | libbcachefs/btree_update.c | 6 | ||||
-rw-r--r-- | libbcachefs/btree_update_interior.c | 8 | ||||
-rw-r--r-- | libbcachefs/errcode.h | 1 | ||||
-rw-r--r-- | libbcachefs/fs.c | 4 | ||||
-rw-r--r-- | libbcachefs/fsck.c | 7 | ||||
-rw-r--r-- | libbcachefs/inode.c | 7 | ||||
-rw-r--r-- | libbcachefs/logged_ops.h | 2 | ||||
-rw-r--r-- | libbcachefs/sb-errors_format.h | 4 | ||||
-rw-r--r-- | libbcachefs/sb-members.c | 116 | ||||
-rw-r--r-- | libbcachefs/sb-members.h | 25 | ||||
-rw-r--r-- | libbcachefs/snapshot.c | 2 | ||||
-rw-r--r-- | src/device_scan.rs | 57 | ||||
-rw-r--r-- | src/rust_to_c.h | 17 |
23 files changed, 309 insertions, 108 deletions
diff --git a/.bcachefs_revision b/.bcachefs_revision index 738f6942..409a75d2 100644 --- a/.bcachefs_revision +++ b/.bcachefs_revision @@ -1 +1 @@ -86a9bf9142f7ff7c097951508b7662a8818492e1 +dca6a42b74674732d1d7683c282f6002752b2bda diff --git a/bch_bindgen/build.rs b/bch_bindgen/build.rs index 22d702b2..b9f7eb65 100644 --- a/bch_bindgen/build.rs +++ b/bch_bindgen/build.rs @@ -85,6 +85,7 @@ fn main() { .opaque_type("gc_stripe") .opaque_type("open_bucket.*") .opaque_type("replicas_delta_list") + .allowlist_type("sb_names") .no_copy("btree_trans") .no_copy("printbuf") .no_partialeq("bkey") diff --git a/bch_bindgen/src/libbcachefs_wrapper.h b/bch_bindgen/src/libbcachefs_wrapper.h index 128592c3..be9656f9 100644 --- a/bch_bindgen/src/libbcachefs_wrapper.h +++ b/bch_bindgen/src/libbcachefs_wrapper.h @@ -13,6 +13,7 @@ #include "include/linux/blkdev.h" #include "cmds.h" #include "raid/raid.h" +#include "src/rust_to_c.h" /* Fix753 is a workaround for https://github.com/rust-lang/rust-bindgen/issues/753 * Functional macro are not expanded with bindgen, e.g. ioctl are automatically ignored diff --git a/c_src/cmd_format.c b/c_src/cmd_format.c index 740b0e81..841a7913 100644 --- a/c_src/cmd_format.c +++ b/c_src/cmd_format.c @@ -21,6 +21,7 @@ #include <uuid/uuid.h> #include "cmds.h" +#include "cmd_super.h" #include "tools-util.h" #include "posix_to_bcachefs.h" #include "libbcachefs.h" @@ -293,7 +294,7 @@ int cmd_format(int argc, char *argv[]) struct printbuf buf = PRINTBUF; buf.human_readable_units = true; - bch2_sb_to_text(&buf, sb, false, 1 << BCH_SB_FIELD_members_v2); + bch2_sb_to_text_with_names(&buf, sb, false, 1 << BCH_SB_FIELD_members_v2, -1); printf("%s", buf.buf); printbuf_exit(&buf); } diff --git a/c_src/cmd_super.c b/c_src/cmd_super.c index 3161205f..00776b1b 100644 --- a/c_src/cmd_super.c +++ b/c_src/cmd_super.c @@ -21,6 +21,7 @@ #include <uuid/uuid.h> #include "cmds.h" +#include "cmd_super.h" #include "libbcachefs.h" #include "libbcachefs/opts.h" #include "libbcachefs/super-io.h" @@ -28,6 +29,8 @@ #include "libbcachefs/darray.h" +#include "src/rust_to_c.h" + static void show_super_usage(void) { puts("bcachefs show-super \n" @@ -42,6 +45,72 @@ static void show_super_usage(void) exit(EXIT_SUCCESS); } +static struct sb_name *sb_dev_to_name(sb_names sb_names, unsigned idx) +{ + darray_for_each(sb_names, i) + if (i->sb.sb->dev_idx == idx) + return i; + return NULL; +} + +static void print_one_member(struct printbuf *out, sb_names sb_names, + struct bch_sb *sb, + struct bch_sb_field_disk_groups *gi, + struct bch_member m, unsigned idx) +{ + struct sb_name *name = sb_dev_to_name(sb_names, idx); + prt_printf(out, "Device %u:\t%s\t", idx, name ? name->name : "(not found)"); + + if (name) { + char *model = fd_to_dev_model(name->sb.bdev->bd_fd); + prt_str(out, model); + free(model); + } + prt_newline(out); + + printbuf_indent_add(out, 2); + bch2_member_to_text(out, &m, gi, sb, idx); + printbuf_indent_sub(out, 2); +} + +void bch2_sb_to_text_with_names(struct printbuf *out, struct bch_sb *sb, + bool print_layout, unsigned fields, int field_only) +{ + CLASS(printbuf, uuid_buf)(); + prt_str(&uuid_buf, "UUID="); + pr_uuid(&uuid_buf, sb->user_uuid.b); + + sb_names sb_names = {}; + bch2_scan_device_sbs(uuid_buf.buf, &sb_names); + + if (field_only >= 0) { + struct bch_sb_field *f = bch2_sb_field_get_id(sb, field_only); + + if (f) + __bch2_sb_field_to_text(out, sb, f); + } else { + printbuf_tabstop_push(out, 44); + + bch2_sb_to_text(out, sb, print_layout, + fields & ~(BIT(BCH_SB_FIELD_members_v1)| + BIT(BCH_SB_FIELD_members_v2))); + + struct bch_sb_field_disk_groups *gi = bch2_sb_field_get(sb, disk_groups); + + struct bch_sb_field_members_v1 *mi1; + if ((fields & BIT(BCH_SB_FIELD_members_v1)) && + (mi1 = bch2_sb_field_get(sb, members_v1))) + for (unsigned i = 0; i < sb->nr_devices; i++) + print_one_member(out, sb_names, sb, gi, bch2_members_v1_get(mi1, i), i); + + struct bch_sb_field_members_v2 *mi2; + if ((fields & BIT(BCH_SB_FIELD_members_v2)) && + (mi2 = bch2_sb_field_get(sb, members_v2))) + for (unsigned i = 0; i < sb->nr_devices; i++) + print_one_member(out, sb_names, sb, gi, bch2_members_v2_get(mi2, i), i); + } +} + int cmd_show_super(int argc, char *argv[]) { static const struct option longopts[] = { @@ -98,32 +167,16 @@ int cmd_show_super(int argc, char *argv[]) if (print_default_fields) { fields |= bch2_sb_field_get(sb.sb, members_v2) - ? 1 << BCH_SB_FIELD_members_v2 - : 1 << BCH_SB_FIELD_members_v1; - fields |= 1 << BCH_SB_FIELD_errors; + ? BIT(BCH_SB_FIELD_members_v2) + : BIT(BCH_SB_FIELD_members_v1); + fields |= BIT(BCH_SB_FIELD_errors); } struct printbuf buf = PRINTBUF; buf.human_readable_units = true; - if (field_only >= 0) { - struct bch_sb_field *f = bch2_sb_field_get_id(sb.sb, field_only); - - if (f) - __bch2_sb_field_to_text(&buf, sb.sb, f); - } else { - printbuf_tabstop_push(&buf, 44); - - char *model = fd_to_dev_model(sb.bdev->bd_fd); - prt_str(&buf, "Device:"); - prt_tab(&buf); - prt_str(&buf, model); - prt_newline(&buf); - free(model); - - bch2_sb_to_text(&buf, sb.sb, print_layout, fields); - } + bch2_sb_to_text_with_names(&buf, sb.sb, print_layout, fields, field_only); printf("%s", buf.buf); bch2_free_super(&sb); diff --git a/c_src/cmd_super.h b/c_src/cmd_super.h new file mode 100644 index 00000000..78f71967 --- /dev/null +++ b/c_src/cmd_super.h @@ -0,0 +1,8 @@ +#ifndef _TOOLS_CMD_SHOW_SUPER_H +#define _TOOLS_CMD_SHOW_SUPER_H + +#include "libbcachefs/super-io.h" + +void bch2_sb_to_text_with_names(struct printbuf *, struct bch_sb *, bool, unsigned, int); + +#endif /* _TOOLS_CMD_SHOW_SUPER_H */ diff --git a/c_src/tools-util.c b/c_src/tools-util.c index 5a15f306..f48d3f21 100644 --- a/c_src/tools-util.c +++ b/c_src/tools-util.c @@ -22,6 +22,7 @@ #include "linux/sort.h" #include "tools-util.h" #include "libbcachefs/util.h" +#include "src/rust_to_c.h" void die(const char *fmt, ...) { @@ -777,7 +778,9 @@ darray_const_str get_or_split_cmdline_devs(int argc, char *argv[]) darray_const_str ret = {}; if (argc == 1) { - bch2_split_devs(argv[0], &ret); + char *dev = bch2_scan_devices(argv[0]); + + bch2_split_devs(dev, &ret); } else { for (unsigned i = 0; i < argc; i++) darray_push(&ret, strdup(argv[i])); diff --git a/libbcachefs/btree_cache.c b/libbcachefs/btree_cache.c index 25b01e75..9261ad04 100644 --- a/libbcachefs/btree_cache.c +++ b/libbcachefs/btree_cache.c @@ -215,7 +215,7 @@ void bch2_node_pin(struct bch_fs *c, struct btree *b) struct btree_cache *bc = &c->btree_cache; guard(mutex)(&bc->lock); - if (b != btree_node_root(c, b) && !btree_node_pinned(b)) { + if (!btree_node_is_root(c, b) && !btree_node_pinned(b)) { set_btree_node_pinned(b); list_move(&b->list, &bc->live[1].list); bc->live[0].nr--; diff --git a/libbcachefs/btree_cache.h b/libbcachefs/btree_cache.h index 649e9dfd..035b2cb2 100644 --- a/libbcachefs/btree_cache.h +++ b/libbcachefs/btree_cache.h @@ -144,6 +144,14 @@ static inline struct btree *btree_node_root(struct bch_fs *c, struct btree *b) return r ? r->b : NULL; } +static inline bool btree_node_is_root(struct bch_fs *c, struct btree *b) +{ + struct btree *root = btree_node_root(c, b); + + BUG_ON(b != root && b->c.level >= root->c.level); + return b == root; +} + const char *bch2_btree_id_str(enum btree_id); /* avoid */ void bch2_btree_id_to_text(struct printbuf *, enum btree_id); void bch2_btree_id_level_to_text(struct printbuf *, enum btree_id, unsigned); diff --git a/libbcachefs/btree_gc.c b/libbcachefs/btree_gc.c index ce3c7750..6b916496 100644 --- a/libbcachefs/btree_gc.c +++ b/libbcachefs/btree_gc.c @@ -282,6 +282,41 @@ fsck_err: return ret; } +static int btree_check_root_boundaries(struct btree_trans *trans, struct btree *b) +{ + struct bch_fs *c = trans->c; + struct printbuf buf = PRINTBUF; + int ret = 0; + + BUG_ON(b->key.k.type == KEY_TYPE_btree_ptr_v2 && + !bpos_eq(bkey_i_to_btree_ptr_v2(&b->key)->v.min_key, + b->data->min_key)); + + prt_str(&buf, " at "); + bch2_btree_pos_to_text(&buf, c, b); + + if (mustfix_fsck_err_on(!bpos_eq(b->data->min_key, POS_MIN), + trans, btree_node_topology_bad_root_min_key, + "btree root with incorrect min_key%s", buf.buf)) { + ret = set_node_min(c, b, POS_MIN); + if (ret) + goto err; + } + + if (mustfix_fsck_err_on(!bpos_eq(b->data->max_key, SPOS_MAX), + trans, btree_node_topology_bad_root_max_key, + "btree root with incorrect min_key%s", buf.buf)) { + ret = set_node_max(c, b, SPOS_MAX); + if (ret) + goto err; + } + +err: +fsck_err: + printbuf_exit(&buf); + return ret; +} + static int btree_repair_node_end(struct btree_trans *trans, struct btree *b, struct btree *child, struct bpos *pulled_from_scan) { @@ -586,7 +621,8 @@ recover: struct btree *b = r->b; btree_node_lock_nopath_nofail(trans, &b->c, SIX_LOCK_read); - ret = bch2_btree_repair_topology_recurse(trans, b, &pulled_from_scan); + ret = btree_check_root_boundaries(trans, b) ?: + bch2_btree_repair_topology_recurse(trans, b, &pulled_from_scan); six_unlock_read(&b->c.lock); if (bch2_err_matches(ret, BCH_ERR_topology_repair_drop_this_node)) { diff --git a/libbcachefs/btree_update.c b/libbcachefs/btree_update.c index 56647872..6f3b5757 100644 --- a/libbcachefs/btree_update.c +++ b/libbcachefs/btree_update.c @@ -215,7 +215,7 @@ int bch2_trans_update_extent_overwrite(struct btree_trans *trans, return ret; } - if (bkey_le(old.k->p, new.k->p)) { + if (!back_split) { update = bch2_trans_kmalloc(trans, sizeof(*update)); if ((ret = PTR_ERR_OR_ZERO(update))) return ret; @@ -238,9 +238,7 @@ int bch2_trans_update_extent_overwrite(struct btree_trans *trans, BTREE_UPDATE_internal_snapshot_node|flags); if (ret) return ret; - } - - if (back_split) { + } else { update = bch2_bkey_make_mut_noupdate(trans, old); if ((ret = PTR_ERR_OR_ZERO(update))) return ret; diff --git a/libbcachefs/btree_update_interior.c b/libbcachefs/btree_update_interior.c index 5f4f8296..76897cf1 100644 --- a/libbcachefs/btree_update_interior.c +++ b/libbcachefs/btree_update_interior.c @@ -66,6 +66,10 @@ int bch2_btree_node_check_topology(struct btree_trans *trans, struct btree *b) bkey_init(&prev.k->k); bch2_btree_and_journal_iter_init_node_iter(trans, &iter, b); + /* + * Don't use btree_node_is_root(): we're called by btree split, after + * creating a new root but before setting it + */ if (b == btree_node_root(c, b)) { if (!bpos_eq(b->data->min_key, POS_MIN)) { bch2_log_msg_start(c, &buf); @@ -1655,7 +1659,7 @@ static int btree_split(struct btree_update *as, struct btree_trans *trans, int ret = 0; bch2_verify_btree_nr_keys(b); - BUG_ON(!parent && (b != btree_node_root(c, b))); + BUG_ON(!parent && !btree_node_is_root(c, b)); BUG_ON(parent && !btree_node_intent_locked(trans->paths + path, b->c.level + 1)); ret = bch2_btree_node_check_topology(trans, b); @@ -2527,7 +2531,7 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans, if (ret) goto err; } else { - BUG_ON(btree_node_root(c, b) != b); + BUG_ON(!btree_node_is_root(c, b)); struct jset_entry *e = bch2_trans_jset_entry_alloc(trans, jset_u64s(new_key->k.u64s)); diff --git a/libbcachefs/errcode.h b/libbcachefs/errcode.h index cec8b0f4..adc1f931 100644 --- a/libbcachefs/errcode.h +++ b/libbcachefs/errcode.h @@ -119,6 +119,7 @@ x(ENOENT, ENOENT_not_directory) \ x(ENOENT, ENOENT_directory_dead) \ x(ENOENT, ENOENT_subvolume) \ + x(ENOENT, ENOENT_snapshot) \ x(ENOENT, ENOENT_snapshot_tree) \ x(ENOENT, ENOENT_dirent_doesnt_match_inode) \ x(ENOENT, ENOENT_dev_not_found) \ diff --git a/libbcachefs/fs.c b/libbcachefs/fs.c index 3b289f69..b5e3090f 100644 --- a/libbcachefs/fs.c +++ b/libbcachefs/fs.c @@ -511,8 +511,8 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum) struct bch_subvolume subvol; int ret = lockrestart_do(trans, bch2_subvolume_get(trans, inum.subvol, true, &subvol) ?: - bch2_inode_find_by_inum_trans(trans, inum, &inode_u)) ?: - PTR_ERR_OR_ZERO(inode = bch2_inode_hash_init_insert(trans, inum, &inode_u, &subvol)); + bch2_inode_find_by_inum_trans(trans, inum, &inode_u) ?: + PTR_ERR_OR_ZERO(inode = bch2_inode_hash_init_insert(trans, inum, &inode_u, &subvol))); return ret ? ERR_PTR(ret) : &inode->v; } diff --git a/libbcachefs/fsck.c b/libbcachefs/fsck.c index 8d5ea217..6ccea092 100644 --- a/libbcachefs/fsck.c +++ b/libbcachefs/fsck.c @@ -923,9 +923,10 @@ lookup_inode_for_snapshot(struct btree_trans *trans, struct inode_walker *w, str bkey_init(&whiteout.k); whiteout.k.type = KEY_TYPE_whiteout; whiteout.k.p = SPOS(0, i->inode.bi_inum, k.k->p.snapshot); - ret = bch2_btree_insert_nonextent(trans, BTREE_ID_inodes, - &whiteout, - BTREE_UPDATE_internal_snapshot_node); + ret = bch2_btree_insert_trans(trans, BTREE_ID_inodes, + &whiteout, + BTREE_ITER_cached| + BTREE_UPDATE_internal_snapshot_node); } if (ret) diff --git a/libbcachefs/inode.c b/libbcachefs/inode.c index 85013e8d..d5e5190f 100644 --- a/libbcachefs/inode.c +++ b/libbcachefs/inode.c @@ -463,9 +463,10 @@ int __bch2_fsck_write_inode(struct btree_trans *trans, struct bch_inode_unpacked bch2_inode_pack(inode_p, inode); inode_p->inode.k.p.snapshot = inode->bi_snapshot; - return bch2_btree_insert_nonextent(trans, BTREE_ID_inodes, - &inode_p->inode.k_i, - BTREE_UPDATE_internal_snapshot_node); + return bch2_btree_insert_trans(trans, BTREE_ID_inodes, + &inode_p->inode.k_i, + BTREE_ITER_cached| + BTREE_UPDATE_internal_snapshot_node); } int bch2_fsck_write_inode(struct btree_trans *trans, struct bch_inode_unpacked *inode) diff --git a/libbcachefs/logged_ops.h b/libbcachefs/logged_ops.h index 30ae9ef7..6dea6e2a 100644 --- a/libbcachefs/logged_ops.h +++ b/libbcachefs/logged_ops.h @@ -10,7 +10,7 @@ static inline int bch2_logged_op_update(struct btree_trans *trans, struct bkey_i *op) { - return bch2_btree_insert_nonextent(trans, BTREE_ID_logged_ops, op, 0); + return bch2_btree_insert_trans(trans, BTREE_ID_logged_ops, op, BTREE_ITER_cached); } int bch2_resume_logged_ops(struct bch_fs *); diff --git a/libbcachefs/sb-errors_format.h b/libbcachefs/sb-errors_format.h index dd4ee466..5317b1bf 100644 --- a/libbcachefs/sb-errors_format.h +++ b/libbcachefs/sb-errors_format.h @@ -76,6 +76,8 @@ enum bch_fsck_flags { x(btree_node_read_error, 62, FSCK_AUTOFIX) \ x(btree_node_topology_bad_min_key, 63, FSCK_AUTOFIX) \ x(btree_node_topology_bad_max_key, 64, FSCK_AUTOFIX) \ + x(btree_node_topology_bad_root_min_key, 323, FSCK_AUTOFIX) \ + x(btree_node_topology_bad_root_max_key, 324, FSCK_AUTOFIX) \ x(btree_node_topology_overwritten_by_prev_node, 65, FSCK_AUTOFIX) \ x(btree_node_topology_overwritten_by_next_node, 66, FSCK_AUTOFIX) \ x(btree_node_topology_interior_node_empty, 67, FSCK_AUTOFIX) \ @@ -334,7 +336,7 @@ enum bch_fsck_flags { x(dirent_stray_data_after_cf_name, 305, 0) \ x(rebalance_work_incorrectly_set, 309, FSCK_AUTOFIX) \ x(rebalance_work_incorrectly_unset, 310, FSCK_AUTOFIX) \ - x(MAX, 323, 0) + x(MAX, 325, 0) enum bch_sb_error_id { #define x(t, n, ...) BCH_FSCK_ERR_##t = n, diff --git a/libbcachefs/sb-members.c b/libbcachefs/sb-members.c index 0573c7b0..e3c73d90 100644 --- a/libbcachefs/sb-members.c +++ b/libbcachefs/sb-members.c @@ -68,34 +68,13 @@ struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i) return __bch2_members_v2_get_mut(bch2_sb_field_get(sb, members_v2), i); } -static struct bch_member members_v2_get(struct bch_sb_field_members_v2 *mi, int i) -{ - struct bch_member ret, *p = __bch2_members_v2_get_mut(mi, i); - memset(&ret, 0, sizeof(ret)); - memcpy(&ret, p, min_t(size_t, le16_to_cpu(mi->member_bytes), sizeof(ret))); - return ret; -} - -static struct bch_member *members_v1_get_mut(struct bch_sb_field_members_v1 *mi, int i) -{ - return (void *) mi->_members + (i * BCH_MEMBER_V1_BYTES); -} - -static struct bch_member members_v1_get(struct bch_sb_field_members_v1 *mi, int i) -{ - struct bch_member ret, *p = members_v1_get_mut(mi, i); - memset(&ret, 0, sizeof(ret)); - memcpy(&ret, p, min_t(size_t, BCH_MEMBER_V1_BYTES, sizeof(ret))); - return ret; -} - struct bch_member bch2_sb_member_get(struct bch_sb *sb, int i) { struct bch_sb_field_members_v2 *mi2 = bch2_sb_field_get(sb, members_v2); if (mi2) - return members_v2_get(mi2, i); + return bch2_members_v2_get(mi2, i); struct bch_sb_field_members_v1 *mi1 = bch2_sb_field_get(sb, members_v1); - return members_v1_get(mi1, i); + return bch2_members_v1_get(mi1, i); } static int sb_members_v2_resize_entries(struct bch_fs *c) @@ -211,33 +190,25 @@ static int validate_member(struct printbuf *err, return 0; } -static void member_to_text(struct printbuf *out, - struct bch_member m, - struct bch_sb_field_disk_groups *gi, - struct bch_sb *sb, - int i) +void bch2_member_to_text(struct printbuf *out, + struct bch_member *m, + struct bch_sb_field_disk_groups *gi, + struct bch_sb *sb, + unsigned idx) { - unsigned data_have = bch2_sb_dev_has_data(sb, i); - u64 bucket_size = le16_to_cpu(m.bucket_size); - u64 device_size = le64_to_cpu(m.nbuckets) * bucket_size; - - if (!bch2_member_alive(&m)) - return; - - prt_printf(out, "Device:\t%u\n", i); - - printbuf_indent_add(out, 2); + u64 bucket_size = le16_to_cpu(m->bucket_size); + u64 device_size = le64_to_cpu(m->nbuckets) * bucket_size; prt_printf(out, "Label:\t"); - if (BCH_MEMBER_GROUP(&m)) + if (BCH_MEMBER_GROUP(m)) bch2_disk_path_to_text_sb(out, sb, - BCH_MEMBER_GROUP(&m) - 1); + BCH_MEMBER_GROUP(m) - 1); else prt_printf(out, "(none)"); prt_newline(out); prt_printf(out, "UUID:\t"); - pr_uuid(out, m.uuid.b); + pr_uuid(out, m->uuid.b); prt_newline(out); prt_printf(out, "Size:\t"); @@ -245,40 +216,41 @@ static void member_to_text(struct printbuf *out, prt_newline(out); for (unsigned i = 0; i < BCH_MEMBER_ERROR_NR; i++) - prt_printf(out, "%s errors:\t%llu\n", bch2_member_error_strs[i], le64_to_cpu(m.errors[i])); + prt_printf(out, "%s errors:\t%llu\n", bch2_member_error_strs[i], le64_to_cpu(m->errors[i])); for (unsigned i = 0; i < BCH_IOPS_NR; i++) - prt_printf(out, "%s iops:\t%u\n", bch2_iops_measurements[i], le32_to_cpu(m.iops[i])); + prt_printf(out, "%s iops:\t%u\n", bch2_iops_measurements[i], le32_to_cpu(m->iops[i])); prt_printf(out, "Bucket size:\t"); prt_units_u64(out, bucket_size << 9); prt_newline(out); - prt_printf(out, "First bucket:\t%u\n", le16_to_cpu(m.first_bucket)); - prt_printf(out, "Buckets:\t%llu\n", le64_to_cpu(m.nbuckets)); + prt_printf(out, "First bucket:\t%u\n", le16_to_cpu(m->first_bucket)); + prt_printf(out, "Buckets:\t%llu\n", le64_to_cpu(m->nbuckets)); prt_printf(out, "Last mount:\t"); - if (m.last_mount) - bch2_prt_datetime(out, le64_to_cpu(m.last_mount)); + if (m->last_mount) + bch2_prt_datetime(out, le64_to_cpu(m->last_mount)); else prt_printf(out, "(never)"); prt_newline(out); - prt_printf(out, "Last superblock write:\t%llu\n", le64_to_cpu(m.seq)); + prt_printf(out, "Last superblock write:\t%llu\n", le64_to_cpu(m->seq)); prt_printf(out, "State:\t%s\n", - BCH_MEMBER_STATE(&m) < BCH_MEMBER_STATE_NR - ? bch2_member_states[BCH_MEMBER_STATE(&m)] + BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR + ? bch2_member_states[BCH_MEMBER_STATE(m)] : "unknown"); prt_printf(out, "Data allowed:\t"); - if (BCH_MEMBER_DATA_ALLOWED(&m)) - prt_bitflags(out, __bch2_data_types, BCH_MEMBER_DATA_ALLOWED(&m)); + if (BCH_MEMBER_DATA_ALLOWED(m)) + prt_bitflags(out, __bch2_data_types, BCH_MEMBER_DATA_ALLOWED(m)); else prt_printf(out, "(none)"); prt_newline(out); prt_printf(out, "Has data:\t"); + unsigned data_have = bch2_sb_dev_has_data(sb, idx); if (data_have) prt_bitflags(out, __bch2_data_types, data_have); else @@ -286,22 +258,36 @@ static void member_to_text(struct printbuf *out, prt_newline(out); prt_printf(out, "Btree allocated bitmap blocksize:\t"); - if (m.btree_bitmap_shift < 64) - prt_units_u64(out, 1ULL << m.btree_bitmap_shift); + if (m->btree_bitmap_shift < 64) + prt_units_u64(out, 1ULL << m->btree_bitmap_shift); else - prt_printf(out, "(invalid shift %u)", m.btree_bitmap_shift); + prt_printf(out, "(invalid shift %u)", m->btree_bitmap_shift); prt_newline(out); prt_printf(out, "Btree allocated bitmap:\t"); - bch2_prt_u64_base2_nbits(out, le64_to_cpu(m.btree_allocated_bitmap), 64); + bch2_prt_u64_base2_nbits(out, le64_to_cpu(m->btree_allocated_bitmap), 64); prt_newline(out); - prt_printf(out, "Durability:\t%llu\n", BCH_MEMBER_DURABILITY(&m) ? BCH_MEMBER_DURABILITY(&m) - 1 : 1); + prt_printf(out, "Durability:\t%llu\n", BCH_MEMBER_DURABILITY(m) ? BCH_MEMBER_DURABILITY(m) - 1 : 1); + + prt_printf(out, "Discard:\t%llu\n", BCH_MEMBER_DISCARD(m)); + prt_printf(out, "Freespace initialized:\t%llu\n", BCH_MEMBER_FREESPACE_INITIALIZED(m)); + prt_printf(out, "Resize on mount:\t%llu\n", BCH_MEMBER_RESIZE_ON_MOUNT(m)); +} + +static void member_to_text(struct printbuf *out, + struct bch_member m, + struct bch_sb_field_disk_groups *gi, + struct bch_sb *sb, + unsigned idx) +{ + if (!bch2_member_alive(&m)) + return; - prt_printf(out, "Discard:\t%llu\n", BCH_MEMBER_DISCARD(&m)); - prt_printf(out, "Freespace initialized:\t%llu\n", BCH_MEMBER_FREESPACE_INITIALIZED(&m)); - prt_printf(out, "Resize on mount:\t%llu\n", BCH_MEMBER_RESIZE_ON_MOUNT(&m)); + prt_printf(out, "Device:\t%u\n", idx); + printbuf_indent_add(out, 2); + bch2_member_to_text(out, &m, gi, sb, idx); printbuf_indent_sub(out, 2); } @@ -317,7 +303,7 @@ static int bch2_sb_members_v1_validate(struct bch_sb *sb, struct bch_sb_field *f } for (i = 0; i < sb->nr_devices; i++) { - struct bch_member m = members_v1_get(mi, i); + struct bch_member m = bch2_members_v1_get(mi, i); int ret = validate_member(err, m, sb, i); if (ret) @@ -343,7 +329,7 @@ static void bch2_sb_members_v1_to_text(struct printbuf *out, struct bch_sb *sb, prt_printf(out, "nr_devices mismatch: have %i entries, should be %u", nr, sb->nr_devices); for (unsigned i = 0; i < min(sb->nr_devices, nr); i++) - member_to_text(out, members_v1_get(mi, i), gi, sb, i); + member_to_text(out, bch2_members_v1_get(mi, i), gi, sb, i); } const struct bch_sb_field_ops bch_sb_field_ops_members_v1 = { @@ -377,7 +363,7 @@ static void bch2_sb_members_v2_to_text(struct printbuf *out, struct bch_sb *sb, */ for (unsigned i = 0; i < min(sb->nr_devices, nr); i++) - member_to_text(out, members_v2_get(mi, i), gi, sb, i); + member_to_text(out, bch2_members_v2_get(mi, i), gi, sb, i); } static int bch2_sb_members_v2_validate(struct bch_sb *sb, struct bch_sb_field *f, @@ -394,7 +380,7 @@ static int bch2_sb_members_v2_validate(struct bch_sb *sb, struct bch_sb_field *f } for (unsigned i = 0; i < sb->nr_devices; i++) { - int ret = validate_member(err, members_v2_get(mi, i), sb, i); + int ret = validate_member(err, bch2_members_v2_get(mi, i), sb, i); if (ret) return ret; } @@ -430,7 +416,7 @@ void bch2_sb_members_to_cpu(struct bch_fs *c) struct bch_sb_field_members_v2 *mi2 = bch2_sb_field_get(c->disk_sb.sb, members_v2); if (mi2) for (unsigned i = 0; i < c->sb.nr_devices; i++) { - struct bch_member m = members_v2_get(mi2, i); + struct bch_member m = bch2_members_v2_get(mi2, i); bool removed = uuid_equal(&m.uuid, &BCH_SB_MEMBER_DELETED_UUID); mod_bit(i, c->devs_removed.d, removed); } diff --git a/libbcachefs/sb-members.h b/libbcachefs/sb-members.h index 35d4ab9b..6de999cf 100644 --- a/libbcachefs/sb-members.h +++ b/libbcachefs/sb-members.h @@ -14,11 +14,36 @@ __bch2_members_v2_get_mut(struct bch_sb_field_members_v2 *mi, unsigned i) return (void *) mi->_members + (i * le16_to_cpu(mi->member_bytes)); } +static inline struct bch_member bch2_members_v2_get(struct bch_sb_field_members_v2 *mi, int i) +{ + struct bch_member ret, *p = __bch2_members_v2_get_mut(mi, i); + memset(&ret, 0, sizeof(ret)); + memcpy(&ret, p, min_t(size_t, le16_to_cpu(mi->member_bytes), sizeof(ret))); + return ret; +} + +static inline struct bch_member *members_v1_get_mut(struct bch_sb_field_members_v1 *mi, int i) +{ + return (void *) mi->_members + (i * BCH_MEMBER_V1_BYTES); +} + +static inline struct bch_member bch2_members_v1_get(struct bch_sb_field_members_v1 *mi, int i) +{ + struct bch_member ret, *p = members_v1_get_mut(mi, i); + memset(&ret, 0, sizeof(ret)); + memcpy(&ret, p, min_t(size_t, BCH_MEMBER_V1_BYTES, sizeof(ret))); + return ret; +} + int bch2_sb_members_v2_init(struct bch_fs *c); int bch2_sb_members_cpy_v2_v1(struct bch_sb_handle *disk_sb); struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i); struct bch_member bch2_sb_member_get(struct bch_sb *sb, int i); +void bch2_member_to_text(struct printbuf *, struct bch_member *, + struct bch_sb_field_disk_groups *, + struct bch_sb *, unsigned); + static inline bool bch2_dev_is_online(struct bch_dev *ca) { return !enumerated_ref_is_zero(&ca->io_ref[READ]); diff --git a/libbcachefs/snapshot.c b/libbcachefs/snapshot.c index 5a1f8174..84f987d3 100644 --- a/libbcachefs/snapshot.c +++ b/libbcachefs/snapshot.c @@ -1146,7 +1146,7 @@ static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) if (bch2_fs_inconsistent_on(i == 2, c, "snapshot %u missing child pointer to %u", parent_id, id)) - return ret; + return bch_err_throw(c, ENOENT_snapshot); parent->v.children[i] = cpu_to_le32(child_id); diff --git a/src/device_scan.rs b/src/device_scan.rs index 4bed2d13..a6b62290 100644 --- a/src/device_scan.rs +++ b/src/device_scan.rs @@ -1,4 +1,5 @@ use std::{ + ffi::{CStr, CString, c_char, c_int}, collections::HashMap, env, path::{Path, PathBuf}, @@ -6,7 +7,12 @@ use std::{ }; use anyhow::Result; -use bch_bindgen::{bcachefs, bcachefs::bch_sb_handle, opt_set}; +use bch_bindgen::{bcachefs, opt_set}; +use bcachefs::{ + bch_sb_handle, + sb_name, + sb_names, +}; use bcachefs::bch_opts; use uuid::Uuid; use log::debug; @@ -171,3 +177,52 @@ pub fn joined_device_str(sbs: &Vec<(PathBuf, bch_sb_handle)>) -> String { .collect::<Vec<_>>() .join(":") } + +pub fn scan_devices(device: &String, opts: &bch_opts) -> Result<String> { + let mut sbs = scan_sbs(device, opts)?; + + for sb in &mut sbs { + unsafe { + bch_bindgen::sb_io::bch2_free_super(&mut sb.1); + } + } + + Ok(joined_device_str(&sbs)) +} + +#[no_mangle] +pub extern "C" fn bch2_scan_device_sbs(device: *const c_char, ret: *mut sb_names) -> c_int { + let device = unsafe { CStr::from_ptr(device) }; + let device = device.to_str().unwrap().to_string(); + + // how to initialize to default/empty? + let opts = bch_bindgen::opts::parse_mount_opts(None, None, true).unwrap_or_default(); + + let sbs = scan_sbs(&device, &opts).unwrap(); + + let mut sbs = sbs.iter() + .map(|(name, sb)| sb_name { + name: CString::new(name.clone().into_os_string().into_string().unwrap()).unwrap().into_raw(), + sb: *sb } ) + .collect::<Vec<sb_name>>(); + + unsafe { + (*ret).data = sbs.as_mut_ptr(); + (*ret).nr = sbs.len(); + (*ret).size = sbs.capacity(); + + std::mem::forget(sbs); + } + 0 +} + +#[no_mangle] +pub extern "C" fn bch2_scan_devices(device: *const c_char) -> *mut c_char { + let device = unsafe { CStr::from_ptr(device) }; + let device = device.to_str().unwrap().to_string(); + + // how to initialize to default/empty? + let opts = bch_bindgen::opts::parse_mount_opts(None, None, true).unwrap_or_default(); + + CString::new(scan_devices(&device, &opts).unwrap()).unwrap().into_raw() +} diff --git a/src/rust_to_c.h b/src/rust_to_c.h new file mode 100644 index 00000000..b64059c4 --- /dev/null +++ b/src/rust_to_c.h @@ -0,0 +1,17 @@ +#ifndef _BCACHEFS_TOOLS_RUST_TO_C_H +#define _BCACHEFS_TOOLS_RUST_TO_C_H + +#include "libbcachefs/super_types.h" +#include "libbcachefs/darray.h" + +struct sb_name { + const char *name; + struct bch_sb_handle sb; +}; +typedef DARRAY(struct sb_name) sb_names; + +int bch2_scan_device_sbs(char *, sb_names *ret); + +char *bch2_scan_devices(char *); + +#endif /* _BCACHEFS_TOOLS_RUST_TO_C_H */ |