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 #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 #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/src/device_scan.rs b/src/device_scan.rs index fda2d460..a6b62290 100644 --- a/src/device_scan.rs +++ b/src/device_scan.rs @@ -1,5 +1,5 @@ use std::{ - ffi::{CStr, CString, c_char}, + ffi::{CStr, CString, c_char, c_int}, collections::HashMap, env, path::{Path, PathBuf}, @@ -7,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; @@ -185,13 +190,39 @@ pub fn scan_devices(device: &String, opts: &bch_opts) -> Result { 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::>(); + + 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(); - let opts = bch_bindgen::opts::parse_mount_opts(None, None, true) - .unwrap_or_default(); + // 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 index 4f23e1dd..b64059c4 100644 --- a/src/rust_to_c.h +++ b/src/rust_to_c.h @@ -1,6 +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 */