diff options
Diffstat (limited to 'bch_bindgen')
-rw-r--r-- | bch_bindgen/.gitignore | 15 | ||||
-rw-r--r-- | bch_bindgen/Cargo.lock | 250 | ||||
-rw-r--r-- | bch_bindgen/Cargo.toml | 22 | ||||
-rw-r--r-- | bch_bindgen/build.rs | 116 | ||||
-rw-r--r-- | bch_bindgen/rustfmt.toml | 3 | ||||
-rw-r--r-- | bch_bindgen/src/bcachefs.rs | 112 | ||||
-rw-r--r-- | bch_bindgen/src/bkey.rs | 125 | ||||
-rw-r--r-- | bch_bindgen/src/btree.rs | 197 | ||||
-rw-r--r-- | bch_bindgen/src/errcode.rs | 40 | ||||
-rw-r--r-- | bch_bindgen/src/fs.rs | 27 | ||||
-rw-r--r-- | bch_bindgen/src/keyutils.rs | 6 | ||||
-rw-r--r-- | bch_bindgen/src/keyutils_wrapper.h | 1 | ||||
-rw-r--r-- | bch_bindgen/src/lib.rs | 168 | ||||
-rw-r--r-- | bch_bindgen/src/libbcachefs_wrapper.h | 22 | ||||
-rw-r--r-- | bch_bindgen/src/opts.rs | 35 | ||||
-rw-r--r-- | bch_bindgen/src/rs.rs | 29 |
16 files changed, 1168 insertions, 0 deletions
diff --git a/bch_bindgen/.gitignore b/bch_bindgen/.gitignore new file mode 100644 index 00000000..0aa133ac --- /dev/null +++ b/bch_bindgen/.gitignore @@ -0,0 +1,15 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +# Required By Nix +# Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/bch_bindgen/Cargo.lock b/bch_bindgen/Cargo.lock new file mode 100644 index 00000000..521c77c2 --- /dev/null +++ b/bch_bindgen/Cargo.lock @@ -0,0 +1,250 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bch_bindgen" +version = "0.1.0" +dependencies = [ + "anyhow", + "bindgen", + "bitfield", + "bitflags", + "byteorder", + "memoffset", + "paste", + "pkg-config", + "uuid", +] + +[[package]] +name = "bindgen" +version = "0.64.0" +source = "git+https://evilpiepirate.org/git/rust-bindgen.git#f773267b090bf16b9e8375fcbdcd8ba5e88806a8" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "clang-sys" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +dependencies = [ + "glob", + "libc", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pkg-config" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" + +[[package]] +name = "proc-macro2" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "uuid" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" diff --git a/bch_bindgen/Cargo.toml b/bch_bindgen/Cargo.toml new file mode 100644 index 00000000..33090ae9 --- /dev/null +++ b/bch_bindgen/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "bch_bindgen" +version = "0.1.0" +authors = [ "Kayla Firestack <dev@kaylafire.me>", "Yuxuan Shui <yshuiv7@gmail.com>", "Kent Overstreet <kent.overstreet@linux.dev>" ] +edition = "2021" + +[lib] +crate-type = ["lib"] +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0" +uuid = "1.2.2" +bitfield = "0.14.0" +memoffset = "0.8.0" +byteorder = "1.3" +bitflags = "1.3.2" +paste = "1.0.11" + +[build-dependencies] +pkg-config = "0.3" +bindgen = { git = "https://evilpiepirate.org/git/rust-bindgen.git", default-features = false } diff --git a/bch_bindgen/build.rs b/bch_bindgen/build.rs new file mode 100644 index 00000000..facea217 --- /dev/null +++ b/bch_bindgen/build.rs @@ -0,0 +1,116 @@ + +#[derive(Debug)] +pub struct Fix753 {} +impl bindgen::callbacks::ParseCallbacks for Fix753 { + fn item_name(&self, original_item_name: &str) -> Option<String> { + Some(original_item_name.trim_start_matches("Fix753_").to_owned()) + } +} + +fn main() { + use std::path::PathBuf; + + println!("cargo:rerun-if-changed=src/libbcachefs_wrapper.h"); + + let out_dir: PathBuf = std::env::var_os("OUT_DIR") + .expect("ENV Var 'OUT_DIR' Expected") + .into(); + let top_dir: PathBuf = std::env::var_os("CARGO_MANIFEST_DIR") + .expect("ENV Var 'CARGO_MANIFEST_DIR' Expected") + .into(); + + let libbcachefs_inc_dir = std::path::Path::new("../c_src"); + + let bindings = bindgen::builder() + .header( + top_dir + .join("src") + .join("libbcachefs_wrapper.h") + .display() + .to_string(), + ) + .clang_arg(format!( + "-I{}", + libbcachefs_inc_dir.join("include").display() + )) + .clang_arg(format!("-I{}", libbcachefs_inc_dir.display())) + .clang_arg("-DZSTD_STATIC_LINKING_ONLY") + .clang_arg("-DNO_BCACHEFS_FS") + .clang_arg("-D_GNU_SOURCE") + .clang_arg("-DRUST_BINDGEN") + .clang_arg("-fkeep-inline-functions") + .derive_debug(true) + .derive_default(true) + .layout_tests(true) + .default_enum_style(bindgen::EnumVariation::Rust { + non_exhaustive: true, + }) + .allowlist_function("bcachefs_usage") + .allowlist_function("raid_init") + .allowlist_function("cmd_.*") + .allowlist_function(".*_cmds") + .allowlist_function(".*bch2_.*") + .allowlist_function("bio_.*") + .allowlist_function("derive_passphrase") + .allowlist_function("request_key") + .allowlist_function("add_key") + .allowlist_function("keyctl_search") + .allowlist_function("match_string") + .allowlist_function("printbuf.*") + .blocklist_type("bch_extent_ptr") + .blocklist_type("btree_node") + .blocklist_type("bch_extent_crc32") + .blocklist_type("rhash_lock_head") + .blocklist_type("srcu_struct") + .allowlist_var("BCH_.*") + .allowlist_var("KEY_SPEC_.*") + .allowlist_var("Fix753_FMODE_.*") + .allowlist_var("bch.*") + .allowlist_var("__bch2.*") + .allowlist_var("__BTREE_ITER.*") + .allowlist_var("BTREE_ITER.*") + .blocklist_item("bch2_bkey_ops") + .allowlist_type("bch_.*") + .allowlist_type("fsck_err_opts") + .rustified_enum("fsck_err_opts") + .allowlist_type("nonce") + .no_debug("bch_replicas_padded") + .newtype_enum("bch_kdf_types") + .rustified_enum("bch_key_types") + .opaque_type("gendisk") + .opaque_type("gc_stripe") + .opaque_type("open_bucket.*") + .opaque_type("replicas_delta_list") + .no_copy("btree_trans") + .no_copy("printbuf") + .no_partialeq("bkey") + .no_partialeq("bpos") + .generate_inline_functions(true) + .parse_callbacks(Box::new(Fix753 {})) + .generate() + .expect("BindGen Generation Failiure: [libbcachefs_wrapper]"); + bindings + .write_to_file(out_dir.join("bcachefs.rs")) + .expect("Writing to output file failed for: `bcachefs.rs`"); + + let keyutils = pkg_config::probe_library("libkeyutils").expect("Failed to find keyutils lib"); + let bindings = bindgen::builder() + .header( + top_dir + .join("src") + .join("keyutils_wrapper.h") + .display() + .to_string(), + ) + .clang_args( + keyutils + .include_paths + .iter() + .map(|p| format!("-I{}", p.display())), + ) + .generate() + .expect("BindGen Generation Failiure: [Keyutils]"); + bindings + .write_to_file(out_dir.join("keyutils.rs")) + .expect("Writing to output file failed for: `keyutils.rs`"); +} diff --git a/bch_bindgen/rustfmt.toml b/bch_bindgen/rustfmt.toml new file mode 100644 index 00000000..42f2ad7c --- /dev/null +++ b/bch_bindgen/rustfmt.toml @@ -0,0 +1,3 @@ +# Default settings, i.e. idiomatic rust +edition = "2021" +newline_style = "Unix"
\ No newline at end of file diff --git a/bch_bindgen/src/bcachefs.rs b/bch_bindgen/src/bcachefs.rs new file mode 100644 index 00000000..8e897c08 --- /dev/null +++ b/bch_bindgen/src/bcachefs.rs @@ -0,0 +1,112 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +include!(concat!(env!("OUT_DIR"), "/bcachefs.rs")); + +use bitfield::bitfield; +bitfield! { + pub struct bch_scrypt_flags(u64); + pub N, _: 15, 0; + pub R, _: 31, 16; + pub P, _: 47, 32; +} +bitfield! { + pub struct bch_crypt_flags(u64); + pub TYPE, _: 4, 0; +} +use memoffset::offset_of; +impl bch_sb_field_crypt { + pub fn scrypt_flags(&self) -> Option<bch_scrypt_flags> { + use std::convert::TryInto; + match bch_kdf_types(bch_crypt_flags(self.flags).TYPE().try_into().ok()?) { + bch_kdf_types::BCH_KDF_SCRYPT => Some(bch_scrypt_flags(self.kdf_flags)), + _ => None, + } + } + pub fn key(&self) -> &bch_encrypted_key { + &self.key + } +} +impl PartialEq for bch_sb { + fn eq(&self, other: &Self) -> bool { + self.magic.b == other.magic.b + && self.user_uuid.b == other.user_uuid.b + && self.block_size == other.block_size + && self.version == other.version + && self.uuid.b == other.uuid.b + && self.seq == other.seq + } +} + +impl bch_sb { + pub fn crypt(&self) -> Option<&bch_sb_field_crypt> { + unsafe { + let ptr = bch2_sb_field_get_id( + self as *const _ as *mut _, + bch_sb_field_type::BCH_SB_FIELD_crypt, + ) as *const u8; + if ptr.is_null() { + None + } else { + let offset = offset_of!(bch_sb_field_crypt, field); + Some(&*((ptr.sub(offset)) as *const _)) + } + } + } + pub fn uuid(&self) -> uuid::Uuid { + uuid::Uuid::from_bytes(self.user_uuid.b) + } + + /// Get the nonce used to encrypt the superblock + pub fn nonce(&self) -> nonce { + use byteorder::{LittleEndian, ReadBytesExt}; + let mut internal_uuid = &self.uuid.b[..]; + let dword1 = internal_uuid.read_u32::<LittleEndian>().unwrap(); + let dword2 = internal_uuid.read_u32::<LittleEndian>().unwrap(); + nonce { + d: [0, 0, dword1, dword2], + } + } +} +impl bch_sb_handle { + pub fn sb(&self) -> &bch_sb { + unsafe { &*self.sb } + } + + pub fn bdev(&self) -> &block_device { + unsafe { &*self.bdev } + } +} + +#[repr(C)] +// #[repr(align(8))] +#[derive(Debug, Default, Copy, Clone)] +pub struct bch_extent_ptr { + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>, +} + +#[repr(C, packed(8))] +pub struct btree_node { + pub csum: bch_csum, + pub magic: __le64, + pub flags: __le64, + pub min_key: bpos, + pub max_key: bpos, + pub _ptr: bch_extent_ptr, + pub format: bkey_format, + pub __bindgen_anon_1: btree_node__bindgen_ty_1, +} + +#[repr(C, packed(8))] +// #[repr(align(8))] +#[derive(Debug, Default, Copy, Clone)] +pub struct bch_extent_crc32 { + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, + pub csum: __u32, +} + +// #[repr(u8)] +pub enum rhash_lock_head {} +pub enum srcu_struct {} diff --git a/bch_bindgen/src/bkey.rs b/bch_bindgen/src/bkey.rs new file mode 100644 index 00000000..d4830839 --- /dev/null +++ b/bch_bindgen/src/bkey.rs @@ -0,0 +1,125 @@ +#![allow(non_camel_case_types)] + +use crate::c; +use crate::fs::Fs; +use crate::btree::BtreeIter; +use crate::printbuf_to_formatter; +use std::fmt; +use std::marker::PhantomData; +use std::mem::transmute; + +pub struct BkeySC<'a> { + pub k: &'a c::bkey, + pub v: &'a c::bch_val, + pub(crate) iter: PhantomData<&'a mut BtreeIter<'a>> +} + +pub enum BkeyValC<'a> { + deleted, + whiteout, + error, + cookie(&'a c::bch_cookie), + hash_whiteout(&'a c::bch_hash_whiteout), + btree_ptr(&'a c::bch_btree_ptr), + extent(&'a c::bch_extent), + reservation(&'a c::bch_reservation), + inode(&'a c::bch_inode), + inode_generation(&'a c::bch_inode_generation), + dirent(&'a c::bch_dirent), + xattr(&'a c::bch_xattr), + alloc(&'a c::bch_alloc), + quota(&'a c::bch_quota), + stripe(&'a c::bch_stripe), + reflink_p(&'a c::bch_reflink_p), + reflink_v(&'a c::bch_reflink_v), + inline_data(&'a c::bch_inline_data), + btree_ptr_v2(&'a c::bch_btree_ptr_v2), + indirect_inline_data(&'a c::bch_indirect_inline_data), + alloc_v2(&'a c::bch_alloc_v2), + subvolume(&'a c::bch_subvolume), + snapshot(&'a c::bch_snapshot), + inode_v2(&'a c::bch_inode_v2), + alloc_v3(&'a c::bch_alloc_v3), + set, + lru(&'a c::bch_lru), + alloc_v4(&'a c::bch_alloc_v4), + backpointer(&'a c::bch_backpointer), + inode_v3(&'a c::bch_inode_v3), + bucket_gens(&'a c::bch_bucket_gens), + snapshot_tree(&'a c::bch_snapshot_tree), + logged_op_truncate(&'a c::bch_logged_op_truncate), + logged_op_finsert(&'a c::bch_logged_op_finsert), +} + +impl<'a, 'b> BkeySC<'a> { + unsafe fn to_raw(&self) -> c::bkey_s_c { + c::bkey_s_c { k: self.k, v: self.v } + } + + pub fn to_text(&'a self, fs: &'b Fs) -> BkeySCToText<'a, 'b> { + BkeySCToText { k: self, fs } + } + + pub fn v(&'a self) -> BkeyValC { + let ty: c::bch_bkey_type = unsafe { transmute(self.k.type_ as u32) }; + + use c::bch_bkey_type::*; + use BkeyValC::*; + match ty { + KEY_TYPE_deleted => deleted, + KEY_TYPE_whiteout => whiteout, + KEY_TYPE_error => error, + KEY_TYPE_cookie => cookie(unsafe { transmute(self.v) }), + KEY_TYPE_hash_whiteout => hash_whiteout(unsafe { transmute(self.v) }), + KEY_TYPE_btree_ptr => btree_ptr(unsafe { transmute(self.v) }), + KEY_TYPE_extent => extent(unsafe { transmute(self.v) }), + KEY_TYPE_reservation => reservation(unsafe { transmute(self.v) }), + KEY_TYPE_inode => inode(unsafe { transmute(self.v) }), + KEY_TYPE_inode_generation => inode_generation(unsafe { transmute(self.v) }), + KEY_TYPE_dirent => dirent(unsafe { transmute(self.v) }), + KEY_TYPE_xattr => xattr(unsafe { transmute(self.v) }), + KEY_TYPE_alloc => alloc(unsafe { transmute(self.v) }), + KEY_TYPE_quota => quota(unsafe { transmute(self.v) }), + KEY_TYPE_stripe => stripe(unsafe { transmute(self.v) }), + KEY_TYPE_reflink_p => reflink_p(unsafe { transmute(self.v) }), + KEY_TYPE_reflink_v => reflink_v(unsafe { transmute(self.v) }), + KEY_TYPE_inline_data => inline_data(unsafe { transmute(self.v) }), + KEY_TYPE_btree_ptr_v2 => btree_ptr_v2(unsafe { transmute(self.v) }), + KEY_TYPE_indirect_inline_data => indirect_inline_data(unsafe { transmute(self.v) }), + KEY_TYPE_alloc_v2 => alloc_v2(unsafe { transmute(self.v) }), + KEY_TYPE_subvolume => subvolume(unsafe { transmute(self.v) }), + KEY_TYPE_snapshot => snapshot(unsafe { transmute(self.v) }), + KEY_TYPE_inode_v2 => inode_v2(unsafe { transmute(self.v) }), + KEY_TYPE_alloc_v3 => inode_v3(unsafe { transmute(self.v) }), + KEY_TYPE_set => set, + KEY_TYPE_lru => lru(unsafe { transmute(self.v) }), + KEY_TYPE_alloc_v4 => alloc_v4(unsafe { transmute(self.v) }), + KEY_TYPE_backpointer => backpointer(unsafe { transmute(self.v) }), + KEY_TYPE_inode_v3 => inode_v3(unsafe { transmute(self.v) }), + KEY_TYPE_bucket_gens => bucket_gens(unsafe { transmute(self.v) }), + KEY_TYPE_snapshot_tree => snapshot_tree(unsafe { transmute(self.v) }), + KEY_TYPE_logged_op_truncate => logged_op_truncate(unsafe { transmute(self.v) }), + KEY_TYPE_logged_op_finsert => logged_op_finsert(unsafe { transmute(self.v) }), + KEY_TYPE_MAX => unreachable!(), + } + } +} + +impl<'a> From<&'a c::bkey_i> for BkeySC<'a> { + fn from(k: &'a c::bkey_i) -> Self { + BkeySC { k: &k.k, v: &k.v, iter: PhantomData } + } +} + +pub struct BkeySCToText<'a, 'b> { + k: &'a BkeySC<'a>, + fs: &'b Fs, +} + +impl<'a, 'b> fmt::Display for BkeySCToText<'a, 'b> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { + printbuf_to_formatter(f, |buf| c::bch2_bkey_val_to_text(buf, self.fs.raw, self.k.to_raw())) + } + } +} diff --git a/bch_bindgen/src/btree.rs b/bch_bindgen/src/btree.rs new file mode 100644 index 00000000..09e86b34 --- /dev/null +++ b/bch_bindgen/src/btree.rs @@ -0,0 +1,197 @@ +use crate::SPOS_MAX; +use crate::c; +use crate::bkey::BkeySC; +use crate::fs::Fs; +use crate::errcode::{bch_errcode, errptr_to_result_c}; +use crate::printbuf_to_formatter; +use std::fmt; +use std::marker::PhantomData; +use std::mem::MaybeUninit; +use bitflags::bitflags; + +pub struct BtreeTrans<'f> { + raw: *mut c::btree_trans, + fs: PhantomData<&'f Fs> +} + +impl<'f> BtreeTrans<'f> { + pub fn new(fs: &'f Fs) -> BtreeTrans { + unsafe { + BtreeTrans { raw: &mut *c::__bch2_trans_get(fs.raw, 0), fs: PhantomData } + } + } +} + +impl<'f> Drop for BtreeTrans<'f> { + fn drop(&mut self) { + unsafe { c::bch2_trans_put(&mut *self.raw) } + } +} + +bitflags! { + pub struct BtreeIterFlags: u16 { + const SLOTS = c::BTREE_ITER_SLOTS as u16; + const INTENT = c::BTREE_ITER_INTENT as u16; + const PREFETCH = c::BTREE_ITER_PREFETCH as u16; + const IS_EXTENTS = c::BTREE_ITER_IS_EXTENTS as u16; + const NOT_EXTENTS = c::BTREE_ITER_NOT_EXTENTS as u16; + const CACHED = c::BTREE_ITER_CACHED as u16; + const KEY_CACHED = c::BTREE_ITER_WITH_KEY_CACHE as u16; + const WITH_UPDATES = c::BTREE_ITER_WITH_UPDATES as u16; + const WITH_JOURNAL = c::BTREE_ITER_WITH_JOURNAL as u16; + const __ALL_SNAPSHOTS = c::__BTREE_ITER_ALL_SNAPSHOTS as u16; + const ALL_SNAPSHOTS = c::BTREE_ITER_ALL_SNAPSHOTS as u16; + const FILTER_SNAPSHOTS = c::BTREE_ITER_FILTER_SNAPSHOTS as u16; + const NOPRESERVE = c::BTREE_ITER_NOPRESERVE as u16; + const CACHED_NOFILL = c::BTREE_ITER_CACHED_NOFILL as u16; + const KEY_CACHE_FILL = c::BTREE_ITER_KEY_CACHE_FILL as u16; + } +} + +pub struct BtreeIter<'t> { + raw: c::btree_iter, + trans: PhantomData<&'t BtreeTrans<'t>>, +} + +impl<'t> BtreeIter<'t> { + pub fn new(trans: &'t BtreeTrans<'t>, btree: c::btree_id, pos: c::bpos, flags: BtreeIterFlags) -> BtreeIter<'t> { + unsafe { + let mut iter: MaybeUninit<c::btree_iter> = MaybeUninit::uninit(); + + c::bch2_trans_iter_init_outlined( + trans.raw, + iter.as_mut_ptr(), + btree, + pos, + flags.bits as u32); + + BtreeIter { raw: iter.assume_init(), trans: PhantomData } + } + } + + pub fn peek_upto<'i>(&'i mut self, end: c::bpos) -> Result<Option<BkeySC>, bch_errcode> { + unsafe { + let k = c::bch2_btree_iter_peek_upto(&mut self.raw, end); + errptr_to_result_c(k.k) + .map(|_| if !k.k.is_null() { Some(BkeySC { k: &*k.k, v: &*k.v, iter: PhantomData }) } else { None } ) + } + } + + pub fn peek(&mut self) -> Result<Option<BkeySC>, bch_errcode> { + self.peek_upto(SPOS_MAX) + } + + pub fn peek_and_restart(&mut self) -> Result<Option<BkeySC>, bch_errcode> { + unsafe { + let k = c::bch2_btree_iter_peek_and_restart_outlined(&mut self.raw); + + errptr_to_result_c(k.k) + .map(|_| if !k.k.is_null() { Some(BkeySC{ k: &*k.k, v: &*k.v, iter: PhantomData }) } else { None } ) + } + } + + pub fn advance(&mut self) { + unsafe { + c::bch2_btree_iter_advance(&mut self.raw); + } + } +} + +impl<'t> Drop for BtreeIter<'t> { + fn drop(&mut self) { + unsafe { c::bch2_trans_iter_exit(self.raw.trans, &mut self.raw) } + } +} + +pub struct BtreeNodeIter<'t> { + raw: c::btree_iter, + trans: PhantomData<&'t BtreeTrans<'t>>, +} + +impl<'t> BtreeNodeIter<'t> { + pub fn new(trans: &'t BtreeTrans<'t>, + btree: c::btree_id, + pos: c::bpos, + locks_want: u32, + depth: u32, + flags: BtreeIterFlags) -> BtreeNodeIter { + unsafe { + let mut iter: MaybeUninit<c::btree_iter> = MaybeUninit::uninit(); + c::bch2_trans_node_iter_init( + trans.raw, + iter.as_mut_ptr(), + btree, + pos, + locks_want, + depth, + flags.bits as u32); + + BtreeNodeIter { raw: iter.assume_init(), trans: PhantomData } + } + } + + pub fn peek<'i>(&'i mut self) -> Result<Option<&'i c::btree>, bch_errcode> { + unsafe { + let b = c::bch2_btree_iter_peek_node(&mut self.raw); + errptr_to_result_c(b).map(|b| if !b.is_null() { Some(&*b) } else { None }) + } + } + + pub fn peek_and_restart<'i>(&'i mut self) -> Result<Option<&'i c::btree>, bch_errcode> { + unsafe { + let b = c::bch2_btree_iter_peek_node_and_restart(&mut self.raw); + errptr_to_result_c(b).map(|b| if !b.is_null() { Some(&*b) } else { None }) + } + } + + pub fn advance<'i>(&'i mut self) { + unsafe { + c::bch2_btree_iter_next_node(&mut self.raw); + } + } + + pub fn next<'i>(&'i mut self) -> Result<Option<&'i c::btree>, bch_errcode> { + unsafe { + let b = c::bch2_btree_iter_next_node(&mut self.raw); + errptr_to_result_c(b).map(|b| if !b.is_null() { Some(&*b) } else { None }) + } + } +} + +impl<'t> Drop for BtreeNodeIter<'t> { + fn drop(&mut self) { + unsafe { c::bch2_trans_iter_exit(self.raw.trans, &mut self.raw) } + } +} + +impl<'b, 'f> c::btree { + pub fn to_text(&'b self, fs: &'f Fs) -> BtreeNodeToText<'b, 'f> { + BtreeNodeToText { b: &self, fs } + } + + pub fn ondisk_to_text(&'b self, fs: &'f Fs) -> BtreeNodeOndiskToText<'b, 'f> { + BtreeNodeOndiskToText { b: &self, fs } + } +} + +pub struct BtreeNodeToText<'b, 'f> { + b: &'b c::btree, + fs: &'f Fs, +} + +impl<'b, 'f> fmt::Display for BtreeNodeToText<'b, 'f> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + printbuf_to_formatter(f, |buf| unsafe { c::bch2_btree_node_to_text(buf, self.fs.raw, self.b) }) + } +} + +pub struct BtreeNodeOndiskToText<'b, 'f> { + b: &'b c::btree, + fs: &'f Fs, +} + +impl<'b, 'f> fmt::Display for BtreeNodeOndiskToText<'b, 'f> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + printbuf_to_formatter(f, |buf| unsafe { c::bch2_btree_node_ondisk_to_text(buf, self.fs.raw, self.b) }) + } +} diff --git a/bch_bindgen/src/errcode.rs b/bch_bindgen/src/errcode.rs new file mode 100644 index 00000000..4d75f1d2 --- /dev/null +++ b/bch_bindgen/src/errcode.rs @@ -0,0 +1,40 @@ +use crate::bcachefs; +use std::ffi::CStr; +use std::fmt; + +pub use crate::c::bch_errcode; + +impl fmt::Display for bch_errcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = unsafe { CStr::from_ptr(bcachefs::bch2_err_str(*self as i32)) }; + write!(f, "{:?}", s) + } +} + +/* Can we make a function generic over ptr constness? */ + +pub fn errptr_to_result<T>(p: *mut T) -> Result<*mut T, bch_errcode> { + let addr = p as usize; + let max_err: isize = -4096; + if addr > max_err as usize { + let addr = addr as i32; + let err: bch_errcode = unsafe { std::mem::transmute(-addr) }; + Err(err) + } else { + Ok(p) + } +} + +pub fn errptr_to_result_c<T>(p: *const T) -> Result<*const T, bch_errcode> { + let addr = p as usize; + let max_err: isize = -4096; + if addr > max_err as usize { + let addr = addr as i32; + let err: bch_errcode = unsafe { std::mem::transmute(-addr) }; + Err(err) + } else { + Ok(p) + } +} + +impl std::error::Error for bch_errcode {} diff --git a/bch_bindgen/src/fs.rs b/bch_bindgen/src/fs.rs new file mode 100644 index 00000000..b26c51b6 --- /dev/null +++ b/bch_bindgen/src/fs.rs @@ -0,0 +1,27 @@ +use std::ffi::CString; +use std::os::unix::ffi::OsStrExt; +use std::path::PathBuf; +use crate::c; +use crate::errcode::{bch_errcode, errptr_to_result}; + +pub struct Fs { + pub raw: *mut c::bch_fs, +} + +impl Fs { + pub fn open(devs: &Vec<PathBuf>, opts: c::bch_opts) -> Result<Fs, bch_errcode> { + let devs: Vec<_> = devs.iter() + .map(|i| CString::new(i.as_os_str().as_bytes()).unwrap().into_raw()) + .collect(); + + let ret = unsafe { c::bch2_fs_open(devs[..].as_ptr(), devs.len() as u32, opts) }; + + errptr_to_result(ret).map(|fs| Fs { raw: fs}) + } +} + +impl Drop for Fs { + fn drop(&mut self) { + unsafe { c::bch2_fs_stop(self.raw) } + } +} diff --git a/bch_bindgen/src/keyutils.rs b/bch_bindgen/src/keyutils.rs new file mode 100644 index 00000000..30fc56f9 --- /dev/null +++ b/bch_bindgen/src/keyutils.rs @@ -0,0 +1,6 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +include!(concat!(env!("OUT_DIR"), "/keyutils.rs")); diff --git a/bch_bindgen/src/keyutils_wrapper.h b/bch_bindgen/src/keyutils_wrapper.h new file mode 100644 index 00000000..857cee2e --- /dev/null +++ b/bch_bindgen/src/keyutils_wrapper.h @@ -0,0 +1 @@ +#include <keyutils.h> diff --git a/bch_bindgen/src/lib.rs b/bch_bindgen/src/lib.rs new file mode 100644 index 00000000..4c549442 --- /dev/null +++ b/bch_bindgen/src/lib.rs @@ -0,0 +1,168 @@ +pub mod bcachefs; +pub mod btree; +pub mod bkey; +pub mod errcode; +pub mod keyutils; +pub mod rs; +pub mod fs; +pub mod opts; +pub use paste::paste; + +pub mod c { + pub use crate::bcachefs::*; +} + +use c::bpos as Bpos; + +pub const fn spos(inode: u64, offset: u64, snapshot: u32) -> Bpos { + Bpos { inode, offset, snapshot } +} + +pub const fn pos(inode: u64, offset: u64) -> Bpos { + spos(inode, offset, 0) +} + +pub const POS_MIN: Bpos = spos(0, 0, 0); +pub const POS_MAX: Bpos = spos(u64::MAX, u64::MAX, 0); +pub const SPOS_MAX: Bpos = spos(u64::MAX, u64::MAX, u32::MAX); + +use std::cmp::Ordering; + +impl PartialEq for Bpos { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl Eq for Bpos {} + +impl PartialOrd for Bpos { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for Bpos { + fn cmp(&self, other: &Self) -> Ordering { + let l_inode = self.inode; + let r_inode = other.inode; + let l_offset = self.offset; + let r_offset = other.offset; + let l_snapshot = self.snapshot; + let r_snapshot = other.snapshot; + + l_inode.cmp(&r_inode) + .then(l_offset.cmp(&r_offset)) + .then(l_snapshot.cmp(&r_snapshot)) + } +} + +use std::ffi::CStr; +use std::fmt; + +impl fmt::Display for c::btree_id { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = unsafe { CStr::from_ptr(c::bch2_btree_id_str(*self)) }; + let s = s.to_str().unwrap(); + write!(f, "{}", s) + } +} + +use std::str::FromStr; +use std::ffi::CString; + +use std::error::Error; + +#[derive(Debug)] +pub struct InvalidBtreeId; + +impl fmt::Display for InvalidBtreeId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "invalid btree id") + } +} + +impl Error for InvalidBtreeId { +} + +impl FromStr for c::btree_id { + type Err = InvalidBtreeId; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let s = CString::new(s).unwrap(); + let p = s.as_ptr(); + + let v = unsafe {c::match_string(c::__bch2_btree_ids[..].as_ptr(), (-(1 as isize)) as usize, p)}; + if v >= 0 { + Ok(unsafe { std::mem::transmute(v) }) + } else { + Err(InvalidBtreeId) + } + } +} + +impl c::printbuf { + fn new() -> c::printbuf { + let mut buf: c::printbuf = Default::default(); + + buf.set_heap_allocated(true); + buf + } +} + +impl Drop for c::printbuf { + fn drop(&mut self) { + unsafe { c::bch2_printbuf_exit(self) } + } +} + +impl fmt::Display for Bpos { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut buf = c::printbuf::new(); + + unsafe { c::bch2_bpos_to_text(&mut buf, *self) }; + + let s = unsafe { CStr::from_ptr(buf.buf) }; + let s = s.to_str().unwrap(); + write!(f, "{}", s) + } +} + +impl FromStr for c::bpos { + type Err = InvalidBtreeId; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + if s == "POS_MIN" { + return Ok(POS_MIN); + } + + if s == "POS_MAX" { + return Ok(POS_MAX); + } + + if s == "SPOS_MAX" { + return Ok(SPOS_MAX); + } + + let mut fields = s.split(':'); + let ino_str = fields.next().ok_or(InvalidBtreeId)?; + let off_str = fields.next().ok_or(InvalidBtreeId)?; + let snp_str = fields.next(); + + let ino: u64 = ino_str.parse().map_err(|_| InvalidBtreeId)?; + let off: u64 = off_str.parse().map_err(|_| InvalidBtreeId)?; + let snp: u32 = snp_str.map(|s| s.parse().ok()).flatten().unwrap_or(0); + + Ok(c::bpos { inode: ino, offset: off, snapshot: snp }) + } +} + +pub fn printbuf_to_formatter<F>(f: &mut fmt::Formatter<'_>, func: F) -> fmt::Result + where F: Fn(*mut c::printbuf) { + let mut buf = c::printbuf::new(); + + func(&mut buf); + + let s = unsafe { CStr::from_ptr(buf.buf) }; + f.write_str(s.to_str().unwrap()) +} diff --git a/bch_bindgen/src/libbcachefs_wrapper.h b/bch_bindgen/src/libbcachefs_wrapper.h new file mode 100644 index 00000000..141b0835 --- /dev/null +++ b/bch_bindgen/src/libbcachefs_wrapper.h @@ -0,0 +1,22 @@ +#include "libbcachefs/super-io.h" +#include "libbcachefs/checksum.h" +#include "libbcachefs/bcachefs_format.h" +#include "libbcachefs/btree_cache.h" +#include "libbcachefs/btree_iter.h" +#include "libbcachefs/debug.h" +#include "libbcachefs/errcode.h" +#include "libbcachefs/error.h" +#include "libbcachefs/opts.h" +#include "libbcachefs.h" +#include "crypto.h" +#include "include/linux/bio.h" +#include "include/linux/blkdev.h" +#include "cmds.h" +#include "raid/raid.h" + + +#define MARK_FIX_753(req_name) const blk_mode_t Fix753_##req_name = req_name; + +MARK_FIX_753(BLK_OPEN_READ); +MARK_FIX_753(BLK_OPEN_WRITE); +MARK_FIX_753(BLK_OPEN_EXCL); diff --git a/bch_bindgen/src/opts.rs b/bch_bindgen/src/opts.rs new file mode 100644 index 00000000..d38d469c --- /dev/null +++ b/bch_bindgen/src/opts.rs @@ -0,0 +1,35 @@ +#[macro_export] +macro_rules! opt_set { + ($opts:ident, $n:ident, $v:expr) => { + bch_bindgen::paste! { + $opts.$n = $v; + $opts.[<set_ $n _defined>](1) + } + }; +} + +#[macro_export] +macro_rules! opt_defined { + ($opts:ident, $n:ident) => { + bch_bindgen::paste! { + $opts.[< $n _defined>]() + } + }; +} + +#[macro_export] +macro_rules! opt_get { + ($opts:ident, $n:ident) => { + if bch_bindgen::opt_defined!($opts, $n) == 0 { + bch_bindgen::paste! { + unsafe { + bch_bindgen::bcachefs::bch2_opts_default.$n + } + } + } else { + bch_bindgen::paste! { + $opts.$n + } + } + }; +} diff --git a/bch_bindgen/src/rs.rs b/bch_bindgen/src/rs.rs new file mode 100644 index 00000000..24594ae1 --- /dev/null +++ b/bch_bindgen/src/rs.rs @@ -0,0 +1,29 @@ +use anyhow::anyhow; +use crate::bcachefs; +use crate::bcachefs::*; +use crate::errcode::bch_errcode; + +pub fn read_super_opts( + path: &std::path::Path, + mut opts: bch_opts, +) -> anyhow::Result<bch_sb_handle> { + use std::os::unix::ffi::OsStrExt; + let path = std::ffi::CString::new(path.as_os_str().as_bytes()).unwrap(); + + let mut sb = std::mem::MaybeUninit::zeroed(); + + let ret = + unsafe { crate::bcachefs::bch2_read_super(path.as_ptr(), &mut opts, sb.as_mut_ptr()) }; + + if ret != 0 { + let err: bch_errcode = unsafe { ::std::mem::transmute(ret) }; + Err(anyhow!(err)) + } else { + Ok(unsafe { sb.assume_init() }) + } +} + +pub fn read_super(path: &std::path::Path) -> anyhow::Result<bch_sb_handle> { + let opts = bcachefs::bch_opts::default(); + read_super_opts(path, opts) +} |