From 92705f6a4af888960c919191518096d052301d48 Mon Sep 17 00:00:00 2001 From: Akira Hayakawa Date: Thu, 1 Jan 2026 18:55:55 +0900 Subject: [PATCH 1/6] Use workspace style --- Cargo.toml | 43 +++-------------------- wbtools/Cargo.toml | 38 ++++++++++++++++++++ {data => wbtools/data}/sample.cache.226 | Bin {data => wbtools/data}/sample.status.226 | 0 {data => wbtools/data}/sample.table.226 | 0 {data => wbtools/data}/sys_dev.0 | 0 {src => wbtools/src}/lib.rs | 0 {src => wbtools/src}/wbcheck.rs | 0 {src => wbtools/src}/wbcreate.rs | 0 {src => wbtools/src}/wbdump.rs | 0 {src => wbtools/src}/wbmeta.rs | 0 {src => wbtools/src}/wbremove.rs | 0 {src => wbtools/src}/wbstatus.rs | 0 13 files changed, 43 insertions(+), 38 deletions(-) create mode 100644 wbtools/Cargo.toml rename {data => wbtools/data}/sample.cache.226 (100%) rename {data => wbtools/data}/sample.status.226 (100%) rename {data => wbtools/data}/sample.table.226 (100%) rename {data => wbtools/data}/sys_dev.0 (100%) rename {src => wbtools/src}/lib.rs (100%) rename {src => wbtools/src}/wbcheck.rs (100%) rename {src => wbtools/src}/wbcreate.rs (100%) rename {src => wbtools/src}/wbdump.rs (100%) rename {src => wbtools/src}/wbmeta.rs (100%) rename {src => wbtools/src}/wbremove.rs (100%) rename {src => wbtools/src}/wbstatus.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index c3058d8..33b979f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,38 +1,5 @@ -[package] -name = "wbtools" -version = "1.1.0" -authors = ["Akira Hayakawa "] - -[dependencies] -crc = "3" -byteorder = "1" -clap = { version = "4", features = ["derive"] } -anyhow = "1" - -[[bin]] -name = "wbcheck" -path = "src/wbcheck.rs" - -[[bin]] -name = "wbcreate" -path = "src/wbcreate.rs" - -[[bin]] -name = "wbdump" -path = "src/wbdump.rs" - -[[bin]] -name = "wbmeta" -path = "src/wbmeta.rs" - -[[bin]] -name = "wbremove" -path = "src/wbremove.rs" - -[[bin]] -name = "wbstatus" -path = "src/wbstatus.rs" - -[lib] -name = "lib" -path = "src/lib.rs" +[workspace] +resolver = "2" +members = [ + "wbtools" +] \ No newline at end of file diff --git a/wbtools/Cargo.toml b/wbtools/Cargo.toml new file mode 100644 index 0000000..c3058d8 --- /dev/null +++ b/wbtools/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "wbtools" +version = "1.1.0" +authors = ["Akira Hayakawa "] + +[dependencies] +crc = "3" +byteorder = "1" +clap = { version = "4", features = ["derive"] } +anyhow = "1" + +[[bin]] +name = "wbcheck" +path = "src/wbcheck.rs" + +[[bin]] +name = "wbcreate" +path = "src/wbcreate.rs" + +[[bin]] +name = "wbdump" +path = "src/wbdump.rs" + +[[bin]] +name = "wbmeta" +path = "src/wbmeta.rs" + +[[bin]] +name = "wbremove" +path = "src/wbremove.rs" + +[[bin]] +name = "wbstatus" +path = "src/wbstatus.rs" + +[lib] +name = "lib" +path = "src/lib.rs" diff --git a/data/sample.cache.226 b/wbtools/data/sample.cache.226 similarity index 100% rename from data/sample.cache.226 rename to wbtools/data/sample.cache.226 diff --git a/data/sample.status.226 b/wbtools/data/sample.status.226 similarity index 100% rename from data/sample.status.226 rename to wbtools/data/sample.status.226 diff --git a/data/sample.table.226 b/wbtools/data/sample.table.226 similarity index 100% rename from data/sample.table.226 rename to wbtools/data/sample.table.226 diff --git a/data/sys_dev.0 b/wbtools/data/sys_dev.0 similarity index 100% rename from data/sys_dev.0 rename to wbtools/data/sys_dev.0 diff --git a/src/lib.rs b/wbtools/src/lib.rs similarity index 100% rename from src/lib.rs rename to wbtools/src/lib.rs diff --git a/src/wbcheck.rs b/wbtools/src/wbcheck.rs similarity index 100% rename from src/wbcheck.rs rename to wbtools/src/wbcheck.rs diff --git a/src/wbcreate.rs b/wbtools/src/wbcreate.rs similarity index 100% rename from src/wbcreate.rs rename to wbtools/src/wbcreate.rs diff --git a/src/wbdump.rs b/wbtools/src/wbdump.rs similarity index 100% rename from src/wbdump.rs rename to wbtools/src/wbdump.rs diff --git a/src/wbmeta.rs b/wbtools/src/wbmeta.rs similarity index 100% rename from src/wbmeta.rs rename to wbtools/src/wbmeta.rs diff --git a/src/wbremove.rs b/wbtools/src/wbremove.rs similarity index 100% rename from src/wbremove.rs rename to wbtools/src/wbremove.rs diff --git a/src/wbstatus.rs b/wbtools/src/wbstatus.rs similarity index 100% rename from src/wbstatus.rs rename to wbtools/src/wbstatus.rs From ecf1bbcd0a753a677cd52dc3ffcd691e8f5080b3 Mon Sep 17 00:00:00 2001 From: Akira Hayakawa Date: Thu, 1 Jan 2026 18:58:18 +0900 Subject: [PATCH 2/6] Create writeboost-cli crate from wbtools by copying --- Cargo.toml | 3 +- writeboost-cli/Cargo.toml | 38 ++++ writeboost-cli/data/sample.cache.226 | Bin 0 -> 4194304 bytes writeboost-cli/data/sample.status.226 | 1 + writeboost-cli/data/sample.table.226 | 1 + writeboost-cli/data/sys_dev.0 | 5 + writeboost-cli/src/lib.rs | 239 ++++++++++++++++++++++++++ writeboost-cli/src/wbcheck.rs | 68 ++++++++ writeboost-cli/src/wbcreate.rs | 108 ++++++++++++ writeboost-cli/src/wbdump.rs | 49 ++++++ writeboost-cli/src/wbmeta.rs | 74 ++++++++ writeboost-cli/src/wbremove.rs | 79 +++++++++ writeboost-cli/src/wbstatus.rs | 63 +++++++ 13 files changed, 727 insertions(+), 1 deletion(-) create mode 100644 writeboost-cli/Cargo.toml create mode 100644 writeboost-cli/data/sample.cache.226 create mode 100644 writeboost-cli/data/sample.status.226 create mode 100644 writeboost-cli/data/sample.table.226 create mode 100644 writeboost-cli/data/sys_dev.0 create mode 100644 writeboost-cli/src/lib.rs create mode 100644 writeboost-cli/src/wbcheck.rs create mode 100644 writeboost-cli/src/wbcreate.rs create mode 100644 writeboost-cli/src/wbdump.rs create mode 100644 writeboost-cli/src/wbmeta.rs create mode 100644 writeboost-cli/src/wbremove.rs create mode 100644 writeboost-cli/src/wbstatus.rs diff --git a/Cargo.toml b/Cargo.toml index 33b979f..668303b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] resolver = "2" members = [ - "wbtools" + "wbtools", + "writeboost-cli" ] \ No newline at end of file diff --git a/writeboost-cli/Cargo.toml b/writeboost-cli/Cargo.toml new file mode 100644 index 0000000..94f7832 --- /dev/null +++ b/writeboost-cli/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "writeboost-cli" +version = "1.1.0" +authors = ["Akira Hayakawa "] + +[dependencies] +crc = "3" +byteorder = "1" +clap = { version = "4", features = ["derive"] } +anyhow = "1" + +[[bin]] +name = "wbcheck" +path = "src/wbcheck.rs" + +[[bin]] +name = "wbcreate" +path = "src/wbcreate.rs" + +[[bin]] +name = "wbdump" +path = "src/wbdump.rs" + +[[bin]] +name = "wbmeta" +path = "src/wbmeta.rs" + +[[bin]] +name = "wbremove" +path = "src/wbremove.rs" + +[[bin]] +name = "wbstatus" +path = "src/wbstatus.rs" + +[lib] +name = "lib" +path = "src/lib.rs" diff --git a/writeboost-cli/data/sample.cache.226 b/writeboost-cli/data/sample.cache.226 new file mode 100644 index 0000000000000000000000000000000000000000..00e4a58e470d62785b38eef0190d2372c4efdf1c GIT binary patch literal 4194304 zcmeF)4RmB@Vc+4a-L<_o8!U(cK@13TdZN;_6?GDXjj?tecD3Lb1shPHX_Nv%#C(W= zK_!qK;sA{uS8)idWvSHGEiuipE-v-XbkO8d%J9C`LlZhKYWRN+Q|009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjZJLEw1(95)_2ar3@yIGcj4@_x{~=8AeNh009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7dXDe&z(KYmBK zslEwVe*5=8Wm0{7X?=U>7xz8p)8)s9%D3+4&({{p?Owihz2rAnuI>K)WAFa>HE;Zz z4?X@raxw zCp__+U6ZFzS5J=h+xpYz?0uhb4*NFF+jnLCyazW!^^kzT^dUw8i!Q(SGQ_J<<(yHx8)y;^6kFg z>SH-G-rj>n{qmcR_wbP$kCdNv-|70T{J5NkY61?H+jAOIb#3Q-Yc}5Q`dJ!Sn|;gi zURyrA9pgRcu~rAv$1+gO^;HkvUtCabZ@Q_we7otUTdEz(+u-{9Qm@*UGn`#N$7pqq z>yN+p_4^vnj@-xyEh^B;`vj_!%>jqZ!?j~<8~j2?;}jvk2~jUJ00kDiFGMNdXg zMW2kGj-H90jh>61k6wsgj9!Xfj$Vmgjb4i`o*MHX-5uQ%-5cE(-5)&=Js3R{Jsdp} zJsLe0Jsv#~U5lQKo{ByhJsmw0JsUk2Js-Ugy%@a|y&Sy~y&An1T|6!3Ke{`*C%QMf zFS^!*lhM=BGtslrbJ6qB3(3zPPe;XKvNc z0o>#E%;_7iJoMJF$;P(6!-egYsLPvXXWf?L;d6%^YYs6#&(O(**M$!8jWiHU;UOt=Q#hbtuII^4mX|u zEk3!2&Q0Ll=KsXn#{8dH+v2k{=6`*cYW_bs_pg7TzW-T|H9JR~|A_f-rnG(c9lyRP z_HWLTxU=bJR~Y z|82^(cvvUq|0^H)+SghfPVV+J^PeQ!+nt#I_q_f8JgUu6UuXW?lxy*@PR##L|Jpa6 z*y3<f^@uX{(Rxk5vz?f2**xKe4*;Runt+&*!Z#{x6SQAF+2^3Y7DI zyxd{){1290eM`8yulnFsfSKd_pyOQnPUT*%|VQc-EPR#$6uYdFFS|8C_d;X01Kg(m= zqZ9N0jkmn@Ic*O773RN9xfT!W#Qgu#yWjS~7Kf9&z0&+A$@X?9=Km?bciUu}qrTbv zw<*`+VV#)&N8Ry`zix3jx!bGEf0Ar(cVhm(`1|kr(>6!_YV+TwT#JWwV*VfW>ra1R zi^Iv?Cd_}5Y;SjB{+E8^X@9@XQU43`-=1^Z$dt^Ao??;&5`e*P8z%+1~EN{D14WpZk$ENBuhU-=*WzKFnEx-m^?Qa|98T^w zYW|aCd%F|!|J}7mzpTws|D^eEQ?A9sIx+u4Q{P?v+;}^;e{TNUVQc-EPR#%7-}SJ^ zv_7J<_I#fCKg(m=qZ9N0?b!$XMVkYEzWHxcuEoPTG5=5a{0mndsT*x#;=mh3LiTrRe48 zmFU&zwdkV$o0A*!b1=F)x+l6fx-YsvdLVi*dMJ80dL()@dMtW8dLp_OJsCX}eKLAF zdM0`{dM0%$Ntmi|D4Uv>3~km|G;fuzWkg9b!O+A%>NmT`{Scd z%>S{uKl^WOj{U{vzfHLo59`GIzvW|p^4S)Lle@jd{3prwb|>cl3%CFI?QM?wrRKj) zxfT!W#Qa}A^O;(U!^z!VX8x08d%F|!f88hk;L~l6df5E8Dc9m*otXbO{K3b*+Tw6> zw;whCNwU4&iTVGl_x#bVZI1dG=D$t377y#h{6FjipZwhxhm*VAVE&V2d%F|!KX%J| zM%o<1g4rJ4UbUoiHU<>TE&abmTxpDh6b1PBly zK!5-N0t5&UAh2@<%GdwbmZQtp|K)4@ja#$V|F3-PU-p%cdi~!(vL!%(009C72oNAZ zfB*pkJ6xdY_x~?1w)+16MYVT6_dVrhmHV7n+u@gIcmxO#AV7cs0RjXF5FkK+Kq>IB zy24*PW%;>}B(moOx{Hlp&E5F-<%)Vgur6`1=vn`$@pyN1QSVFd-v6@L|LiV`jXtyg z#!{0r=RdpGmzk7jJhT7Cj}o2P|LiV`jXpE}jW1=L+5hZb|1#ED=RXkRKf8-!qZ{K{ zJN@Xh_U{SLp783aUw>mfJ=HRr@^+@rzMh`?m*UPmp5s|Ryy)84cu#-;0RjXF5FkK+ z0D*fIXuAIY^7@OC@~9^3|1TQ*^4FhLKIHrV_p0gv0t5&UAV7cs0RjXF5FkK+z|IjE zIehGBIhyL*#}^evtr}SM@xJPV@>YGk`CH5T%PzkGUH#n0#?O8<`T9_G+;{x;8*dnU z@^^d?yI=t2{2woexq1GpQCIW4KJSg+3%b|0`8=;Z^uqU6P`mv$a`@m-!827Z9HbX`vuDRbR$53009C7_LxA^pZ{+xIxa2p?}g=E7e2e| zT^}m9zW=|+o+~bw009C72oNAZfB*pk1a_}L)Aj$2A4)DStJ&-SPab{TvGO6W|99`S z8#w_21PBlyK!5-N0t5)`F@cezHymmFj){&}@Au!e9QR~a>rpq~%Fo$#>&DyNcdxHs z{_4=<9&-0RKDdX#ruF~j+TL3Ac;&Y1*Z=pu?VUr_#kg%Puxb5&WB#iHtpAVyz~z4j zA7A{h&uuNcJ07jC|GzM=uW|XGy67R}<&{|f-vBw!w!7n5YLo;B5FkK+z;+5WUH^aC znb+$1_rmgXU+|A^|6Hxy`u_iRPK0w2AV7cs0RjXF5FkK+0D=2apy~Sm%eMUe{}=q} z@(XV+hvfDD{Wvd9O@IIa0t5&UAV7cs0RjZJQ^5NF?bO_T=i0RXzx@5)wdw-Si}nBC zoT+_&_svG%4Ov)PK6_>(#%Tuh-%|2utVjgJ5U0t5&UAV7cs0RjXFoDs18 z|BS_6{Aknq|8k9Qts-b){eQLYV`J?{t{dJdhM&0Vj$hd+W7)~$*tGt?G5^(Yt^bd8 z-uXPg;U7NYnw>nat&Xj}{{KK;U*qz>`qy82T=})$^0{$I`ST%{l>bJ=B^Nawv)%my ztv*leM}PnU0t5)0KLSnH{~y|N{r~>2eC_yuE(QGlzw_s5;7SM(AV7cs0RjXF5FkL{ zJQrxX{{PUH>;L!vzz4qdppwPw|MUF0;qnL&AV7cs0RjXF5FkK+0D<#EVAJ~la?N+G zx~LY`|DPz=|5tBCk?V%5`*y>e=P0J=lMsjyz(_W zeQsMBUw!@m{=B}%<-hu(M?SDTPr3fTDA)fN<@*1^`u_&bd9W?#(~STD0t5&U*kb}s z*Z&{fa{d3l2fXT+?<$#m|9_7?S6nUu0t5&UAV7cs0RjXF>|TMU>;DgKx&D9OS06u6 zU9i{xyLZ}+oB#m=1PBlyK!5-N0tEJ$fZzYW$0j^3chma+edp8q|3`ju`q$%9WfOr- z>;D_`U+rc6f2{4!_3;P3|FeghaPGRh>g)ga<@Gf#|D7Mb<=XP1tp9I-oM+oz_k=ZI z0t5&UAVAgK-1PBlyK!5-N0t5&UAV8oq0!`Qd zAJ}sJf7jb@yZN7#qx1T|GgIWV5FkK+009C72oNAZfB=E}EMWcreJ0%1C)l+9zx=)b zwdz{Vi{JnM*CoUet^aS#fAyKI|BrRvxjz1j5BuD09h##1_0!bX|99o} zH7@_%&+q-Uasbxa0K8VYUp2lGE`$FaY7d`P=fB55#$88A^AV7cs0RjXF5FkK+0D+w^(De0x z&z7(MFZ}vvUU%KjzcM2vK!5-N0t5&UAV7cs0RjXX0!?54U$*7z{|jz=N&n9^j<+R1 zfB*pk1PBlyK!5-N0t9xxK-1U%-CMr?KQOrZw=diIS7w9+2oNAZfB*pk1PBlyK!89) zpy})XLtDQ7-~WQgy#Eo6<828LAV7cs0RjXF5FkK+0D+w^(De2H!7X3^@B7dvUiN^U ze`Q8UfB*pk1PBlyK!5-N0t5&&1e(77Kd|NN|E|wG;;~O`9B)g2009C72oNAZfB*pk z1PJVWfsvy(94U(Kje#Dx=Xjg^`+r5TuW0N!SU=)$eOsQZ=qid@l?SVLMR7^-;Zys{ zLmItt@1ct?-hXLPJba^y!TR><_3i$~;wB zJ!#`Cr|T!{j~<8~j2?;}jvk2~jUJ00kDiFGMNdXgMW2kGj-H90jh>61k6wsgj9!Xf zj$Vmgjb4i`u0DId4n}uJ_eA$b_eJ+d4@3_}4@D10k3^3~k42A1Pej+EC!?pLPexBi z&qU8g&qdEiFGMd!FGVj$uSBm#uSFM6j`@%7j_!%>jqZ!?j~<8~j2?;}jvk2~jUJ00 zkDiFGMNdXgMW2kGj-H90jh>61k6wsgj9!Xfj$Vmgjb4i`u8H}N?vCz>?v3t??vEab z9*iD}9*!P~9*rK09*>@gu0>BqPeq@Mo{pZ0o{gT1o{wILUW{IfUXEUgUX5OhE(T-% zqr0PfqBoBAo&W&?1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7csfmQ@=a@)%Sryg8?lDzbP?|<=$ zR-Q2SIj;m(p47d5J+=B(t=9W=z1O0Pt2g#;{ zGND zbbs_f^kDQ*^l0^mz0{bS-)^dMf&4^mO!0^lbE8^nCO}^kVc<^m6n{^lJ24 zba740e{^?rPjqi|Uvz);K=ferQ1o#0Nc3p*SoC=GM072BGI}cdWb}0OO!RE@T=abO zLiA$vQuK24O7v>(E-4op#-51>-JrF$@Jrq40JrX?{Jr+G4JrP}to{XM~ zJ{dh7Jrg|}Jr_M6y%4<^y;N_1x2yk!#)bd^0t5&UDE9Ifzg#;30t5&UAV7csfxRZ+ zB@h7u1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0Rs1*z_I$NkDa<<@ZkOTX`Fe73iJ+c z4D57$e0|aV(F4(g(L>S0(Ie4?8vz0Y2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB=CG3f$zjmjzCB@Tulg5gx9NxUF1=4brVr_-^mF={KKqpQPY=?=^hJ7<9;YwUSLsQ5nx3WS=|%cFy-cst zH|cfyHhq`APjAxO^h0`=-lreahxAkWIeko@ea`x)2kBw@B0Wlv)0gS1^dvn^&(ibs zB7L1+rdR2k^g4Z;zDwVyH|cHqA-zlQ(~s#x`YHXKKBmtmS^xAPJxpJuN9l3;GJTbv zq^IdwdY)dSuhYx)Dt(h)r*G4D>HG91y*;(F-RVH%Mt}eT0xtq@`R9kZ6Cgl<009C7 z2oNAZ;4KOG3?@K;009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk M1PBly@R|jF1LnDR%>V!Z literal 0 HcmV?d00001 diff --git a/writeboost-cli/data/sample.status.226 b/writeboost-cli/data/sample.status.226 new file mode 100644 index 0000000..fd41ea7 --- /dev/null +++ b/writeboost-cli/data/sample.status.226 @@ -0,0 +1 @@ +0 204800 writeboost 2 762 6 73 73 67 391 12 224 0 0 15 9 1 0 15 6567 0 0 1 0 15 0 11 10 writeback_threshold 0 nr_cur_batched_writeback 1 sync_data_interval 0 update_sb_record_interval 0 read_cache_threshold 0 diff --git a/writeboost-cli/data/sample.table.226 b/writeboost-cli/data/sample.table.226 new file mode 100644 index 0000000..262516c --- /dev/null +++ b/writeboost-cli/data/sample.table.226 @@ -0,0 +1 @@ +0 204800 writeboost 251:0 251:3 diff --git a/writeboost-cli/data/sys_dev.0 b/writeboost-cli/data/sys_dev.0 new file mode 100644 index 0000000..cb196e4 --- /dev/null +++ b/writeboost-cli/data/sys_dev.0 @@ -0,0 +1,5 @@ +MAJOR=252 +MINOR=1 +DEVNAME=vda1 +DEVTYPE=partition +PARTN=1 diff --git a/writeboost-cli/src/lib.rs b/writeboost-cli/src/lib.rs new file mode 100644 index 0000000..de67f83 --- /dev/null +++ b/writeboost-cli/src/lib.rs @@ -0,0 +1,239 @@ +extern crate byteorder; + +use byteorder::{LittleEndian, ReadBytesExt}; +use std::collections::HashMap; +use std::fs::File; +use std::io::Cursor; +use std::io::Read; +use std::io::Seek; +use std::io::SeekFrom; +use std::process::Command; + +pub static VERSION: &'static str = "1.0.1"; +pub static AUTHOR: &'static str = "Akira Hayakawa "; + +pub struct BlockDevice { + name: String, +} + +impl BlockDevice { + pub fn new(name_: String) -> Self { + BlockDevice { name: name_ } + } + pub fn name(&self) -> String { + self.name.to_owned() + } + pub fn size(&self) -> i64 { + use std::str::FromStr; + let output: Vec = Command::new("blockdev") + .arg("--getsz") + .arg(&self.name()) + .output() + .expect(&format!("Failed to get the size of {}", self.name())) + .stdout; + let output = String::from_utf8(output) + .expect("Invalid utf8 output") + .to_string(); + let output = output.trim_end(); + i64::from_str(output).expect("Couldn't parse as i64") + } +} + +pub struct CacheDevice { + pub dev: BlockDevice, +} + +impl CacheDevice { + pub fn new(name: String) -> Self { + CacheDevice { + dev: BlockDevice::new(name), + } + } + fn nr_segments(&self) -> i32 { + ((self.dev.size() - (1 << 11)) / (1 << 10)) as i32 + } + pub fn calc_segment_start(&self, id: i32) -> i32 { + let idx = (id - 1) % self.nr_segments(); + (1 << 11) + (idx * (1 << 10)) + } +} + +pub struct SegmentHeader { + pub id: u64, + pub checksum: u32, + pub length: u8, +} + +impl SegmentHeader { + pub fn from_buf(data: &[u8]) -> SegmentHeader { + let mut rdr = Cursor::new(data); + let id_ = rdr.read_u64::().unwrap(); + let checksum_ = rdr.read_u32::().unwrap(); + let length_ = rdr.read_u8().unwrap(); + SegmentHeader { + id: id_, + checksum: checksum_, + length: length_, + } + } + pub fn uninitialized(&self) -> bool { + self.id == 0 + } +} + +pub struct Metablock { + pub sector: u64, + pub dirty_bits: u8, +} + +pub struct Segment {} + +impl Segment { + pub fn from_buf(buf: &[u8]) -> (SegmentHeader, Vec) { + let seg = SegmentHeader::from_buf(buf); + + let mut metablocks = Vec::new(); + let mut rdr = Cursor::new(buf); + rdr.seek(SeekFrom::Start(512)).unwrap(); + for _ in 0..seg.length { + let sector_ = rdr.read_u64::().unwrap(); + let dirty_bits_ = rdr.read_u8().unwrap(); + let metablock = Metablock { + sector: sector_, + dirty_bits: dirty_bits_, + }; + metablocks.push(metablock); + let padding = 16 - (8 + 1); + rdr.seek(SeekFrom::Current(padding)).unwrap(); + } + (seg, metablocks) + } +} + +pub struct SuperBlockHeader { + pub magic: u32, +} + +impl SuperBlockHeader { + pub fn from_buf(data: &[u8]) -> SuperBlockHeader { + let mut rdr = Cursor::new(data); + let magic_ = rdr.read_u32::().unwrap(); + SuperBlockHeader { magic: magic_ } + } +} + +pub struct SuperBlockRecord { + pub last_writeback_segment_id: u64, +} + +impl SuperBlockRecord { + pub fn from_buf(data: &[u8]) -> SuperBlockRecord { + let mut rdr = Cursor::new(data); + let last_writeback_segment_id_ = rdr.read_u64::().unwrap(); + SuperBlockRecord { + last_writeback_segment_id: last_writeback_segment_id_, + } + } +} + +#[derive(Debug)] +pub struct SysDevTable { + map: HashMap, +} + +impl SysDevTable { + pub fn from_file(path: &str) -> SysDevTable { + let mut f = File::open(path).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + let it = s.lines().map(|line| { + let v: Vec<&str> = line.split("=").collect(); + (v[0].to_string(), v[1].to_string()) + }); + let mut m = HashMap::new(); + for (k, v) in it { + m.insert(k, v); + } + SysDevTable { map: m } + } + pub fn get(&self, name: &str) -> String { + self.map[name].to_string() + } +} + +#[test] +fn test_read_sys_dev_file() { + let t = SysDevTable::from_file("data/sys_dev.0"); + assert_eq!(t.get("DEVNAME"), "vda1"); +} + +pub struct BlockNumber { + value: String, +} + +impl BlockNumber { + pub fn unwrap(&self) -> String { + self.value.to_owned() + } + pub fn sys_dev_table(&self) -> SysDevTable { + let path = format!("/sys/dev/block/{}/uevent", self.value); + SysDevTable::from_file(&path) + } +} + +pub struct DMTable { + pub backing_dev: BlockNumber, + pub cache_dev: BlockNumber, +} + +impl DMTable { + pub fn parse(line: String) -> DMTable { + let line: Vec = line + .split(" ") + .filter(|x| x != &"") + .map(|x| x.to_string()) + .collect(); + DMTable { + backing_dev: BlockNumber { + value: line[3].clone(), + }, + cache_dev: BlockNumber { + value: line[4].clone(), + }, + } + } +} + +#[test] +fn test_dmtable_parse() { + let mut s = String::new(); + let mut f = File::open("data/sample.table.226").unwrap(); + f.read_to_string(&mut s).unwrap(); + let t = DMTable::parse(s.trim().to_string()); + println!("{}", s.clone()); + assert_eq!(t.backing_dev.unwrap(), "251:0"); + assert_eq!(t.cache_dev.unwrap(), "251:3"); +} + +pub struct WBDev { + name: String, +} + +impl WBDev { + pub fn new(name_: String) -> WBDev { + WBDev { name: name_ } + } + pub fn table(&self) -> DMTable { + let output = Command::new("dmsetup") + .arg("table") + .arg(&self.name) + .output() + .expect("Fail to dmsetup table") + .stdout; + let output = String::from_utf8(output) + .expect("Invalid utf8 output") + .to_string(); + let output = output.trim().to_string(); + DMTable::parse(output) + } +} diff --git a/writeboost-cli/src/wbcheck.rs b/writeboost-cli/src/wbcheck.rs new file mode 100644 index 0000000..6adc41b --- /dev/null +++ b/writeboost-cli/src/wbcheck.rs @@ -0,0 +1,68 @@ +extern crate clap; +extern crate crc; + +use std::fs::File; +use std::io::Read; +use std::io::Seek; +use std::io::SeekFrom; + +use crc::{Crc, CRC_32_ISCSI}; +pub const CASTAGNOLI: Crc = Crc::::new(&CRC_32_ISCSI); +fn checksum(data: &[u8]) -> u32 { + CASTAGNOLI.checksum(data) +} + +use clap::Parser; +#[derive(Parser)] +#[command(name = "wbcheck")] +#[command(about = "Check if the segment is broken")] +#[command(author, version)] +struct Args { + #[arg(help = "Path to the cache device")] + cachedev: String, + #[arg(help = "Segment id")] + segid: i32, +} + +#[test] +fn test_checksum() { + let buf = vec![0; 4096 - 512]; + assert_eq!(checksum(&buf), 143703573); +} + +fn main() { + let args = Args::parse(); + + let devname: String = args.cachedev; + let id = args.segid; + let cache_dev = lib::CacheDevice::new(devname.to_owned()); + + let mut f = File::open(&devname).expect(&format!("Device {} not found", &devname)); + + let start_byte: u64 = (cache_dev.calc_segment_start(id) as u64) << 9; + f.seek(SeekFrom::Start(start_byte)).unwrap(); + + let header = { + let mut buf = vec![0; 512]; + f.read(&mut buf).unwrap(); + lib::SegmentHeader::from_buf(&buf) + }; + + if header.uninitialized() { + std::process::exit(0); + } + + let computed = { + let size: usize = (4096 - 512) + ((header.length as usize) << 12); + let mut buf = vec![0; size]; + f.read(&mut buf).unwrap(); + checksum(&buf) + }; + + if computed != header.checksum { + panic!( + "Checksum is broken. computed={}, expected={}", + computed, header.checksum + ); + } +} diff --git a/writeboost-cli/src/wbcreate.rs b/writeboost-cli/src/wbcreate.rs new file mode 100644 index 0000000..9450071 --- /dev/null +++ b/writeboost-cli/src/wbcreate.rs @@ -0,0 +1,108 @@ +extern crate clap; + +use std::process::Command; + +use clap::Parser; +#[derive(Parser)] +#[command(name = "wbcreate")] +#[command(about = "Create a writeboost device")] +#[command(author, version)] +#[clap(rename_all = "snake_case")] +struct Args { + #[arg(help = "Name of the writeboost device")] + lvname: String, + #[arg(help = "Path to the backing device")] + backingdev: String, + #[arg(help = "Path to the cache device")] + cachedev: String, + #[arg( + help = "Reformat the cache device. This cleans up all existing cache blocks", + long + )] + reformat: bool, + #[arg(long)] + write_around_mode: bool, + #[arg(long, value_name = "INT")] + writeback_threshold: Option, + #[arg(long, value_name = "INT")] + nr_max_batched_writeback: Option, + #[arg(long, value_name = "INT")] + update_sb_record_interval: Option, + #[arg(long, value_name = "INT")] + sync_data_interval: Option, + #[arg(long, value_name = "INT")] + read_cache_threshold: Option, +} + +fn main() { + let args = Args::parse(); + + let wbname = args.lvname; + let backing_dev = { + let name = args.backingdev; + lib::BlockDevice::new(name) + }; + let cache_dev_name = args.cachedev; + + if args.reformat { + let status = Command::new("dd") + .arg("if=/dev/zero") + .arg(format!("of={}", cache_dev_name)) + .arg("bs=512") + .arg("count=1") + .status() + .expect("Failed to zero out the cache device"); + assert!(status.success()); + } + + let mut optionals: Vec = Vec::new(); + if args.write_around_mode { + optionals.push("write_around_mode".to_string()); + optionals.push("1".to_string()); + } + if let Some(v) = args.writeback_threshold { + optionals.push("writeback_threshold".to_string()); + optionals.push(v.to_string()); + } + if let Some(v) = args.nr_max_batched_writeback { + optionals.push("nr_max_batched_writeback".to_string()); + optionals.push(v.to_string()); + } + if let Some(v) = args.update_sb_record_interval { + optionals.push("update_sb_record_interval".to_string()); + optionals.push(v.to_string()); + } + if let Some(v) = args.sync_data_interval { + optionals.push("sync_data_interval".to_string()); + optionals.push(v.to_string()); + } + if let Some(v) = args.read_cache_threshold { + optionals.push("read_cache_threshold".to_string()); + optionals.push(v.to_string()); + } + + let n = optionals.len(); + + let optionals_table = if n == 0 { + "".to_string() + } else { + format!(" {} {}", n, optionals.join(" ")) + }; + + let table = format!( + "0 {} writeboost {} {}{}", + backing_dev.size(), + backing_dev.name(), + cache_dev_name, + optionals_table + ); + + let status = Command::new("dmsetup") + .arg("create") + .arg(wbname) + .arg("--table") + .arg(table) + .status() + .expect("Failed to execute dmsetup create"); + assert!(status.success()); +} diff --git a/writeboost-cli/src/wbdump.rs b/writeboost-cli/src/wbdump.rs new file mode 100644 index 0000000..ad339ed --- /dev/null +++ b/writeboost-cli/src/wbdump.rs @@ -0,0 +1,49 @@ +extern crate clap; + +use std::str::FromStr; + +use clap::Parser; +#[derive(Parser)] +#[command(name = "wbdump")] +#[command(about = "Dump a cache block")] +#[command(author, version)] +struct Args { + #[arg(help = "Path to the cache device")] + cachedev: String, + #[arg(help = "Metablock index")] + mbidx: i32, + #[arg(long, help = "MBIDX is relative to this SEGID (default is 1)")] + #[arg(default_value_t = 1)] + segid: i32, +} + +fn main() { + let args = Args::parse(); + + let mb_idx: i32 = args.mbidx; + let cache_dev = { + let devname = args.cachedev; + lib::CacheDevice::new(devname.to_owned()) + }; + + let mut base_id = args.segid; + + base_id += mb_idx / 127; + let idx_inseg = mb_idx % 127; + let start_byte = (cache_dev.calc_segment_start(base_id) << 9) + ((1 + idx_inseg) << 12); + + use std::process::Command; + let output = Command::new("od") + .arg(format!("-j{}", start_byte)) + .arg("-N4096") + .arg("-Ax") + .arg(&cache_dev.dev.name()) + .output() + .expect("failed to execute od") + .stdout; + let output = String::from_utf8(output) + .expect("invalid utf8 output") + .to_string(); + let output = output.trim(); + println!("{}", output); +} diff --git a/writeboost-cli/src/wbmeta.rs b/writeboost-cli/src/wbmeta.rs new file mode 100644 index 0000000..b3709b9 --- /dev/null +++ b/writeboost-cli/src/wbmeta.rs @@ -0,0 +1,74 @@ +extern crate clap; + +use std::fs::File; +use std::io::Read; +use std::io::Seek; +use std::io::SeekFrom; + +use clap::Parser; +#[derive(Parser)] +#[command(name = "wbmeta")] +#[command(about = "Dump a segment header")] +#[command(author, version)] +struct Args { + #[arg(help = "Path to the cache device")] + cachedev: String, + #[arg(help = "Segment id. 0 means the superblock")] + segid: i32, +} + +fn main() { + let args = Args::parse(); + + let devname: String = args.cachedev; + let id: i32 = args.segid; + + let cache_dev = lib::CacheDevice::new(devname.to_owned()); + + if id == 0 { + // superblock + let mut buf = [0; 512]; + let mut f = File::open(&devname).unwrap(); + f.read(&mut buf).unwrap(); + let sup_header = lib::SuperBlockHeader::from_buf(&buf); + + let s = if sup_header.magic == 0x57427374 { + "formatted" + } else { + "unformatted" + }; + + println!("[superblock header]"); + println!("magic = {} ({})", sup_header.magic, s); + + f.seek(SeekFrom::Start((1u64 << 20) - 512)).unwrap(); + f.read(&mut buf).unwrap(); + let sup_record = lib::SuperBlockRecord::from_buf(&buf); + + println!("[superblock record]"); + println!( + "last writeback id = {}", + sup_record.last_writeback_segment_id + ); + } else { + // header + let mut buf = [0; 4096]; + let mut f = File::open(&devname).unwrap(); + let start_byte: u64 = (cache_dev.calc_segment_start(id) as u64) << 9; + f.seek(SeekFrom::Start(start_byte)).unwrap(); + f.read(&mut buf).unwrap(); + let (header, metablocks) = lib::Segment::from_buf(&buf); + + println!("[segment header]"); + println!("id = {}", header.id); + println!("checksumx = {}", header.checksum); + println!("length = {}", header.length); + + for (i, metablock) in metablocks.iter().enumerate() { + println!( + "[{}] sector={}, dirty_bits={}", + i, metablock.sector, metablock.dirty_bits + ); + } + } +} diff --git a/writeboost-cli/src/wbremove.rs b/writeboost-cli/src/wbremove.rs new file mode 100644 index 0000000..07c7eb3 --- /dev/null +++ b/writeboost-cli/src/wbremove.rs @@ -0,0 +1,79 @@ +extern crate clap; + +use clap::Parser; +use std::process::Command; + +#[derive(Parser)] +#[command(name = "wbremove")] +#[command(about = "Remove a writeboost device")] +#[command(author, version)] +struct Args { + #[arg(help = "Name of the writeboost device")] + lvname: String, + #[arg(long, help = "Don't flush RAM buffer to cache device before removing")] + noflush: bool, + #[arg( + long, + help = "Don't write back dirty caches to the backing device before removing" + )] + nowriteback: bool, +} + +fn main() { + let args = Args::parse(); + + let wbname = args.lvname; + + let do_flush = !args.noflush; + if do_flush { + let status = Command::new("dmsetup") + .arg("suspend") + .arg(&wbname) + .status() + .expect("Failed to flush transient data"); + assert!(status.success()); + + let status = Command::new("dmsetup") + .arg("resume") + .arg(&wbname) + .status() + .expect("Failed to flush transient data"); + assert!(status.success()); + } + + let do_writeback = !args.nowriteback; + if do_writeback { + let status = Command::new("dmsetup") + .arg("message") + .arg(&wbname) + .arg("0") + .arg("drop_caches") + .status() + .expect("Failed to drop caches"); + assert!(status.success()); + } + + let cache_dev_name = lib::WBDev::new(wbname.to_string()) + .table() + .cache_dev + .sys_dev_table() + .get("DEVNAME"); + + let status = Command::new("dmsetup") + .arg("remove") + .arg(&wbname) + .status() + .expect("Failed to execute dmsetup remove"); + assert!(status.success()); + + if do_writeback { + let status = Command::new("dd") + .arg("if=/dev/zero") + .arg(format!("of=/dev/{}", cache_dev_name)) + .arg("bs=512") + .arg("count=1") + .status() + .expect("Failed to zero out the cache device"); + assert!(status.success()); + } +} diff --git a/writeboost-cli/src/wbstatus.rs b/writeboost-cli/src/wbstatus.rs new file mode 100644 index 0000000..822b1a6 --- /dev/null +++ b/writeboost-cli/src/wbstatus.rs @@ -0,0 +1,63 @@ +extern crate clap; + +use std::io::{self, Read}; + +fn print_status(s: &str) { + let toks: Vec<&str> = { s.split_whitespace().collect() }; + + println!("cursor pos = {}", toks[3]); + println!("# of cache blocks = {}", toks[4]); + println!("# of segments = {}", toks[5]); + println!("current id = {}", toks[6]); + println!("last flushed id = {}", toks[7]); + println!("last writeback id = {}", toks[8]); + println!("# of dirty cache blocks = {}", toks[9]); + println!("# of partial flushes = {}", toks[26]); + + println!("write? hit? on_buffer? fullsize?"); + for i in 0..16 { + let b = |bit: usize| { + if (i & (1 << bit)) > 0 { + 1 + } else { + 0 + } + }; + let v = toks[10 + i]; + println!( + "{} {} {} {} {}", + b(3), + b(2), + b(1), + b(0), + v + ); + } +} + +#[test] +fn test_print_status() { + let mut buf = String::new(); + let mut f = std::fs::File::open("data/sample.status.226").unwrap(); + f.read_to_string(&mut buf).unwrap(); + print_status(&buf); +} + +use clap::Parser; +#[derive(Parser)] +#[command(name = "wbstatus")] +#[command(about = "Pretty-print the dmsetup status output")] +#[command(override_usage = "dmsetup status wbdev | wbstatus")] +#[command(author, version)] +struct Args; + +fn main() -> anyhow::Result<()> { + let _ = Args::parse(); + + let mut buf = String::new(); + io::stdin().read_to_string(&mut buf)?; + + print_status(&buf); + + Ok(()) +} From 225c6500668e119d65fb2a58d3a95c0550f891f4 Mon Sep 17 00:00:00 2001 From: Akira Hayakawa Date: Thu, 1 Jan 2026 21:10:35 +0900 Subject: [PATCH 3/6] Change to subcommand style --- writeboost-cli/Cargo.toml | 35 +++---------------- writeboost-cli/src/main.rs | 35 +++++++++++++++++++ .../src/{wbcheck.rs => sub/check/mod.rs} | 18 ++++------ .../src/{wbcreate.rs => sub/create/mod.rs} | 16 ++++----- .../src/{wbdump.rs => sub/dump/mod.rs} | 16 +++------ .../src/{wbmeta.rs => sub/meta/mod.rs} | 20 +++++------ writeboost-cli/src/sub/mod.rs | 8 +++++ .../src/{wbremove.rs => sub/remove/mod.rs} | 14 +++----- .../src/{wbstatus.rs => sub/status/mod.rs} | 16 +++------ writeboost-cli/src/{lib.rs => utils.rs} | 5 +-- 10 files changed, 83 insertions(+), 100 deletions(-) create mode 100644 writeboost-cli/src/main.rs rename writeboost-cli/src/{wbcheck.rs => sub/check/mod.rs} (82%) rename writeboost-cli/src/{wbcreate.rs => sub/create/mod.rs} (94%) rename writeboost-cli/src/{wbdump.rs => sub/dump/mod.rs} (82%) rename writeboost-cli/src/{wbmeta.rs => sub/meta/mod.rs} (81%) create mode 100644 writeboost-cli/src/sub/mod.rs rename writeboost-cli/src/{wbremove.rs => sub/remove/mod.rs} (90%) rename writeboost-cli/src/{wbstatus.rs => sub/status/mod.rs} (86%) rename writeboost-cli/src/{lib.rs => utils.rs} (97%) diff --git a/writeboost-cli/Cargo.toml b/writeboost-cli/Cargo.toml index 94f7832..8309c04 100644 --- a/writeboost-cli/Cargo.toml +++ b/writeboost-cli/Cargo.toml @@ -1,38 +1,11 @@ [package] name = "writeboost-cli" -version = "1.1.0" +version = "2.0.0" authors = ["Akira Hayakawa "] +edition = "2024" [dependencies] -crc = "3" +anyhow = "1" byteorder = "1" clap = { version = "4", features = ["derive"] } -anyhow = "1" - -[[bin]] -name = "wbcheck" -path = "src/wbcheck.rs" - -[[bin]] -name = "wbcreate" -path = "src/wbcreate.rs" - -[[bin]] -name = "wbdump" -path = "src/wbdump.rs" - -[[bin]] -name = "wbmeta" -path = "src/wbmeta.rs" - -[[bin]] -name = "wbremove" -path = "src/wbremove.rs" - -[[bin]] -name = "wbstatus" -path = "src/wbstatus.rs" - -[lib] -name = "lib" -path = "src/lib.rs" +crc = "3" \ No newline at end of file diff --git a/writeboost-cli/src/main.rs b/writeboost-cli/src/main.rs new file mode 100644 index 0000000..c32325b --- /dev/null +++ b/writeboost-cli/src/main.rs @@ -0,0 +1,35 @@ +use clap::{Parser, Args, Subcommand}; + +mod sub; + +mod utils; +use utils::*; + +#[derive(Subcommand)] +enum Sub { + Check(sub::check::Opts), + Create(sub::create::Opts), + Remove(sub::remove::Opts), + Dump(sub::dump::Opts), + Meta(sub::meta::Opts), + Status(sub::status::Opts), +} + +#[derive(Parser)] +struct Opts { + #[clap(subcommand)] + sub: Sub, +} + +fn main() { + let opts = Opts::parse(); + + match opts.sub { + Sub::Check(args) => sub::check::run(args), + Sub::Create(args) => sub::create::run(args), + Sub::Remove(args) => sub::remove::run(args), + Sub::Dump(args) => sub::dump::run(args), + Sub::Meta(args) => sub::meta::run(args), + Sub::Status(args) => sub::status::run(args), + } +} \ No newline at end of file diff --git a/writeboost-cli/src/wbcheck.rs b/writeboost-cli/src/sub/check/mod.rs similarity index 82% rename from writeboost-cli/src/wbcheck.rs rename to writeboost-cli/src/sub/check/mod.rs index 6adc41b..935d45d 100644 --- a/writeboost-cli/src/wbcheck.rs +++ b/writeboost-cli/src/sub/check/mod.rs @@ -1,5 +1,4 @@ -extern crate clap; -extern crate crc; +use super::*; use std::fs::File; use std::io::Read; @@ -12,12 +11,9 @@ fn checksum(data: &[u8]) -> u32 { CASTAGNOLI.checksum(data) } -use clap::Parser; -#[derive(Parser)] -#[command(name = "wbcheck")] +#[derive(Args)] #[command(about = "Check if the segment is broken")] -#[command(author, version)] -struct Args { +pub struct Opts { #[arg(help = "Path to the cache device")] cachedev: String, #[arg(help = "Segment id")] @@ -30,12 +26,10 @@ fn test_checksum() { assert_eq!(checksum(&buf), 143703573); } -fn main() { - let args = Args::parse(); - +pub fn run(args: Opts) { let devname: String = args.cachedev; let id = args.segid; - let cache_dev = lib::CacheDevice::new(devname.to_owned()); + let cache_dev = CacheDevice::new(devname.to_owned()); let mut f = File::open(&devname).expect(&format!("Device {} not found", &devname)); @@ -45,7 +39,7 @@ fn main() { let header = { let mut buf = vec![0; 512]; f.read(&mut buf).unwrap(); - lib::SegmentHeader::from_buf(&buf) + SegmentHeader::from_buf(&buf) }; if header.uninitialized() { diff --git a/writeboost-cli/src/wbcreate.rs b/writeboost-cli/src/sub/create/mod.rs similarity index 94% rename from writeboost-cli/src/wbcreate.rs rename to writeboost-cli/src/sub/create/mod.rs index 9450071..5292d86 100644 --- a/writeboost-cli/src/wbcreate.rs +++ b/writeboost-cli/src/sub/create/mod.rs @@ -1,14 +1,12 @@ -extern crate clap; - +use super::*; + use std::process::Command; -use clap::Parser; -#[derive(Parser)] -#[command(name = "wbcreate")] +#[derive(Args)] #[command(about = "Create a writeboost device")] #[command(author, version)] #[clap(rename_all = "snake_case")] -struct Args { +pub struct Opts { #[arg(help = "Name of the writeboost device")] lvname: String, #[arg(help = "Path to the backing device")] @@ -34,13 +32,11 @@ struct Args { read_cache_threshold: Option, } -fn main() { - let args = Args::parse(); - +pub fn run(args: Opts) { let wbname = args.lvname; let backing_dev = { let name = args.backingdev; - lib::BlockDevice::new(name) + BlockDevice::new(name) }; let cache_dev_name = args.cachedev; diff --git a/writeboost-cli/src/wbdump.rs b/writeboost-cli/src/sub/dump/mod.rs similarity index 82% rename from writeboost-cli/src/wbdump.rs rename to writeboost-cli/src/sub/dump/mod.rs index ad339ed..b036a8e 100644 --- a/writeboost-cli/src/wbdump.rs +++ b/writeboost-cli/src/sub/dump/mod.rs @@ -1,13 +1,9 @@ -extern crate clap; +use super::*; -use std::str::FromStr; - -use clap::Parser; -#[derive(Parser)] -#[command(name = "wbdump")] +#[derive(Args)] #[command(about = "Dump a cache block")] #[command(author, version)] -struct Args { +pub struct Opts { #[arg(help = "Path to the cache device")] cachedev: String, #[arg(help = "Metablock index")] @@ -17,13 +13,11 @@ struct Args { segid: i32, } -fn main() { - let args = Args::parse(); - +pub fn run(args: Opts) { let mb_idx: i32 = args.mbidx; let cache_dev = { let devname = args.cachedev; - lib::CacheDevice::new(devname.to_owned()) + CacheDevice::new(devname.to_owned()) }; let mut base_id = args.segid; diff --git a/writeboost-cli/src/wbmeta.rs b/writeboost-cli/src/sub/meta/mod.rs similarity index 81% rename from writeboost-cli/src/wbmeta.rs rename to writeboost-cli/src/sub/meta/mod.rs index b3709b9..32f68d7 100644 --- a/writeboost-cli/src/wbmeta.rs +++ b/writeboost-cli/src/sub/meta/mod.rs @@ -1,36 +1,32 @@ -extern crate clap; +use super::*; use std::fs::File; use std::io::Read; use std::io::Seek; use std::io::SeekFrom; -use clap::Parser; -#[derive(Parser)] -#[command(name = "wbmeta")] +#[derive(Args)] #[command(about = "Dump a segment header")] #[command(author, version)] -struct Args { +pub struct Opts { #[arg(help = "Path to the cache device")] cachedev: String, #[arg(help = "Segment id. 0 means the superblock")] segid: i32, } -fn main() { - let args = Args::parse(); - +pub fn run(args: Opts) { let devname: String = args.cachedev; let id: i32 = args.segid; - let cache_dev = lib::CacheDevice::new(devname.to_owned()); + let cache_dev = CacheDevice::new(devname.to_owned()); if id == 0 { // superblock let mut buf = [0; 512]; let mut f = File::open(&devname).unwrap(); f.read(&mut buf).unwrap(); - let sup_header = lib::SuperBlockHeader::from_buf(&buf); + let sup_header = SuperBlockHeader::from_buf(&buf); let s = if sup_header.magic == 0x57427374 { "formatted" @@ -43,7 +39,7 @@ fn main() { f.seek(SeekFrom::Start((1u64 << 20) - 512)).unwrap(); f.read(&mut buf).unwrap(); - let sup_record = lib::SuperBlockRecord::from_buf(&buf); + let sup_record = SuperBlockRecord::from_buf(&buf); println!("[superblock record]"); println!( @@ -57,7 +53,7 @@ fn main() { let start_byte: u64 = (cache_dev.calc_segment_start(id) as u64) << 9; f.seek(SeekFrom::Start(start_byte)).unwrap(); f.read(&mut buf).unwrap(); - let (header, metablocks) = lib::Segment::from_buf(&buf); + let (header, metablocks) = Segment::from_buf(&buf); println!("[segment header]"); println!("id = {}", header.id); diff --git a/writeboost-cli/src/sub/mod.rs b/writeboost-cli/src/sub/mod.rs new file mode 100644 index 0000000..52d4eaa --- /dev/null +++ b/writeboost-cli/src/sub/mod.rs @@ -0,0 +1,8 @@ +use super::*; + +pub mod check; +pub mod create; +pub mod dump; +pub mod meta; +pub mod remove; +pub mod status; \ No newline at end of file diff --git a/writeboost-cli/src/wbremove.rs b/writeboost-cli/src/sub/remove/mod.rs similarity index 90% rename from writeboost-cli/src/wbremove.rs rename to writeboost-cli/src/sub/remove/mod.rs index 07c7eb3..32e8cbf 100644 --- a/writeboost-cli/src/wbremove.rs +++ b/writeboost-cli/src/sub/remove/mod.rs @@ -1,13 +1,11 @@ -extern crate clap; +use super::*; -use clap::Parser; use std::process::Command; -#[derive(Parser)] -#[command(name = "wbremove")] +#[derive(Args)] #[command(about = "Remove a writeboost device")] #[command(author, version)] -struct Args { +pub struct Opts { #[arg(help = "Name of the writeboost device")] lvname: String, #[arg(long, help = "Don't flush RAM buffer to cache device before removing")] @@ -19,9 +17,7 @@ struct Args { nowriteback: bool, } -fn main() { - let args = Args::parse(); - +pub fn run(args: Opts) { let wbname = args.lvname; let do_flush = !args.noflush; @@ -53,7 +49,7 @@ fn main() { assert!(status.success()); } - let cache_dev_name = lib::WBDev::new(wbname.to_string()) + let cache_dev_name = WBDev::new(wbname.to_string()) .table() .cache_dev .sys_dev_table() diff --git a/writeboost-cli/src/wbstatus.rs b/writeboost-cli/src/sub/status/mod.rs similarity index 86% rename from writeboost-cli/src/wbstatus.rs rename to writeboost-cli/src/sub/status/mod.rs index 822b1a6..9a3c5f4 100644 --- a/writeboost-cli/src/wbstatus.rs +++ b/writeboost-cli/src/sub/status/mod.rs @@ -1,4 +1,4 @@ -extern crate clap; +use super::*; use std::io::{self, Read}; @@ -43,21 +43,15 @@ fn test_print_status() { print_status(&buf); } -use clap::Parser; -#[derive(Parser)] -#[command(name = "wbstatus")] +#[derive(Args)] #[command(about = "Pretty-print the dmsetup status output")] #[command(override_usage = "dmsetup status wbdev | wbstatus")] #[command(author, version)] -struct Args; - -fn main() -> anyhow::Result<()> { - let _ = Args::parse(); +pub struct Opts; +pub fn run(_: Opts) { let mut buf = String::new(); - io::stdin().read_to_string(&mut buf)?; + io::stdin().read_to_string(&mut buf).unwrap(); print_status(&buf); - - Ok(()) } diff --git a/writeboost-cli/src/lib.rs b/writeboost-cli/src/utils.rs similarity index 97% rename from writeboost-cli/src/lib.rs rename to writeboost-cli/src/utils.rs index de67f83..b6f592b 100644 --- a/writeboost-cli/src/lib.rs +++ b/writeboost-cli/src/utils.rs @@ -1,4 +1,4 @@ -extern crate byteorder; +use super::*; use byteorder::{LittleEndian, ReadBytesExt}; use std::collections::HashMap; @@ -9,9 +9,6 @@ use std::io::Seek; use std::io::SeekFrom; use std::process::Command; -pub static VERSION: &'static str = "1.0.1"; -pub static AUTHOR: &'static str = "Akira Hayakawa "; - pub struct BlockDevice { name: String, } From 023b6cfe2311fcdac19c1c399161ac118e714f8d Mon Sep 17 00:00:00 2001 From: Akira Hayakawa Date: Thu, 1 Jan 2026 22:23:10 +0900 Subject: [PATCH 4/6] refactor --- writeboost-cli/src/main.rs | 18 +++++----- writeboost-cli/src/sub/check/mod.rs | 21 +++++++----- writeboost-cli/src/sub/create/mod.rs | 4 +-- writeboost-cli/src/sub/dump/mod.rs | 4 +-- writeboost-cli/src/sub/meta/mod.rs | 4 +-- writeboost-cli/src/sub/remove/mod.rs | 4 +-- writeboost-cli/src/sub/status/mod.rs | 23 ++++++++----- writeboost-cli/src/utils.rs | 49 ++++++++++++++++++---------- 8 files changed, 75 insertions(+), 52 deletions(-) diff --git a/writeboost-cli/src/main.rs b/writeboost-cli/src/main.rs index c32325b..9e169d8 100644 --- a/writeboost-cli/src/main.rs +++ b/writeboost-cli/src/main.rs @@ -7,24 +7,24 @@ use utils::*; #[derive(Subcommand)] enum Sub { - Check(sub::check::Opts), - Create(sub::create::Opts), - Remove(sub::remove::Opts), - Dump(sub::dump::Opts), - Meta(sub::meta::Opts), - Status(sub::status::Opts), + Check(sub::check::CommandArgs), + Create(sub::create::CommandArgs), + Remove(sub::remove::CommandArgs), + Dump(sub::dump::CommandArgs), + Meta(sub::meta::CommandArgs), + Status(sub::status::CommandArgs), } #[derive(Parser)] -struct Opts { +struct CommandArgs { #[clap(subcommand)] sub: Sub, } fn main() { - let opts = Opts::parse(); + let args = CommandArgs::parse(); - match opts.sub { + match args.sub { Sub::Check(args) => sub::check::run(args), Sub::Create(args) => sub::create::run(args), Sub::Remove(args) => sub::remove::run(args), diff --git a/writeboost-cli/src/sub/check/mod.rs b/writeboost-cli/src/sub/check/mod.rs index 935d45d..404de66 100644 --- a/writeboost-cli/src/sub/check/mod.rs +++ b/writeboost-cli/src/sub/check/mod.rs @@ -11,22 +11,27 @@ fn checksum(data: &[u8]) -> u32 { CASTAGNOLI.checksum(data) } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_checksum() { + let buf = vec![0; 4096 - 512]; + assert_eq!(checksum(&buf), 143703573); + } +} + #[derive(Args)] #[command(about = "Check if the segment is broken")] -pub struct Opts { +pub struct CommandArgs { #[arg(help = "Path to the cache device")] cachedev: String, #[arg(help = "Segment id")] segid: i32, } -#[test] -fn test_checksum() { - let buf = vec![0; 4096 - 512]; - assert_eq!(checksum(&buf), 143703573); -} - -pub fn run(args: Opts) { +pub fn run(args: CommandArgs) { let devname: String = args.cachedev; let id = args.segid; let cache_dev = CacheDevice::new(devname.to_owned()); diff --git a/writeboost-cli/src/sub/create/mod.rs b/writeboost-cli/src/sub/create/mod.rs index 5292d86..a01a999 100644 --- a/writeboost-cli/src/sub/create/mod.rs +++ b/writeboost-cli/src/sub/create/mod.rs @@ -6,7 +6,7 @@ use std::process::Command; #[command(about = "Create a writeboost device")] #[command(author, version)] #[clap(rename_all = "snake_case")] -pub struct Opts { +pub struct CommandArgs { #[arg(help = "Name of the writeboost device")] lvname: String, #[arg(help = "Path to the backing device")] @@ -32,7 +32,7 @@ pub struct Opts { read_cache_threshold: Option, } -pub fn run(args: Opts) { +pub fn run(args: CommandArgs) { let wbname = args.lvname; let backing_dev = { let name = args.backingdev; diff --git a/writeboost-cli/src/sub/dump/mod.rs b/writeboost-cli/src/sub/dump/mod.rs index b036a8e..6ef03d0 100644 --- a/writeboost-cli/src/sub/dump/mod.rs +++ b/writeboost-cli/src/sub/dump/mod.rs @@ -3,7 +3,7 @@ use super::*; #[derive(Args)] #[command(about = "Dump a cache block")] #[command(author, version)] -pub struct Opts { +pub struct CommandArgs { #[arg(help = "Path to the cache device")] cachedev: String, #[arg(help = "Metablock index")] @@ -13,7 +13,7 @@ pub struct Opts { segid: i32, } -pub fn run(args: Opts) { +pub fn run(args: CommandArgs) { let mb_idx: i32 = args.mbidx; let cache_dev = { let devname = args.cachedev; diff --git a/writeboost-cli/src/sub/meta/mod.rs b/writeboost-cli/src/sub/meta/mod.rs index 32f68d7..daa319a 100644 --- a/writeboost-cli/src/sub/meta/mod.rs +++ b/writeboost-cli/src/sub/meta/mod.rs @@ -8,14 +8,14 @@ use std::io::SeekFrom; #[derive(Args)] #[command(about = "Dump a segment header")] #[command(author, version)] -pub struct Opts { +pub struct CommandArgs { #[arg(help = "Path to the cache device")] cachedev: String, #[arg(help = "Segment id. 0 means the superblock")] segid: i32, } -pub fn run(args: Opts) { +pub fn run(args: CommandArgs) { let devname: String = args.cachedev; let id: i32 = args.segid; diff --git a/writeboost-cli/src/sub/remove/mod.rs b/writeboost-cli/src/sub/remove/mod.rs index 32e8cbf..061362f 100644 --- a/writeboost-cli/src/sub/remove/mod.rs +++ b/writeboost-cli/src/sub/remove/mod.rs @@ -5,7 +5,7 @@ use std::process::Command; #[derive(Args)] #[command(about = "Remove a writeboost device")] #[command(author, version)] -pub struct Opts { +pub struct CommandArgs { #[arg(help = "Name of the writeboost device")] lvname: String, #[arg(long, help = "Don't flush RAM buffer to cache device before removing")] @@ -17,7 +17,7 @@ pub struct Opts { nowriteback: bool, } -pub fn run(args: Opts) { +pub fn run(args: CommandArgs) { let wbname = args.lvname; let do_flush = !args.noflush; diff --git a/writeboost-cli/src/sub/status/mod.rs b/writeboost-cli/src/sub/status/mod.rs index 9a3c5f4..9e04e5c 100644 --- a/writeboost-cli/src/sub/status/mod.rs +++ b/writeboost-cli/src/sub/status/mod.rs @@ -35,23 +35,28 @@ fn print_status(s: &str) { } } -#[test] -fn test_print_status() { - let mut buf = String::new(); - let mut f = std::fs::File::open("data/sample.status.226").unwrap(); - f.read_to_string(&mut buf).unwrap(); - print_status(&buf); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_print_status() { + let mut buf = String::new(); + let mut f = std::fs::File::open("data/sample.status.226").unwrap(); + f.read_to_string(&mut buf).unwrap(); + print_status(&buf); + } } #[derive(Args)] #[command(about = "Pretty-print the dmsetup status output")] #[command(override_usage = "dmsetup status wbdev | wbstatus")] #[command(author, version)] -pub struct Opts; +pub struct CommandArgs; -pub fn run(_: Opts) { +pub fn run(_: CommandArgs) { let mut buf = String::new(); io::stdin().read_to_string(&mut buf).unwrap(); print_status(&buf); -} +} \ No newline at end of file diff --git a/writeboost-cli/src/utils.rs b/writeboost-cli/src/utils.rs index b6f592b..7676075 100644 --- a/writeboost-cli/src/utils.rs +++ b/writeboost-cli/src/utils.rs @@ -17,9 +17,11 @@ impl BlockDevice { pub fn new(name_: String) -> Self { BlockDevice { name: name_ } } + pub fn name(&self) -> String { self.name.to_owned() } + pub fn size(&self) -> i64 { use std::str::FromStr; let output: Vec = Command::new("blockdev") @@ -46,9 +48,11 @@ impl CacheDevice { dev: BlockDevice::new(name), } } + fn nr_segments(&self) -> i32 { ((self.dev.size() - (1 << 11)) / (1 << 10)) as i32 } + pub fn calc_segment_start(&self, id: i32) -> i32 { let idx = (id - 1) % self.nr_segments(); (1 << 11) + (idx * (1 << 10)) @@ -73,6 +77,7 @@ impl SegmentHeader { length: length_, } } + pub fn uninitialized(&self) -> bool { self.id == 0 } @@ -83,7 +88,7 @@ pub struct Metablock { pub dirty_bits: u8, } -pub struct Segment {} +pub struct Segment; impl Segment { pub fn from_buf(buf: &[u8]) -> (SegmentHeader, Vec) { @@ -153,17 +158,12 @@ impl SysDevTable { } SysDevTable { map: m } } + pub fn get(&self, name: &str) -> String { self.map[name].to_string() } } -#[test] -fn test_read_sys_dev_file() { - let t = SysDevTable::from_file("data/sys_dev.0"); - assert_eq!(t.get("DEVNAME"), "vda1"); -} - pub struct BlockNumber { value: String, } @@ -172,6 +172,7 @@ impl BlockNumber { pub fn unwrap(&self) -> String { self.value.to_owned() } + pub fn sys_dev_table(&self) -> SysDevTable { let path = format!("/sys/dev/block/{}/uevent", self.value); SysDevTable::from_file(&path) @@ -201,17 +202,6 @@ impl DMTable { } } -#[test] -fn test_dmtable_parse() { - let mut s = String::new(); - let mut f = File::open("data/sample.table.226").unwrap(); - f.read_to_string(&mut s).unwrap(); - let t = DMTable::parse(s.trim().to_string()); - println!("{}", s.clone()); - assert_eq!(t.backing_dev.unwrap(), "251:0"); - assert_eq!(t.cache_dev.unwrap(), "251:3"); -} - pub struct WBDev { name: String, } @@ -220,6 +210,7 @@ impl WBDev { pub fn new(name_: String) -> WBDev { WBDev { name: name_ } } + pub fn table(&self) -> DMTable { let output = Command::new("dmsetup") .arg("table") @@ -234,3 +225,25 @@ impl WBDev { DMTable::parse(output) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_read_sys_dev_file() { + let t = SysDevTable::from_file("data/sys_dev.0"); + assert_eq!(t.get("DEVNAME"), "vda1"); + } + + #[test] + fn test_dmtable_parse() { + let mut s = String::new(); + let mut f = File::open("data/sample.table.226").unwrap(); + f.read_to_string(&mut s).unwrap(); + let t = DMTable::parse(s.trim().to_string()); + println!("{}", s.clone()); + assert_eq!(t.backing_dev.unwrap(), "251:0"); + assert_eq!(t.cache_dev.unwrap(), "251:3"); + } +} \ No newline at end of file From 60d8b6aa82c795e8bbd1cd009a3a4173cccab87d Mon Sep 17 00:00:00 2001 From: Akira Hayakawa Date: Fri, 2 Jan 2026 08:04:11 +0900 Subject: [PATCH 5/6] fmt --- writeboost-cli/src/main.rs | 4 ++-- writeboost-cli/src/sub/check/mod.rs | 4 ++-- writeboost-cli/src/sub/create/mod.rs | 2 +- writeboost-cli/src/sub/mod.rs | 2 +- writeboost-cli/src/sub/status/mod.rs | 8 ++------ writeboost-cli/src/utils.rs | 2 +- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/writeboost-cli/src/main.rs b/writeboost-cli/src/main.rs index 9e169d8..eb386e5 100644 --- a/writeboost-cli/src/main.rs +++ b/writeboost-cli/src/main.rs @@ -1,4 +1,4 @@ -use clap::{Parser, Args, Subcommand}; +use clap::{Args, Parser, Subcommand}; mod sub; @@ -32,4 +32,4 @@ fn main() { Sub::Meta(args) => sub::meta::run(args), Sub::Status(args) => sub::status::run(args), } -} \ No newline at end of file +} diff --git a/writeboost-cli/src/sub/check/mod.rs b/writeboost-cli/src/sub/check/mod.rs index 404de66..7934e4e 100644 --- a/writeboost-cli/src/sub/check/mod.rs +++ b/writeboost-cli/src/sub/check/mod.rs @@ -5,7 +5,7 @@ use std::io::Read; use std::io::Seek; use std::io::SeekFrom; -use crc::{Crc, CRC_32_ISCSI}; +use crc::{CRC_32_ISCSI, Crc}; pub const CASTAGNOLI: Crc = Crc::::new(&CRC_32_ISCSI); fn checksum(data: &[u8]) -> u32 { CASTAGNOLI.checksum(data) @@ -14,7 +14,7 @@ fn checksum(data: &[u8]) -> u32 { #[cfg(test)] mod tests { use super::*; - + #[test] fn test_checksum() { let buf = vec![0; 4096 - 512]; diff --git a/writeboost-cli/src/sub/create/mod.rs b/writeboost-cli/src/sub/create/mod.rs index a01a999..cdb82df 100644 --- a/writeboost-cli/src/sub/create/mod.rs +++ b/writeboost-cli/src/sub/create/mod.rs @@ -1,5 +1,5 @@ use super::*; - + use std::process::Command; #[derive(Args)] diff --git a/writeboost-cli/src/sub/mod.rs b/writeboost-cli/src/sub/mod.rs index 52d4eaa..cd4def1 100644 --- a/writeboost-cli/src/sub/mod.rs +++ b/writeboost-cli/src/sub/mod.rs @@ -5,4 +5,4 @@ pub mod create; pub mod dump; pub mod meta; pub mod remove; -pub mod status; \ No newline at end of file +pub mod status; diff --git a/writeboost-cli/src/sub/status/mod.rs b/writeboost-cli/src/sub/status/mod.rs index 9e04e5c..0402eb3 100644 --- a/writeboost-cli/src/sub/status/mod.rs +++ b/writeboost-cli/src/sub/status/mod.rs @@ -17,11 +17,7 @@ fn print_status(s: &str) { println!("write? hit? on_buffer? fullsize?"); for i in 0..16 { let b = |bit: usize| { - if (i & (1 << bit)) > 0 { - 1 - } else { - 0 - } + if (i & (1 << bit)) > 0 { 1 } else { 0 } }; let v = toks[10 + i]; println!( @@ -59,4 +55,4 @@ pub fn run(_: CommandArgs) { io::stdin().read_to_string(&mut buf).unwrap(); print_status(&buf); -} \ No newline at end of file +} diff --git a/writeboost-cli/src/utils.rs b/writeboost-cli/src/utils.rs index 7676075..4f82146 100644 --- a/writeboost-cli/src/utils.rs +++ b/writeboost-cli/src/utils.rs @@ -246,4 +246,4 @@ mod tests { assert_eq!(t.backing_dev.unwrap(), "251:0"); assert_eq!(t.cache_dev.unwrap(), "251:3"); } -} \ No newline at end of file +} From 313081153013b156f9add0122b96aa7020c56778 Mon Sep 17 00:00:00 2001 From: Akira Hayakawa Date: Fri, 2 Jan 2026 09:38:04 +0900 Subject: [PATCH 6/6] fix README --- README.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 618bacc..4d0d0db 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ Rustup is the best way to install Rust toolset. https://github.com/rust-lang-nursery/rustup.rs -Then `cargo install` to install the commands. +Then `cargo install --path writeboost-cli` to install **writeboost-cli**. +(For older version, `cargo install --path wbtools`) ## Video @@ -19,46 +20,46 @@ https://www.youtube.com/watch?v=QAXbmr2Rf30 ## Commands (Lexicographical order) -### wbcheck +### check Check if the log was written successfully. -* `wbcheck /dev/cache 1` checks the segment ID 1. Returns 0 on success. +* `writeboost-cli check /dev/cache 1` checks the segment ID 1. Returns 0 on success. -### wbcreate +### create Create a WB device (wrapping dmsetup create) -* `wbcreate wbdev /dev/backing /dev/cache --reformat` creates a WB device with reformatting -* `wbcreate wbdev /dev/backing /dev/cache --reformat --read_cache_threshold=4 --writeback_threshold=70` +* `writeboost-cli create wbdev /dev/backing /dev/cache --reformat` creates a WB device with reformatting +* `writeboost-cli create wbdev /dev/backing /dev/cache --reformat --read_cache_threshold=4 --writeback_threshold=70` creates a WB device with some settings -### wbdump +### dump Dump the data blocks corresponding to the specified metablock ID. -* `wbdump /dev/cache 126` dumps the data block of metablock index 126 +* `writeboost-cli dump /dev/cache 126` dumps the data block of metablock index 126 -### wbmeta +### meta Look into the metadata in the cache device. -* `wbmeta /dev/cache 0` dumps the superblock metadata (ID 0 is special) -* `wbmeta /dev/cache 1` dumps the metadata of segment ID 1 +* `writeboost-cli meta /dev/cache 0` dumps the superblock metadata (ID 0 is special) +* `writeboost-cli meta /dev/cache 1` dumps the metadata of segment ID 1 ### wbremove Remove a WB device -* `wbremove wbdev` removes a WB device after flushing data in RAM buffer and then writing back +* `writeboost-cli remove wbdev` removes a WB device after flushing data in RAM buffer and then writing back all cache blocks. This is the way Dmirty Smirnov's writeboost script suggests. (Recommended) -* `wbremove wbdev --nowriteback` remove a WB device without writing back all cache blocks. +* `writeboost-cli remove wbdev --nowriteback` remove a WB device without writing back all cache blocks. ### wbstatus Pretty-print the status line. -* `dmsetup status wbdev | wbstatus` +* `dmsetup status wbdev | writeboost-cli status` ## Author