mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-04-01 00:00:03 +03:00
Compare commits
196 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
33483738c6 | ||
|
ea5bdadabd | ||
|
66c943be6c | ||
|
3d968816a4 | ||
|
76b3ec9d66 | ||
|
3e2d5b2b9a | ||
|
7c47145f6c | ||
|
396545c2ea | ||
|
3bfe433d22 | ||
|
19d3a1778c | ||
|
e54f288992 | ||
|
7c66e9fac5 | ||
|
2160e9a7bd | ||
|
941dfd7a29 | ||
|
18b4914587 | ||
|
8af5c93e48 | ||
|
6657ce2de3 | ||
|
5504533986 | ||
|
a55c655158 | ||
|
b8435c5693 | ||
|
80d0a21ed3 | ||
|
a1080f2f6a | ||
|
3bf9a19571 | ||
|
00dd889d33 | ||
|
1a8e684ae0 | ||
|
3d972489a8 | ||
|
197437be12 | ||
|
0a23a5ab1a | ||
|
017c3cc66e | ||
|
8b7810403b | ||
|
ce0c2241a4 | ||
|
846f3398a2 | ||
|
e6aecdd3b8 | ||
|
62ea232b09 | ||
|
64ce740ac6 | ||
|
c0836924b1 | ||
|
f42ee45c6e | ||
|
6cbadc946d | ||
|
86cbeaf1c2 | ||
|
dd1a882d17 | ||
|
3e15e96cb9 | ||
|
d7f02b4ed5 | ||
|
1606364799 | ||
|
553e605886 | ||
|
55538d928b | ||
|
7d30f895c6 | ||
|
8cc5bdede9 | ||
|
67c9b378c7 | ||
|
55afc8ad37 | ||
|
3fcc955d00 | ||
|
c4e25c6c3c | ||
|
8361ae1a42 | ||
|
895fc9a101 | ||
|
56b2449ded | ||
|
117e5fd7e9 | ||
|
35a13784a2 | ||
|
16e23eaec1 | ||
|
9cc5c9a79b | ||
|
6f1429b4eb | ||
|
7210d5c911 | ||
|
1055935ffe | ||
|
634c812a1e | ||
|
601deb6e5d | ||
|
ef25411bdc | ||
|
8b31dfb350 | ||
|
2aeeac7785 | ||
|
83cc57700f | ||
|
626b1945eb | ||
|
077677e61c | ||
|
a17e2ca95c | ||
|
ac124c8885 | ||
|
c560ff06f4 | ||
|
51ebefdd6e | ||
|
77d72319a4 | ||
|
c2af793c8c | ||
|
de51418b60 | ||
|
6829fb2010 | ||
|
d4932bf0e3 | ||
|
9beb9fabb2 | ||
|
511a714ed3 | ||
|
b7831af74d | ||
|
64767d6443 | ||
|
8d5f44d3b1 | ||
|
5350fd2b7b | ||
|
cb8dc1b2ba | ||
|
9ed0f3fd72 | ||
|
2541755981 | ||
|
553d6f107a | ||
|
4f9293b045 | ||
|
282331defa | ||
|
b1e6d1ced2 | ||
|
3666da87f2 | ||
|
6153c37e38 | ||
|
4e25d26a81 | ||
|
1dba682527 | ||
|
571ca8b8ce | ||
|
01413354a5 | ||
|
1d68a6da59 | ||
|
c4456b4714 | ||
|
d27d4cf7f0 | ||
|
3829e49167 | ||
|
9f20109509 | ||
|
7a98f526b5 | ||
|
bc5d903fda | ||
|
45468a9a6f | ||
|
cd35891eb9 | ||
|
f9ec00d5ca | ||
|
68704c30dc | ||
|
a1122aced2 | ||
|
1a5b11db3f | ||
|
1e058db4b6 | ||
|
b422b19f63 | ||
|
6f938e0399 | ||
|
481a50f0a9 | ||
|
6c32c8d9c9 | ||
|
d30bc11101 | ||
|
ef47274485 | ||
|
31039815a7 | ||
|
8e0023ed4a | ||
|
e2e1493111 | ||
|
8b93af8747 | ||
|
74a48d6da8 | ||
|
6687752a1d | ||
|
5b4ee5cf7b | ||
|
495a54c03b | ||
|
3f885423df | ||
|
8d75a97e1a | ||
|
b00ac20e76 | ||
|
c616061a93 | ||
|
95e8cddd3b | ||
|
da1d5571f5 | ||
|
6958dd8df2 | ||
|
e42312b602 | ||
|
73a271e130 | ||
|
c60ce81890 | ||
|
1eaac529af | ||
|
1e5452a027 | ||
|
fb6a56bb81 | ||
|
b4db95b16e | ||
|
54da29d413 | ||
|
57cd58db1e | ||
|
dfc39d36c4 | ||
|
52dd7f6391 | ||
|
da81a430b1 | ||
|
b105a566ec | ||
|
201b1e8216 | ||
|
cdcc241167 | ||
|
7c68f2758d | ||
|
e218119b01 | ||
|
09cde4869d | ||
|
48c51020e5 | ||
|
ceb5e80d0e | ||
|
52b9e813bd | ||
|
59ccde4a2f | ||
|
60ff4f2f3c | ||
|
9058835b97 | ||
|
573d635b2c | ||
|
088e17a54a | ||
|
f8d6a67db0 | ||
|
9020d202a4 | ||
|
07913d1185 | ||
|
e084e9f65b | ||
|
8594891772 | ||
|
32fbdff2a9 | ||
|
2d60567685 | ||
|
7ebd67e63a | ||
|
9e12dd06b9 | ||
|
061a9ff2a3 | ||
|
a1764e00cd | ||
|
4be409afea | ||
|
0f9b409aee | ||
|
53d7722563 | ||
|
8b06995115 | ||
|
d061c7ea11 | ||
|
755788e2d6 | ||
|
34b5654d9e | ||
|
5cce07e986 | ||
|
176d76bceb | ||
|
df09682869 | ||
|
b0eb3c2930 | ||
|
7a17d429d5 | ||
|
ee5f3719d3 | ||
|
795585e289 | ||
|
9bd3ada1d1 | ||
|
a411e7237f | ||
|
cf180e8f34 | ||
|
91e67ab2bd | ||
|
411df4e53f | ||
|
277ba6d4ac | ||
|
02aa11829a | ||
|
adb63be479 | ||
|
41df701a08 | ||
|
f72ded6a4f | ||
|
e4271d7a3e | ||
|
87ab1fd7ed | ||
|
ad41c2fb76 |
.bcachefs_revision.editorconfig
.github/workflows
.gitignoreCargo.lockCargo.tomlINSTALL.mdMakefileMakefile.compilerarch/etc
bcachefs.8bch_bindgen
c_src
bcachefs.ccmd_attr.ccmd_data.ccmd_device.ccmd_dump.ccmd_format.ccmd_fs.ccmd_fsck.ccmd_fusemount.ccmd_key.ccmd_kill_btree_node.ccmd_list_journal.ccmd_migrate.ccmd_option.ccmd_top.ccmds.hcrypto.ccrypto.hlibbcachefs.clibbcachefs.hposix_to_bcachefs.cposix_to_bcachefs.htools-util.ctools-util.h
debian
doc
flake.lockflake.nixinclude
crypto
linux
libbcachefs
@ -1 +1 @@
|
||||
792ca5ba3c9a07d762d9c1a440e31c0520f37de0
|
||||
7fdc3fa3cb5fb561f5945b4de418d48d1a726a8d
|
||||
|
@ -28,3 +28,7 @@ indent_size = 4
|
||||
[*.rs]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.sh]
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
|
7
.github/workflows/build-packages.yml
vendored
7
.github/workflows/build-packages.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
||||
name: bcachefs-tools-deb
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-22.04]
|
||||
os: [ubuntu-22.04, ubuntu-24.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -21,6 +21,7 @@ jobs:
|
||||
sudo apt-get update && sudo apt-get -y --no-install-recommends install \
|
||||
valgrind \
|
||||
equivs devscripts
|
||||
grep -q 22.04 /etc/os-release && sed -i -e 's/ systemd-dev,/ systemd,/g' debian/control
|
||||
mk-build-deps
|
||||
sudo apt install ./bcachefs-tools-build-deps_*.deb
|
||||
- name: Setup Rust
|
||||
@ -32,7 +33,7 @@ jobs:
|
||||
make -j`nproc` deb
|
||||
mkdir dist && mv ../*.deb ./dist/
|
||||
- name: Upload deb
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bcachefs-tools-deb_${{ matrix.os }}
|
||||
path: dist
|
||||
@ -57,7 +58,7 @@ jobs:
|
||||
make -j`nproc` rpm
|
||||
mv ${HOME}/rpmbuild ./
|
||||
- name: Upload rpm
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bcachefs-tools-rpm
|
||||
path: rpmbuild
|
||||
|
41
.github/workflows/nix-flake.yml
vendored
41
.github/workflows/nix-flake.yml
vendored
@ -1,22 +1,31 @@
|
||||
name: "Nix-Tests"
|
||||
name: Nix Flake actions
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
nix-flake-check:
|
||||
nix-matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v27
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: bcachefs-tools
|
||||
# If you chose API tokens for write access OR if you have a private cache
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
- run: nix flake show
|
||||
- run: nix flake check --print-build-logs
|
||||
- run: nix build --print-build-logs
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
- id: set-matrix
|
||||
name: Generate Nix Matrix
|
||||
run: |
|
||||
set -Eeu
|
||||
matrix="$(nix eval --json '.#githubActions.matrix')"
|
||||
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
|
||||
|
||||
nix-build:
|
||||
name: ${{ matrix.name }} (${{ matrix.system }})
|
||||
needs: nix-matrix
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix: ${{fromJSON(needs.nix-matrix.outputs.matrix)}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
- run: nix build -L '.#${{ matrix.attr }}'
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -10,8 +10,6 @@ TAGS
|
||||
cscope*
|
||||
bcachefs-tools
|
||||
compile_commands.json
|
||||
tests/test_helper
|
||||
tests/__pycache__/
|
||||
|
||||
# dot-files that we don't want to ignore
|
||||
!.gitignore
|
||||
|
396
Cargo.lock
generated
396
Cargo.lock
generated
@ -4,56 +4,57 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.11"
|
||||
version = "0.6.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
|
||||
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.6"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.3"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.2"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.2"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.52.0",
|
||||
@ -61,31 +62,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.79"
|
||||
version = "1.0.89"
|
||||
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"
|
||||
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
|
||||
|
||||
[[package]]
|
||||
name = "bcachefs-tools"
|
||||
version = "0.3.1"
|
||||
version = "1.25.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bch_bindgen",
|
||||
"byteorder",
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"colored",
|
||||
"either",
|
||||
"env_logger",
|
||||
"errno 0.2.8",
|
||||
"libc",
|
||||
"log",
|
||||
"rpassword",
|
||||
"owo-colors",
|
||||
"rustix",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"udev",
|
||||
@ -101,8 +96,6 @@ dependencies = [
|
||||
"bindgen",
|
||||
"bitfield",
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"memoffset",
|
||||
"paste",
|
||||
"pkg-config",
|
||||
"uuid",
|
||||
@ -110,11 +103,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.69.4"
|
||||
version = "0.69.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
|
||||
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"bitflags 2.6.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
@ -145,23 +138,17 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.2"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
version = "1.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -181,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.7.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
@ -192,9 +179,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.18"
|
||||
version = "4.5.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
|
||||
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@ -202,9 +189,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.18"
|
||||
version = "4.5.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
|
||||
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -215,18 +202,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.4.10"
|
||||
version = "4.5.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb745187d7f4d76267b37485a65e0149edd0e91a4cfcdd3f27524ad86cee9f3"
|
||||
checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.4.7"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@ -236,31 +223,30 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.6.0"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
@ -275,9 +261,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
@ -301,9 +287,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
@ -314,6 +300,12 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
@ -325,9 +317,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
@ -337,18 +329,18 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.153"
|
||||
version = "0.2.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.1"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
|
||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -363,30 +355,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.13"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
version = "2.7.4"
|
||||
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",
|
||||
]
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
@ -406,27 +389,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.14"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.29"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.16"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
|
||||
checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
@ -434,27 +423,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.78"
|
||||
version = "1.0.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.3"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
||||
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@ -464,9 +453,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.5"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
|
||||
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@ -475,30 +464,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rpassword"
|
||||
version = "7.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rtoolbox",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtoolbox"
|
||||
version = "0.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
@ -508,12 +476,12 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.31"
|
||||
version = "0.38.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
|
||||
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"errno 0.3.8",
|
||||
"bitflags 2.6.0",
|
||||
"errno 0.3.9",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
@ -533,24 +501,24 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.2"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.2"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@ -561,9 +529,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.48"
|
||||
version = "2.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -572,12 +540,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
|
||||
checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -593,21 +561,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.7.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
|
||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
@ -643,137 +611,87 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
|
23
Cargo.toml
23
Cargo.toml
@ -1,17 +1,23 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
default-members = [".", "bch_bindgen"]
|
||||
|
||||
[package]
|
||||
name = "bcachefs-tools"
|
||||
version = "1.9.0"
|
||||
version = "1.25.0"
|
||||
authors = ["Yuxuan Shui <yshuiv7@gmail.com>", "Kayla Firestack <dev@kaylafire.me>", "Kent Overstreet <kent.overstreet@linux.dev>" ]
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[[bin]]
|
||||
name = "bcachefs"
|
||||
path = "src/bcachefs.rs"
|
||||
|
||||
[features]
|
||||
fuse = []
|
||||
|
||||
[dependencies]
|
||||
log = { version = "0.4", features = ["std"] }
|
||||
colored = "2"
|
||||
clap = { version = "4.0.32", features = ["derive", "wrap_help"] }
|
||||
clap_complete = "4.3.2"
|
||||
anyhow = "1.0"
|
||||
@ -20,9 +26,16 @@ udev = "0.7.0"
|
||||
uuid = "1.2.2"
|
||||
errno = "0.2"
|
||||
either = "1.5"
|
||||
rpassword = "7"
|
||||
bch_bindgen = { path = "bch_bindgen" }
|
||||
byteorder = "1.3"
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
strum_macros = "0.26"
|
||||
zeroize = { version = "1", features = ["std", "zeroize_derive"] }
|
||||
rustix = { version = "0.38.34", features = ["termios"] }
|
||||
owo-colors = "4"
|
||||
|
||||
[dependencies.env_logger]
|
||||
version = "0.10"
|
||||
default-features = false
|
||||
|
||||
[profile.release]
|
||||
strip = "none"
|
||||
|
18
INSTALL.md
18
INSTALL.md
@ -39,12 +39,19 @@ Starting from Debian Trixie and Ubuntu 23.10, you will additionally need:
|
||||
apt install -y systemd-dev
|
||||
```
|
||||
|
||||
Fedora: install the "Development tools" group along with:
|
||||
Fedora: install build dependencies either with `dnf builddep bcachefs-tools` or with:
|
||||
```shell
|
||||
dnf install -y libaio-devel libsodium-devel \
|
||||
dnf install -y @c-development libaio-devel libsodium-devel \
|
||||
libblkid-devel libzstd-devel zlib-devel userspace-rcu-devel \
|
||||
lz4-devel libuuid-devel valgrind-devel keyutils-libs-devel \
|
||||
findutils udev systemd-devel llvm-devel
|
||||
findutils systemd-devel clang-devel llvm-devel rust cargo
|
||||
```
|
||||
|
||||
openSUSE: install build dependencies with:
|
||||
```shell
|
||||
zypper in -y libaio-devel libsodium-devel libblkid-devel liburcu-devel \
|
||||
libzstd-devel zlib-devel liblz4-devel libuuid-devel valgrind-devel \
|
||||
keyutils-devel findutils udev systemd-devel llvm-devel
|
||||
```
|
||||
|
||||
Arch: install bcachefs-tools-git from the AUR.
|
||||
@ -80,6 +87,11 @@ Arch:
|
||||
pacman -S fuse3
|
||||
```
|
||||
|
||||
openSUSE:
|
||||
```shell
|
||||
zypper in -y fuse3-devel
|
||||
```
|
||||
|
||||
Then, make using the `BCACHEFS_FUSE` environment variable (make clean first if
|
||||
previously built without fuse support):
|
||||
|
||||
|
31
Makefile
31
Makefile
@ -1,4 +1,4 @@
|
||||
VERSION=1.9.0
|
||||
VERSION=1.25.0
|
||||
|
||||
PREFIX?=/usr/local
|
||||
LIBEXECDIR?=$(PREFIX)/libexec
|
||||
@ -22,6 +22,13 @@ else
|
||||
CARGO_CLEAN_ARGS = --quiet
|
||||
endif
|
||||
|
||||
# when cross compiling, cargo places the built binary in a different location
|
||||
ifdef CARGO_BUILD_TARGET
|
||||
BUILT_BIN = target/$(CARGO_BUILD_TARGET)/release/bcachefs
|
||||
else
|
||||
BUILT_BIN = target/release/bcachefs
|
||||
endif
|
||||
|
||||
# Prevent recursive expansions of $(CFLAGS) to avoid repeatedly performing
|
||||
# compile tests
|
||||
CFLAGS:=$(CFLAGS)
|
||||
@ -73,12 +80,13 @@ CFLAGS+=$(call cc-disable-warning, zero-length-array)
|
||||
CFLAGS+=$(call cc-disable-warning, shift-overflow)
|
||||
CFLAGS+=$(call cc-disable-warning, enum-conversion)
|
||||
CFLAGS+=$(call cc-disable-warning, gnu-variable-sized-type-not-at-end)
|
||||
export RUSTFLAGS=-C default-linker-libraries
|
||||
|
||||
PKGCONFIG_LIBS="blkid uuid liburcu libsodium zlib liblz4 libzstd libudev libkeyutils udev"
|
||||
PKGCONFIG_LIBS="blkid uuid liburcu libsodium zlib liblz4 libzstd libudev libkeyutils"
|
||||
ifdef BCACHEFS_FUSE
|
||||
PKGCONFIG_LIBS+="fuse3 >= 3.7"
|
||||
CFLAGS+=-DBCACHEFS_FUSE
|
||||
export RUSTFLAGS=--cfg fuse
|
||||
RUSTFLAGS+=--cfg feature="fuse"
|
||||
endif
|
||||
|
||||
PKGCONFIG_CFLAGS:=$(shell $(PKG_CONFIG) --cflags $(PKGCONFIG_LIBS))
|
||||
@ -152,9 +160,6 @@ all: bcachefs $(optional_build)
|
||||
debug: CFLAGS+=-Werror -DCONFIG_BCACHEFS_DEBUG=y -DCONFIG_VALGRIND=y
|
||||
debug: bcachefs
|
||||
|
||||
.PHONY: tests
|
||||
tests: tests/test_helper
|
||||
|
||||
.PHONY: TAGS tags
|
||||
TAGS:
|
||||
ctags -e -R .
|
||||
@ -178,13 +183,9 @@ RUST_SRCS:=$(shell find src bch_bindgen/src -type f -iname '*.rs')
|
||||
bcachefs: $(BCACHEFS_DEPS) $(RUST_SRCS)
|
||||
$(Q)$(CARGO_BUILD)
|
||||
|
||||
libbcachefs.a: $(filter-out ./tests/%.o, $(OBJS))
|
||||
libbcachefs.a: $(OBJS)
|
||||
@echo " [AR] $@"
|
||||
$(Q)ar -rc $@ $+
|
||||
|
||||
tests/test_helper: $(filter ./tests/%.o, $(OBJS))
|
||||
@echo " [LD] $@"
|
||||
$(Q)$(CC) $(LDFLAGS) $+ $(LOADLIBES) $(LDLIBS) -o $@
|
||||
$(Q)$(AR) -rc $@ $+
|
||||
|
||||
# If the version string differs from the last build, update the last version
|
||||
ifneq ($(VERSION),$(shell cat .version 2>/dev/null))
|
||||
@ -201,7 +202,7 @@ cmd_version.o : .version
|
||||
install: INITRAMFS_HOOK=$(INITRAMFS_DIR)/hooks/bcachefs
|
||||
install: INITRAMFS_SCRIPT=$(INITRAMFS_DIR)/scripts/local-premount/bcachefs
|
||||
install: bcachefs $(optional_install)
|
||||
$(INSTALL) -m0755 -D target/release/bcachefs -t $(DESTDIR)$(ROOT_SBINDIR)
|
||||
$(INSTALL) -m0755 -D $(BUILT_BIN) -t $(DESTDIR)$(ROOT_SBINDIR)
|
||||
$(INSTALL) -m0644 -D bcachefs.8 -t $(DESTDIR)$(PREFIX)/share/man/man8/
|
||||
$(INSTALL) -m0755 -D initramfs/script $(DESTDIR)$(INITRAMFS_SCRIPT)
|
||||
$(INSTALL) -m0755 -D initramfs/hook $(DESTDIR)$(INITRAMFS_HOOK)
|
||||
@ -225,7 +226,7 @@ install_systemd: $(systemd_services) $(systemd_libexecfiles)
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Cleaning all"
|
||||
$(Q)$(RM) libbcachefs.a c_src/libbcachefs.a tests/test_helper .version *.tar.xz $(OBJS) $(DEPS) $(DOCGENERATED)
|
||||
$(Q)$(RM) libbcachefs.a c_src/libbcachefs.a .version *.tar.xz $(OBJS) $(DEPS) $(DOCGENERATED)
|
||||
$(Q)$(CARGO_CLEAN)
|
||||
$(Q)$(RM) -f $(built_scripts)
|
||||
|
||||
@ -294,7 +295,7 @@ tarball: $(SRCTARXZ)
|
||||
|
||||
$(SRCTARXZ) : .gitcensus
|
||||
$(Q)tar --transform "s,^,$(SRCDIR)/," -Jcf $(SRCDIR).tar.xz \
|
||||
`cat .gitcensus`
|
||||
`cat .gitcensus`
|
||||
@echo Wrote: $@
|
||||
|
||||
.PHONY: .gitcensus
|
||||
|
@ -13,7 +13,7 @@ cc-cross-prefix = $(firstword $(foreach c, $(1), \
|
||||
$(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c))))
|
||||
|
||||
# output directory for tests below
|
||||
TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$
|
||||
TMPOUT = .tmp_$$$$
|
||||
|
||||
# try-run
|
||||
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
|
||||
@ -53,13 +53,11 @@ cc-option = $(call __cc-option, $(CC),\
|
||||
|
||||
# cc-option-yn
|
||||
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
|
||||
cc-option-yn = $(call try-run,\
|
||||
$(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
|
||||
cc-option-yn = $(if $(call cc-option,$1),y,n)
|
||||
|
||||
# cc-disable-warning
|
||||
# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
|
||||
cc-disable-warning = $(call try-run,\
|
||||
$(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
|
||||
cc-disable-warning = $(if $(call cc-option,-W$(strip $1)),-Wno-$(strip $1))
|
||||
|
||||
# gcc-min-version
|
||||
# Usage: cflags-$(call gcc-min-version, 70100) += -foo
|
||||
@ -72,3 +70,20 @@ clang-min-version = $(call test-ge, $(CONFIG_CLANG_VERSION), $1)
|
||||
# ld-option
|
||||
# Usage: KBUILD_LDFLAGS += $(call ld-option, -X, -Y)
|
||||
ld-option = $(call try-run, $(LD) $(KBUILD_LDFLAGS) $(1) -v,$(1),$(2),$(3))
|
||||
|
||||
# __rustc-option
|
||||
# Usage: MY_RUSTFLAGS += $(call __rustc-option,$(RUSTC),$(MY_RUSTFLAGS),-Cinstrument-coverage,-Zinstrument-coverage)
|
||||
# TODO: remove RUSTC_BOOTSTRAP=1 when we raise the minimum GNU Make version to 4.4
|
||||
__rustc-option = $(call try-run,\
|
||||
echo '#![allow(missing_docs)]#![feature(no_core)]#![no_core]' | RUSTC_BOOTSTRAP=1\
|
||||
$(1) --sysroot=/dev/null $(filter-out --sysroot=/dev/null,$(2)) $(3)\
|
||||
--crate-type=rlib --out-dir=$(TMPOUT) --emit=obj=- - >/dev/null,$(3),$(4))
|
||||
|
||||
# rustc-option
|
||||
# Usage: rustflags-y += $(call rustc-option,-Cinstrument-coverage,-Zinstrument-coverage)
|
||||
rustc-option = $(call __rustc-option, $(RUSTC),\
|
||||
$(KBUILD_RUSTFLAGS),$(1),$(2))
|
||||
|
||||
# rustc-option-yn
|
||||
# Usage: flag := $(call rustc-option-yn,-Cinstrument-coverage)
|
||||
rustc-option-yn = $(if $(call rustc-option,$1),y,n)
|
||||
|
15
arch/etc/initcpio/hooks/bcachefs
Normal file
15
arch/etc/initcpio/hooks/bcachefs
Normal file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/ash
|
||||
|
||||
run_hook() {
|
||||
local rootdev
|
||||
if rootdev="$(resolve_device "$root")" && bcachefs unlock -c "$rootdev" >/dev/null 2>&1
|
||||
then
|
||||
echo "Unlocking $rootdev:"
|
||||
while true
|
||||
do
|
||||
bcachefs unlock "$rootdev" && break
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# vim: set ft=sh ts=4 sw=4 et:
|
16
arch/etc/initcpio/install/bcachefs
Normal file
16
arch/etc/initcpio/install/bcachefs
Normal file
@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
build() {
|
||||
add_module bcachefs
|
||||
add_binary bcachefs
|
||||
|
||||
add_runscript
|
||||
}
|
||||
|
||||
help() {
|
||||
cat <<HELPEOF
|
||||
This hook is for getting the bcachefs unlock prompt at boot
|
||||
HELPEOF
|
||||
}
|
||||
|
||||
# vim set ft=sh ts=4 sw=4 et:
|
66
arch/etc/mkinitcpio.conf
Normal file
66
arch/etc/mkinitcpio.conf
Normal file
@ -0,0 +1,66 @@
|
||||
# vim:set ft=sh
|
||||
# MODULES
|
||||
# The following modules are loaded before any boot hooks are
|
||||
# run. Advanced users may wish to specify all system modules
|
||||
# in this array. For instance:
|
||||
# MODULES=(piix ide_disk reiserfs)
|
||||
MODULES=(bcachefs)
|
||||
|
||||
# BINARIES
|
||||
# This setting includes any additional binaries a given user may
|
||||
# wish into the CPIO image. This is run last, so it may be used to
|
||||
# override the actual binaries included by a given hook
|
||||
# BINARIES are dependency parsed, so you may safely ignore libraries
|
||||
BINARIES=(bcachefs)
|
||||
|
||||
# FILES
|
||||
# This setting is similar to BINARIES above, however, files are added
|
||||
# as-is and are not parsed in any way. This is useful for config files.
|
||||
FILES=()
|
||||
|
||||
# HOOKS
|
||||
# This is the most important setting in this file. The HOOKS control the
|
||||
# modules and scripts added to the image, and what happens at boot time.
|
||||
# Order is important, and it is recommended that you do not change the
|
||||
# order in which HOOKS are added. Run 'mkinitcpio -H <hook name>' for
|
||||
# help on a given hook.
|
||||
# 'base' is _required_ unless you know precisely what you are doing.
|
||||
# 'udev' is _required_ in order to automatically load modules
|
||||
# 'filesystems' is _required_ unless you specify your fs modules in MODULES
|
||||
# Examples:
|
||||
## This setup specifies all modules in the MODULES setting above.
|
||||
## No raid, lvm2, or encrypted root is needed.
|
||||
# HOOKS="base"
|
||||
#
|
||||
## This setup will autodetect all modules for your system and should
|
||||
## work as a sane default
|
||||
# HOOKS="base udev autodetect block filesystems"
|
||||
#
|
||||
## This setup will generate a 'full' image which supports most systems.
|
||||
## No autodetection is done.
|
||||
# HOOKS="base udev block filesystems"
|
||||
#
|
||||
## This setup assembles a pata mdadm array with an encrypted root FS.
|
||||
## Note: See 'mkinitcpio -H mdadm' for more information on raid devices.
|
||||
# HOOKS="base udev block mdadm encrypt filesystems"
|
||||
#
|
||||
## This setup loads an lvm2 volume group on a usb device.
|
||||
# HOOKS="base udev block lvm2 filesystems"
|
||||
#
|
||||
## NOTE: If you have /usr on a separate partition, you MUST include the
|
||||
# usr, fsck and shutdown hooks.
|
||||
HOOKS=(base udev autodetect modconf block filesystems bcachefs keyboard fsck)
|
||||
|
||||
# COMPRESSION
|
||||
# Use this to compress the initramfs image. By default, gzip compression
|
||||
# is used. Use 'cat' to create an uncompressed image.
|
||||
#COMPRESSION="gzip"
|
||||
#COMPRESSION="bzip2"
|
||||
#COMPRESSION="lzma"
|
||||
#COMPRESSION="xz"
|
||||
#COMPRESSION="lzop"
|
||||
#COMPRESSION="lz4"
|
||||
|
||||
# COMPRESSION_OPTIONS
|
||||
# Additional options for the compressor
|
||||
#COMPRESSION_OPTIONS=""
|
@ -20,7 +20,7 @@ which are documented in detail below:
|
||||
Format one or a list of devices with bcachefs data structures.
|
||||
.It Ic show-super
|
||||
Dump superblock information to stdout.
|
||||
.It Ic set-option
|
||||
.It Ic set-fs-option
|
||||
Set a filesystem option
|
||||
.El
|
||||
.Ss Mount commands
|
||||
@ -91,7 +91,7 @@ Add default superblock, after bcachefs migrate
|
||||
.El
|
||||
.Ss Commands for operating on files in a bcachefs filesystem
|
||||
.Bl -tag -width 18n -compact
|
||||
.It Ic setattr
|
||||
.It Ic set-file-option
|
||||
Set various per file attributes
|
||||
.El
|
||||
.Ss Commands for debugging
|
||||
@ -248,7 +248,7 @@ List of sections to print
|
||||
.It Fl l , Fl -layout
|
||||
Print superblock layout
|
||||
.El
|
||||
.It Nm Ic set-option Oo Ar options Oc Ar device
|
||||
.It Nm Ic set-fs-option Oo Ar options Oc Ar device
|
||||
.Bl -tag -width Ds
|
||||
.It Fl -errors Ns = Ns ( Cm continue | ro | panic )
|
||||
Action to take on filesystem error
|
||||
@ -574,7 +574,7 @@ Offset of existing superblock
|
||||
.El
|
||||
.Sh Commands for operating on files in a bcachefs filesystem
|
||||
.Bl -tag -width Ds
|
||||
.It Nm Ic setattr Oo Ar options Oc Ar devices\ ...
|
||||
.It Nm Ic set-file-option Oo Ar options Oc Ar devices\ ...
|
||||
.Bl -tag -width Ds
|
||||
.It Fl -data_replicas Ns = Ns Ar number
|
||||
Number of data replicas
|
||||
|
@ -3,6 +3,7 @@ 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"
|
||||
rust-version = "1.77"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
@ -12,8 +13,6 @@ crate-type = ["lib"]
|
||||
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"
|
||||
|
||||
|
@ -63,7 +63,6 @@ fn main() {
|
||||
.allowlist_function("printbuf.*")
|
||||
.blocklist_type("rhash_lock_head")
|
||||
.blocklist_type("srcu_struct")
|
||||
.blocklist_type("bch_ioctl_data.*")
|
||||
.allowlist_var("BCH_.*")
|
||||
.allowlist_var("KEY_SPEC_.*")
|
||||
.allowlist_var("Fix753_.*")
|
||||
|
@ -3,6 +3,8 @@
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(unused)]
|
||||
|
||||
use crate::c;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bcachefs.rs"));
|
||||
|
||||
use bitfield::bitfield;
|
||||
@ -16,7 +18,7 @@ bitfield! {
|
||||
pub struct bch_crypt_flags(u64);
|
||||
pub TYPE, _: 4, 0;
|
||||
}
|
||||
use memoffset::offset_of;
|
||||
use std::mem::offset_of;
|
||||
impl bch_sb_field_crypt {
|
||||
pub fn scrypt_flags(&self) -> Option<bch_scrypt_flags> {
|
||||
use std::convert::TryInto;
|
||||
@ -59,16 +61,15 @@ impl bch_sb {
|
||||
uuid::Uuid::from_bytes(self.user_uuid.b)
|
||||
}
|
||||
|
||||
pub fn number_of_devices(&self) -> u8 {
|
||||
self.nr_devices
|
||||
pub fn number_of_devices(&self) -> u32 {
|
||||
unsafe { c::bch2_sb_nr_devices(self) }
|
||||
}
|
||||
|
||||
/// 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();
|
||||
let [a, b, c, d, e, f, g, h, _rest @ ..] = self.uuid.b;
|
||||
let dword1 = u32::from_le_bytes([a, b, c, d]);
|
||||
let dword2 = u32::from_le_bytes([e, f, g, h]);
|
||||
nonce {
|
||||
d: [0, 0, dword1, dword2],
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ pub enum BkeyValC<'a> {
|
||||
logged_op_truncate(&'a c::bch_logged_op_truncate),
|
||||
logged_op_finsert(&'a c::bch_logged_op_finsert),
|
||||
accounting(&'a c::bch_accounting),
|
||||
inode_alloc_cursor(&'a c::bch_inode_alloc_cursor),
|
||||
}
|
||||
|
||||
impl<'a, 'b> BkeySC<'a> {
|
||||
@ -64,7 +65,7 @@ impl<'a, 'b> BkeySC<'a> {
|
||||
BkeySCToText { k: self, fs }
|
||||
}
|
||||
|
||||
pub fn v(&'a self) -> BkeyValC {
|
||||
pub fn v(&'a self) -> BkeyValC<'a> {
|
||||
unsafe {
|
||||
let ty: c::bch_bkey_type = transmute(self.k.type_ as u32);
|
||||
|
||||
@ -106,6 +107,7 @@ impl<'a, 'b> BkeySC<'a> {
|
||||
KEY_TYPE_logged_op_truncate => logged_op_truncate(transmute(self.v)),
|
||||
KEY_TYPE_logged_op_finsert => logged_op_finsert(transmute(self.v)),
|
||||
KEY_TYPE_accounting => accounting(transmute(self.v)),
|
||||
KEY_TYPE_inode_alloc_cursor => inode_alloc_cursor(transmute(self.v)),
|
||||
KEY_TYPE_MAX => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ pub struct BtreeTrans<'f> {
|
||||
}
|
||||
|
||||
impl<'f> BtreeTrans<'f> {
|
||||
pub fn new(fs: &'f Fs) -> BtreeTrans {
|
||||
pub fn new(fs: &'f Fs) -> BtreeTrans<'f> {
|
||||
unsafe {
|
||||
BtreeTrans {
|
||||
raw: &mut *c::__bch2_trans_get(fs.raw, 0),
|
||||
@ -81,9 +81,9 @@ impl<'t> BtreeIter<'t> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek_upto<'i>(&'i mut self, end: c::bpos) -> Result<Option<BkeySC>, bch_errcode> {
|
||||
pub fn peek_max<'i>(&'i mut self, end: c::bpos) -> Result<Option<BkeySC<'i>>, bch_errcode> {
|
||||
unsafe {
|
||||
let k = c::bch2_btree_iter_peek_upto(&mut self.raw, end);
|
||||
let k = c::bch2_btree_iter_peek_max(&mut self.raw, end);
|
||||
errptr_to_result_c(k.k).map(|_| {
|
||||
if !k.k.is_null() {
|
||||
Some(BkeySC {
|
||||
@ -99,7 +99,7 @@ impl<'t> BtreeIter<'t> {
|
||||
}
|
||||
|
||||
pub fn peek(&mut self) -> Result<Option<BkeySC>, bch_errcode> {
|
||||
self.peek_upto(SPOS_MAX)
|
||||
self.peek_max(SPOS_MAX)
|
||||
}
|
||||
|
||||
pub fn peek_and_restart(&mut self) -> Result<Option<BkeySC>, bch_errcode> {
|
||||
@ -146,7 +146,7 @@ impl<'t> BtreeNodeIter<'t> {
|
||||
locks_want: u32,
|
||||
depth: u32,
|
||||
flags: BtreeIterFlags,
|
||||
) -> BtreeNodeIter {
|
||||
) -> BtreeNodeIter<'t> {
|
||||
unsafe {
|
||||
let mut iter: MaybeUninit<c::btree_iter> = MaybeUninit::uninit();
|
||||
c::bch2_trans_node_iter_init(
|
||||
|
@ -1,3 +1,7 @@
|
||||
use crate::c;
|
||||
use crate::fs::Fs;
|
||||
use std::ffi::{CString, c_char};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! opt_set {
|
||||
($opts:ident, $n:ident, $v:expr) => {
|
||||
@ -33,3 +37,29 @@ macro_rules! opt_get {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parse_mount_opts(fs: Option<&mut Fs>, optstr: Option<&str>, ignore_unknown: bool)
|
||||
-> Result<c::bch_opts, c::bch_errcode> {
|
||||
let mut opts: c::bch_opts = Default::default();
|
||||
|
||||
if let Some(optstr) = optstr {
|
||||
let optstr = CString::new(optstr).unwrap();
|
||||
let optstr_ptr = optstr.as_ptr();
|
||||
|
||||
let ret = unsafe {
|
||||
c::bch2_parse_mount_opts(fs.map_or(std::ptr::null_mut(), |f| f.raw),
|
||||
&mut opts as *mut c::bch_opts,
|
||||
std::ptr::null_mut(),
|
||||
optstr_ptr as *mut c_char,
|
||||
ignore_unknown)
|
||||
};
|
||||
|
||||
drop(optstr);
|
||||
|
||||
if ret != 0 {
|
||||
let err: c::bch_errcode = unsafe { std::mem::transmute(-ret) };
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
Ok(opts)
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ use crate::errcode::bch_errcode;
|
||||
use crate::path_to_cstr;
|
||||
use anyhow::anyhow;
|
||||
|
||||
pub use crate::bcachefs::bch2_free_super;
|
||||
|
||||
pub fn read_super_opts(
|
||||
path: &std::path::Path,
|
||||
mut opts: bch_opts,
|
||||
|
@ -33,7 +33,8 @@ void bcachefs_usage(void)
|
||||
"Superblock commands:\n"
|
||||
" format Format a new filesystem\n"
|
||||
" show-super Dump superblock information to stdout\n"
|
||||
" set-option Set a filesystem option\n"
|
||||
" recover-super Attempt to recover overwritten superblock from backups\n"
|
||||
" set-fs-option Set a filesystem option\n"
|
||||
" reset-counters Reset all counters on an unmounted device\n"
|
||||
"\n"
|
||||
"Mount:\n"
|
||||
@ -52,6 +53,7 @@ void bcachefs_usage(void)
|
||||
#endif
|
||||
"Commands for managing a running filesystem:\n"
|
||||
" fs usage Show disk usage\n"
|
||||
" fs top Show runtime performance information\n"
|
||||
"\n"
|
||||
"Commands for managing devices within a running filesystem:\n"
|
||||
" device add Add a new device to an existing filesystem\n"
|
||||
@ -70,6 +72,7 @@ void bcachefs_usage(void)
|
||||
"\n"
|
||||
"Commands for managing filesystem data:\n"
|
||||
" data rereplicate Rereplicate degraded data\n"
|
||||
" data scrub Verify checksums and correct errors, if possible\n"
|
||||
" data job Kick off low level data jobs\n"
|
||||
"\n"
|
||||
"Encryption:\n"
|
||||
@ -82,7 +85,7 @@ void bcachefs_usage(void)
|
||||
" migrate-superblock Add default superblock, after bcachefs migrate\n"
|
||||
"\n"
|
||||
"Commands for operating on files in a bcachefs filesystem:\n"
|
||||
" setattr Set various per file attributes\n"
|
||||
" set-file-option Set various attributes on files or directories\n"
|
||||
"\n"
|
||||
"Debug:\n"
|
||||
"These commands work on offline, unmounted filesystems\n"
|
||||
@ -90,9 +93,11 @@ void bcachefs_usage(void)
|
||||
" list List filesystem metadata in textual form\n"
|
||||
" list_journal List contents of journal\n"
|
||||
"\n"
|
||||
#ifdef BCACHEFS_FUSE
|
||||
"FUSE:\n"
|
||||
" fusemount Mount a filesystem via FUSE\n"
|
||||
"\n"
|
||||
#endif
|
||||
"Miscellaneous:\n"
|
||||
" completions Generate shell completions\n"
|
||||
" version Display the version of the invoked bcachefs tool\n");
|
||||
@ -113,14 +118,15 @@ int fs_cmds(int argc, char *argv[])
|
||||
{
|
||||
char *cmd = pop_cmd(&argc, argv);
|
||||
|
||||
if (argc < 1) {
|
||||
bcachefs_usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (argc < 1)
|
||||
return fs_usage();
|
||||
if (!strcmp(cmd, "usage"))
|
||||
return cmd_fs_usage(argc, argv);
|
||||
if (!strcmp(cmd, "top"))
|
||||
return cmd_fs_top(argc, argv);
|
||||
|
||||
return 0;
|
||||
fs_usage();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int device_cmds(int argc, char *argv[])
|
||||
@ -146,7 +152,8 @@ int device_cmds(int argc, char *argv[])
|
||||
if (!strcmp(cmd, "resize-journal"))
|
||||
return cmd_device_resize_journal(argc, argv);
|
||||
|
||||
return 0;
|
||||
device_usage();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int data_cmds(int argc, char *argv[])
|
||||
@ -157,8 +164,11 @@ int data_cmds(int argc, char *argv[])
|
||||
return data_usage();
|
||||
if (!strcmp(cmd, "rereplicate"))
|
||||
return cmd_data_rereplicate(argc, argv);
|
||||
if (!strcmp(cmd, "scrub"))
|
||||
return cmd_data_scrub(argc, argv);
|
||||
if (!strcmp(cmd, "job"))
|
||||
return cmd_data_job(argc, argv);
|
||||
|
||||
return 0;
|
||||
data_usage();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -85,8 +85,8 @@ static void do_setattr(char *path, struct bch_opt_strs opts)
|
||||
|
||||
static void setattr_usage(void)
|
||||
{
|
||||
puts("bcachefs setattr - set attributes on files in a bcachefs filesystem\n"
|
||||
"Usage: bcachefs setattr [OPTIONS]... <files>\n"
|
||||
puts("bcachefs set-file-option - set attributes on files in a bcachefs filesystem\n"
|
||||
"Usage: bcachefs set-file-option [OPTIONS]... <files>\n"
|
||||
"\n"
|
||||
"Options:");
|
||||
|
||||
|
203
c_src/cmd_data.c
203
c_src/cmd_data.c
@ -1,5 +1,5 @@
|
||||
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
@ -64,6 +64,207 @@ int cmd_data_rereplicate(int argc, char *argv[])
|
||||
});
|
||||
}
|
||||
|
||||
static void data_scrub_usage(void)
|
||||
{
|
||||
puts("bcachefs data scrub\n"
|
||||
"Usage: bcachefs data scrub [filesystem|device]\n"
|
||||
"\n"
|
||||
"Check data for errors, fix from another replica if possible\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -m, --metadata check metadata only\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
"Report bugs to <linux-bcachefs@vger.kernel.org>");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int cmd_data_scrub(int argc, char *argv[])
|
||||
{
|
||||
static const struct option longopts[] = {
|
||||
{ "metadata", no_argument, NULL, 'm' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ NULL }
|
||||
};
|
||||
struct bch_ioctl_data cmd = {
|
||||
.op = BCH_DATA_OP_scrub,
|
||||
.scrub.data_types = ~0,
|
||||
};
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hm", longopts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'm':
|
||||
cmd.scrub.data_types = BIT(BCH_DATA_btree);
|
||||
break;
|
||||
case 'h':
|
||||
data_scrub_usage();
|
||||
break;
|
||||
}
|
||||
args_shift(optind);
|
||||
|
||||
char *path = arg_pop();
|
||||
if (!path)
|
||||
die("Please supply a filesystem");
|
||||
|
||||
if (argc)
|
||||
die("too many arguments");
|
||||
|
||||
printf("Starting scrub on");
|
||||
|
||||
struct bchfs_handle fs = bcache_fs_open(path);
|
||||
dev_names dev_names = bchu_fs_get_devices(fs);
|
||||
|
||||
struct scrub_device {
|
||||
const char *name;
|
||||
int progress_fd;
|
||||
u64 done, corrected, uncorrected, total;
|
||||
enum bch_ioctl_data_event_ret ret;
|
||||
};
|
||||
DARRAY(struct scrub_device) scrub_devs = {};
|
||||
|
||||
if (fs.dev_idx >= 0) {
|
||||
cmd.scrub.dev = fs.dev_idx;
|
||||
struct scrub_device d = {
|
||||
.name = dev_idx_to_name(&dev_names, fs.dev_idx)->dev,
|
||||
.progress_fd = xioctl(fs.ioctl_fd, BCH_IOCTL_DATA, &cmd),
|
||||
};
|
||||
darray_push(&scrub_devs, d);
|
||||
} else {
|
||||
/* Scrubbing every device */
|
||||
darray_for_each(dev_names, dev) {
|
||||
cmd.scrub.dev = dev->idx;
|
||||
struct scrub_device d = {
|
||||
.name = dev->dev,
|
||||
.progress_fd = xioctl(fs.ioctl_fd, BCH_IOCTL_DATA, &cmd),
|
||||
};
|
||||
darray_push(&scrub_devs, d);
|
||||
}
|
||||
}
|
||||
|
||||
printf(" %zu devices: ", scrub_devs.nr);
|
||||
darray_for_each(scrub_devs, dev)
|
||||
printf(" %s", dev->name);
|
||||
printf("\n");
|
||||
|
||||
struct timespec now, last;
|
||||
bool first = true;
|
||||
|
||||
struct printbuf buf = PRINTBUF;
|
||||
printbuf_tabstop_push(&buf, 16);
|
||||
printbuf_tabstop_push(&buf, 12);
|
||||
printbuf_tabstop_push(&buf, 12);
|
||||
printbuf_tabstop_push(&buf, 12);
|
||||
printbuf_tabstop_push(&buf, 12);
|
||||
printbuf_tabstop_push(&buf, 6);
|
||||
|
||||
prt_printf(&buf, "device\t");
|
||||
prt_printf(&buf, "checked\r");
|
||||
prt_printf(&buf, "corrected\r");
|
||||
prt_printf(&buf, "uncorrected\r");
|
||||
prt_printf(&buf, "total\r");
|
||||
puts(buf.buf);
|
||||
|
||||
while (1) {
|
||||
bool done = true;
|
||||
|
||||
printbuf_reset_keep_tabstops(&buf);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
u64 ns_since_last = 0;
|
||||
if (!first)
|
||||
ns_since_last = (now.tv_sec - last.tv_sec) * NSEC_PER_SEC +
|
||||
now.tv_nsec - last.tv_nsec;
|
||||
|
||||
darray_for_each(scrub_devs, dev) {
|
||||
struct bch_ioctl_data_event e;
|
||||
|
||||
if (dev->progress_fd >= 0 &&
|
||||
read(dev->progress_fd, &e, sizeof(e)) != sizeof(e)) {
|
||||
close(dev->progress_fd);
|
||||
dev->progress_fd = -1;
|
||||
}
|
||||
|
||||
u64 rate = 0;
|
||||
|
||||
if (dev->progress_fd >= 0) {
|
||||
if (ns_since_last)
|
||||
rate = ((e.p.sectors_done - dev->done) << 9)
|
||||
* NSEC_PER_SEC
|
||||
/ ns_since_last;
|
||||
|
||||
dev->done = e.p.sectors_done;
|
||||
dev->corrected = e.p.sectors_error_corrected;
|
||||
dev->uncorrected= e.p.sectors_error_uncorrected;
|
||||
dev->total = e.p.sectors_total;
|
||||
}
|
||||
|
||||
if (dev->progress_fd >= 0 && e.ret) {
|
||||
close(dev->progress_fd);
|
||||
dev->progress_fd = -1;
|
||||
dev->ret = e.ret;
|
||||
}
|
||||
|
||||
if (dev->progress_fd >= 0)
|
||||
done = false;
|
||||
|
||||
prt_printf(&buf, "%s\t", dev->name ?: "(offline)");
|
||||
|
||||
prt_human_readable_u64(&buf, dev->done << 9);
|
||||
prt_tab_rjust(&buf);
|
||||
|
||||
prt_human_readable_u64(&buf, dev->corrected << 9);
|
||||
prt_tab_rjust(&buf);
|
||||
|
||||
prt_human_readable_u64(&buf, dev->uncorrected << 9);
|
||||
prt_tab_rjust(&buf);
|
||||
|
||||
prt_human_readable_u64(&buf, dev->total << 9);
|
||||
prt_tab_rjust(&buf);
|
||||
|
||||
prt_printf(&buf, "%llu%%",
|
||||
dev->total
|
||||
? dev->done * 100 / dev->total
|
||||
: 0);
|
||||
prt_tab_rjust(&buf);
|
||||
|
||||
prt_str(&buf, " ");
|
||||
|
||||
if (dev->progress_fd >= 0) {
|
||||
prt_human_readable_u64(&buf, rate);
|
||||
prt_str(&buf, "/sec");
|
||||
} else if (dev->ret == BCH_IOCTL_DATA_EVENT_RET_device_offline) {
|
||||
prt_str(&buf, "offline");
|
||||
} else {
|
||||
prt_str(&buf, "complete");
|
||||
}
|
||||
|
||||
if (dev != &darray_last(scrub_devs))
|
||||
prt_newline(&buf);
|
||||
}
|
||||
|
||||
fputs(buf.buf, stdout);
|
||||
fflush(stdout);
|
||||
|
||||
if (done)
|
||||
break;
|
||||
|
||||
last = now;
|
||||
first = false;
|
||||
sleep(1);
|
||||
|
||||
for (unsigned i = 0; i < scrub_devs.nr; i++) {
|
||||
if (i)
|
||||
printf("\033[1A");
|
||||
printf("\33[2K\r");
|
||||
}
|
||||
}
|
||||
|
||||
fputs("\n", stdout);
|
||||
printbuf_exit(&buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void data_job_usage(void)
|
||||
{
|
||||
puts("bcachefs data job\n"
|
||||
|
@ -47,11 +47,11 @@ static void device_add_usage(void)
|
||||
puts("bcachefs device add - add a device to an existing filesystem\n"
|
||||
"Usage: bcachefs device add [OPTION]... filesystem device\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -S, --fs_size=size Size of filesystem on device\n"
|
||||
" -B, --bucket=size Bucket size\n"
|
||||
" -D, --discard Enable discards\n"
|
||||
" -l, --label=label Disk label\n"
|
||||
"Options:\n");
|
||||
|
||||
bch2_opts_usage(OPT_FORMAT|OPT_DEVICE);
|
||||
|
||||
puts(" -l, --label=label Disk label\n"
|
||||
" -f, --force Use device even if it appears to already be formatted\n"
|
||||
" -h, --help Display this help and exit\n"
|
||||
"\n"
|
||||
@ -61,9 +61,6 @@ static void device_add_usage(void)
|
||||
int cmd_device_add(int argc, char *argv[])
|
||||
{
|
||||
static const struct option longopts[] = {
|
||||
{ "fs_size", required_argument, NULL, 'S' },
|
||||
{ "bucket", required_argument, NULL, 'B' },
|
||||
{ "discard", no_argument, NULL, 'D' },
|
||||
{ "label", required_argument, NULL, 'l' },
|
||||
{ "force", no_argument, NULL, 'f' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
@ -72,22 +69,31 @@ int cmd_device_add(int argc, char *argv[])
|
||||
struct format_opts format_opts = format_opts_default();
|
||||
struct dev_opts dev_opts = dev_opts_default();
|
||||
bool force = false;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "S:B:Dl:fh",
|
||||
longopts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'S':
|
||||
if (bch2_strtoull_h(optarg, &dev_opts.size))
|
||||
die("invalid filesystem size");
|
||||
break;
|
||||
case 'B':
|
||||
if (bch2_strtoull_h(optarg, &dev_opts.bucket_size))
|
||||
die("bad bucket_size %s", optarg);
|
||||
break;
|
||||
case 'D':
|
||||
dev_opts.discard = true;
|
||||
while (true) {
|
||||
const struct bch_option *opt =
|
||||
bch2_cmdline_opt_parse(argc, argv, OPT_FORMAT|OPT_DEVICE);
|
||||
if (opt) {
|
||||
unsigned id = opt - bch2_opt_table;
|
||||
u64 v;
|
||||
struct printbuf err = PRINTBUF;
|
||||
int ret = bch2_opt_parse(NULL, opt, optarg, &v, &err);
|
||||
if (ret)
|
||||
die("invalid %s: %s", opt->attr.name, err.buf);
|
||||
|
||||
if (opt->flags & OPT_DEVICE)
|
||||
bch2_opt_set_by_id(&dev_opts.opts, id, v);
|
||||
else
|
||||
die("got bch_opt of wrong type %s", opt->attr.name);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
int optid = getopt_long(argc, argv, "S:B:Dl:fh", longopts, NULL);
|
||||
if (optid == -1)
|
||||
break;
|
||||
|
||||
switch (optid) {
|
||||
case 'l':
|
||||
dev_opts.label = strdup(optarg);
|
||||
break;
|
||||
@ -97,7 +103,11 @@ int cmd_device_add(int argc, char *argv[])
|
||||
case 'h':
|
||||
device_add_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
args_shift(optind);
|
||||
|
||||
char *fs_path = arg_pop();
|
||||
@ -127,10 +137,11 @@ int cmd_device_add(int argc, char *argv[])
|
||||
opt_set(fs_opts, btree_node_size,
|
||||
read_file_u64(fs.sysfs_fd, "options/btree_node_size"));
|
||||
|
||||
struct bch_sb *sb = bch2_format(fs_opt_strs,
|
||||
fs_opts,
|
||||
format_opts,
|
||||
&dev_opts, 1);
|
||||
dev_opts_list devs = {};
|
||||
darray_push(&devs, dev_opts);
|
||||
|
||||
struct bch_sb *sb = bch2_format(fs_opt_strs, fs_opts, format_opts, devs);
|
||||
darray_exit(&devs);
|
||||
free(sb);
|
||||
bchu_disk_add(fs, dev_opts.path);
|
||||
return 0;
|
||||
|
@ -70,26 +70,24 @@ static void dump_one_device(struct bch_fs *c, struct bch_dev *ca, int fd,
|
||||
/* Btree: */
|
||||
for (i = 0; i < BTREE_ID_NR; i++) {
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
struct btree_iter iter;
|
||||
struct btree *b;
|
||||
|
||||
__for_each_btree_node(trans, iter, i, POS_MIN, 0, 1, 0, b, ret) {
|
||||
ret = __for_each_btree_node(trans, iter, i, POS_MIN, 0, 1, 0, b, ({
|
||||
struct btree_node_iter iter;
|
||||
struct bkey u;
|
||||
struct bkey_s_c k;
|
||||
|
||||
for_each_btree_node_key_unpack(b, k, &iter, &u)
|
||||
dump_node(c, ca, k, &data);
|
||||
}
|
||||
0;
|
||||
}));
|
||||
|
||||
if (ret)
|
||||
die("error %s walking btree nodes", bch2_err_str(ret));
|
||||
|
||||
b = bch2_btree_id_root(c, i)->b;
|
||||
struct btree *b = bch2_btree_id_root(c, i)->b;
|
||||
if (!btree_node_fake(b))
|
||||
dump_node(c, ca, bkey_i_to_s_c(&b->key), &data);
|
||||
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
bch2_trans_put(trans);
|
||||
}
|
||||
|
||||
@ -114,6 +112,7 @@ int cmd_dump(int argc, char *argv[])
|
||||
int fd, opt;
|
||||
|
||||
opt_set(opts, direct_io, false);
|
||||
opt_set(opts, noexcl, true);
|
||||
opt_set(opts, read_only, true);
|
||||
opt_set(opts, nochanges, true);
|
||||
opt_set(opts, norecovery, true);
|
||||
|
@ -39,11 +39,7 @@ x('L', fs_label, required_argument) \
|
||||
x('U', uuid, required_argument) \
|
||||
x(0, fs_size, required_argument) \
|
||||
x(0, superblock_size, required_argument) \
|
||||
x(0, bucket_size, required_argument) \
|
||||
x('l', label, required_argument) \
|
||||
x(0, discard, no_argument) \
|
||||
x(0, data_allowed, required_argument) \
|
||||
x(0, durability, required_argument) \
|
||||
x(0, version, required_argument) \
|
||||
x(0, no_initialize, no_argument) \
|
||||
x(0, source, required_argument) \
|
||||
@ -52,17 +48,16 @@ x('q', quiet, no_argument) \
|
||||
x('v', verbose, no_argument) \
|
||||
x('h', help, no_argument)
|
||||
|
||||
static void usage(void)
|
||||
static void format_usage(void)
|
||||
{
|
||||
puts("bcachefs format - create a new bcachefs filesystem on one or more devices\n"
|
||||
"Usage: bcachefs format [OPTION]... <devices>\n"
|
||||
"\n"
|
||||
"Options:");
|
||||
|
||||
bch2_opts_usage(OPT_FORMAT);
|
||||
bch2_opts_usage(OPT_FORMAT|OPT_FS);
|
||||
|
||||
puts(
|
||||
" --replicas=# Sets both data and metadata replicas\n"
|
||||
puts(" --replicas=# Sets both data and metadata replicas\n"
|
||||
" --encrypted Enable whole filesystem encryption (chacha20/poly1305)\n"
|
||||
" --no_passphrase Don't encrypt master encryption key\n"
|
||||
" -L, --fs_label=label\n"
|
||||
@ -72,9 +67,10 @@ static void usage(void)
|
||||
"\n"
|
||||
"Device specific options:");
|
||||
|
||||
bch2_opts_usage(OPT_DEVICE);
|
||||
bch2_opts_usage(OPT_FORMAT|OPT_DEVICE);
|
||||
|
||||
puts(" -l, --label=label Disk label\n"
|
||||
puts(" --fs_size=size Size of filesystem on device\n"
|
||||
" -l, --label=label Disk label\n"
|
||||
"\n"
|
||||
" -f, --force\n"
|
||||
" -q, --quiet Only print errors\n"
|
||||
@ -125,32 +121,60 @@ void build_fs(struct bch_fs *c, const char *src_path)
|
||||
if (!S_ISDIR(stat.st_mode))
|
||||
die("%s is not a directory", src_path);
|
||||
|
||||
copy_fs(c, src_fd, src_path, &s);
|
||||
copy_fs(c, src_fd, src_path, &s, 0);
|
||||
}
|
||||
|
||||
int cmd_format(int argc, char *argv[])
|
||||
{
|
||||
DARRAY(struct dev_opts) devices = { 0 };
|
||||
DARRAY(char *) device_paths = { 0 };
|
||||
dev_opts_list devices = {};
|
||||
darray_str device_paths = {};
|
||||
struct format_opts opts = format_opts_default();
|
||||
struct dev_opts dev_opts = dev_opts_default();
|
||||
bool force = false, no_passphrase = false, quiet = false, initialize = true, verbose = false;
|
||||
bool unconsumed_dev_option = false;
|
||||
unsigned v;
|
||||
int opt;
|
||||
|
||||
struct bch_opt_strs fs_opt_strs =
|
||||
bch2_cmdline_opts_get(&argc, argv, OPT_FORMAT);
|
||||
struct bch_opts fs_opts = bch2_parse_opts(fs_opt_strs);
|
||||
struct bch_opt_strs fs_opt_strs = {};
|
||||
struct bch_opts fs_opts = bch2_opts_empty();
|
||||
|
||||
if (getenv("BCACHEFS_KERNEL_ONLY"))
|
||||
initialize = false;
|
||||
|
||||
while ((opt = getopt_long(argc, argv,
|
||||
"-L:U:g:fqhv",
|
||||
format_opts,
|
||||
NULL)) != -1)
|
||||
switch (opt) {
|
||||
while (true) {
|
||||
const struct bch_option *opt =
|
||||
bch2_cmdline_opt_parse(argc, argv, OPT_FORMAT|OPT_FS|OPT_DEVICE);
|
||||
if (opt) {
|
||||
unsigned id = opt - bch2_opt_table;
|
||||
u64 v;
|
||||
struct printbuf err = PRINTBUF;
|
||||
int ret = bch2_opt_parse(NULL, opt, optarg, &v, &err);
|
||||
if (ret == -BCH_ERR_option_needs_open_fs) {
|
||||
fs_opt_strs.by_id[id] = strdup(optarg);
|
||||
continue;
|
||||
}
|
||||
if (ret)
|
||||
die("invalid option: %s", err.buf);
|
||||
|
||||
if (opt->flags & OPT_DEVICE) {
|
||||
bch2_opt_set_by_id(&dev_opts.opts, id, v);
|
||||
unconsumed_dev_option = true;
|
||||
} else if (opt->flags & OPT_FS) {
|
||||
bch2_opt_set_by_id(&fs_opts, id, v);
|
||||
} else {
|
||||
die("got bch_opt of wrong type %s", opt->attr.name);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
int optid = getopt_long(argc, argv,
|
||||
"-L:l:U:g:fqhv",
|
||||
format_opts,
|
||||
NULL);
|
||||
if (optid == -1)
|
||||
break;
|
||||
|
||||
switch (optid) {
|
||||
case O_replicas:
|
||||
if (kstrtouint(optarg, 10, &v) ||
|
||||
!v ||
|
||||
@ -183,7 +207,7 @@ int cmd_format(int argc, char *argv[])
|
||||
force = true;
|
||||
break;
|
||||
case O_fs_size:
|
||||
if (bch2_strtoull_h(optarg, &dev_opts.size))
|
||||
if (bch2_strtoull_h(optarg, &dev_opts.fs_size))
|
||||
die("invalid filesystem size");
|
||||
unconsumed_dev_option = true;
|
||||
break;
|
||||
@ -193,35 +217,13 @@ int cmd_format(int argc, char *argv[])
|
||||
|
||||
opts.superblock_size >>= 9;
|
||||
break;
|
||||
case O_bucket_size:
|
||||
if (bch2_strtoull_h(optarg, &dev_opts.bucket_size))
|
||||
die("bad bucket_size %s", optarg);
|
||||
unconsumed_dev_option = true;
|
||||
break;
|
||||
case O_label:
|
||||
case 'l':
|
||||
dev_opts.label = optarg;
|
||||
unconsumed_dev_option = true;
|
||||
break;
|
||||
case O_discard:
|
||||
dev_opts.discard = true;
|
||||
unconsumed_dev_option = true;
|
||||
break;
|
||||
case O_data_allowed:
|
||||
dev_opts.data_allowed =
|
||||
read_flag_list_or_die(optarg,
|
||||
__bch2_data_types, "data type");
|
||||
unconsumed_dev_option = true;
|
||||
break;
|
||||
case O_durability:
|
||||
if (kstrtouint(optarg, 10, &dev_opts.durability) ||
|
||||
dev_opts.durability > BCH_REPLICAS_MAX)
|
||||
die("invalid durability");
|
||||
unconsumed_dev_option = true;
|
||||
break;
|
||||
case O_version:
|
||||
if (kstrtouint(optarg, 10, &opts.version))
|
||||
die("invalid version");
|
||||
opts.version = version_parse(optarg);
|
||||
break;
|
||||
case O_no_initialize:
|
||||
initialize = false;
|
||||
@ -230,7 +232,7 @@ int cmd_format(int argc, char *argv[])
|
||||
darray_push(&device_paths, optarg);
|
||||
dev_opts.path = optarg;
|
||||
darray_push(&devices, dev_opts);
|
||||
dev_opts.size = 0;
|
||||
dev_opts.fs_size = 0;
|
||||
unconsumed_dev_option = false;
|
||||
break;
|
||||
case O_quiet:
|
||||
@ -239,15 +241,19 @@ int cmd_format(int argc, char *argv[])
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case O_help:
|
||||
case 'h':
|
||||
usage();
|
||||
format_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case '?':
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
default:
|
||||
die("getopt ret %i %c", optid, optid);
|
||||
}
|
||||
}
|
||||
|
||||
if (unconsumed_dev_option)
|
||||
die("Options for devices apply to subsequent devices; got a device option with no device");
|
||||
@ -269,11 +275,7 @@ int cmd_format(int argc, char *argv[])
|
||||
die("Error opening %s: %s", dev_opts.path, strerror(-ret));
|
||||
}
|
||||
|
||||
struct bch_sb *sb =
|
||||
bch2_format(fs_opt_strs,
|
||||
fs_opts,
|
||||
opts,
|
||||
devices.data, devices.nr);
|
||||
struct bch_sb *sb = bch2_format(fs_opt_strs, fs_opts, opts, devices);
|
||||
bch2_opt_strs_free(&fs_opt_strs);
|
||||
|
||||
if (!quiet) {
|
||||
@ -433,3 +435,204 @@ int cmd_show_super(int argc, char *argv[])
|
||||
printbuf_exit(&buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "libbcachefs/super-io.h"
|
||||
#include "libbcachefs/sb-members.h"
|
||||
|
||||
typedef DARRAY(struct bch_sb *) probed_sb_list;
|
||||
|
||||
static void probe_one_super(int dev_fd, unsigned sb_size, u64 offset,
|
||||
probed_sb_list *sbs, bool verbose)
|
||||
{
|
||||
darray_char sb_buf = {};
|
||||
darray_resize(&sb_buf, sb_size);
|
||||
|
||||
xpread(dev_fd, sb_buf.data, sb_buf.size, offset);
|
||||
|
||||
struct printbuf err = PRINTBUF;
|
||||
int ret = bch2_sb_validate((void *) sb_buf.data, offset >> 9, 0, &err);
|
||||
printbuf_exit(&err);
|
||||
|
||||
if (!ret) {
|
||||
if (verbose) {
|
||||
struct printbuf buf = PRINTBUF;
|
||||
prt_human_readable_u64(&buf, offset);
|
||||
printf("found superblock at %s\n", buf.buf);
|
||||
printbuf_exit(&buf);
|
||||
}
|
||||
|
||||
darray_push(sbs, (void *) sb_buf.data);
|
||||
sb_buf.data = NULL;
|
||||
}
|
||||
|
||||
darray_exit(&sb_buf);
|
||||
}
|
||||
|
||||
static void probe_sb_range(int dev_fd, u64 start_offset, u64 end_offset,
|
||||
probed_sb_list *sbs, bool verbose)
|
||||
{
|
||||
start_offset &= ~((u64) 511);
|
||||
end_offset &= ~((u64) 511);
|
||||
|
||||
size_t buflen = end_offset - start_offset;
|
||||
void *buf = malloc(buflen);
|
||||
xpread(dev_fd, buf, buflen, start_offset);
|
||||
|
||||
for (u64 offset = 0; offset < buflen; offset += 512) {
|
||||
struct bch_sb *sb = buf + offset;
|
||||
|
||||
if (!uuid_equal(&sb->magic, &BCACHE_MAGIC) &&
|
||||
!uuid_equal(&sb->magic, &BCHFS_MAGIC))
|
||||
continue;
|
||||
|
||||
size_t bytes = vstruct_bytes(sb);
|
||||
if (offset + bytes > buflen) {
|
||||
fprintf(stderr, "found sb %llu size %zu that overran buffer\n",
|
||||
start_offset + offset, bytes);
|
||||
continue;
|
||||
}
|
||||
struct printbuf err = PRINTBUF;
|
||||
int ret = bch2_sb_validate(sb, (start_offset + offset) >> 9, 0, &err);
|
||||
if (ret)
|
||||
fprintf(stderr, "found sb %llu that failed to validate: %s\n",
|
||||
start_offset + offset, err.buf);
|
||||
printbuf_exit(&err);
|
||||
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
if (verbose) {
|
||||
struct printbuf buf = PRINTBUF;
|
||||
prt_human_readable_u64(&buf, start_offset + offset);
|
||||
printf("found superblock at %s\n", buf.buf);
|
||||
printbuf_exit(&buf);
|
||||
}
|
||||
|
||||
void *sb_copy = malloc(bytes);
|
||||
memcpy(sb_copy, sb, bytes);
|
||||
darray_push(sbs, sb_copy);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static u64 bch2_sb_last_mount_time(struct bch_sb *sb)
|
||||
{
|
||||
u64 ret = 0;
|
||||
for (unsigned i = 0; i < sb->nr_devices; i++)
|
||||
ret = max(ret, le64_to_cpu(bch2_sb_member_get(sb, i).last_mount));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_sb_time_cmp(struct bch_sb *l, struct bch_sb *r)
|
||||
{
|
||||
return cmp_int(bch2_sb_last_mount_time(l),
|
||||
bch2_sb_last_mount_time(r));
|
||||
}
|
||||
|
||||
static void recover_super_usage(void)
|
||||
{
|
||||
puts("bcachefs recover-super \n"
|
||||
"Usage: bcachefs recover-super [OPTION].. device\n"
|
||||
"\n"
|
||||
"Attempt to recover a filesystem on a device that has had the main superblock\n"
|
||||
"and superblock layout overwritten.\n"
|
||||
"All options will be guessed if not provided\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -d, --dev_size size of filessytem on device, in bytes \n"
|
||||
" -o, --offset offset to probe, in bytes\n"
|
||||
" -y, --yes Recover without prompting\n"
|
||||
" -v, --verbose Increase logging level\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
"Report bugs to <linux-bcachefs@vger.kernel.org>");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int cmd_recover_super(int argc, char *argv[])
|
||||
{
|
||||
static const struct option longopts[] = {
|
||||
{ "dev_size", 1, NULL, 'd' },
|
||||
{ "offset", 1, NULL, 'o' },
|
||||
{ "yes", 0, NULL, 'y' },
|
||||
{ "verbose", 0, NULL, 'v' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ NULL }
|
||||
};
|
||||
u64 dev_size = 0, offset = 0;
|
||||
bool yes = false, verbose = false;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "d:o:yvh", longopts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
if (bch2_strtoull_h(optarg, &dev_size))
|
||||
die("invalid offset");
|
||||
break;
|
||||
case 'o':
|
||||
if (bch2_strtoull_h(optarg, &offset))
|
||||
die("invalid offset");
|
||||
|
||||
if (offset & 511)
|
||||
die("offset must be a multiple of 512");
|
||||
break;
|
||||
case 'y':
|
||||
yes = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case 'h':
|
||||
recover_super_usage();
|
||||
break;
|
||||
}
|
||||
args_shift(optind);
|
||||
|
||||
char *dev_path = arg_pop();
|
||||
if (!dev_path)
|
||||
die("please supply a device");
|
||||
if (argc)
|
||||
die("too many arguments");
|
||||
|
||||
int dev_fd = xopen(dev_path, O_RDWR);
|
||||
|
||||
if (!dev_size)
|
||||
dev_size = get_size(dev_fd);
|
||||
|
||||
probed_sb_list sbs = {};
|
||||
|
||||
if (offset) {
|
||||
probe_one_super(dev_fd, SUPERBLOCK_SIZE_DEFAULT, offset, &sbs, verbose);
|
||||
} else {
|
||||
unsigned scan_len = 16 << 20; /* 16MB, start and end of device */
|
||||
|
||||
probe_sb_range(dev_fd, 4096, scan_len, &sbs, verbose);
|
||||
probe_sb_range(dev_fd, dev_size - scan_len, dev_size, &sbs, verbose);
|
||||
}
|
||||
|
||||
if (!sbs.nr) {
|
||||
printf("Found no bcachefs superblocks\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct bch_sb *best = NULL;
|
||||
darray_for_each(sbs, sb)
|
||||
if (!best || bch2_sb_time_cmp(best, *sb) < 0)
|
||||
best = *sb;
|
||||
|
||||
struct printbuf buf = PRINTBUF;
|
||||
bch2_sb_to_text(&buf, best, true, BIT_ULL(BCH_SB_FIELD_members_v2));
|
||||
|
||||
printf("Found superblock:\n%s", buf.buf);
|
||||
printf("Recover?");
|
||||
|
||||
if (yes || ask_yn())
|
||||
bch2_super_write(dev_fd, best);
|
||||
|
||||
printbuf_exit(&buf);
|
||||
darray_for_each(sbs, sb)
|
||||
kfree(*sb);
|
||||
darray_exit(&sbs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -122,14 +122,6 @@ static int dev_by_label_cmp(const void *_l, const void *_r)
|
||||
cmp_int(l->idx, r->idx);
|
||||
}
|
||||
|
||||
static struct dev_name *dev_idx_to_name(dev_names *dev_names, unsigned idx)
|
||||
{
|
||||
darray_for_each(*dev_names, dev)
|
||||
if (dev->idx == idx)
|
||||
return dev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void devs_usage_to_text(struct printbuf *out,
|
||||
struct bchfs_handle fs,
|
||||
dev_names dev_names)
|
||||
@ -185,7 +177,7 @@ static void replicas_usage_to_text(struct printbuf *out,
|
||||
unsigned dev_idx = r->devs[i];
|
||||
struct dev_name *dev = dev_idx_to_name(dev_names, dev_idx);
|
||||
|
||||
durability += dev->durability;
|
||||
durability += dev ? dev->durability : 0;
|
||||
|
||||
if (i)
|
||||
*d++ = ' ';
|
||||
@ -230,8 +222,6 @@ static int accounting_p_cmp(const void *_l, const void *_r)
|
||||
|
||||
struct bpos lp = (*l)->k.p, rp = (*r)->k.p;
|
||||
|
||||
bch2_bpos_swab(&lp);
|
||||
bch2_bpos_swab(&rp);
|
||||
return bpos_cmp(lp, rp);
|
||||
}
|
||||
|
||||
@ -247,6 +237,18 @@ static void accounting_sort(darray_accounting_p *sorted,
|
||||
sort(sorted->data, sorted->nr, sizeof(sorted->data[0]), accounting_p_cmp, NULL);
|
||||
}
|
||||
|
||||
static void accounting_swab_if_old(struct bch_ioctl_query_accounting *in)
|
||||
{
|
||||
unsigned kernel_version = bcachefs_kernel_version();
|
||||
|
||||
if (kernel_version &&
|
||||
kernel_version < bcachefs_metadata_version_disk_accounting_big_endian)
|
||||
for (struct bkey_i_accounting *a = in->accounting;
|
||||
a < (struct bkey_i_accounting *) ((u64 *) in->accounting + in->accounting_u64s);
|
||||
a = bkey_i_to_accounting(bkey_next(&a->k_i)))
|
||||
bch2_bpos_swab(&a->k.p);
|
||||
}
|
||||
|
||||
static int fs_usage_v1_to_text(struct printbuf *out,
|
||||
struct bchfs_handle fs,
|
||||
dev_names dev_names)
|
||||
@ -261,6 +263,8 @@ static int fs_usage_v1_to_text(struct printbuf *out,
|
||||
if (!a)
|
||||
return -1;
|
||||
|
||||
accounting_swab_if_old(a);
|
||||
|
||||
darray_accounting_p a_sorted = {};
|
||||
|
||||
accounting_sort(&a_sorted, a);
|
||||
@ -487,6 +491,19 @@ devs:
|
||||
bcache_fs_close(fs);
|
||||
}
|
||||
|
||||
int fs_usage(void)
|
||||
{
|
||||
puts("bcachefs fs - manage a running filesystem\n"
|
||||
"Usage: bcachefs fs <CMD> [OPTIONS]\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" usage Display detailed filesystem usage\n"
|
||||
" top Show runtime performance information\n"
|
||||
"\n"
|
||||
"Report bugs to <linux-bcachefs@vger.kernel.org>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fs_usage_usage(void)
|
||||
{
|
||||
puts("bcachefs fs usage - display detailed filesystem usage\n"
|
||||
|
@ -21,7 +21,6 @@ static void fsck_usage(void)
|
||||
" -y Assume \"yes\" to all questions\n"
|
||||
" -f Force checking even if filesystem is marked clean\n"
|
||||
" -r, --ratelimit_errors Don't display more than 10 errors of a given type\n"
|
||||
" -R, --reconstruct_alloc Reconstruct the alloc btree\n"
|
||||
" -k, --kernel Use the in-kernel fsck implementation\n"
|
||||
" -v Be verbose\n"
|
||||
" -h, --help Display this help and exit\n"
|
||||
@ -90,12 +89,14 @@ static int splice_fd_to_stdinout(int fd)
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
static int fsck_online(const char *dev_path)
|
||||
static int fsck_online(const char *dev_path, const char *opt_str)
|
||||
{
|
||||
int dev_idx;
|
||||
struct bchfs_handle fs = bchu_fs_open_by_dev(dev_path, &dev_idx);
|
||||
|
||||
struct bch_ioctl_fsck_online fsck = { 0 };
|
||||
struct bch_ioctl_fsck_online fsck = {
|
||||
.opts = (unsigned long) opt_str
|
||||
};
|
||||
|
||||
int fsck_fd = ioctl(fs.ioctl_fd, BCH_IOCTL_FSCK_ONLINE, &fsck);
|
||||
if (fsck_fd < 0)
|
||||
@ -113,9 +114,9 @@ static void append_opt(struct printbuf *out, const char *opt)
|
||||
|
||||
static bool should_use_kernel_fsck(darray_str devs)
|
||||
{
|
||||
unsigned kernel_version = !access("/sys/module/bcachefs/parameters/version", R_OK)
|
||||
? read_file_u64(AT_FDCWD, "/sys/module/bcachefs/parameters/version")
|
||||
: 0;
|
||||
system("modprobe bcachefs");
|
||||
|
||||
unsigned kernel_version = bcachefs_kernel_version();
|
||||
|
||||
if (!kernel_version)
|
||||
return false;
|
||||
@ -158,11 +159,49 @@ static bool should_use_kernel_fsck(darray_str devs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool is_blockdev(const char *path)
|
||||
{
|
||||
struct stat s;
|
||||
if (stat(path, &s))
|
||||
return true;
|
||||
return S_ISBLK(s.st_mode);
|
||||
}
|
||||
|
||||
static void loopdev_free(const char *path)
|
||||
{
|
||||
char *cmd = mprintf("losetup -d %s", path);
|
||||
system(cmd);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
static char *loopdev_alloc(const char *path)
|
||||
{
|
||||
char *cmd = mprintf("losetup --show -f %s", path);
|
||||
FILE *f = popen(cmd, "r");
|
||||
free(cmd);
|
||||
if (!f) {
|
||||
fprintf(stderr, "error executing losetup: %m\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *line = NULL;
|
||||
size_t n = 0;
|
||||
getline(&line, &n, f);
|
||||
int ret = pclose(f);
|
||||
if (ret) {
|
||||
fprintf(stderr, "error executing losetup: %i\n", ret);
|
||||
free(line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strim(line);
|
||||
return line;
|
||||
}
|
||||
|
||||
int cmd_fsck(int argc, char *argv[])
|
||||
{
|
||||
static const struct option longopts[] = {
|
||||
{ "ratelimit_errors", no_argument, NULL, 'r' },
|
||||
{ "reconstruct_alloc", no_argument, NULL, 'R' },
|
||||
{ "kernel", no_argument, NULL, 'k' },
|
||||
{ "no-kernel", no_argument, NULL, 'K' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
@ -181,10 +220,13 @@ int cmd_fsck(int argc, char *argv[])
|
||||
append_opt(&opts_str, "read_only");
|
||||
|
||||
while ((opt = getopt_long(argc, argv,
|
||||
"apynfo:rRkvh",
|
||||
"apynfo:rkKvh",
|
||||
longopts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'a': /* outdated alias for -p */
|
||||
case 'a':
|
||||
/* "automatic" run, called by the system, for us to do checks as needed.
|
||||
* we don't need checks here: */
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'p':
|
||||
case 'y':
|
||||
append_opt(&opts_str, "fix_errors=yes");
|
||||
@ -202,9 +244,6 @@ int cmd_fsck(int argc, char *argv[])
|
||||
case 'r':
|
||||
append_opt(&opts_str, "ratelimit_errors");
|
||||
break;
|
||||
case 'R':
|
||||
append_opt(&opts_str, "reconstruct_alloc");
|
||||
break;
|
||||
case 'k':
|
||||
kernel = true;
|
||||
break;
|
||||
@ -228,8 +267,10 @@ int cmd_fsck(int argc, char *argv[])
|
||||
darray_str devs = get_or_split_cmdline_devs(argc, argv);
|
||||
|
||||
darray_for_each(devs, i)
|
||||
if (dev_mounted(*i))
|
||||
return fsck_online(*i);
|
||||
if (dev_mounted(*i)) {
|
||||
printf("Running fsck online\n");
|
||||
return fsck_online(*i, opts_str.buf);
|
||||
}
|
||||
|
||||
int kernel_probed = kernel;
|
||||
if (kernel_probed < 0)
|
||||
@ -239,18 +280,35 @@ int cmd_fsck(int argc, char *argv[])
|
||||
struct printbuf parse_later = PRINTBUF;
|
||||
|
||||
if (kernel_probed) {
|
||||
struct bch_ioctl_fsck_offline *fsck = calloc(sizeof(*fsck) +
|
||||
sizeof(u64) * devs.nr, 1);
|
||||
darray_str loopdevs = {};
|
||||
int fsck_fd = -1;
|
||||
|
||||
printf("Running in-kernel offline fsck\n");
|
||||
struct bch_ioctl_fsck_offline *fsck = calloc(sizeof(*fsck) + sizeof(u64) * devs.nr, 1);
|
||||
|
||||
fsck->opts = (unsigned long)opts_str.buf;
|
||||
darray_for_each(devs, i)
|
||||
fsck->devs[i - devs.data] = (unsigned long) *i;
|
||||
darray_for_each(devs, i) {
|
||||
if (is_blockdev(*i)) {
|
||||
fsck->devs[i - devs.data] = (unsigned long) *i;
|
||||
} else {
|
||||
char *l = loopdev_alloc(*i);
|
||||
if (!l)
|
||||
goto kernel_fsck_err;
|
||||
darray_push(&loopdevs, l);
|
||||
fsck->devs[i - devs.data] = (unsigned long) l;
|
||||
}
|
||||
}
|
||||
fsck->nr_devs = devs.nr;
|
||||
|
||||
int ctl_fd = bcachectl_open();
|
||||
int fsck_fd = ioctl(ctl_fd, BCH_IOCTL_FSCK_OFFLINE, fsck);
|
||||
fsck_fd = ioctl(ctl_fd, BCH_IOCTL_FSCK_OFFLINE, fsck);
|
||||
kernel_fsck_err:
|
||||
free(fsck);
|
||||
|
||||
darray_for_each(loopdevs, i)
|
||||
loopdev_free(*i);
|
||||
darray_exit(&loopdevs);
|
||||
|
||||
if (fsck_fd < 0 && kernel < 0)
|
||||
goto userland_fsck;
|
||||
|
||||
@ -260,7 +318,8 @@ int cmd_fsck(int argc, char *argv[])
|
||||
ret = splice_fd_to_stdinout(fsck_fd);
|
||||
} else {
|
||||
userland_fsck:
|
||||
ret = bch2_parse_mount_opts(NULL, &opts, &parse_later, opts_str.buf);
|
||||
printf("Running userspace offline fsck\n");
|
||||
ret = bch2_parse_mount_opts(NULL, &opts, &parse_later, opts_str.buf, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "libbcachefs/dirent.h"
|
||||
#include "libbcachefs/errcode.h"
|
||||
#include "libbcachefs/error.h"
|
||||
#include "libbcachefs/fs-common.h"
|
||||
#include "libbcachefs/namei.h"
|
||||
#include "libbcachefs/inode.h"
|
||||
#include "libbcachefs/io_read.h"
|
||||
#include "libbcachefs/io_write.h"
|
||||
@ -31,9 +31,6 @@
|
||||
|
||||
#include <linux/dcache.h>
|
||||
|
||||
/* XXX cut and pasted from fsck.c */
|
||||
#define QSTR(n) { { { .len = strlen(n) } }, .name = n }
|
||||
|
||||
/* used by write_aligned function for waiting on bch2_write closure */
|
||||
struct write_aligned_op_t {
|
||||
struct closure cl;
|
||||
@ -242,7 +239,7 @@ static int do_create(struct bch_fs *c, subvol_inum dir,
|
||||
|
||||
bch2_inode_init_early(c, new_inode);
|
||||
|
||||
return bch2_trans_do(c, NULL, NULL, 0,
|
||||
return bch2_trans_commit_do(c, NULL, NULL, 0,
|
||||
bch2_create_trans(trans,
|
||||
dir, &dir_u,
|
||||
new_inode, &qstr,
|
||||
@ -295,7 +292,7 @@ static void bcachefs_fuse_unlink(fuse_req_t req, fuse_ino_t dir_ino,
|
||||
|
||||
fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_unlink(%llu, %s)\n", dir.inum, name);
|
||||
|
||||
int ret = bch2_trans_do(c, NULL, NULL,
|
||||
int ret = bch2_trans_commit_do(c, NULL, NULL,
|
||||
BCH_TRANS_COMMIT_no_enospc,
|
||||
bch2_unlink_trans(trans, dir, &dir_u,
|
||||
&inode_u, &qstr, false));
|
||||
@ -330,7 +327,7 @@ static void bcachefs_fuse_rename(fuse_req_t req,
|
||||
src_dir.inum, srcname, dst_dir.inum, dstname, flags);
|
||||
|
||||
/* XXX handle overwrites */
|
||||
ret = bch2_trans_do(c, NULL, NULL, 0,
|
||||
ret = bch2_trans_commit_do(c, NULL, NULL, 0,
|
||||
bch2_rename_trans(trans,
|
||||
src_dir, &src_dir_u,
|
||||
dst_dir, &dst_dir_u,
|
||||
@ -354,7 +351,7 @@ static void bcachefs_fuse_link(fuse_req_t req, fuse_ino_t ino,
|
||||
fuse_log(FUSE_LOG_DEBUG, "bcachefs_fuse_link(%llu, %llu, %s)\n",
|
||||
inum.inum, newparent.inum, newname);
|
||||
|
||||
ret = bch2_trans_do(c, NULL, NULL, 0,
|
||||
ret = bch2_trans_commit_do(c, NULL, NULL, 0,
|
||||
bch2_link_trans(trans, newparent, &dir_u,
|
||||
inum, &inode_u, &qstr));
|
||||
|
||||
@ -478,10 +475,9 @@ static int read_aligned(struct bch_fs *c, subvol_inum inum, size_t aligned_size,
|
||||
closure_init_stack(&cl);
|
||||
|
||||
closure_get(&cl);
|
||||
rbio.bio.bi_end_io = bcachefs_fuse_read_endio;
|
||||
rbio.bio.bi_private = &cl;
|
||||
rbio.bio.bi_private = &cl;
|
||||
|
||||
bch2_read(c, rbio_init(&rbio.bio, io_opts), inum);
|
||||
bch2_read(c, rbio_init(&rbio.bio, c, io_opts, bcachefs_fuse_read_endio), inum);
|
||||
|
||||
closure_sync(&cl);
|
||||
|
||||
@ -1203,6 +1199,7 @@ int cmd_fusemount(int argc, char *argv[])
|
||||
struct bch_opts bch_opts = bch2_opts_empty();
|
||||
struct bf_context ctx = { 0 };
|
||||
struct bch_fs *c = NULL;
|
||||
struct fuse_session *se = NULL;
|
||||
int ret = 0, i;
|
||||
|
||||
/* Parse arguments. */
|
||||
@ -1221,9 +1218,9 @@ int cmd_fusemount(int argc, char *argv[])
|
||||
goto out;
|
||||
}
|
||||
if (fuse_opts.show_version) {
|
||||
/* TODO: Show bcachefs version. */
|
||||
printf("FUSE library version %s\n", fuse_pkgversion());
|
||||
fuse_lowlevel_version();
|
||||
printf("bcachefs version: %s\n", VERSION_STRING);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
@ -1263,17 +1260,22 @@ int cmd_fusemount(int argc, char *argv[])
|
||||
bch2_err_str(PTR_ERR(c)));
|
||||
|
||||
/* Fuse */
|
||||
struct fuse_session *se =
|
||||
fuse_session_new(&args, &bcachefs_fuse_ops,
|
||||
sizeof(bcachefs_fuse_ops), c);
|
||||
if (!se)
|
||||
die("fuse_lowlevel_new err: %m");
|
||||
se = fuse_session_new(&args, &bcachefs_fuse_ops,
|
||||
sizeof(bcachefs_fuse_ops), c);
|
||||
if (!se) {
|
||||
fprintf(stderr, "fuse_lowlevel_new err: %m\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (fuse_set_signal_handlers(se) < 0)
|
||||
die("fuse_set_signal_handlers err: %m");
|
||||
if (fuse_set_signal_handlers(se) < 0) {
|
||||
fprintf(stderr, "fuse_set_signal_handlers err: %m\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (fuse_session_mount(se, fuse_opts.mountpoint))
|
||||
die("fuse_mount err: %m");
|
||||
if (fuse_session_mount(se, fuse_opts.mountpoint)) {
|
||||
fprintf(stderr, "fuse_mount err: %m\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* This print statement is a trigger for tests. */
|
||||
printf("Fuse mount initialized.\n");
|
||||
@ -1287,17 +1289,22 @@ int cmd_fusemount(int argc, char *argv[])
|
||||
|
||||
ret = fuse_session_loop(se);
|
||||
|
||||
/* Cleanup */
|
||||
fuse_session_unmount(se);
|
||||
fuse_remove_signal_handlers(se);
|
||||
fuse_session_destroy(se);
|
||||
|
||||
out:
|
||||
if (se) {
|
||||
fuse_session_unmount(se);
|
||||
fuse_remove_signal_handlers(se);
|
||||
fuse_session_destroy(se);
|
||||
}
|
||||
|
||||
free(fuse_opts.mountpoint);
|
||||
fuse_opt_free_args(&args);
|
||||
bf_context_free(&ctx);
|
||||
|
||||
return ret ? 1 : 0;
|
||||
|
||||
err:
|
||||
bch2_fs_stop(c);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#endif /* BCACHEFS_FUSE */
|
||||
|
@ -104,24 +104,19 @@ int cmd_set_passphrase(int argc, char *argv[])
|
||||
if (IS_ERR(c))
|
||||
die("Error opening %s: %s", argv[1], bch2_err_str(PTR_ERR(c)));
|
||||
|
||||
struct bch_sb_field_crypt *crypt = bch2_sb_field_get(c->disk_sb.sb, crypt);
|
||||
struct bch_sb *sb = c->disk_sb.sb;
|
||||
struct bch_sb_field_crypt *crypt = bch2_sb_field_get(sb, crypt);
|
||||
if (!crypt)
|
||||
die("Filesystem does not have encryption enabled");
|
||||
|
||||
struct bch_encrypted_key new_key;
|
||||
new_key.magic = BCH_KEY_MAGIC;
|
||||
|
||||
int ret = bch2_decrypt_sb_key(c, crypt, &new_key.key);
|
||||
struct bch_key key;
|
||||
int ret = bch2_decrypt_sb_key(c, crypt, &key);
|
||||
if (ret)
|
||||
die("Error getting current key");
|
||||
|
||||
char *new_passphrase = read_passphrase_twice("Enter new passphrase: ");
|
||||
struct bch_key passphrase_key = derive_passphrase(crypt, new_passphrase);
|
||||
|
||||
if (bch2_chacha_encrypt_key(&passphrase_key, __bch2_sb_key_nonce(c->disk_sb.sb),
|
||||
&new_key, sizeof(new_key)))
|
||||
die("error encrypting key");
|
||||
crypt->key = new_key;
|
||||
bch_crypt_update_passphrase(sb, crypt, &key, new_passphrase);
|
||||
|
||||
bch2_revoke_key(c->disk_sb.sb);
|
||||
bch2_write_super(c);
|
||||
@ -142,18 +137,17 @@ int cmd_remove_passphrase(int argc, char *argv[])
|
||||
if (IS_ERR(c))
|
||||
die("Error opening %s: %s", argv[1], bch2_err_str(PTR_ERR(c)));
|
||||
|
||||
struct bch_sb_field_crypt *crypt = bch2_sb_field_get(c->disk_sb.sb, crypt);
|
||||
struct bch_sb *sb = c->disk_sb.sb;
|
||||
struct bch_sb_field_crypt *crypt = bch2_sb_field_get(sb, crypt);
|
||||
if (!crypt)
|
||||
die("Filesystem does not have encryption enabled");
|
||||
|
||||
struct bch_encrypted_key new_key;
|
||||
new_key.magic = BCH_KEY_MAGIC;
|
||||
|
||||
int ret = bch2_decrypt_sb_key(c, crypt, &new_key.key);
|
||||
struct bch_key key;
|
||||
int ret = bch2_decrypt_sb_key(c, crypt, &key);
|
||||
if (ret)
|
||||
die("Error getting current key");
|
||||
|
||||
crypt->key = new_key;
|
||||
bch_crypt_update_passphrase(sb, crypt, &key, NULL);
|
||||
|
||||
bch2_write_super(c);
|
||||
bch2_fs_stop(c);
|
||||
|
@ -27,30 +27,44 @@ static void kill_btree_node_usage(void)
|
||||
"Report bugs to <linux-bcachefs@vger.kernel.org>");
|
||||
}
|
||||
|
||||
struct kill_node {
|
||||
unsigned btree;
|
||||
unsigned level;
|
||||
u64 idx;
|
||||
};
|
||||
|
||||
int cmd_kill_btree_node(int argc, char *argv[])
|
||||
{
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
enum btree_id btree_id = 0;
|
||||
unsigned level = 0;
|
||||
u64 node_index = 0;
|
||||
DARRAY(struct kill_node) kill_nodes = {};
|
||||
int opt;
|
||||
|
||||
opt_set(opts, read_only, true);
|
||||
|
||||
while ((opt = getopt(argc, argv, "b:l:i:h")) != -1)
|
||||
while ((opt = getopt(argc, argv, "n:h")) != -1)
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
btree_id = read_string_list_or_die(optarg,
|
||||
__bch2_btree_ids, "btree id");
|
||||
break;
|
||||
case 'l':
|
||||
if (kstrtouint(optarg, 10, &level) || level >= BTREE_MAX_DEPTH)
|
||||
case 'n': {
|
||||
char *p = optarg;
|
||||
const char *str_btree = strsep(&p, ":");
|
||||
const char *str_level = strsep(&p, ":");
|
||||
const char *str_idx = strsep(&p, ":");
|
||||
|
||||
struct kill_node n = {
|
||||
.btree = read_string_list_or_die(str_btree,
|
||||
__bch2_btree_ids, "btree id"),
|
||||
};
|
||||
|
||||
if (str_level &&
|
||||
(kstrtouint(str_level, 10, &n.level) || n.level >= BTREE_MAX_DEPTH))
|
||||
die("invalid level");
|
||||
|
||||
if (str_idx &&
|
||||
kstrtoull(str_idx, 10, &n.idx))
|
||||
die("invalid index %s", str_idx);
|
||||
|
||||
darray_push(&kill_nodes, n);
|
||||
break;
|
||||
case 'i':
|
||||
if (kstrtoull(optarg, 10, &node_index))
|
||||
die("invalid index %s", optarg);
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
kill_btree_node_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -64,9 +78,6 @@ int cmd_kill_btree_node(int argc, char *argv[])
|
||||
if (IS_ERR(c))
|
||||
die("error opening %s: %s", argv[0], bch2_err_str(PTR_ERR(c)));
|
||||
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
struct btree_iter iter;
|
||||
struct btree *b;
|
||||
int ret;
|
||||
void *zeroes;
|
||||
|
||||
@ -74,47 +85,56 @@ int cmd_kill_btree_node(int argc, char *argv[])
|
||||
if (ret)
|
||||
die("error %s from posix_memalign", bch2_err_str(ret));
|
||||
|
||||
__for_each_btree_node(trans, iter, btree_id, POS_MIN, 0, level, 0, b, ret) {
|
||||
if (b->c.level != level)
|
||||
continue;
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
|
||||
if (!node_index) {
|
||||
struct printbuf buf = PRINTBUF;
|
||||
bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&b->key));
|
||||
bch_info(c, "killing btree node %s", buf.buf);
|
||||
printbuf_exit(&buf);
|
||||
darray_for_each(kill_nodes, i) {
|
||||
ret = __for_each_btree_node(trans, iter, i->btree, POS_MIN, 0, i->level, 0, b, ({
|
||||
if (b->c.level != i->level)
|
||||
continue;
|
||||
|
||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(bkey_i_to_s_c(&b->key));
|
||||
bkey_for_each_ptr(ptrs, ptr) {
|
||||
struct bch_dev *ca = bch2_dev_tryget(c, ptr->dev);
|
||||
if (!ca)
|
||||
continue;
|
||||
int ret2 = 0;
|
||||
if (!i->idx) {
|
||||
struct printbuf buf = PRINTBUF;
|
||||
bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&b->key));
|
||||
bch_info(c, "killing btree node %s l=%u %s",
|
||||
bch2_btree_id_str(i->btree), i->level, buf.buf);
|
||||
printbuf_exit(&buf);
|
||||
|
||||
ret = pwrite(ca->disk_sb.bdev->bd_fd, zeroes,
|
||||
c->opts.block_size, ptr->offset << 9);
|
||||
bch2_dev_put(ca);
|
||||
if (ret != c->opts.block_size) {
|
||||
bch_err(c, "pwrite error: expected %u got %i %s",
|
||||
c->opts.block_size, ret, strerror(errno));
|
||||
ret = EXIT_FAILURE;
|
||||
goto done;
|
||||
ret2 = 1;
|
||||
|
||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(bkey_i_to_s_c(&b->key));
|
||||
bkey_for_each_ptr(ptrs, ptr) {
|
||||
struct bch_dev *ca = bch2_dev_tryget(c, ptr->dev);
|
||||
if (!ca)
|
||||
continue;
|
||||
|
||||
int ret3 = pwrite(ca->disk_sb.bdev->bd_fd, zeroes,
|
||||
c->opts.block_size, ptr->offset << 9);
|
||||
bch2_dev_put(ca);
|
||||
if (ret3 != c->opts.block_size) {
|
||||
bch_err(c, "pwrite error: expected %u got %i %s",
|
||||
c->opts.block_size, ret, strerror(errno));
|
||||
ret2 = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
goto done;
|
||||
|
||||
i->idx--;
|
||||
ret2;
|
||||
}));
|
||||
|
||||
if (ret < 0) {
|
||||
bch_err(c, "error %i walking btree nodes", ret);
|
||||
break;
|
||||
} else if (!ret) {
|
||||
bch_err(c, "node at specified index not found");
|
||||
ret = EXIT_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
node_index--;
|
||||
}
|
||||
if (ret)
|
||||
bch_err(c, "error %i walking btree nodes", ret);
|
||||
else
|
||||
bch_err(c, "node at specified index not found");
|
||||
ret = EXIT_FAILURE;
|
||||
done:
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
bch2_trans_put(trans);
|
||||
|
||||
bch2_trans_put(trans);
|
||||
bch2_fs_stop(c);
|
||||
return ret;
|
||||
darray_exit(&kill_nodes);
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
@ -51,6 +51,11 @@ static inline bool entry_is_transaction_start(struct jset_entry *entry)
|
||||
return entry->type == BCH_JSET_ENTRY_log && !entry->level;
|
||||
}
|
||||
|
||||
static inline bool entry_is_log_msg(struct jset_entry *entry)
|
||||
{
|
||||
return entry->type == BCH_JSET_ENTRY_log && entry->level;
|
||||
}
|
||||
|
||||
typedef DARRAY(struct bbpos_range) d_bbpos_range;
|
||||
typedef DARRAY(enum btree_id) d_btree_id;
|
||||
|
||||
@ -60,9 +65,21 @@ static bool bkey_matches_filter(d_bbpos_range filter, struct jset_entry *entry,
|
||||
struct bbpos k_start = BBPOS(entry->btree_id, bkey_start_pos(&k->k));
|
||||
struct bbpos k_end = BBPOS(entry->btree_id, k->k.p);
|
||||
|
||||
if (bbpos_cmp(k_start, i->end) < 0 &&
|
||||
bbpos_cmp(k_end, i->start) > 0)
|
||||
return true;
|
||||
if (!i->start.pos.snapshot &&
|
||||
!i->end.pos.snapshot) {
|
||||
k_start.pos.snapshot = 0;
|
||||
k_end.pos.snapshot = 0;
|
||||
}
|
||||
|
||||
if (!k->k.size) {
|
||||
if (bbpos_cmp(k_start, i->start) >= 0 &&
|
||||
bbpos_cmp(k_end, i->end) <= 0)
|
||||
return true;
|
||||
} else {
|
||||
if (bbpos_cmp(i->start, k_end) <= 0 &&
|
||||
bbpos_cmp(i->end, k_start) >= 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -70,9 +87,9 @@ static bool bkey_matches_filter(d_bbpos_range filter, struct jset_entry *entry,
|
||||
static bool entry_matches_transaction_filter(struct jset_entry *entry,
|
||||
d_bbpos_range filter)
|
||||
{
|
||||
if (entry->type == BCH_JSET_ENTRY_btree_root ||
|
||||
entry->type == BCH_JSET_ENTRY_btree_keys ||
|
||||
entry->type == BCH_JSET_ENTRY_overwrite)
|
||||
if (!entry->level &&
|
||||
(entry->type == BCH_JSET_ENTRY_btree_keys ||
|
||||
entry->type == BCH_JSET_ENTRY_overwrite))
|
||||
jset_entry_for_each_key(entry, k)
|
||||
if (bkey_matches_filter(filter, entry, k))
|
||||
return true;
|
||||
@ -80,17 +97,36 @@ static bool entry_matches_transaction_filter(struct jset_entry *entry,
|
||||
}
|
||||
|
||||
static bool should_print_transaction(struct jset_entry *entry, struct jset_entry *end,
|
||||
d_bbpos_range filter)
|
||||
darray_str msg_filter,
|
||||
d_bbpos_range key_filter)
|
||||
{
|
||||
if (!filter.nr)
|
||||
struct jset_entry_log *l = container_of(entry, struct jset_entry_log, entry);
|
||||
unsigned b = jset_entry_log_msg_bytes(l);
|
||||
bool have_log_messages = false;
|
||||
bool have_non_log_messages = false;
|
||||
|
||||
darray_for_each(msg_filter, i)
|
||||
if (!strncmp(*i, l->d, b))
|
||||
return false;
|
||||
|
||||
if (!key_filter.nr)
|
||||
return true;
|
||||
|
||||
for (entry = vstruct_next(entry);
|
||||
entry != end && !entry_is_transaction_start(entry);
|
||||
entry = vstruct_next(entry))
|
||||
if (entry_matches_transaction_filter(entry, filter))
|
||||
entry = vstruct_next(entry)) {
|
||||
if (entry_matches_transaction_filter(entry, key_filter))
|
||||
return true;
|
||||
|
||||
if (entry_is_log_msg(entry))
|
||||
have_log_messages = true;
|
||||
else
|
||||
have_non_log_messages = true;
|
||||
}
|
||||
|
||||
if (have_log_messages && !have_non_log_messages)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -112,8 +148,41 @@ static bool should_print_entry(struct jset_entry *entry, d_btree_id filter)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void journal_entry_header_to_text(struct printbuf *out,
|
||||
struct bch_fs *c,
|
||||
struct journal_replay *p, bool blacklisted)
|
||||
{
|
||||
if (blacklisted)
|
||||
prt_str(out, "blacklisted ");
|
||||
|
||||
prt_printf(out,
|
||||
"\n"
|
||||
"journal entry %llu\n"
|
||||
" version %u\n"
|
||||
" last seq %llu\n"
|
||||
" flush %u\n"
|
||||
" written at ",
|
||||
le64_to_cpu(p->j.seq),
|
||||
le32_to_cpu(p->j.version),
|
||||
le64_to_cpu(p->j.last_seq),
|
||||
!JSET_NO_FLUSH(&p->j));
|
||||
bch2_journal_ptrs_to_text(out, c, p);
|
||||
|
||||
if (blacklisted)
|
||||
star_start_of_lines(out->buf);
|
||||
}
|
||||
|
||||
static void journal_entry_header_print(struct bch_fs *c, struct journal_replay *p, bool blacklisted)
|
||||
{
|
||||
struct printbuf buf = PRINTBUF;
|
||||
journal_entry_header_to_text(&buf, c, p, blacklisted);
|
||||
printf("%s\n", buf.buf);
|
||||
printbuf_exit(&buf);
|
||||
}
|
||||
|
||||
static void journal_entries_print(struct bch_fs *c, unsigned nr_entries,
|
||||
d_bbpos_range transaction_filter,
|
||||
darray_str transaction_msg_filter,
|
||||
d_bbpos_range transaction_key_filter,
|
||||
d_btree_id key_filter)
|
||||
{
|
||||
struct journal_replay *p, **_p;
|
||||
@ -121,6 +190,8 @@ static void journal_entries_print(struct bch_fs *c, unsigned nr_entries,
|
||||
struct printbuf buf = PRINTBUF;
|
||||
|
||||
genradix_for_each(&c->journal_entries, iter, _p) {
|
||||
bool printed_header = false;
|
||||
|
||||
p = *_p;
|
||||
if (!p)
|
||||
continue;
|
||||
@ -132,28 +203,10 @@ static void journal_entries_print(struct bch_fs *c, unsigned nr_entries,
|
||||
bch2_journal_seq_is_blacklisted(c,
|
||||
le64_to_cpu(p->j.seq), false);
|
||||
|
||||
if (!transaction_filter.nr) {
|
||||
if (blacklisted)
|
||||
printf("blacklisted ");
|
||||
|
||||
printf("journal entry %llu\n", le64_to_cpu(p->j.seq));
|
||||
|
||||
printbuf_reset(&buf);
|
||||
|
||||
prt_printf(&buf,
|
||||
" version %u\n"
|
||||
" last seq %llu\n"
|
||||
" flush %u\n"
|
||||
" written at ",
|
||||
le32_to_cpu(p->j.version),
|
||||
le64_to_cpu(p->j.last_seq),
|
||||
!JSET_NO_FLUSH(&p->j));
|
||||
bch2_journal_ptrs_to_text(&buf, c, p);
|
||||
|
||||
if (blacklisted)
|
||||
star_start_of_lines(buf.buf);
|
||||
printf("%s\n", buf.buf);
|
||||
printbuf_reset(&buf);
|
||||
if (!transaction_msg_filter.nr &&
|
||||
!transaction_key_filter.nr) {
|
||||
journal_entry_header_print(c, p, blacklisted);
|
||||
printed_header = true;
|
||||
}
|
||||
|
||||
struct jset_entry *entry = p->j.start;
|
||||
@ -165,7 +218,9 @@ static void journal_entries_print(struct bch_fs *c, unsigned nr_entries,
|
||||
* commit:
|
||||
*/
|
||||
if (entry_is_transaction_start(entry)) {
|
||||
if (!should_print_transaction(entry, end, transaction_filter)) {
|
||||
if (!should_print_transaction(entry, end,
|
||||
transaction_msg_filter,
|
||||
transaction_key_filter)) {
|
||||
do {
|
||||
entry = vstruct_next(entry);
|
||||
} while (entry != end && !entry_is_transaction_start(entry));
|
||||
@ -179,7 +234,11 @@ static void journal_entries_print(struct bch_fs *c, unsigned nr_entries,
|
||||
if (!should_print_entry(entry, key_filter))
|
||||
goto next;
|
||||
|
||||
bool highlight = entry_matches_transaction_filter(entry, transaction_filter);
|
||||
if (!printed_header)
|
||||
journal_entry_header_print(c, p, blacklisted);
|
||||
printed_header = true;
|
||||
|
||||
bool highlight = entry_matches_transaction_filter(entry, transaction_key_filter);
|
||||
if (highlight)
|
||||
fputs(RED, stdout);
|
||||
|
||||
@ -213,8 +272,9 @@ int cmd_list_journal(int argc, char *argv[])
|
||||
};
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
u32 nr_entries = U32_MAX;
|
||||
d_bbpos_range transaction_filter = { 0 };
|
||||
d_btree_id key_filter = { 0 };
|
||||
darray_str transaction_msg_filter = {};
|
||||
d_bbpos_range transaction_key_filter = {};
|
||||
d_btree_id key_filter = {};
|
||||
int opt;
|
||||
|
||||
opt_set(opts, noexcl, true);
|
||||
@ -228,7 +288,7 @@ int cmd_list_journal(int argc, char *argv[])
|
||||
opt_set(opts, retain_recovery_info ,true);
|
||||
opt_set(opts, read_journal_only,true);
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "an:t:k:vh",
|
||||
while ((opt = getopt_long(argc, argv, "an:m:t:k:vh",
|
||||
longopts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
@ -239,8 +299,11 @@ int cmd_list_journal(int argc, char *argv[])
|
||||
die("error parsing nr_entries");
|
||||
opt_set(opts, read_entire_journal, true);
|
||||
break;
|
||||
case 'm':
|
||||
darray_push(&transaction_msg_filter, strdup(optarg));
|
||||
break;
|
||||
case 't':
|
||||
darray_push(&transaction_filter, bbpos_range_parse(optarg));
|
||||
darray_push(&transaction_key_filter, bbpos_range_parse(optarg));
|
||||
break;
|
||||
case 'k':
|
||||
darray_push(&key_filter, read_string_list_or_die(optarg, __bch2_btree_ids, "btree id"));
|
||||
@ -263,7 +326,10 @@ int cmd_list_journal(int argc, char *argv[])
|
||||
if (IS_ERR(c))
|
||||
die("error opening %s: %s", argv[0], bch2_err_str(PTR_ERR(c)));
|
||||
|
||||
journal_entries_print(c, nr_entries, transaction_filter, key_filter);
|
||||
journal_entries_print(c, nr_entries,
|
||||
transaction_msg_filter,
|
||||
transaction_key_filter,
|
||||
key_filter);
|
||||
bch2_fs_stop(c);
|
||||
return 0;
|
||||
}
|
||||
|
@ -31,9 +31,6 @@
|
||||
#include "libbcachefs/replicas.h"
|
||||
#include "libbcachefs/super.h"
|
||||
|
||||
/* XXX cut and pasted from fsck.c */
|
||||
#define QSTR(n) { { { .len = strlen(n) } }, .name = n }
|
||||
|
||||
static char *dev_t_to_path(dev_t dev)
|
||||
{
|
||||
char link[PATH_MAX], *p;
|
||||
@ -162,9 +159,9 @@ static void find_superblock_space(ranges extents,
|
||||
{
|
||||
darray_for_each(extents, i) {
|
||||
u64 start = round_up(max(256ULL << 10, i->start),
|
||||
dev->bucket_size << 9);
|
||||
dev->opts.bucket_size << 9);
|
||||
u64 end = round_down(i->end,
|
||||
dev->bucket_size << 9);
|
||||
dev->opts.bucket_size << 9);
|
||||
|
||||
/* Need space for two superblocks: */
|
||||
if (start + (opts.superblock_size << 9) * 2 <= end) {
|
||||
@ -212,38 +209,43 @@ static int migrate_fs(const char *fs_path,
|
||||
if (!S_ISDIR(stat.st_mode))
|
||||
die("%s is not a directory", fs_path);
|
||||
|
||||
struct dev_opts dev = dev_opts_default();
|
||||
dev_opts_list devs = {};
|
||||
darray_push(&devs, dev_opts_default());
|
||||
|
||||
dev.path = dev_t_to_path(stat.st_dev);
|
||||
dev.file = bdev_file_open_by_path(dev.path, BLK_OPEN_READ|BLK_OPEN_WRITE, &dev, NULL);
|
||||
struct dev_opts *dev = &devs.data[0];
|
||||
|
||||
int ret = PTR_ERR_OR_ZERO(dev.file);
|
||||
dev->path = dev_t_to_path(stat.st_dev);
|
||||
dev->file = bdev_file_open_by_path(dev->path, BLK_OPEN_READ|BLK_OPEN_WRITE, dev, NULL);
|
||||
|
||||
int ret = PTR_ERR_OR_ZERO(dev->file);
|
||||
if (ret < 0)
|
||||
die("Error opening device to format %s: %s", dev.path, strerror(-ret));
|
||||
dev.bdev = file_bdev(dev.file);
|
||||
die("Error opening device to format %s: %s", dev->path, strerror(-ret));
|
||||
dev->bdev = file_bdev(dev->file);
|
||||
|
||||
opt_set(fs_opts, block_size, get_blocksize(dev.bdev->bd_fd));
|
||||
opt_set(fs_opts, block_size, get_blocksize(dev->bdev->bd_fd));
|
||||
|
||||
char *file_path = mprintf("%s/bcachefs", fs_path);
|
||||
printf("Creating new filesystem on %s in space reserved at %s\n",
|
||||
dev.path, file_path);
|
||||
dev->path, file_path);
|
||||
|
||||
dev.size = get_size(dev.bdev->bd_fd);
|
||||
dev.bucket_size = bch2_pick_bucket_size(fs_opts, &dev);
|
||||
dev.nbuckets = dev.size / dev.bucket_size;
|
||||
dev->fs_size = get_size(dev->bdev->bd_fd);
|
||||
opt_set(dev->opts, bucket_size, bch2_pick_bucket_size(fs_opts, devs));
|
||||
|
||||
bch2_check_bucket_size(fs_opts, &dev);
|
||||
dev->nbuckets = dev->fs_size / dev->opts.bucket_size;
|
||||
|
||||
bch2_check_bucket_size(fs_opts, dev);
|
||||
|
||||
u64 bcachefs_inum;
|
||||
ranges extents = reserve_new_fs_space(file_path,
|
||||
fs_opts.block_size >> 9,
|
||||
get_size(dev.bdev->bd_fd) / 5,
|
||||
get_size(dev->bdev->bd_fd) / 5,
|
||||
&bcachefs_inum, stat.st_dev, force);
|
||||
|
||||
find_superblock_space(extents, format_opts, &dev);
|
||||
find_superblock_space(extents, format_opts, dev);
|
||||
|
||||
struct bch_sb *sb = bch2_format(fs_opt_strs, fs_opts, format_opts, devs);
|
||||
darray_exit(&devs);
|
||||
|
||||
struct bch_sb *sb = bch2_format(fs_opt_strs,
|
||||
fs_opts, format_opts, &dev, 1);
|
||||
u64 sb_offset = le64_to_cpu(sb->layout.sb_offset[0]);
|
||||
|
||||
if (format_opts.passphrase)
|
||||
@ -251,16 +253,14 @@ static int migrate_fs(const char *fs_path,
|
||||
|
||||
free(sb);
|
||||
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
struct bch_fs *c = NULL;
|
||||
char *path[1] = { dev.path };
|
||||
char *path[1] = { dev->path };
|
||||
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
opt_set(opts, sb, sb_offset);
|
||||
opt_set(opts, nostart, true);
|
||||
opt_set(opts, noexcl, true);
|
||||
opt_set(opts, nostart, true);
|
||||
|
||||
c = bch2_fs_open(path, 1, opts);
|
||||
struct bch_fs *c = bch2_fs_open(path, 1, opts);
|
||||
if (IS_ERR(c))
|
||||
die("Error opening new filesystem: %s", bch2_err_str(PTR_ERR(c)));
|
||||
|
||||
@ -268,10 +268,6 @@ static int migrate_fs(const char *fs_path,
|
||||
if (ret)
|
||||
die("Error allocating buckets_nouse: %s", bch2_err_str(ret));
|
||||
|
||||
ret = bch2_fs_start(c);
|
||||
if (IS_ERR(c))
|
||||
die("Error starting new filesystem: %s", bch2_err_str(ret));
|
||||
|
||||
mark_unreserved_space(c, extents);
|
||||
|
||||
ret = bch2_fs_start(c);
|
||||
@ -285,7 +281,10 @@ static int migrate_fs(const char *fs_path,
|
||||
.type = BCH_MIGRATE_migrate,
|
||||
};
|
||||
|
||||
copy_fs(c, fs_fd, fs_path, &s);
|
||||
u64 reserve_start = round_up((format_opts.superblock_size * 2 + 8) << 9,
|
||||
dev->opts.bucket_size);
|
||||
|
||||
copy_fs(c, fs_fd, fs_path, &s, reserve_start);
|
||||
|
||||
bch2_fs_stop(c);
|
||||
|
||||
@ -313,7 +312,7 @@ static int migrate_fs(const char *fs_path,
|
||||
"filesystem. That file can be deleted once the old filesystem is\n"
|
||||
"no longer needed (and should be deleted prior to running\n"
|
||||
"bcachefs migrate-superblock)\n",
|
||||
sb_offset, dev.path, dev.path, sb_offset);
|
||||
sb_offset, dev->path, dev->path, sb_offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -377,7 +376,7 @@ static void migrate_superblock_usage(void)
|
||||
int cmd_migrate_superblock(int argc, char *argv[])
|
||||
{
|
||||
char *dev = NULL;
|
||||
u64 offset = 0;
|
||||
u64 sb_offset = 0;
|
||||
int opt, ret;
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:o:h")) != -1)
|
||||
@ -386,7 +385,7 @@ int cmd_migrate_superblock(int argc, char *argv[])
|
||||
dev = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
ret = kstrtou64(optarg, 10, &offset);
|
||||
ret = kstrtou64(optarg, 10, &sb_offset);
|
||||
if (ret)
|
||||
die("Invalid offset");
|
||||
break;
|
||||
@ -398,29 +397,72 @@ int cmd_migrate_superblock(int argc, char *argv[])
|
||||
if (!dev)
|
||||
die("Please specify a device");
|
||||
|
||||
if (!offset)
|
||||
if (!sb_offset)
|
||||
die("Please specify offset of existing superblock");
|
||||
|
||||
int fd = xopen(dev, O_RDWR);
|
||||
struct bch_sb *sb = __bch2_super_read(fd, offset);
|
||||
struct bch_sb *sb = __bch2_super_read(fd, sb_offset);
|
||||
unsigned sb_size = 1U << sb->layout.sb_max_size_bits;
|
||||
|
||||
if (sb->layout.nr_superblocks >= ARRAY_SIZE(sb->layout.sb_offset))
|
||||
die("Can't add superblock: no space left in superblock layout");
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < sb->layout.nr_superblocks; i++)
|
||||
if (le64_to_cpu(sb->layout.sb_offset[i]) == BCH_SB_SECTOR)
|
||||
die("Superblock layout already has default superblock");
|
||||
for (unsigned i = 0; i < sb->layout.nr_superblocks; i++)
|
||||
if (le64_to_cpu(sb->layout.sb_offset[i]) == BCH_SB_SECTOR ||
|
||||
le64_to_cpu(sb->layout.sb_offset[i]) == BCH_SB_SECTOR + sb_size)
|
||||
die("Superblock layout already has default superblocks");
|
||||
|
||||
memmove(&sb->layout.sb_offset[1],
|
||||
memmove(&sb->layout.sb_offset[2],
|
||||
&sb->layout.sb_offset[0],
|
||||
sb->layout.nr_superblocks * sizeof(u64));
|
||||
sb->layout.nr_superblocks++;
|
||||
|
||||
sb->layout.nr_superblocks += 2;
|
||||
sb->layout.sb_offset[0] = cpu_to_le64(BCH_SB_SECTOR);
|
||||
sb->layout.sb_offset[1] = cpu_to_le64(BCH_SB_SECTOR + sb_size);
|
||||
|
||||
/* also write first 0-3.5k bytes with zeroes, ensure we blow away old
|
||||
* superblock */
|
||||
static const char zeroes[BCH_SB_SECTOR << 9];
|
||||
xpwrite(fd, zeroes, BCH_SB_SECTOR << 9, 0, "zeroing start of disk");
|
||||
|
||||
bch2_super_write(fd, sb);
|
||||
close(fd);
|
||||
|
||||
/* mark new superblocks */
|
||||
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
opt_set(opts, nostart, true);
|
||||
opt_set(opts, sb, sb_offset);
|
||||
|
||||
struct bch_fs *c = bch2_fs_open(&dev, 1, opts);
|
||||
ret = PTR_ERR_OR_ZERO(c) ?:
|
||||
bch2_buckets_nouse_alloc(c);
|
||||
if (ret)
|
||||
die("error opening filesystem: %s", bch2_err_str(ret));
|
||||
|
||||
struct bch_dev *ca = c->devs[0];
|
||||
for (u64 b = 0; bucket_to_sector(ca, b) < BCH_SB_SECTOR + sb_size * 2; b++)
|
||||
set_bit(b, ca->buckets_nouse);
|
||||
|
||||
ret = bch2_fs_start(c);
|
||||
if (ret)
|
||||
die("Error starting filesystem: %s", bch2_err_str(ret));
|
||||
|
||||
bch2_fs_stop(c);
|
||||
|
||||
opts = bch2_opts_empty();
|
||||
opt_set(opts, fsck, true);
|
||||
opt_set(opts, fix_errors, true);
|
||||
|
||||
/*
|
||||
* Hack: the free space counters are coming out wrong after marking the
|
||||
* new superblock, but it's just the device counters so it's
|
||||
* inconsequential:
|
||||
*/
|
||||
|
||||
c = bch2_fs_open(&dev, 1, opts);
|
||||
ret = PTR_ERR_OR_ZERO(c);
|
||||
if (ret)
|
||||
die("error opening filesystem: %s", bch2_err_str(ret));
|
||||
bch2_fs_stop(c);
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,28 +26,54 @@
|
||||
|
||||
static void set_option_usage(void)
|
||||
{
|
||||
puts("bcachefs set-option \n"
|
||||
"Usage: bcachefs set-option [OPTION].. device\n"
|
||||
puts("bcachefs set-fs-option \n"
|
||||
"Usage: bcachefs set-fs-option [OPTION].. device\n"
|
||||
"\n"
|
||||
"Options:\n");
|
||||
bch2_opts_usage(OPT_MOUNT);
|
||||
puts(" -h, --help display this help and exit\n"
|
||||
bch2_opts_usage(OPT_MOUNT|OPT_RUNTIME);
|
||||
puts(" -d, --dev-idx index for device specific options\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
"Report bugs to <linux-bcachefs@vger.kernel.org>");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static int name_to_dev_idx(struct bch_fs *c, const char *dev)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_member_device_rcu(c, ca, NULL)
|
||||
if (!strcmp(ca->name, dev)) {
|
||||
ret = ca->dev_idx;
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_set_option(int argc, char *argv[])
|
||||
{
|
||||
struct bch_opt_strs new_opt_strs = bch2_cmdline_opts_get(&argc, argv, OPT_MOUNT);
|
||||
struct bch_opt_strs new_opt_strs = bch2_cmdline_opts_get(&argc, argv, OPT_MOUNT|OPT_DEVICE);
|
||||
struct bch_opts new_opts = bch2_parse_opts(new_opt_strs);
|
||||
struct bch_opts open_opts = bch2_opts_empty();
|
||||
unsigned i;
|
||||
DARRAY(unsigned) dev_idxs = {};
|
||||
int opt, ret = 0;
|
||||
|
||||
opt_set(open_opts, nostart, true);
|
||||
static const struct option longopts[] = {
|
||||
{ "dev-idx", required_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
while ((opt = getopt(argc, argv, "h")) != -1)
|
||||
while ((opt = getopt_long(argc, argv, "d:h", longopts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'd': {
|
||||
unsigned dev_idx;
|
||||
if (kstrtoint(optarg, 10, &dev_idx))
|
||||
die("error parsing %s", optarg);
|
||||
darray_push(&dev_idxs, dev_idx);
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
set_option_usage();
|
||||
break;
|
||||
@ -59,48 +85,117 @@ int cmd_set_option(int argc, char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
bool online = false;
|
||||
unsigned i;
|
||||
for (i = 0; i < argc; i++)
|
||||
if (dev_mounted(argv[i]))
|
||||
goto online;
|
||||
|
||||
struct bch_fs *c = bch2_fs_open(argv, argc, open_opts);
|
||||
if (IS_ERR(c)) {
|
||||
fprintf(stderr, "error opening %s: %s\n", argv[0], bch2_err_str(PTR_ERR(c)));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < bch2_opts_nr; i++) {
|
||||
u64 v = bch2_opt_get_by_id(&new_opts, i);
|
||||
|
||||
if (!bch2_opt_defined_by_id(&new_opts, i))
|
||||
continue;
|
||||
|
||||
ret = bch2_opt_check_may_set(c, i, v);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error setting %s: %i\n",
|
||||
bch2_opt_table[i].attr.name, ret);
|
||||
if (dev_mounted(argv[i])) {
|
||||
online = true;
|
||||
break;
|
||||
}
|
||||
|
||||
bch2_opt_set_sb(c, bch2_opt_table + i, v);
|
||||
bch2_opt_set_by_id(&c->opts, i, v);
|
||||
}
|
||||
if (!online) {
|
||||
struct bch_opts open_opts = bch2_opts_empty();
|
||||
opt_set(open_opts, nostart, true);
|
||||
|
||||
bch2_fs_stop(c);
|
||||
return ret;
|
||||
online:
|
||||
{
|
||||
struct bch_fs *c = bch2_fs_open(argv, argc, open_opts);
|
||||
if (IS_ERR(c)) {
|
||||
fprintf(stderr, "error opening %s: %s\n", argv[0], bch2_err_str(PTR_ERR(c)));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < bch2_opts_nr; i++) {
|
||||
const struct bch_option *opt = bch2_opt_table + i;
|
||||
|
||||
u64 v = bch2_opt_get_by_id(&new_opts, i);
|
||||
|
||||
if (!bch2_opt_defined_by_id(&new_opts, i))
|
||||
continue;
|
||||
|
||||
if (!(opt->flags & (OPT_FS|OPT_DEVICE)))
|
||||
fprintf(stderr, "Can't set option %s\n", opt->attr.name);
|
||||
|
||||
if (opt->flags & OPT_FS) {
|
||||
ret = bch2_opt_check_may_set(c, NULL, i, v);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error setting %s: %i\n", opt->attr.name, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
bch2_opt_set_sb(c, NULL, opt, v);
|
||||
}
|
||||
|
||||
if (opt->flags & OPT_DEVICE) {
|
||||
if (dev_idxs.nr) {
|
||||
darray_for_each(dev_idxs, dev) {
|
||||
struct bch_dev *ca = bch2_dev_tryget_noerror(c, *dev);
|
||||
if (!ca) {
|
||||
fprintf(stderr, "Couldn't look up device %u\n", *dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = bch2_opt_check_may_set(c, ca, i, v);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error setting %s: %i\n", opt->attr.name, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
bch2_opt_set_sb(c, ca, opt, v);
|
||||
bch2_dev_put(ca);
|
||||
}
|
||||
} else {
|
||||
for (unsigned dev = 0; dev < argc; dev++) {
|
||||
int dev_idx = name_to_dev_idx(c, argv[dev]);
|
||||
if (dev_idx < 0) {
|
||||
fprintf(stderr, "Couldn't look up device %s\n", argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
bch2_opt_set_sb(c, c->devs[dev_idx], opt, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bch2_fs_stop(c);
|
||||
return ret;
|
||||
} else {
|
||||
unsigned dev_idx;
|
||||
struct bchfs_handle fs = bchu_fs_open_by_dev(argv[i], &dev_idx);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
struct bchfs_handle fs2 = bchu_fs_open_by_dev(argv[i], &dev_idx);
|
||||
if (memcmp(&fs.uuid, &fs2.uuid, sizeof(fs2.uuid)))
|
||||
die("Filesystem mounted, but not all devices are members");
|
||||
bcache_fs_close(fs2);
|
||||
}
|
||||
|
||||
for (i = 0; i < bch2_opts_nr; i++) {
|
||||
if (!new_opt_strs.by_id[i])
|
||||
continue;
|
||||
|
||||
char *path = mprintf("options/%s", bch2_opt_table[i].attr.name);
|
||||
const struct bch_option *opt = bch2_opt_table + i;
|
||||
|
||||
write_file_str(fs.sysfs_fd, path, new_opt_strs.by_id[i]);
|
||||
free(path);
|
||||
if (!(opt->flags & (OPT_FS|OPT_DEVICE)))
|
||||
fprintf(stderr, "Can't set option %s\n", opt->attr.name);
|
||||
|
||||
if (opt->flags & OPT_FS) {
|
||||
char *path = mprintf("options/%s", opt->attr.name);
|
||||
|
||||
write_file_str(fs.sysfs_fd, path, new_opt_strs.by_id[i]);
|
||||
free(path);
|
||||
}
|
||||
|
||||
if (opt->flags & OPT_DEVICE) {
|
||||
for (unsigned dev = 0; dev < argc; dev++) {
|
||||
struct bchfs_handle fs2 = bchu_fs_open_by_dev(argv[i], &dev_idx);
|
||||
bcache_fs_close(fs2);
|
||||
|
||||
|
||||
char *path = mprintf("dev-%u/%s", dev_idx, opt->attr.name);
|
||||
write_file_str(fs.sysfs_fd, path, new_opt_strs.by_id[i]);
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
98
c_src/cmd_top.c
Normal file
98
c_src/cmd_top.c
Normal file
@ -0,0 +1,98 @@
|
||||
#include <dirent.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "cmds.h"
|
||||
#include "libbcachefs.h"
|
||||
#include "libbcachefs/sb-counters.h"
|
||||
|
||||
static const u8 counters_to_stable_map[] = {
|
||||
#define x(n, id, ...) [BCH_COUNTER_##n] = BCH_COUNTER_STABLE_##n,
|
||||
BCH_PERSISTENT_COUNTERS()
|
||||
#undef x
|
||||
};
|
||||
|
||||
static struct bch_ioctl_query_counters *read_counters(struct bchfs_handle fs)
|
||||
{
|
||||
struct bch_ioctl_query_counters *ret =
|
||||
kzalloc(sizeof(*ret) + sizeof(ret->d[0]) * BCH_COUNTER_NR, GFP_KERNEL);
|
||||
|
||||
ret->nr = BCH_COUNTER_NR;
|
||||
|
||||
xioctl(fs.ioctl_fd, BCH_IOCTL_QUERY_COUNTERS, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fs_top(const char *path, bool human_readable)
|
||||
{
|
||||
struct bchfs_handle fs = bcache_fs_open(path);
|
||||
|
||||
struct bch_ioctl_query_counters *curr, *prev = NULL;
|
||||
|
||||
curr = read_counters(fs);
|
||||
|
||||
while (true) {
|
||||
sleep(1);
|
||||
kfree(prev);
|
||||
prev = curr;
|
||||
curr = read_counters(fs);
|
||||
|
||||
printf("\033[2J");
|
||||
printf("\033[H");
|
||||
|
||||
for (unsigned i = 0; i < BCH_COUNTER_NR; i++) {
|
||||
unsigned stable = counters_to_stable_map[i];
|
||||
u64 v = stable < curr->nr
|
||||
? curr->d[stable] - prev->d[stable]
|
||||
: 0;
|
||||
printf("%-48s %llu\n",
|
||||
bch2_counter_names[i],
|
||||
v);
|
||||
}
|
||||
}
|
||||
|
||||
bcache_fs_close(fs);
|
||||
}
|
||||
|
||||
static void fs_top_usage(void)
|
||||
{
|
||||
puts("bcachefs fs top - display runtime perfomance info\n"
|
||||
"Usage: bcachefs fs top [OPTION]... <mountpoint>\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --human-readable Human readable units\n"
|
||||
" -H, --help Display this help and exit\n"
|
||||
"Report bugs to <linux-bcachefs@vger.kernel.org>");
|
||||
}
|
||||
|
||||
int cmd_fs_top(int argc, char *argv[])
|
||||
{
|
||||
static const struct option longopts[] = {
|
||||
{ "help", no_argument, NULL, 'H' },
|
||||
{ "human-readable", no_argument, NULL, 'h' },
|
||||
{ NULL }
|
||||
};
|
||||
bool human_readable = false;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "Hh",
|
||||
longopts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
human_readable = true;
|
||||
break;
|
||||
case 'H':
|
||||
fs_top_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
default:
|
||||
fs_top_usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
args_shift(optind);
|
||||
|
||||
fs_top(arg_pop() ?: ".", human_readable) ;
|
||||
return 0;
|
||||
}
|
@ -11,10 +11,13 @@
|
||||
|
||||
int cmd_format(int argc, char *argv[]);
|
||||
int cmd_show_super(int argc, char *argv[]);
|
||||
int cmd_recover_super(int argc, char *argv[]);
|
||||
int cmd_reset_counters(int argc, char *argv[]);
|
||||
int cmd_set_option(int argc, char *argv[]);
|
||||
|
||||
int fs_usage(void);
|
||||
int cmd_fs_usage(int argc, char *argv[]);
|
||||
int cmd_fs_top(int argc, char *argv[]);
|
||||
|
||||
int device_usage(void);
|
||||
int cmd_device_add(int argc, char *argv[]);
|
||||
@ -28,6 +31,7 @@ int cmd_device_resize_journal(int argc, char *argv[]);
|
||||
|
||||
int data_usage(void);
|
||||
int cmd_data_rereplicate(int argc, char *argv[]);
|
||||
int cmd_data_scrub(int argc, char *argv[]);
|
||||
int cmd_data_job(int argc, char *argv[]);
|
||||
|
||||
int cmd_unlock(int argc, char *argv[]);
|
||||
|
@ -176,26 +176,47 @@ void bch_sb_crypt_init(struct bch_sb *sb,
|
||||
struct bch_sb_field_crypt *crypt,
|
||||
const char *passphrase)
|
||||
{
|
||||
struct bch_key key;
|
||||
get_random_bytes(&key, sizeof(key));
|
||||
|
||||
crypt->key.magic = BCH_KEY_MAGIC;
|
||||
get_random_bytes(&crypt->key.key, sizeof(crypt->key.key));
|
||||
crypt->key.key = key;
|
||||
|
||||
if (passphrase) {
|
||||
bch_crypt_update_passphrase(sb, crypt, &key, passphrase);
|
||||
}
|
||||
|
||||
void bch_crypt_update_passphrase(
|
||||
struct bch_sb *sb,
|
||||
struct bch_sb_field_crypt *crypt,
|
||||
struct bch_key *key,
|
||||
const char *new_passphrase)
|
||||
{
|
||||
|
||||
struct bch_encrypted_key new_key;
|
||||
new_key.magic = BCH_KEY_MAGIC;
|
||||
new_key.key = *key;
|
||||
|
||||
if(!new_passphrase) {
|
||||
crypt->key = new_key;
|
||||
return;
|
||||
}
|
||||
|
||||
// If crypt already has an encrypted key reuse it's encryption params
|
||||
if (!bch2_key_is_encrypted(&crypt->key)) {
|
||||
SET_BCH_CRYPT_KDF_TYPE(crypt, BCH_KDF_SCRYPT);
|
||||
SET_BCH_KDF_SCRYPT_N(crypt, ilog2(16384));
|
||||
SET_BCH_KDF_SCRYPT_R(crypt, ilog2(8));
|
||||
SET_BCH_KDF_SCRYPT_P(crypt, ilog2(16));
|
||||
|
||||
struct bch_key passphrase_key = derive_passphrase(crypt, passphrase);
|
||||
|
||||
assert(!bch2_key_is_encrypted(&crypt->key));
|
||||
|
||||
if (bch2_chacha_encrypt_key(&passphrase_key, __bch2_sb_key_nonce(sb),
|
||||
&crypt->key, sizeof(crypt->key)))
|
||||
die("error encrypting key");
|
||||
|
||||
assert(bch2_key_is_encrypted(&crypt->key));
|
||||
|
||||
memzero_explicit(&passphrase_key, sizeof(passphrase_key));
|
||||
}
|
||||
|
||||
struct bch_key passphrase_key = derive_passphrase(crypt, new_passphrase);
|
||||
|
||||
if (bch2_chacha_encrypt_key(&passphrase_key, __bch2_sb_key_nonce(sb),
|
||||
&new_key, sizeof(new_key)))
|
||||
die("error encrypting key");
|
||||
|
||||
memzero_explicit(&passphrase_key, sizeof(passphrase_key));
|
||||
|
||||
crypt->key = new_key;
|
||||
assert(bch2_key_is_encrypted(&crypt->key));
|
||||
}
|
||||
|
@ -19,4 +19,7 @@ void bch2_add_key(struct bch_sb *, const char *, const char *, const char *);
|
||||
void bch_sb_crypt_init(struct bch_sb *sb, struct bch_sb_field_crypt *,
|
||||
const char *);
|
||||
|
||||
void bch_crypt_update_passphrase(struct bch_sb *sb, struct bch_sb_field_crypt *crypt,
|
||||
struct bch_key *key, const char *new_passphrase);
|
||||
|
||||
#endif /* _CRYPTO_H */
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include "libbcachefs.h"
|
||||
#include "crypto.h"
|
||||
#include "libbcachefs/bcachefs_format.h"
|
||||
@ -31,10 +33,10 @@
|
||||
|
||||
#define NSEC_PER_SEC 1000000000L
|
||||
|
||||
static void init_layout(struct bch_sb_layout *l,
|
||||
unsigned block_size,
|
||||
unsigned sb_size,
|
||||
u64 sb_start, u64 sb_end)
|
||||
void bch2_sb_layout_init(struct bch_sb_layout *l,
|
||||
unsigned block_size,
|
||||
unsigned sb_size,
|
||||
u64 sb_start, u64 sb_end)
|
||||
{
|
||||
u64 sb_pos = sb_start;
|
||||
unsigned i;
|
||||
@ -60,83 +62,86 @@ static void init_layout(struct bch_sb_layout *l,
|
||||
sb_start, sb_pos, sb_end, sb_size);
|
||||
}
|
||||
|
||||
/* minimum size filesystem we can create, given a bucket size: */
|
||||
static u64 min_size(unsigned bucket_size)
|
||||
static u64 dev_max_bucket_size(u64 dev_size)
|
||||
{
|
||||
return BCH_MIN_NR_NBUCKETS * bucket_size;
|
||||
return rounddown_pow_of_two(dev_size / (BCH_MIN_NR_NBUCKETS * 4));
|
||||
}
|
||||
|
||||
u64 bch2_pick_bucket_size(struct bch_opts opts, struct dev_opts *dev)
|
||||
u64 bch2_pick_bucket_size(struct bch_opts opts, dev_opts_list devs)
|
||||
{
|
||||
u64 bucket_size;
|
||||
|
||||
if (dev->size < min_size(opts.block_size))
|
||||
die("cannot format %s, too small (%llu bytes, min %llu)",
|
||||
dev->path, dev->size, min_size(opts.block_size));
|
||||
|
||||
/* Bucket size must be >= block size: */
|
||||
bucket_size = opts.block_size;
|
||||
u64 bucket_size = opts.block_size;
|
||||
|
||||
/* Bucket size must be >= btree node size: */
|
||||
if (opt_defined(opts, btree_node_size))
|
||||
bucket_size = max_t(unsigned, bucket_size,
|
||||
opts.btree_node_size);
|
||||
bucket_size = max_t(u64, bucket_size, opts.btree_node_size);
|
||||
|
||||
/* Want a bucket size of at least 128k, if possible: */
|
||||
bucket_size = max(bucket_size, 128ULL << 10);
|
||||
u64 min_dev_size = BCH_MIN_NR_NBUCKETS * bucket_size;
|
||||
darray_for_each(devs, i)
|
||||
if (i->fs_size < min_dev_size)
|
||||
die("cannot format %s, too small (%llu bytes, min %llu)",
|
||||
i->path, i->fs_size, min_dev_size);
|
||||
|
||||
if (dev->size >= min_size(bucket_size)) {
|
||||
unsigned scale = max(1,
|
||||
ilog2(dev->size / min_size(bucket_size)) / 4);
|
||||
u64 total_fs_size = 0;
|
||||
darray_for_each(devs, i)
|
||||
total_fs_size += i->fs_size;
|
||||
|
||||
scale = rounddown_pow_of_two(scale);
|
||||
struct sysinfo info;
|
||||
si_meminfo(&info);
|
||||
|
||||
/* max bucket size 1 mb */
|
||||
bucket_size = min(bucket_size * scale, 1ULL << 20);
|
||||
} else {
|
||||
do {
|
||||
bucket_size /= 2;
|
||||
} while (dev->size < min_size(bucket_size));
|
||||
}
|
||||
/*
|
||||
* Large fudge factor to allow for other fsck processes and devices
|
||||
* being added after creation
|
||||
*/
|
||||
u64 mem_available_for_fsck = info.totalram / 8;
|
||||
u64 buckets_can_fsck = mem_available_for_fsck / (sizeof(struct bucket) * 1.5);
|
||||
u64 mem_lower_bound = roundup_pow_of_two(total_fs_size / buckets_can_fsck);
|
||||
|
||||
/*
|
||||
* Lower bound to avoid fragmenting encoded (checksummed, compressed)
|
||||
* extents too much as they're moved:
|
||||
*/
|
||||
bucket_size = max(bucket_size, opt_get(opts, encoded_extent_max) * 4);
|
||||
|
||||
/* Lower bound to ensure we can fsck: */
|
||||
bucket_size = max(bucket_size, mem_lower_bound);
|
||||
|
||||
u64 perf_lower_bound = min(2ULL << 20, total_fs_size / (1ULL << 20));
|
||||
|
||||
/* We also prefer larger buckets for performance, up to 2MB at 2T */
|
||||
bucket_size = max(bucket_size, perf_lower_bound);
|
||||
|
||||
return bucket_size;
|
||||
}
|
||||
|
||||
void bch2_check_bucket_size(struct bch_opts opts, struct dev_opts *dev)
|
||||
{
|
||||
if (dev->bucket_size < opts.block_size)
|
||||
die("Bucket size (%llu) cannot be smaller than block size (%u)",
|
||||
dev->bucket_size, opts.block_size);
|
||||
if (dev->opts.bucket_size < opts.block_size)
|
||||
die("Bucket size (%u) cannot be smaller than block size (%u)",
|
||||
dev->opts.bucket_size, opts.block_size);
|
||||
|
||||
if (opt_defined(opts, btree_node_size) &&
|
||||
dev->bucket_size < opts.btree_node_size)
|
||||
die("Bucket size (%llu) cannot be smaller than btree node size (%u)",
|
||||
dev->bucket_size, opts.btree_node_size);
|
||||
dev->opts.bucket_size < opts.btree_node_size)
|
||||
die("Bucket size (%u) cannot be smaller than btree node size (%u)",
|
||||
dev->opts.bucket_size, opts.btree_node_size);
|
||||
|
||||
if (dev->nbuckets < BCH_MIN_NR_NBUCKETS)
|
||||
die("Not enough buckets: %llu, need %u (bucket size %llu)",
|
||||
dev->nbuckets, BCH_MIN_NR_NBUCKETS, dev->bucket_size);
|
||||
|
||||
if (dev->bucket_size > (u32) U16_MAX << 9)
|
||||
die("Bucket size (%llu) too big (max %u)",
|
||||
dev->bucket_size, (u32) U16_MAX << 9);
|
||||
die("Not enough buckets: %llu, need %u (bucket size %u)",
|
||||
dev->nbuckets, BCH_MIN_NR_NBUCKETS, dev->opts.bucket_size);
|
||||
}
|
||||
|
||||
static unsigned parse_target(struct bch_sb_handle *sb,
|
||||
struct dev_opts *devs, size_t nr_devs,
|
||||
dev_opts_list devs,
|
||||
const char *s)
|
||||
{
|
||||
struct dev_opts *i;
|
||||
int idx;
|
||||
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
for (i = devs; i < devs + nr_devs; i++)
|
||||
darray_for_each(devs, i)
|
||||
if (!strcmp(s, i->path))
|
||||
return dev_to_target(i - devs);
|
||||
return dev_to_target(i - devs.data);
|
||||
|
||||
idx = bch2_disk_path_find(sb, s);
|
||||
int idx = bch2_disk_path_find(sb, s);
|
||||
if (idx >= 0)
|
||||
return group_to_target(idx);
|
||||
|
||||
@ -144,56 +149,61 @@ static unsigned parse_target(struct bch_sb_handle *sb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bch2_opt_set_sb_all(struct bch_sb *sb, int dev_idx, struct bch_opts *opts)
|
||||
{
|
||||
for (unsigned id = 0; id < bch2_opts_nr; id++) {
|
||||
u64 v = bch2_opt_defined_by_id(opts, id)
|
||||
? bch2_opt_get_by_id(opts, id)
|
||||
: bch2_opt_get_by_id(&bch2_opts_default, id);
|
||||
|
||||
__bch2_opt_set_sb(sb, dev_idx, &bch2_opt_table[id], v);
|
||||
}
|
||||
}
|
||||
|
||||
struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
|
||||
struct bch_opts fs_opts,
|
||||
struct format_opts opts,
|
||||
struct dev_opts *devs,
|
||||
size_t nr_devs)
|
||||
dev_opts_list devs)
|
||||
{
|
||||
struct bch_sb_handle sb = { NULL };
|
||||
struct dev_opts *i;
|
||||
unsigned max_dev_block_size = 0;
|
||||
unsigned opt_id;
|
||||
u64 min_bucket_size = U64_MAX;
|
||||
|
||||
for (i = devs; i < devs + nr_devs; i++)
|
||||
darray_for_each(devs, i)
|
||||
max_dev_block_size = max(max_dev_block_size, get_blocksize(i->bdev->bd_fd));
|
||||
|
||||
/* calculate block size: */
|
||||
if (!opt_defined(fs_opts, block_size)) {
|
||||
if (!opt_defined(fs_opts, block_size))
|
||||
opt_set(fs_opts, block_size, max_dev_block_size);
|
||||
} else if (fs_opts.block_size < max_dev_block_size)
|
||||
|
||||
if (fs_opts.block_size < max_dev_block_size)
|
||||
die("blocksize too small: %u, must be greater than device blocksize %u",
|
||||
fs_opts.block_size, max_dev_block_size);
|
||||
|
||||
/* get device size, if it wasn't specified: */
|
||||
for (i = devs; i < devs + nr_devs; i++)
|
||||
if (!i->size)
|
||||
i->size = get_size(i->bdev->bd_fd);
|
||||
darray_for_each(devs, i)
|
||||
if (!i->fs_size)
|
||||
i->fs_size = get_size(i->bdev->bd_fd);
|
||||
|
||||
/* calculate bucket sizes: */
|
||||
for (i = devs; i < devs + nr_devs; i++)
|
||||
min_bucket_size = min(min_bucket_size,
|
||||
i->bucket_size ?: bch2_pick_bucket_size(fs_opts, i));
|
||||
u64 fs_bucket_size = bch2_pick_bucket_size(fs_opts, devs);
|
||||
|
||||
for (i = devs; i < devs + nr_devs; i++)
|
||||
if (!i->bucket_size)
|
||||
i->bucket_size = min_bucket_size;
|
||||
darray_for_each(devs, i)
|
||||
if (!opt_defined(i->opts, bucket_size))
|
||||
opt_set(i->opts, bucket_size,
|
||||
min(fs_bucket_size, dev_max_bucket_size(i->fs_size)));
|
||||
|
||||
for (i = devs; i < devs + nr_devs; i++) {
|
||||
i->nbuckets = i->size / i->bucket_size;
|
||||
darray_for_each(devs, i) {
|
||||
i->nbuckets = i->fs_size / i->opts.bucket_size;
|
||||
bch2_check_bucket_size(fs_opts, i);
|
||||
}
|
||||
|
||||
/* calculate btree node size: */
|
||||
if (!opt_defined(fs_opts, btree_node_size)) {
|
||||
/* 256k default btree node size */
|
||||
opt_set(fs_opts, btree_node_size, 256 << 10);
|
||||
unsigned s = bch2_opts_default.btree_node_size;
|
||||
|
||||
for (i = devs; i < devs + nr_devs; i++)
|
||||
fs_opts.btree_node_size =
|
||||
min_t(unsigned, fs_opts.btree_node_size,
|
||||
i->bucket_size);
|
||||
darray_for_each(devs, i)
|
||||
s = min(s, i->opts.bucket_size);
|
||||
opt_set(fs_opts, btree_node_size, s);
|
||||
}
|
||||
|
||||
if (uuid_is_null(opts.uuid.b))
|
||||
@ -206,7 +216,8 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
|
||||
sb.sb->version_min = le16_to_cpu(opts.version);
|
||||
sb.sb->magic = BCHFS_MAGIC;
|
||||
sb.sb->user_uuid = opts.uuid;
|
||||
sb.sb->nr_devices = nr_devs;
|
||||
sb.sb->nr_devices = devs.nr;
|
||||
SET_BCH_SB_VERSION_INCOMPAT_ALLOWED(sb.sb, opts.version);
|
||||
|
||||
if (opts.version == bcachefs_metadata_version_current)
|
||||
sb.sb->features[0] |= cpu_to_le64(BCH_SB_FEATURES_ALL);
|
||||
@ -218,17 +229,7 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
|
||||
opts.label,
|
||||
min(strlen(opts.label), sizeof(sb.sb->label)));
|
||||
|
||||
for (opt_id = 0;
|
||||
opt_id < bch2_opts_nr;
|
||||
opt_id++) {
|
||||
u64 v;
|
||||
|
||||
v = bch2_opt_defined_by_id(&fs_opts, opt_id)
|
||||
? bch2_opt_get_by_id(&fs_opts, opt_id)
|
||||
: bch2_opt_get_by_id(&bch2_opts_default, opt_id);
|
||||
|
||||
__bch2_opt_set_sb(sb.sb, &bch2_opt_table[opt_id], v);
|
||||
}
|
||||
bch2_opt_set_sb_all(sb.sb, -1, &fs_opts);
|
||||
|
||||
struct timespec now;
|
||||
if (clock_gettime(CLOCK_REALTIME, &now))
|
||||
@ -240,31 +241,25 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
|
||||
/* Member info: */
|
||||
struct bch_sb_field_members_v2 *mi =
|
||||
bch2_sb_field_resize(&sb, members_v2,
|
||||
(sizeof(*mi) + sizeof(struct bch_member) *
|
||||
nr_devs) / sizeof(u64));
|
||||
(sizeof(*mi) + sizeof(struct bch_member) * devs.nr) / sizeof(u64));
|
||||
|
||||
mi->member_bytes = cpu_to_le16(sizeof(struct bch_member));
|
||||
for (i = devs; i < devs + nr_devs; i++) {
|
||||
struct bch_member *m = bch2_members_v2_get_mut(sb.sb, (i - devs));
|
||||
darray_for_each(devs, i) {
|
||||
unsigned idx = i - devs.data;
|
||||
struct bch_member *m = bch2_members_v2_get_mut(sb.sb, idx);
|
||||
|
||||
uuid_generate(m->uuid.b);
|
||||
m->nbuckets = cpu_to_le64(i->nbuckets);
|
||||
m->first_bucket = 0;
|
||||
m->bucket_size = cpu_to_le16(i->bucket_size >> 9);
|
||||
|
||||
SET_BCH_MEMBER_DISCARD(m, i->discard);
|
||||
SET_BCH_MEMBER_DATA_ALLOWED(m, i->data_allowed);
|
||||
SET_BCH_MEMBER_DURABILITY(m, i->durability + 1);
|
||||
bch2_opt_set_sb_all(sb.sb, idx, &i->opts);
|
||||
}
|
||||
|
||||
/* Disk labels*/
|
||||
for (i = devs; i < devs + nr_devs; i++) {
|
||||
struct bch_member *m;
|
||||
int idx;
|
||||
|
||||
darray_for_each(devs, i) {
|
||||
if (!i->label)
|
||||
continue;
|
||||
|
||||
idx = bch2_disk_path_find_or_create(&sb, i->label);
|
||||
int idx = bch2_disk_path_find_or_create(&sb, i->label);
|
||||
if (idx < 0)
|
||||
die("error creating disk path: %s", strerror(-idx));
|
||||
|
||||
@ -272,18 +267,18 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
|
||||
* Recompute mi and m after each sb modification: its location
|
||||
* in memory may have changed due to reallocation.
|
||||
*/
|
||||
m = bch2_members_v2_get_mut(sb.sb, (i - devs));
|
||||
struct bch_member *m = bch2_members_v2_get_mut(sb.sb, (i - devs.data));
|
||||
SET_BCH_MEMBER_GROUP(m, idx + 1);
|
||||
}
|
||||
|
||||
SET_BCH_SB_FOREGROUND_TARGET(sb.sb,
|
||||
parse_target(&sb, devs, nr_devs, fs_opt_strs.foreground_target));
|
||||
parse_target(&sb, devs, fs_opt_strs.foreground_target));
|
||||
SET_BCH_SB_BACKGROUND_TARGET(sb.sb,
|
||||
parse_target(&sb, devs, nr_devs, fs_opt_strs.background_target));
|
||||
parse_target(&sb, devs, fs_opt_strs.background_target));
|
||||
SET_BCH_SB_PROMOTE_TARGET(sb.sb,
|
||||
parse_target(&sb, devs, nr_devs, fs_opt_strs.promote_target));
|
||||
parse_target(&sb, devs, fs_opt_strs.promote_target));
|
||||
SET_BCH_SB_METADATA_TARGET(sb.sb,
|
||||
parse_target(&sb, devs, nr_devs, fs_opt_strs.metadata_target));
|
||||
parse_target(&sb, devs, fs_opt_strs.metadata_target));
|
||||
|
||||
/* Crypt: */
|
||||
if (opts.encrypted) {
|
||||
@ -296,19 +291,19 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
|
||||
|
||||
bch2_sb_members_cpy_v2_v1(&sb);
|
||||
|
||||
for (i = devs; i < devs + nr_devs; i++) {
|
||||
u64 size_sectors = i->size >> 9;
|
||||
darray_for_each(devs, i) {
|
||||
u64 size_sectors = i->fs_size >> 9;
|
||||
|
||||
sb.sb->dev_idx = i - devs;
|
||||
sb.sb->dev_idx = i - devs.data;
|
||||
|
||||
if (!i->sb_offset) {
|
||||
i->sb_offset = BCH_SB_SECTOR;
|
||||
i->sb_end = size_sectors;
|
||||
}
|
||||
|
||||
init_layout(&sb.sb->layout, fs_opts.block_size,
|
||||
opts.superblock_size,
|
||||
i->sb_offset, i->sb_end);
|
||||
bch2_sb_layout_init(&sb.sb->layout, fs_opts.block_size,
|
||||
opts.superblock_size,
|
||||
i->sb_offset, i->sb_end);
|
||||
|
||||
/*
|
||||
* Also create a backup superblock at the end of the disk:
|
||||
@ -321,7 +316,7 @@ struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs,
|
||||
struct bch_sb_layout *l = &sb.sb->layout;
|
||||
u64 backup_sb = size_sectors - (1 << l->sb_max_size_bits);
|
||||
|
||||
backup_sb = rounddown(backup_sb, i->bucket_size >> 9);
|
||||
backup_sb = rounddown(backup_sb, i->opts.bucket_size >> 9);
|
||||
l->sb_offset[l->nr_superblocks++] = cpu_to_le64(backup_sb);
|
||||
}
|
||||
|
||||
@ -352,9 +347,9 @@ void bch2_super_write(int fd, struct bch_sb *sb)
|
||||
if (sb->offset == BCH_SB_SECTOR) {
|
||||
/* Write backup layout */
|
||||
|
||||
BUG_ON(bs > 4096);
|
||||
unsigned buflen = max(bs, 4096);
|
||||
|
||||
char *buf = aligned_alloc(bs, bs);
|
||||
char *buf = aligned_alloc(buflen, buflen);
|
||||
xpread(fd, buf, bs, 4096 - bs);
|
||||
memcpy(buf + bs - sizeof(sb->layout),
|
||||
&sb->layout,
|
||||
@ -411,43 +406,107 @@ void bcache_fs_close(struct bchfs_handle fs)
|
||||
close(fs.sysfs_fd);
|
||||
}
|
||||
|
||||
struct bchfs_handle bcache_fs_open(const char *path)
|
||||
static int bcache_fs_open_by_uuid(const char *uuid_str, struct bchfs_handle *fs)
|
||||
{
|
||||
struct bchfs_handle ret;
|
||||
if (uuid_parse(uuid_str, fs->uuid.b))
|
||||
return -1;
|
||||
|
||||
if (!uuid_parse(path, ret.uuid.b)) {
|
||||
/* It's a UUID, look it up in sysfs: */
|
||||
char *sysfs = mprintf(SYSFS_BASE "%s", path);
|
||||
ret.sysfs_fd = xopen(sysfs, O_RDONLY);
|
||||
char *sysfs = mprintf(SYSFS_BASE "%s", uuid_str);
|
||||
fs->sysfs_fd = open(sysfs, O_RDONLY);
|
||||
free(sysfs);
|
||||
|
||||
char *minor = read_file_str(ret.sysfs_fd, "minor");
|
||||
char *ctl = mprintf("/dev/bcachefs%s-ctl", minor);
|
||||
ret.ioctl_fd = xopen(ctl, O_RDWR);
|
||||
if (fs->sysfs_fd < 0)
|
||||
return -errno;
|
||||
|
||||
free(sysfs);
|
||||
free(minor);
|
||||
free(ctl);
|
||||
} else {
|
||||
/* It's a path: */
|
||||
ret.ioctl_fd = open(path, O_RDONLY);
|
||||
if (ret.ioctl_fd < 0)
|
||||
die("Error opening filesystem at %s: %m", path);
|
||||
char *minor = read_file_str(fs->sysfs_fd, "minor");
|
||||
char *ctl = mprintf("/dev/bcachefs%s-ctl", minor);
|
||||
fs->ioctl_fd = open(ctl, O_RDWR);
|
||||
free(minor);
|
||||
free(ctl);
|
||||
|
||||
struct bch_ioctl_query_uuid uuid;
|
||||
if (ioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid) < 0)
|
||||
die("error opening %s: not a bcachefs filesystem", path);
|
||||
return fs->ioctl_fd < 0 ? -errno : 0;
|
||||
}
|
||||
|
||||
ret.uuid = uuid.uuid;
|
||||
int bcache_fs_open_fallible(const char *path, struct bchfs_handle *fs)
|
||||
{
|
||||
memset(fs, 0, sizeof(*fs));
|
||||
fs->dev_idx = -1;
|
||||
|
||||
if (!uuid_parse(path, fs->uuid.b))
|
||||
return bcache_fs_open_by_uuid(path, fs);
|
||||
|
||||
/* It's a path: */
|
||||
int path_fd = open(path, O_RDONLY);
|
||||
if (path_fd < 0)
|
||||
return -errno;
|
||||
|
||||
struct bch_ioctl_query_uuid uuid;
|
||||
if (!ioctl(path_fd, BCH_IOCTL_QUERY_UUID, &uuid)) {
|
||||
/* It's a path to the mounted filesystem: */
|
||||
fs->ioctl_fd = path_fd;
|
||||
|
||||
fs->uuid = uuid.uuid;
|
||||
|
||||
char uuid_str[40];
|
||||
uuid_unparse(uuid.uuid.b, uuid_str);
|
||||
|
||||
char *sysfs = mprintf(SYSFS_BASE "%s", uuid_str);
|
||||
ret.sysfs_fd = xopen(sysfs, O_RDONLY);
|
||||
fs->sysfs_fd = xopen(sysfs, O_RDONLY);
|
||||
free(sysfs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
char buf[1024], *uuid_str;
|
||||
|
||||
struct stat stat = xstat(path);
|
||||
close(path_fd);
|
||||
|
||||
if (S_ISBLK(stat.st_mode)) {
|
||||
char *sysfs = mprintf("/sys/dev/block/%u:%u/bcachefs",
|
||||
major(stat.st_rdev),
|
||||
minor(stat.st_rdev));
|
||||
|
||||
ssize_t len = readlink(sysfs, buf, sizeof(buf));
|
||||
free(sysfs);
|
||||
|
||||
if (len <= 0)
|
||||
goto read_super;
|
||||
|
||||
char *p = strrchr(buf, '/');
|
||||
if (!p || sscanf(p + 1, "dev-%u", &fs->dev_idx) != 1)
|
||||
die("error parsing sysfs");
|
||||
|
||||
*p = '\0';
|
||||
p = strrchr(buf, '/');
|
||||
uuid_str = p + 1;
|
||||
} else {
|
||||
read_super:
|
||||
opt_set(opts, noexcl, true);
|
||||
opt_set(opts, nochanges, true);
|
||||
|
||||
struct bch_sb_handle sb;
|
||||
int ret = bch2_read_super(path, &opts, &sb);
|
||||
if (ret)
|
||||
die("Error opening %s: %s", path, strerror(-ret));
|
||||
|
||||
fs->dev_idx = sb.sb->dev_idx;
|
||||
uuid_str = buf;
|
||||
uuid_unparse(sb.sb->user_uuid.b, uuid_str);
|
||||
|
||||
bch2_free_super(&sb);
|
||||
}
|
||||
|
||||
return bcache_fs_open_by_uuid(uuid_str, fs);
|
||||
}
|
||||
|
||||
struct bchfs_handle bcache_fs_open(const char *path)
|
||||
{
|
||||
struct bchfs_handle fs;
|
||||
int ret = bcache_fs_open_fallible(path, &fs);
|
||||
if (ret)
|
||||
die("Error opening filesystem at %s: %s", path, strerror(-ret));
|
||||
return fs;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -523,7 +582,7 @@ int bchu_data(struct bchfs_handle fs, struct bch_ioctl_data cmd)
|
||||
if (e.type)
|
||||
continue;
|
||||
|
||||
if (e.p.data_type == U8_MAX)
|
||||
if (e.ret || e.p.data_type == U8_MAX)
|
||||
break;
|
||||
|
||||
printf("\33[2K\r");
|
||||
@ -554,6 +613,8 @@ int bchu_data(struct bchfs_handle fs, struct bch_ioctl_data cmd)
|
||||
|
||||
/* option parsing */
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
void bch2_opt_strs_free(struct bch_opt_strs *opts)
|
||||
{
|
||||
unsigned i;
|
||||
@ -564,6 +625,64 @@ void bch2_opt_strs_free(struct bch_opt_strs *opts)
|
||||
}
|
||||
}
|
||||
|
||||
static bool opt_type_filter(const struct bch_option *opt, unsigned opt_types)
|
||||
{
|
||||
if (!(opt->flags & opt_types))
|
||||
return false;
|
||||
|
||||
if ((opt_types & OPT_FORMAT) &&
|
||||
!opt->set_sb && !opt->set_member)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const struct bch_option *bch2_cmdline_opt_parse(int argc, char *argv[],
|
||||
unsigned opt_types)
|
||||
{
|
||||
if (optind >= argc)
|
||||
return NULL;
|
||||
|
||||
if (argv[optind][0] != '-' ||
|
||||
argv[optind][1] != '-')
|
||||
return NULL;
|
||||
|
||||
char *optstr = strdup(argv[optind] + 2);
|
||||
optarg = argv[optind + 1];
|
||||
|
||||
char *eq = strchr(optstr, '=');
|
||||
if (eq) {
|
||||
*eq = '\0';
|
||||
optarg = eq + 1;
|
||||
}
|
||||
|
||||
if (!optarg)
|
||||
optarg = "1";
|
||||
|
||||
|
||||
int optid = bch2_opt_lookup(optstr);
|
||||
if (optid < 0)
|
||||
goto noopt;
|
||||
|
||||
const struct bch_option *opt = bch2_opt_table + optid;
|
||||
if (!opt_type_filter(opt, opt_types))
|
||||
goto noopt;
|
||||
|
||||
optind++;
|
||||
|
||||
if (opt->type != BCH_OPT_BOOL) {
|
||||
if (optarg == argv[optind])
|
||||
optind++;
|
||||
} else {
|
||||
optarg = NULL;
|
||||
}
|
||||
|
||||
return opt;
|
||||
noopt:
|
||||
free(optstr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bch_opt_strs bch2_cmdline_opts_get(int *argc, char *argv[],
|
||||
unsigned opt_types)
|
||||
{
|
||||
@ -651,19 +770,17 @@ struct bch_opts bch2_parse_opts(struct bch_opt_strs strs)
|
||||
#define newline(c) \
|
||||
do { \
|
||||
printf("\n"); \
|
||||
c = 0; \
|
||||
c = 0; \
|
||||
} while(0)
|
||||
void bch2_opts_usage(unsigned opt_types)
|
||||
{
|
||||
const struct bch_option *opt;
|
||||
unsigned i, c = 0, helpcol = 30;
|
||||
|
||||
|
||||
|
||||
for (opt = bch2_opt_table;
|
||||
opt < bch2_opt_table + bch2_opts_nr;
|
||||
opt++) {
|
||||
if (!(opt->flags & opt_types))
|
||||
if (!opt_type_filter(opt, opt_types))
|
||||
continue;
|
||||
|
||||
c += printf(" --%s", opt->attr.name);
|
||||
@ -733,6 +850,8 @@ dev_names bchu_fs_get_devices(struct bchfs_handle fs)
|
||||
if (r > 0) {
|
||||
sysfs_block_buf[r] = '\0';
|
||||
n.dev = strdup(basename(sysfs_block_buf));
|
||||
} else {
|
||||
n.dev = mprintf("(offline dev %u)", n.idx);
|
||||
}
|
||||
|
||||
free(block_attr);
|
||||
@ -752,3 +871,11 @@ dev_names bchu_fs_get_devices(struct bchfs_handle fs)
|
||||
|
||||
return devs;
|
||||
}
|
||||
|
||||
struct dev_name *dev_idx_to_name(dev_names *dev_names, unsigned idx)
|
||||
{
|
||||
darray_for_each(*dev_names, dev)
|
||||
if (dev->idx == idx)
|
||||
return dev;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -28,6 +28,9 @@ struct {
|
||||
};
|
||||
|
||||
void bch2_opt_strs_free(struct bch_opt_strs *);
|
||||
|
||||
const struct bch_option *bch2_cmdline_opt_parse(int argc, char *argv[],
|
||||
unsigned opt_types);
|
||||
struct bch_opt_strs bch2_cmdline_opts_get(int *, char *[], unsigned);
|
||||
struct bch_opts bch2_parse_opts(struct bch_opt_strs);
|
||||
void bch2_opts_usage(unsigned);
|
||||
@ -42,14 +45,18 @@ struct format_opts {
|
||||
char *source;
|
||||
};
|
||||
|
||||
static inline unsigned bcachefs_kernel_version(void)
|
||||
{
|
||||
return !access("/sys/module/bcachefs/parameters/version", R_OK)
|
||||
? read_file_u64(AT_FDCWD, "/sys/module/bcachefs/parameters/version")
|
||||
: 0;
|
||||
}
|
||||
|
||||
static inline struct format_opts format_opts_default()
|
||||
{
|
||||
unsigned version = !access( "/sys/module/bcachefs/parameters/version", R_OK)
|
||||
? read_file_u64(AT_FDCWD, "/sys/module/bcachefs/parameters/version")
|
||||
: bcachefs_metadata_version_current;
|
||||
|
||||
return (struct format_opts) {
|
||||
.version = version,
|
||||
.version = bcachefs_kernel_version() ?:
|
||||
bcachefs_metadata_version_current,
|
||||
.superblock_size = SUPERBLOCK_SIZE_DEFAULT,
|
||||
};
|
||||
}
|
||||
@ -58,33 +65,35 @@ struct dev_opts {
|
||||
struct file *file;
|
||||
struct block_device *bdev;
|
||||
char *path;
|
||||
u64 size; /* bytes*/
|
||||
u64 bucket_size; /* bytes */
|
||||
const char *label;
|
||||
unsigned data_allowed;
|
||||
unsigned durability;
|
||||
bool discard;
|
||||
|
||||
u64 nbuckets;
|
||||
|
||||
u64 sb_offset;
|
||||
u64 sb_end;
|
||||
|
||||
u64 nbuckets;
|
||||
u64 fs_size;
|
||||
|
||||
const char *label; /* make this a bch_opt */
|
||||
|
||||
struct bch_opts opts;
|
||||
};
|
||||
|
||||
typedef DARRAY(struct dev_opts) dev_opts_list;
|
||||
|
||||
static inline struct dev_opts dev_opts_default()
|
||||
{
|
||||
return (struct dev_opts) {
|
||||
.data_allowed = ~0U << 2,
|
||||
.durability = 1,
|
||||
};
|
||||
return (struct dev_opts) { .opts = bch2_opts_empty() };
|
||||
}
|
||||
|
||||
u64 bch2_pick_bucket_size(struct bch_opts, struct dev_opts *);
|
||||
void bch2_sb_layout_init(struct bch_sb_layout *,
|
||||
unsigned, unsigned, u64, u64);
|
||||
|
||||
u64 bch2_pick_bucket_size(struct bch_opts, dev_opts_list);
|
||||
void bch2_check_bucket_size(struct bch_opts, struct dev_opts *);
|
||||
|
||||
struct bch_sb *bch2_format(struct bch_opt_strs,
|
||||
struct bch_opts,
|
||||
struct format_opts, struct dev_opts *, size_t);
|
||||
struct format_opts,
|
||||
dev_opts_list devs);
|
||||
|
||||
void bch2_super_write(int, struct bch_sb *);
|
||||
struct bch_sb *__bch2_super_read(int, u64);
|
||||
@ -97,11 +106,16 @@ struct bchfs_handle {
|
||||
__uuid_t uuid;
|
||||
int ioctl_fd;
|
||||
int sysfs_fd;
|
||||
int dev_idx;
|
||||
};
|
||||
|
||||
void bcache_fs_close(struct bchfs_handle);
|
||||
|
||||
int bcache_fs_open_fallible(const char *, struct bchfs_handle *);
|
||||
|
||||
struct bchfs_handle bcache_fs_open(const char *);
|
||||
struct bchfs_handle bchu_fs_open_by_dev(const char *, int *);
|
||||
|
||||
int bchu_dev_path_to_idx(struct bchfs_handle, const char *);
|
||||
|
||||
static inline void bchu_disk_add(struct bchfs_handle fs, char *dev)
|
||||
@ -296,5 +310,6 @@ struct dev_name {
|
||||
typedef DARRAY(struct dev_name) dev_names;
|
||||
|
||||
dev_names bchu_fs_get_devices(struct bchfs_handle);
|
||||
struct dev_name *dev_idx_to_name(dev_names *dev_names, unsigned idx);
|
||||
|
||||
#endif /* _LIBBCACHE_H */
|
||||
|
@ -1,12 +1,13 @@
|
||||
#include <dirent.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/xattr.h>
|
||||
|
||||
#include "posix_to_bcachefs.h"
|
||||
#include "libbcachefs/alloc_foreground.h"
|
||||
#include "libbcachefs/buckets.h"
|
||||
#include "libbcachefs/fs-common.h"
|
||||
#include "libbcachefs/io_write.h"
|
||||
#include "libbcachefs/namei.h"
|
||||
#include "libbcachefs/str_hash.h"
|
||||
#include "libbcachefs/xattr.h"
|
||||
|
||||
@ -32,7 +33,7 @@ void create_link(struct bch_fs *c,
|
||||
struct bch_inode_unpacked parent_u;
|
||||
struct bch_inode_unpacked inode;
|
||||
|
||||
int ret = bch2_trans_do(c, NULL, NULL, 0,
|
||||
int ret = bch2_trans_commit_do(c, NULL, NULL, 0,
|
||||
bch2_link_trans(trans,
|
||||
(subvol_inum) { 1, parent->bi_inum }, &parent_u,
|
||||
(subvol_inum) { 1, inum }, &inode, &qstr));
|
||||
@ -51,7 +52,7 @@ struct bch_inode_unpacked create_file(struct bch_fs *c,
|
||||
|
||||
bch2_inode_init_early(c, &new_inode);
|
||||
|
||||
int ret = bch2_trans_do(c, NULL, NULL, 0,
|
||||
int ret = bch2_trans_commit_do(c, NULL, NULL, 0,
|
||||
bch2_create_trans(trans,
|
||||
(subvol_inum) { 1, parent->bi_inum }, parent,
|
||||
&new_inode, &qstr,
|
||||
@ -71,7 +72,7 @@ struct bch_inode_unpacked create_file(struct bch_fs *c,
|
||||
|
||||
static const struct xattr_handler *xattr_resolve_name(char **name)
|
||||
{
|
||||
const struct xattr_handler **handlers = bch2_xattr_handlers;
|
||||
const struct xattr_handler * const *handlers = bch2_xattr_handlers;
|
||||
const struct xattr_handler *handler;
|
||||
|
||||
for_each_xattr_handler(handlers, handler) {
|
||||
@ -122,12 +123,13 @@ void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
die("error getting xattr val: %m");
|
||||
|
||||
const struct xattr_handler *h = xattr_resolve_name(&attr);
|
||||
struct bch_inode_unpacked inode_u;
|
||||
if (IS_ERR(h))
|
||||
continue;
|
||||
|
||||
int ret = bch2_trans_do(c, NULL, NULL, 0,
|
||||
int ret = bch2_trans_commit_do(c, NULL, NULL, 0,
|
||||
bch2_xattr_set(trans,
|
||||
(subvol_inum) { 1, dst->bi_inum },
|
||||
&inode_u, &hash_info, attr,
|
||||
dst, &hash_info, attr,
|
||||
val, val_size, h->flags, 0));
|
||||
if (ret < 0)
|
||||
die("error creating xattr: %s", bch2_err_str(ret));
|
||||
@ -157,7 +159,7 @@ static void write_data(struct bch_fs *c,
|
||||
op.nr_replicas = 1;
|
||||
op.subvol = 1;
|
||||
op.pos = SPOS(dst_inode->bi_inum, dst_offset >> 9, U32_MAX);
|
||||
op.flags |= BCH_WRITE_SYNC;
|
||||
op.flags |= BCH_WRITE_sync;
|
||||
|
||||
int ret = bch2_disk_reservation_get(c, &op.res, len >> 9,
|
||||
c->opts.data_replicas, 0);
|
||||
@ -166,7 +168,7 @@ static void write_data(struct bch_fs *c,
|
||||
|
||||
closure_call(&op.cl, bch2_write, NULL, NULL);
|
||||
|
||||
BUG_ON(!(op.flags & BCH_WRITE_DONE));
|
||||
BUG_ON(!(op.flags & BCH_WRITE_submitted));
|
||||
dst_inode->bi_sectors += len >> 9;
|
||||
|
||||
if (op.error)
|
||||
@ -262,7 +264,8 @@ void copy_link(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
|
||||
static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
int src_fd, u64 src_size,
|
||||
char *src_path, struct copy_fs_state *s)
|
||||
char *src_path, struct copy_fs_state *s,
|
||||
u64 reserve_start)
|
||||
{
|
||||
struct fiemap_iter iter;
|
||||
struct fiemap_extent e;
|
||||
@ -293,11 +296,8 @@ static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the data is below 1 MB, copy it so it doesn't conflict
|
||||
* with bcachefs's potentially larger superblock:
|
||||
*/
|
||||
if (e.fe_physical < 1 << 20) {
|
||||
/* If the data is in bcachefs's superblock region, copy it: */
|
||||
if (e.fe_physical < reserve_start) {
|
||||
copy_data(c, dst, src_fd, e.fe_logical,
|
||||
e.fe_logical + min(src_size - e.fe_logical,
|
||||
e.fe_length));
|
||||
@ -316,7 +316,8 @@ static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
static void copy_dir(struct copy_fs_state *s,
|
||||
struct bch_fs *c,
|
||||
struct bch_inode_unpacked *dst,
|
||||
int src_fd, const char *src_path)
|
||||
int src_fd, const char *src_path,
|
||||
u64 reserve_start)
|
||||
{
|
||||
DIR *dir = fdopendir(src_fd);
|
||||
struct dirent *d;
|
||||
@ -367,7 +368,7 @@ static void copy_dir(struct copy_fs_state *s,
|
||||
switch (mode_to_type(stat.st_mode)) {
|
||||
case DT_DIR:
|
||||
fd = xopen(d->d_name, O_RDONLY|O_NOATIME);
|
||||
copy_dir(s, c, &inode, fd, child_path);
|
||||
copy_dir(s, c, &inode, fd, child_path, reserve_start);
|
||||
close(fd);
|
||||
break;
|
||||
case DT_REG:
|
||||
@ -375,7 +376,7 @@ static void copy_dir(struct copy_fs_state *s,
|
||||
|
||||
fd = xopen(d->d_name, O_RDONLY|O_NOATIME);
|
||||
copy_file(c, &inode, fd, stat.st_size,
|
||||
child_path, s);
|
||||
child_path, s, reserve_start);
|
||||
close(fd);
|
||||
break;
|
||||
case DT_LNK:
|
||||
@ -407,7 +408,8 @@ next:
|
||||
|
||||
static void reserve_old_fs_space(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *root_inode,
|
||||
ranges *extents)
|
||||
ranges *extents,
|
||||
u64 reserve_start)
|
||||
{
|
||||
struct bch_dev *ca = c->devs[0];
|
||||
struct bch_inode_unpacked dst;
|
||||
@ -420,14 +422,20 @@ static void reserve_old_fs_space(struct bch_fs *c,
|
||||
|
||||
ranges_sort_merge(extents);
|
||||
|
||||
for_each_hole(iter, *extents, bucket_to_sector(ca, ca->mi.nbuckets) << 9, i)
|
||||
link_data(c, &dst, i.start, i.start, i.end - i.start);
|
||||
for_each_hole(iter, *extents, bucket_to_sector(ca, ca->mi.nbuckets) << 9, i) {
|
||||
if (i.end <= reserve_start)
|
||||
continue;
|
||||
|
||||
u64 start = max(i.start, reserve_start);
|
||||
|
||||
link_data(c, &dst, start, start, i.end - start);
|
||||
}
|
||||
|
||||
update_inode(c, &dst);
|
||||
}
|
||||
|
||||
void copy_fs(struct bch_fs *c, int src_fd, const char *src_path,
|
||||
struct copy_fs_state *s)
|
||||
struct copy_fs_state *s, u64 reserve_start)
|
||||
{
|
||||
syncfs(src_fd);
|
||||
|
||||
@ -446,10 +454,10 @@ void copy_fs(struct bch_fs *c, int src_fd, const char *src_path,
|
||||
|
||||
|
||||
/* now, copy: */
|
||||
copy_dir(s, c, &root_inode, src_fd, src_path);
|
||||
copy_dir(s, c, &root_inode, src_fd, src_path, reserve_start);
|
||||
|
||||
if (BCH_MIGRATE_migrate == s->type)
|
||||
reserve_old_fs_space(c, &root_inode, &s->extents);
|
||||
reserve_old_fs_space(c, &root_inode, &s->extents, reserve_start);
|
||||
|
||||
update_inode(c, &root_inode);
|
||||
|
||||
|
@ -50,5 +50,5 @@ struct copy_fs_state {
|
||||
* initialized (`hardlinks` is initialized with zeroes).
|
||||
*/
|
||||
void copy_fs(struct bch_fs *c, int src_fd, const char *src_path,
|
||||
struct copy_fs_state *s);
|
||||
struct copy_fs_state *s, u64);
|
||||
#endif /* _LIBBCACHE_H */
|
||||
|
@ -185,6 +185,24 @@ unsigned get_blocksize(int fd)
|
||||
/* Open a block device, do magic blkid stuff to probe for existing filesystems: */
|
||||
int open_for_format(struct dev_opts *dev, bool force)
|
||||
{
|
||||
int blkid_version_code = blkid_get_library_version(NULL, NULL);
|
||||
if (blkid_version_code < 2401) {
|
||||
if (force) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Continuing with out of date libblkid %s because --force was passed.\n",
|
||||
BLKID_VERSION);
|
||||
} else {
|
||||
// Reference for picking 2.40.1:
|
||||
// https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.40/v2.40.1-ReleaseNotes
|
||||
// https://github.com/util-linux/util-linux/issues/3103
|
||||
die(
|
||||
"Refusing to format when using libblkid %s\n"
|
||||
"libblkid >= 2.40.1 is required to check for existing filesystems\n"
|
||||
"Earlier versions may not recognize some bcachefs filesystems.\n", BLKID_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
blkid_probe pr;
|
||||
const char *fs_type = NULL, *fs_label = NULL;
|
||||
size_t fs_type_len, fs_label_len;
|
||||
@ -708,6 +726,28 @@ struct bbpos_range bbpos_range_parse(char *buf)
|
||||
return (struct bbpos_range) { .start = start, .end = end };
|
||||
}
|
||||
|
||||
unsigned version_parse(char *buf)
|
||||
{
|
||||
char *s = buf;
|
||||
char *major_str = strsep(&s, ".");
|
||||
char *minor_str = strsep(&s, ".");
|
||||
|
||||
unsigned major, minor;
|
||||
|
||||
if (!minor_str) {
|
||||
major = 0;
|
||||
if (kstrtouint(major_str, 10, &minor))
|
||||
die("invalid version %s", buf);
|
||||
} else {
|
||||
|
||||
if (kstrtouint(major_str, 10, &major) ||
|
||||
kstrtouint(minor_str, 10, &minor))
|
||||
die("invalid version %s", buf);
|
||||
}
|
||||
|
||||
return BCH_VERSION(major, minor);
|
||||
}
|
||||
|
||||
darray_str get_or_split_cmdline_devs(int argc, char *argv[])
|
||||
{
|
||||
darray_str ret = {};
|
||||
|
@ -174,6 +174,8 @@ struct fiemap_extent fiemap_iter_next(struct fiemap_iter *);
|
||||
|
||||
char *strcmp_prefix(char *, const char *);
|
||||
|
||||
/* Avoid conflicts with libblkid's crc32 function in static builds */
|
||||
#define crc32c bch_crc32c
|
||||
u32 crc32c(u32, const void *, size_t);
|
||||
|
||||
char *dev_to_name(dev_t);
|
||||
@ -207,6 +209,8 @@ struct bbpos_range {
|
||||
|
||||
struct bbpos_range bbpos_range_parse(char *);
|
||||
|
||||
unsigned version_parse(char *);
|
||||
|
||||
darray_str get_or_split_cmdline_devs(int argc, char *argv[]);
|
||||
|
||||
#endif /* _TOOLS_UTIL_H */
|
||||
|
1
debian/bcachefs.triggers
vendored
Normal file
1
debian/bcachefs.triggers
vendored
Normal file
@ -0,0 +1 @@
|
||||
activate update-initramfs
|
176
debian/changelog
vendored
176
debian/changelog
vendored
@ -1,44 +1,158 @@
|
||||
bcachefs-tools (1.0.8-2~bpo8+1) jessie-backports; urgency=medium
|
||||
bcachefs-tools (1:1.9.1-1) unstable; urgency=medium
|
||||
|
||||
* Rebuild for jessie-backports.
|
||||
* New upstream release
|
||||
* New build-depency: librust-strum-dev
|
||||
* Update copyright file
|
||||
|
||||
-- Mathieu Parent <sathieu@debian.org> Mon, 21 Sep 2015 21:18:39 +0200
|
||||
-- Jonathan Carter <jcc@debian.org> Thu, 20 Jun 2024 17:28:12 +0200
|
||||
|
||||
bcachefs-tools (1.0.8-2) unstable; urgency=medium
|
||||
bcachefs-tools (1:1.7.0-1) unstable; urgency=medium
|
||||
|
||||
* Only run update-initramfs if installed. Fix dracut. (Closes: #788442)
|
||||
* Upload to unstable (Closes: #1066929)
|
||||
* Bump epoch
|
||||
- Ack from pochu:
|
||||
https://lists.debian.org/msgid-search/1c5f86c9-1525-4d44-996f-3d4eed1e64d6@debian.org
|
||||
|
||||
-- David Mohr <david@mcbf.net> Thu, 11 Jun 2015 10:23:48 -0600
|
||||
-- Jonathan Carter <jcc@debian.org> Wed, 15 May 2024 12:04:38 +0200
|
||||
|
||||
bcachefs-tools (1.0.8-1) unstable; urgency=medium
|
||||
bcachefs-tools (24+really1.7.0-1~exp1) experimental; urgency=medium
|
||||
|
||||
[ James Page ]
|
||||
* d/control: Add Vcs fields.
|
||||
[ Steinar H. Gunderson ]
|
||||
* New upstream release.
|
||||
* Remove the do-not-install-mount-symlink patch.
|
||||
* Add epoch to deal with new upstream versioning scheme,
|
||||
and disable pristine-tar option in gbp.conf, since there is no
|
||||
pristine-tar branch. (Closes: #1054620)
|
||||
* revert-bindgen-changes.patch: New patch, reinstates upstream
|
||||
hack that makes bcachefs-tools work with bindgen older than 0.69.4
|
||||
(which isn't in Debian yet).
|
||||
* Build-depend on systemd-dev, since udev.pc has moved there.
|
||||
* Enable Rust parts, including mount.bcachefs. (Closes: #1060256)
|
||||
* Include the right .mk flags to get DEB_HOST_RUST_TYPE etc., and
|
||||
export that (needed for Debian's cargo wrapper).
|
||||
* Override CARGO, and set CARGO_HOME during installation.
|
||||
* Run prepare-debian in dh_auto_configure, and clean up the vendor dir
|
||||
in dh_auto_clean.
|
||||
* Remove Cargo.lock before the build, so that we can use Debian's versions
|
||||
of all Rust crates. Also remove it in dh_auto_clean, so that it does not
|
||||
take a diff.
|
||||
* revert-bindgen-changes.patch: New patch, loosen required versions
|
||||
of Rust crates
|
||||
- errno (0.2 -> >= 0.2, < 1; Debian has 0.4)
|
||||
- udev (0.7 -> >= 0.7, < 1; Debian has 0.8)
|
||||
- memoffset (0.8.0 -> 0.6; Debian has 0.6.5, so a downgrade)
|
||||
- paste (1.0.11 -> 1.0; Debian has 1.0.8, so a downgrade)
|
||||
- bindgen (0.69.4 -> 0.66; see revert-bindgen-changes.patch above)
|
||||
* Add build-dependency on all relevant Rust crates, and on python3:native
|
||||
due to use of the Cargo wrapper.
|
||||
* Build-Depend on pkgconf instead of pkg-config (Lintian warning).
|
||||
* Add debhelper tokens to postinst and postrm scripts (Lintian warning).
|
||||
* Depend on python3:any due to bcachefsck_all being a Python script
|
||||
(Lintian warning).
|
||||
|
||||
[ David Mohr ]
|
||||
* Don't depend on initramfs-tools, instead recommend it (Closes: #775674)
|
||||
* New upstream release 1.0.8
|
||||
* Update changelog
|
||||
* Add patch to clean bcache-register
|
||||
* Update changelog
|
||||
* Adding dep3 headers to the 0001 patch
|
||||
* Update watch to use http://evilpiepirate.org/git/bcache-tools.git
|
||||
* Add patch for gcc-5 compatibility.
|
||||
Thanks to James Cowgill (Closes: #777798)
|
||||
[ Jonathan Carter ]
|
||||
* Upload to experimental
|
||||
* Add librust-chrono-dev, librust-getset-dev and
|
||||
librust-gag-dev to build-depends
|
||||
* Recreate dependencies patch to match new upstream source
|
||||
* Update standards version to 4.7.0
|
||||
* Update above mentioned revert-bindgen-changes.patch
|
||||
|
||||
-- David Mohr <david@mcbf.net> Tue, 26 May 2015 20:57:58 -0600
|
||||
-- Jonathan Carter <jcc@debian.org> Thu, 25 Apr 2024 13:53:55 +0200
|
||||
|
||||
bcachefs-tools (1.0.7-1) unstable; urgency=medium
|
||||
bcachefs-tools (24+really1.3.4-2) unstable; urgency=medium
|
||||
|
||||
[ David Mohr ]
|
||||
* Based on work by Gabriel de Perthuis <g2p.code+debian@gmail.com>
|
||||
* Initial release. (Closes: #708132)
|
||||
* Upload to unstable
|
||||
|
||||
[ Robie Basak ]
|
||||
* Remove unnecessary file bcache-tools.postrm.
|
||||
* debian/copyright fixes.
|
||||
* Add shebang to bcache-tools.preinst.
|
||||
* Drop Vcs-* for now.
|
||||
* Add self to Uploaders.
|
||||
-- Jonathan Carter <jcc@debian.org> Wed, 03 Jan 2024 17:06:16 +0200
|
||||
|
||||
-- Robie Basak <robie@justgohome.co.uk> Mon, 27 Oct 2014 13:32:08 +0000
|
||||
bcachefs-tools (24+really1.3.4-2~exp1) experimental; urgency=medium
|
||||
|
||||
[ Chris Hofstaedtler ]
|
||||
* Non-maintainer upload.
|
||||
* Install files into /usr instead of /. (Closes: #1059373)
|
||||
|
||||
[ Jonathan Carter ]
|
||||
* Do not install bcachefs.mount symlink (Closes: #1057295)
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Wed, 27 Dec 2023 19:22:06 +0200
|
||||
|
||||
bcachefs-tools (24+really1.3.4-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Tue, 21 Nov 2023 17:26:13 +0200
|
||||
|
||||
bcachefs-tools (24+really1.2-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release (Closes: #1054613)
|
||||
* Disable new rust build
|
||||
(dependencies currently unavailable in Debian, see debian/README.todo)
|
||||
* Remove unneeded override_dh_auto_clean from debian/rules
|
||||
(Closes: #1043654)
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Thu, 28 Sep 2023 19:54:47 +0200
|
||||
|
||||
bcachefs-tools (24-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Tue, 29 Nov 2022 09:40:27 +0200
|
||||
|
||||
bcachefs-tools (23-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
* Update standards version to 4.6.1
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Mon, 31 Oct 2022 11:45:25 +0200
|
||||
|
||||
bcachefs-tools (0.1+git20220216.a1e928a-1) unstable; urgency=medium
|
||||
|
||||
* New upstream snapshot
|
||||
* Grab patch from Ubuntu to reduce memory on amd64 builders
|
||||
(http://launchpadlibrarian.net/580140160/bcachefs-tools_0.1+git20210805.6c42566-2_0.1+git20210805.6c42566-2ubuntu1.diff.gz)
|
||||
* Update copyright years
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Wed, 16 Feb 2022 14:42:20 +0200
|
||||
|
||||
bcachefs-tools (0.1+git20210805.6c42566-2) unstable; urgency=medium
|
||||
|
||||
* Remove valgrind as build-dependency, seems unneeded unless
|
||||
doing debug work and is not available on all architectures.
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Fri, 03 Sep 2021 16:07:11 +0200
|
||||
|
||||
bcachefs-tools (0.1+git20210805.6c42566-1) unstable; urgency=medium
|
||||
|
||||
* New upstream snapshot
|
||||
* Update standards version to 4.6.0
|
||||
* Add python3-docutils as dependency
|
||||
* Do not run tests at package build time
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Tue, 06 Apr 2021 15:11:27 +0200
|
||||
|
||||
bcachefs-tools (0.1+git20201025.742dbbdb-1) unstable; urgency=medium
|
||||
|
||||
* New upstream snapshot
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Mon, 26 Oct 2020 08:45:37 +0200
|
||||
|
||||
bcachefs-tools (0.1+git20201017.8a4408-1~exp1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
* Bump debhelper-compat to 13
|
||||
* Update standards version to 4.5.0
|
||||
* Declare Rules-Requires-Root: no
|
||||
* debian/copyright:
|
||||
- Update copyright years
|
||||
- Update copyright owners
|
||||
- Add intel and ccan copyright
|
||||
* Add build-dep on libudev-dev, python3-pytest and valgrind
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Sun, 18 Oct 2020 17:29:27 +0200
|
||||
|
||||
bcachefs-tools (0.1+git20190829.aa2a42b-1~exp1) experimental; urgency=medium
|
||||
|
||||
* Initial Release (Closes: #935178)
|
||||
|
||||
-- Jonathan Carter <jcc@debian.org> Mon, 16 Sep 2019 10:36:04 +0000
|
||||
|
1
debian/compat
vendored
1
debian/compat
vendored
@ -1 +0,0 @@
|
||||
10
|
35
debian/control
vendored
35
debian/control
vendored
@ -1,18 +1,39 @@
|
||||
Source: bcachefs-tools
|
||||
Maintainer: Kent Overstreet <kent.overstreet@gmail.com>
|
||||
Maintainer: Jonathan Carter <jcc@debian.org>
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Standards-Version: 3.9.5
|
||||
Build-Depends: debhelper (>= 9), dh-python, pkg-config, libaio-dev, libblkid-dev,
|
||||
libkeyutils-dev, liblz4-dev, libsodium-dev, liburcu-dev, libudev-dev,
|
||||
libzstd-dev, uuid-dev, zlib1g-dev, python3, python3-docutils,
|
||||
rustc, cargo, llvm, clang, libclang-dev, systemd, udev
|
||||
Standards-Version: 4.7.0
|
||||
Rules-Requires-Root: no
|
||||
Build-Depends: debhelper-compat (= 13),
|
||||
cargo,
|
||||
python3:native,
|
||||
pkgconf,
|
||||
python3-docutils,
|
||||
libaio-dev,
|
||||
libfuse3-dev,
|
||||
libblkid-dev,
|
||||
libkeyutils-dev,
|
||||
liblz4-dev,
|
||||
libscrypt-dev,
|
||||
libsodium-dev,
|
||||
libudev-dev,
|
||||
liburcu-dev,
|
||||
libzstd-dev,
|
||||
systemd-dev,
|
||||
uuid-dev,
|
||||
zlib1g-dev,
|
||||
Homepage: https://bcachefs.org/
|
||||
Vcs-Git: https://salsa.debian.org/jcc/bcachefs-tools.git
|
||||
Vcs-Browser: https://salsa.debian.org/jcc/bcachefs-tools
|
||||
|
||||
Package: bcachefs-tools
|
||||
Architecture: linux-any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${python3:Depends}
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, python3:any
|
||||
Recommends: initramfs-tools | linux-initramfs-tool
|
||||
Description: bcachefs userspace tools
|
||||
Userspace tools for bcachefs, a modern copy on write, checksumming, multi
|
||||
device filesystem.
|
||||
.
|
||||
Note: The current Debian kernels do not come with bcachefs support, you
|
||||
will have to use your own kernel or one provided by a 3rd party that
|
||||
contains bcachefs support.
|
||||
|
89
debian/copyright
vendored
89
debian/copyright
vendored
@ -1,22 +1,67 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Contact: kent.overstreet@gmail.com
|
||||
linux-bcachefs@vger.kernel.org
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Contact: kmo@daterainc.com
|
||||
linux-bcache@vger.kernel.org
|
||||
Source: https://evilpiepirate.org/git/bcachefs-tools.git
|
||||
|
||||
Files: *
|
||||
Copyright: 2013 Kent Overstreet <kmo@daterainc.com>
|
||||
Copyright: 2023-2024 Oracle
|
||||
2013-2022 Kent Overstreet <kmo@daterainc.com>
|
||||
2018 SUSE Linux
|
||||
2012-2016, Yann Collet
|
||||
2013 Gabriel de Perthuis <g2p.code@gmail.com>
|
||||
2015 Martin Willi
|
||||
2007-2015 Herbert Xu <herbert@gondor.apana.org.au>
|
||||
2014-2015 Thomas Graf <tgraf@suug.ch>
|
||||
2008-2014 Patrick McHardy <kaber@trash.net>
|
||||
2004-2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
|
||||
2012 Google Inc
|
||||
2010-2011 Inter Corp
|
||||
2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||
2006-2008 Greg Kroah-Hartman <greg@kroah.com>
|
||||
2006-2008 Novell Inc.
|
||||
2007-2008 Intel Corporation <willy@linux.intel.com>
|
||||
2002-2003 Patrick Mochel
|
||||
2002-2003 Open Source Development Labs
|
||||
2002 James Morris <jmorris@intercode.com.au>
|
||||
2001-2002 Silicon Graphics, Inc.
|
||||
2002 David S. Miller (davem@redhat.com)
|
||||
2001 Jens Axboe <axboe@kernel.dk>
|
||||
2001 Ming Lei <ming.lei@canonical.com>
|
||||
2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
|
||||
2001 Linus Torvalds
|
||||
License: GPL-2
|
||||
|
||||
Files: bcache-super-show.c
|
||||
Copyright: 2013 Gabriel de Perthuis <g2p.code@gmail.com>
|
||||
License: GPL-2
|
||||
Files: ccan/*
|
||||
Copyright: Copyright waived
|
||||
License: cc0-1.0
|
||||
On Debian systems, the complete text of the Creative Commons CC0 1.0
|
||||
Universal license (CC0-1.0) can be found in
|
||||
"/usr/share/common-licenses/CC0-1.0".
|
||||
|
||||
Files: bcache.c
|
||||
Copyright: 1996-2001, PostgreSQL Global Development Group
|
||||
License: PostgreSQL
|
||||
Files: ccan/darray/*
|
||||
Copyright: 2011 Joseph Adams <joeyadams3.14159@gmail.com>
|
||||
License: expat
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2014 Tom Strickx <tstrickx@rootcu.be>,
|
||||
Copyright: 2019-2024 Jonathan Carter <jcc@debian.org>
|
||||
2014 Tom Strickx <tstrickx@rootcu.be>,
|
||||
2014 David Mohr <david@mcbf.net>
|
||||
License: GPL-2+
|
||||
|
||||
@ -62,25 +107,3 @@ License: GPL-2+
|
||||
On Debian systems, the full text of the GNU General Public
|
||||
License version 2 can be found in the file
|
||||
`/usr/share/common-licenses/GPL-2'.
|
||||
|
||||
License: PostgreSQL
|
||||
Permission to use, copy, modify, and distribute this
|
||||
software and its documentation for any purpose, without fee,
|
||||
and without a written agreement is hereby granted, provided
|
||||
that the above copyright notice and this paragraph and the
|
||||
following two paragraphs appear in all copies.
|
||||
.
|
||||
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO
|
||||
ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
|
||||
CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
|
||||
OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
|
||||
THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
.
|
||||
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
|
||||
BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
|
||||
TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||
MODIFICATIONS.
|
||||
|
2
debian/gbp.conf
vendored
2
debian/gbp.conf
vendored
@ -1,5 +1,5 @@
|
||||
[DEFAULT]
|
||||
pristine-tar = True
|
||||
pristine-tar = False
|
||||
upstream-tag = v%(version)s
|
||||
ignore-branch = True
|
||||
|
||||
|
36
debian/rules
vendored
36
debian/rules
vendored
@ -1,9 +1,41 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
include /usr/share/dpkg/architecture.mk
|
||||
include /usr/share/rustc/architecture.mk
|
||||
|
||||
export DEB_HOST_RUST_TYPE DEB_HOST_GNU_TYPE
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS=hardening=+all
|
||||
export CARGO=/usr/share/cargo/bin/cargo
|
||||
export CARGO_HOME=$(CURDIR)/debian/cargo_home
|
||||
export DEB_CARGO_CRATE=bcachefs-tools_$(DEB_VERSION_UPSTREAM)
|
||||
|
||||
PREFIX := /usr
|
||||
ROOT_SBINDIR := /usr/sbin
|
||||
|
||||
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
|
||||
|
||||
ifeq ($(DEB_BUILD_ARCH),amd64)
|
||||
DEB_BUILD_MAINT_OPTIONS += optimize=-lto
|
||||
endif
|
||||
|
||||
%:
|
||||
dh $@ --with python3
|
||||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
$(CARGO) prepare-debian $(CURDIR)/vendor --link-from-system
|
||||
|
||||
override_dh_auto_build:
|
||||
$(RM) Cargo.lock
|
||||
dh_auto_build -- CARGO="$(CARGO)"
|
||||
|
||||
override_dh_auto_install:
|
||||
dh_auto_install -- "PREFIX=$(PREFIX)"
|
||||
dh_auto_install -- "PREFIX=$(PREFIX)" "ROOT_SBINDIR=$(ROOT_SBINDIR)"
|
||||
|
||||
override_dh_auto_clean:
|
||||
! [ -d $(CURDIR)/vendor ] || $(RM) -r $(CURDIR)/vendor
|
||||
! [ -d $(CARGO_HOME) ] || $(RM) -r $(CARGO_HOME)
|
||||
$(RM) Cargo.lock
|
||||
dh_auto_clean
|
||||
|
||||
override_dh_auto_test:
|
||||
|
2
debian/watch
vendored
2
debian/watch
vendored
@ -1,3 +1,3 @@
|
||||
version=4
|
||||
opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/bcachefs-tools_$1\.tar\.gz/ \
|
||||
opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/bcachefs-tools_$1\.tar\.gz/,uversionmangle=s/(\d)/$1/ \
|
||||
https://github.com/koverstreet/bcachefs-tools/tags .*/v?(\d\S+)\.tar\.gz
|
||||
|
@ -394,7 +394,7 @@ The following subcommands exist for managing subvolumes and snapshots:
|
||||
existing subvolume
|
||||
\end{itemize}
|
||||
|
||||
A subvolume can also be deleting with a normal rmdir after deleting all the
|
||||
A subvolume can also be deleted with a normal rmdir after deleting all the
|
||||
contents, as with \texttt{rm -rf}. Still to be implemented: read-only snapshots,
|
||||
recursive snapshot creation, and a method for recursively listing subvolumes.
|
||||
|
||||
@ -505,8 +505,8 @@ the \texttt{journal\_reclaim\_delay} parameter, with a default of 100
|
||||
milliseconds.
|
||||
|
||||
The journal should be sized sufficiently that bursts of activity do not fill up
|
||||
the journal too quickly; also, a larger journal mean that we can queue up larger
|
||||
btree writes. The \texttt{bcachefs device resize-journal} can be used for
|
||||
the journal too quickly; also, a larger journal means that we can queue up
|
||||
larger btree writes. The \texttt{bcachefs device resize-journal} can be used for
|
||||
resizing the journal on disk on a particular device - it can be used on a
|
||||
mounted or unmounted filesystem.
|
||||
|
||||
@ -578,8 +578,8 @@ ensuring that checksums are valid, fixing bitrot when a valid copy can be found.
|
||||
Most bcachefs options can be set filesystem wide, and a significant subset can
|
||||
also be set on inodes (files and directories), overriding the global defaults.
|
||||
Filesystem wide options may be set when formatting, when mounting, or at runtime
|
||||
via \texttt{/sys/fs/bcachefs/<uuid>/options/}. When set at runtime via sysfs the
|
||||
persistent options in the superblock are updated as well; when options are
|
||||
via \texttt{/sys/fs/bcachefs/<uuid>/options/}. When set at runtime via sysfs,
|
||||
the persistent options in the superblock are updated as well; when options are
|
||||
passed as mount parameters the persistent options are unmodified.
|
||||
|
||||
\subsection{File and directory options}
|
||||
@ -593,8 +593,8 @@ inherited attributes to change we fail the rename with -EXDEV, causing userspace
|
||||
to do the rename file by file so that inherited attributes stay consistent.
|
||||
|
||||
Inode options are available as extended attributes. The options that have been
|
||||
explicitly set are available under the \texttt{bcachefs} namespace, and the effective
|
||||
options (explicitly set and inherited options) are available under the
|
||||
explicitly set are available under the \texttt{bcachefs} namespace, and the
|
||||
effective options (explicitly set and inherited options) are available under the
|
||||
\texttt{bcachefs\_effective} namespace. Examples of listing options with the
|
||||
getfattr command:
|
||||
|
||||
@ -1150,7 +1150,7 @@ variable length sections:
|
||||
|
||||
\item \texttt{BCH\_SB\_FIELD\_replicas} \\
|
||||
Contains a list of replica entries, which are lists of devices
|
||||
that have extents replicated across them.
|
||||
that have extents replicated across them.
|
||||
|
||||
\item \texttt{BCH\_SB\_FIELD\_quota} \\
|
||||
Contains timelimit and warnlimit fields for each quota type
|
||||
|
@ -29,9 +29,10 @@ time, mount time (as mount -o parameters), or changed at runtime via sysfs (via
|
||||
the /sys/fs/bcachefs/<UUID>/options/ directory).
|
||||
|
||||
Many of those options (particularly those that control the IO path) can also be
|
||||
set on individual files and directories, via the bcachefs setattr command (which
|
||||
internally mostly works via the extended attribute interface, but the setattr
|
||||
command takes care to propagate options to children correctly).
|
||||
set on individual files and directories, via the bcachefs set-file-option
|
||||
command (which internally mostly works via the extended attribute interface, but
|
||||
the set-file-option command takes care to propagate options to children
|
||||
correctly).
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@ -48,7 +49,7 @@ at the same time.
|
||||
We generally avoid per-device options, preferring instead options that can be
|
||||
overridden on files or directories, but there are some:
|
||||
|
||||
*durability*
|
||||
*durability*
|
||||
|
||||
Device labels, targets
|
||||
----------------------
|
||||
|
117
flake.lock
generated
117
flake.lock
generated
@ -1,17 +1,12 @@
|
||||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1718474113,
|
||||
"narHash": "sha256-UKrfy/46YF2TRnxTtKCYzqf2f5ZPRRWwKCCJb7O5X8U=",
|
||||
"lastModified": 1742394900,
|
||||
"narHash": "sha256-vVOAp9ahvnU+fQoKd4SEXB2JG2wbENkpqcwlkIXgUC0=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "0095fd8ea00ae0a9e6014f39c375e40c2fbd3386",
|
||||
"rev": "70947c1908108c0c551ddfd73d4f750ff2ea67cd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -20,35 +15,14 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717827974,
|
||||
"narHash": "sha256-ixopuTeTouxqTxfMuzs6IaRttbT8JqRW5C9Q/57WxQw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "ab655c627777ab5f9964652fe23bbb1dfbd687a8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"lastModified": 1733328505,
|
||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -62,11 +36,11 @@
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717285511,
|
||||
"narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=",
|
||||
"lastModified": 1741352980,
|
||||
"narHash": "sha256-+u2UunDA4Cl5Fci3m7S643HzKmIDAe+fiXrLqYsR2fs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8",
|
||||
"rev": "f4330d22f1c5d2ba72d3d22df5597d123fdb60a9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -75,13 +49,33 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737420293,
|
||||
"narHash": "sha256-F1G5ifvqTpJq7fdkT34e/Jy9VCyzd5XfJ9TO8fHhJWE=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "f4158fa080ef4503c8f4c820967d946c2af31ec9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1718318537,
|
||||
"narHash": "sha256-4Zu0RYRcAY/VWuu6awwq4opuiD//ahpc2aFHg2CWqFY=",
|
||||
"lastModified": 1742422364,
|
||||
"narHash": "sha256-mNqIplmEohk5jRkqYqG19GA8MbQ/D4gQSK0Mu4LvfRQ=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e9ee548d90ff586a6471b4ae80ae9cfcbceb3420",
|
||||
"rev": "a84ebe20c6bc2ecbcfb000a50776219f48d134cc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -93,40 +87,47 @@
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1717284937,
|
||||
"narHash": "sha256-lIbdfCsf8LMFloheeE6N31+BMIeixqyQWbSr2vk79EQ=",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
|
||||
"lastModified": 1740877520,
|
||||
"narHash": "sha256-oiwv/ZK/2FhGxrCkQkB83i7GnWXPPLzoqFHpDD3uYpk=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "147dee35aab2193b174e4c0868bd80ead5ce755c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"fenix": "fenix",
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-parts": "flake-parts",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717583671,
|
||||
"narHash": "sha256-+lRAmz92CNUxorqWusgJbL9VE1eKCnQQojglRemzwkw=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "48bbdd6a74f3176987d5c809894ac33957000d19",
|
||||
"lastModified": 1742524367,
|
||||
"narHash": "sha256-KzTwk/5ETJavJZYV1DEWdCx05M4duFCxCpRbQSKWpng=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "70bf752d176b2ce07417e346d85486acea9040ef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
@ -137,11 +138,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1718522839,
|
||||
"narHash": "sha256-ULzoKzEaBOiLRtjeY3YoGFJMwWSKRYOic6VNw2UyTls=",
|
||||
"lastModified": 1742370146,
|
||||
"narHash": "sha256-XRE8hL4vKIQyVMDXykFh4ceo3KSpuJF3ts8GKwh5bIU=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "68eb1dc333ce82d0ab0c0357363ea17c31ea1f81",
|
||||
"rev": "adc195eef5da3606891cedf80c0d9ce2d3190808",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
327
flake.nix
327
flake.nix
@ -11,13 +11,10 @@
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
crane = {
|
||||
url = "github:ipetkov/crane";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
crane.url = "github:ipetkov/crane";
|
||||
|
||||
fenix = {
|
||||
url = "github:nix-community/fenix";
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
@ -25,6 +22,11 @@
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
nix-github-actions = {
|
||||
url = "github:nix-community/nix-github-actions";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
@ -33,26 +35,31 @@
|
||||
nixpkgs,
|
||||
flake-parts,
|
||||
treefmt-nix,
|
||||
fenix,
|
||||
crane,
|
||||
...
|
||||
rust-overlay,
|
||||
flake-compat,
|
||||
nix-github-actions,
|
||||
}:
|
||||
let
|
||||
systems = nixpkgs.lib.filter (s: nixpkgs.lib.hasSuffix "-linux" s) nixpkgs.lib.systems.flakeExposed;
|
||||
in
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [ inputs.treefmt-nix.flakeModule ];
|
||||
|
||||
# can be extended, but these have proper binary cache support in nixpkgs
|
||||
# as of writing.
|
||||
systems = [
|
||||
"aarch64-linux"
|
||||
"x86_64-linux"
|
||||
];
|
||||
flake = {
|
||||
githubActions = nix-github-actions.lib.mkGithubMatrix {
|
||||
# github actions supports fewer architectures
|
||||
checks = nixpkgs.lib.getAttrs [ "aarch64-linux" "x86_64-linux" ] self.checks;
|
||||
};
|
||||
};
|
||||
|
||||
inherit systems;
|
||||
|
||||
perSystem =
|
||||
{
|
||||
self',
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
system,
|
||||
...
|
||||
}:
|
||||
@ -61,113 +68,225 @@
|
||||
inherit (lib.lists) findFirst;
|
||||
inherit (lib.strings) hasPrefix removePrefix substring;
|
||||
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ (import rust-overlay) ];
|
||||
};
|
||||
|
||||
cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
|
||||
rustfmtToml = builtins.fromTOML (builtins.readFile ./rustfmt.toml);
|
||||
|
||||
craneLib = crane.mkLib pkgs;
|
||||
|
||||
rev = self.shortRev or self.dirtyShortRev or (substring 0 8 self.lastModifiedDate);
|
||||
makefileVersion = removePrefix "VERSION=" (
|
||||
findFirst (line: hasPrefix "VERSION=" line) "VERSION=0.0.0" (split "\n" (readFile ./Makefile))
|
||||
);
|
||||
version = "${makefileVersion}+${rev}";
|
||||
|
||||
commonArgs = {
|
||||
inherit version;
|
||||
src = self;
|
||||
mkCommon =
|
||||
{
|
||||
crane,
|
||||
pkgs,
|
||||
rustVersion ? "latest",
|
||||
|
||||
env = {
|
||||
PKG_CONFIG_SYSTEMD_SYSTEMDSYSTEMUNITDIR = "${placeholder "out"}/lib/systemd/system";
|
||||
PKG_CONFIG_UDEV_UDEVDIR = "${placeholder "out"}/lib/udev";
|
||||
# build time
|
||||
buildPackages,
|
||||
pkg-config,
|
||||
rustPlatform,
|
||||
stdenv,
|
||||
|
||||
# run time
|
||||
keyutils,
|
||||
libaio,
|
||||
libsodium,
|
||||
liburcu,
|
||||
libuuid,
|
||||
lz4,
|
||||
udev,
|
||||
zlib,
|
||||
zstd,
|
||||
}:
|
||||
let
|
||||
inherit (stdenv) cc hostPlatform;
|
||||
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain (
|
||||
p: p.rust-bin.stable."${rustVersion}".minimal.override { extensions = [ "clippy" ]; }
|
||||
);
|
||||
|
||||
args = {
|
||||
inherit version;
|
||||
src = self;
|
||||
strictDeps = true;
|
||||
|
||||
env = {
|
||||
PKG_CONFIG_SYSTEMD_SYSTEMDSYSTEMUNITDIR = "${placeholder "out"}/lib/systemd/system";
|
||||
PKG_CONFIG_UDEV_UDEVDIR = "${placeholder "out"}/lib/udev";
|
||||
|
||||
CARGO_BUILD_TARGET = hostPlatform.rust.rustcTargetSpec;
|
||||
"CARGO_TARGET_${hostPlatform.rust.cargoEnvVarTarget}_LINKER" = "${cc.targetPrefix}cc";
|
||||
HOST_CC = "${cc.nativePrefix}cc";
|
||||
TARGET_CC = "${cc.targetPrefix}cc";
|
||||
};
|
||||
|
||||
makeFlags = [
|
||||
"INITRAMFS_DIR=${placeholder "out"}/etc/initramfs-tools"
|
||||
"PREFIX=${placeholder "out"}"
|
||||
"VERSION=${version}"
|
||||
];
|
||||
|
||||
dontStrip = true;
|
||||
|
||||
depsBuildBuild = [
|
||||
buildPackages.stdenv.cc
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkg-config
|
||||
rustPlatform.bindgenHook
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
keyutils
|
||||
libaio
|
||||
libsodium
|
||||
liburcu
|
||||
libuuid
|
||||
lz4
|
||||
udev
|
||||
zlib
|
||||
zstd
|
||||
];
|
||||
|
||||
meta = {
|
||||
description = "Userspace tools for bcachefs";
|
||||
license = lib.licenses.gpl2Only;
|
||||
mainProgram = "bcachefs";
|
||||
};
|
||||
};
|
||||
|
||||
cargoArtifacts = craneLib.buildDepsOnly args;
|
||||
in
|
||||
{
|
||||
inherit args cargoArtifacts craneLib;
|
||||
};
|
||||
common = pkgs.callPackage mkCommon { inherit crane; };
|
||||
|
||||
makeFlags = [
|
||||
"INITRAMFS_DIR=${placeholder "out"}/etc/initramfs-tools"
|
||||
"PREFIX=${placeholder "out"}"
|
||||
"VERSION=${version}"
|
||||
];
|
||||
mkPackage =
|
||||
{ common, name }:
|
||||
common.craneLib.buildPackage (
|
||||
common.args
|
||||
// {
|
||||
inherit (common) cargoArtifacts;
|
||||
pname = name;
|
||||
|
||||
dontStrip = true;
|
||||
enableParallelBuilding = true;
|
||||
buildPhaseCargoCommand = ''
|
||||
make ''${enableParallelBuilding:+-j''${NIX_BUILD_CORES}} $makeFlags
|
||||
'';
|
||||
doNotPostBuildInstallCargoBinaries = true;
|
||||
installPhaseCommand = ''
|
||||
make ''${enableParallelBuilding:+-j''${NIX_BUILD_CORES}} $makeFlags install
|
||||
'';
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
pkg-config
|
||||
rustPlatform.bindgenHook
|
||||
];
|
||||
doInstallCheck = true;
|
||||
installCheckPhase = ''
|
||||
runHook preInstallCheck
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
attr
|
||||
keyutils
|
||||
libaio
|
||||
libsodium
|
||||
liburcu
|
||||
libuuid
|
||||
lz4
|
||||
udev
|
||||
zlib
|
||||
zstd
|
||||
];
|
||||
};
|
||||
test "$($out/bin/bcachefs version)" = "${version}"
|
||||
|
||||
cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { pname = cargoToml.package.name; });
|
||||
runHook postInstallCheck
|
||||
'';
|
||||
}
|
||||
);
|
||||
|
||||
mkPackages =
|
||||
name: systems:
|
||||
let
|
||||
packagesForSystem =
|
||||
crossSystem:
|
||||
let
|
||||
localSystem = system;
|
||||
pkgs' = import nixpkgs {
|
||||
inherit crossSystem localSystem;
|
||||
overlays = [ (import rust-overlay) ];
|
||||
};
|
||||
|
||||
common = pkgs'.callPackage mkCommon { inherit crane; };
|
||||
package = pkgs'.callPackage mkPackage { inherit common name; };
|
||||
packageFuse = package.overrideAttrs (
|
||||
final: prev: {
|
||||
makeFlags = prev.makeFlags ++ [ "BCACHEFS_FUSE=1" ];
|
||||
buildInputs = prev.buildInputs ++ [ pkgs'.fuse3 ];
|
||||
}
|
||||
);
|
||||
in
|
||||
[
|
||||
(lib.nameValuePair "${name}-${crossSystem}" package)
|
||||
(lib.nameValuePair "${name}-fuse-${crossSystem}" packageFuse)
|
||||
];
|
||||
in
|
||||
lib.listToAttrs (lib.flatten (map packagesForSystem systems));
|
||||
in
|
||||
{
|
||||
packages.default = config.packages.bcachefs-tools;
|
||||
packages.bcachefs-tools = craneLib.buildPackage (
|
||||
commonArgs
|
||||
packages =
|
||||
let
|
||||
inherit (cargoToml.package) name;
|
||||
in
|
||||
(mkPackages name systems)
|
||||
// {
|
||||
inherit cargoArtifacts;
|
||||
${name} = config.packages."${name}-${system}";
|
||||
"${name}-fuse" = config.packages."${name}-fuse-${system}";
|
||||
default = config.packages.${name};
|
||||
};
|
||||
|
||||
enableParallelBuilding = true;
|
||||
buildPhaseCargoCommand = ''
|
||||
make ''${enableParallelBuilding:+-j''${NIX_BUILD_CORES}} $makeFlags
|
||||
'';
|
||||
installPhaseCommand = ''
|
||||
make ''${enableParallelBuilding:+-j''${NIX_BUILD_CORES}} $makeFlags install
|
||||
'';
|
||||
checks = {
|
||||
inherit (config.packages)
|
||||
bcachefs-tools
|
||||
bcachefs-tools-fuse
|
||||
bcachefs-tools-fuse-i686-linux
|
||||
;
|
||||
|
||||
doInstallCheck = true;
|
||||
installCheckPhase = ''
|
||||
runHook preInstallCheck
|
||||
cargo-clippy = common.craneLib.cargoClippy (
|
||||
common.args
|
||||
// {
|
||||
inherit (common) cargoArtifacts;
|
||||
cargoClippyExtraArgs = "--all-targets --all-features -- --deny warnings";
|
||||
}
|
||||
);
|
||||
|
||||
test "$($out/bin/bcachefs version)" = "${version}"
|
||||
# we have to build our own `craneLib.cargoTest`
|
||||
cargo-test = common.craneLib.mkCargoDerivation (
|
||||
common.args
|
||||
// {
|
||||
inherit (common) cargoArtifacts;
|
||||
doCheck = true;
|
||||
|
||||
runHook postInstallCheck
|
||||
'';
|
||||
}
|
||||
);
|
||||
enableParallelChecking = true;
|
||||
|
||||
packages.bcachefs-tools-fuse = config.packages.bcachefs-tools.overrideAttrs (
|
||||
final: prev: {
|
||||
makeFlags = prev.makeFlags ++ [ "BCACHEFS_FUSE=1" ];
|
||||
buildInputs = prev.buildInputs ++ [ pkgs.fuse3 ];
|
||||
}
|
||||
);
|
||||
pnameSuffix = "-test";
|
||||
buildPhaseCargoCommand = "";
|
||||
checkPhaseCargoCommand = ''
|
||||
make ''${enableParallelChecking:+-j''${NIX_BUILD_CORES}} $makeFlags libbcachefs.a
|
||||
cargo test --profile release -- --nocapture
|
||||
'';
|
||||
}
|
||||
);
|
||||
|
||||
checks.cargo-clippy = craneLib.cargoClippy (
|
||||
commonArgs
|
||||
// {
|
||||
inherit cargoArtifacts;
|
||||
cargoClippyExtraArgs = "--all-targets -- --deny warnings";
|
||||
}
|
||||
);
|
||||
|
||||
# we have to build our own `craneLib.cargoTest`
|
||||
checks.cargo-test = craneLib.mkCargoDerivation (
|
||||
commonArgs
|
||||
// {
|
||||
inherit cargoArtifacts;
|
||||
doCheck = true;
|
||||
|
||||
enableParallelChecking = true;
|
||||
|
||||
pnameSuffix = "-test";
|
||||
buildPhaseCargoCommand = "";
|
||||
checkPhaseCargoCommand = ''
|
||||
make ''${enableParallelChecking:+-j''${NIX_BUILD_CORES}} $makeFlags libbcachefs.a
|
||||
cargo test --profile release -- --nocapture
|
||||
'';
|
||||
}
|
||||
);
|
||||
# cargo clippy with the current minimum supported rust version
|
||||
# according to Cargo.toml
|
||||
msrv =
|
||||
let
|
||||
rustVersion = cargoToml.package.rust-version;
|
||||
common = pkgs.callPackage mkCommon { inherit crane rustVersion; };
|
||||
in
|
||||
common.craneLib.cargoClippy (
|
||||
common.args
|
||||
// {
|
||||
pname = "msrv";
|
||||
inherit (common) cargoArtifacts;
|
||||
cargoClippyExtraArgs = "--all-targets --all-features -- --deny warnings";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
devShells.default = pkgs.mkShell {
|
||||
inputsFrom = [
|
||||
@ -183,20 +302,24 @@
|
||||
cargo-audit
|
||||
cargo-outdated
|
||||
clang-tools
|
||||
clippy
|
||||
rust-analyzer
|
||||
rustc
|
||||
(rust-bin.stable.latest.minimal.override {
|
||||
extensions = [
|
||||
"rust-analyzer"
|
||||
"rust-src"
|
||||
];
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
treefmt.config = {
|
||||
projectRootFile = "flake.nix";
|
||||
flakeCheck = false;
|
||||
|
||||
programs = {
|
||||
nixfmt-rfc-style.enable = true;
|
||||
nixfmt.enable = true;
|
||||
rustfmt.edition = rustfmtToml.edition;
|
||||
rustfmt.enable = true;
|
||||
rustfmt.package = fenix.packages.${system}.default.rustfmt;
|
||||
rustfmt.package = pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.rustfmt);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define _CRYPTO_SHA_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <sodium/crypto_hash_sha256.h>
|
||||
|
||||
#define SHA1_DIGEST_SIZE 20
|
||||
#define SHA1_BLOCK_SIZE 64
|
||||
@ -112,4 +113,9 @@ extern int crypto_sha512_update(struct shash_desc *desc, const u8 *data,
|
||||
|
||||
extern int crypto_sha512_finup(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len, u8 *hash);
|
||||
|
||||
static inline void sha256(const u8 *data, unsigned int len, u8 *out)
|
||||
{
|
||||
crypto_hash_sha256(out, data, len);
|
||||
}
|
||||
#endif
|
||||
|
@ -16,71 +16,31 @@ typedef struct {
|
||||
u64 counter;
|
||||
} atomic64_t;
|
||||
|
||||
#ifndef C11_ATOMICS
|
||||
|
||||
#include <urcu/uatomic.h>
|
||||
|
||||
#if (CAA_BITS_PER_LONG != 64)
|
||||
#define ATOMIC64_SPINLOCK
|
||||
#endif
|
||||
|
||||
#define __ATOMIC_READ(p) uatomic_read(p)
|
||||
#define __ATOMIC_SET(p, v) uatomic_set(p, v)
|
||||
#define __ATOMIC_ADD_RETURN(v, p) uatomic_add_return(p, v)
|
||||
#define __ATOMIC_SUB_RETURN(v, p) uatomic_sub_return(p, v)
|
||||
#define __ATOMIC_ADD(v, p) uatomic_add(p, v)
|
||||
#define __ATOMIC_SUB(v, p) uatomic_sub(p, v)
|
||||
#define __ATOMIC_INC(p) uatomic_inc(p)
|
||||
#define __ATOMIC_DEC(p) uatomic_dec(p)
|
||||
#define __ATOMIC_AND(v, p) uatomic_and(p, v)
|
||||
#define __ATOMIC_OR(v, p) uatomic_or(p, v)
|
||||
|
||||
#define xchg(p, v) uatomic_xchg(p, v)
|
||||
#define xchg_acquire(p, v) uatomic_xchg(p, v)
|
||||
#define cmpxchg(p, old, new) uatomic_cmpxchg(p, old, new)
|
||||
#define cmpxchg_acquire(p, old, new) uatomic_cmpxchg(p, old, new)
|
||||
#define cmpxchg_release(p, old, new) uatomic_cmpxchg(p, old, new)
|
||||
|
||||
#define try_cmpxchg(p, _old, _new) \
|
||||
({ \
|
||||
typeof(*(_old)) _v = cmpxchg(p, *(_old), _new); \
|
||||
bool _ret = _v == *(_old); \
|
||||
*(_old) = _v; \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define try_cmpxchg_acquire(p, _old, _new) \
|
||||
try_cmpxchg(p, _old, _new)
|
||||
|
||||
#define smp_mb__before_atomic() cmm_smp_mb__before_uatomic_add()
|
||||
#define smp_mb__after_atomic() cmm_smp_mb__after_uatomic_add()
|
||||
#define smp_wmb() cmm_smp_wmb()
|
||||
#define smp_rmb() cmm_smp_rmb()
|
||||
#define smp_mb() cmm_smp_mb()
|
||||
#define smp_read_barrier_depends() cmm_smp_read_barrier_depends()
|
||||
#define smp_acquire__after_ctrl_dep() cmm_smp_mb()
|
||||
|
||||
#else /* C11_ATOMICS */
|
||||
|
||||
#define __ATOMIC_READ(p) __atomic_load_n(p, __ATOMIC_RELAXED)
|
||||
#define __ATOMIC_SET(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED)
|
||||
#define __ATOMIC_SET_RELEASE(p, v) __atomic_store_n(p, v, __ATOMIC_RELEASE)
|
||||
#define __ATOMIC_ADD_RETURN(v, p) __atomic_add_fetch(p, v, __ATOMIC_RELAXED)
|
||||
#define __ATOMIC_ADD_RETURN_RELEASE(v, p) \
|
||||
__atomic_add_fetch(p, v, __ATOMIC_RELEASE)
|
||||
#define __ATOMIC_SUB_RETURN(v, p) __atomic_sub_fetch(p, v, __ATOMIC_RELAXED)
|
||||
#define __ATOMIC_SUB_RETURN_RELEASE(v, p) \
|
||||
__atomic_sub_fetch(p, v, __ATOMIC_RELEASE)
|
||||
#define __ATOMIC_AND(p) __atomic_and_fetch(p, v, __ATOMIC_RELAXED)
|
||||
#define __ATOMIC_OR(p) __atomic_or_fetch(p, v, __ATOMIC_RELAXED)
|
||||
#define __ATOMIC_AND(v, p) __atomic_and_fetch(&(p)->counter, v, __ATOMIC_RELAXED)
|
||||
#define __ATOMIC_OR(v, p) __atomic_or_fetch(&(p)->counter, v, __ATOMIC_RELAXED)
|
||||
|
||||
#define xchg(p, v) __atomic_exchange_n(p, v, __ATOMIC_SEQ_CST)
|
||||
#define xchg_acquire(p, v) __atomic_exchange_n(p, v, __ATOMIC_ACQUIRE)
|
||||
|
||||
#define try_cmpxchg(p, old, new) \
|
||||
__atomic_compare_exchange_n((p), __old, new, false, \
|
||||
__atomic_compare_exchange_n((p), old, new, false, \
|
||||
__ATOMIC_SEQ_CST, \
|
||||
__ATOMIC_SEQ_CST)
|
||||
|
||||
#define try_cmpxchg_acquire(p, old, new) \
|
||||
__atomic_compare_exchange_n((p), old, new, false, \
|
||||
__ATOMIC_ACQUIRE, \
|
||||
__ATOMIC_RELAXED)
|
||||
|
||||
#define cmpxchg(p, old, new) \
|
||||
({ \
|
||||
typeof(*(p)) __old = (old); \
|
||||
@ -107,7 +67,7 @@ typedef struct {
|
||||
\
|
||||
__atomic_compare_exchange_n((p), &__old, new, false, \
|
||||
__ATOMIC_RELEASE, \
|
||||
__ATOMIC_RELEASE); \
|
||||
__ATOMIC_RELAXED); \
|
||||
__old; \
|
||||
})
|
||||
|
||||
@ -117,9 +77,7 @@ typedef struct {
|
||||
#define smp_rmb() __atomic_thread_fence(__ATOMIC_SEQ_CST)
|
||||
#define smp_mb() __atomic_thread_fence(__ATOMIC_SEQ_CST)
|
||||
#define smp_read_barrier_depends()
|
||||
|
||||
#endif
|
||||
|
||||
#define smp_acquire__after_ctrl_dep() __atomic_thread_fence(__ATOMIC_SEQ_CST)
|
||||
#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
|
||||
|
||||
#define smp_load_acquire(p) \
|
||||
@ -186,7 +144,12 @@ static inline i_type a_type##_read_acquire(const a_type##_t *v) \
|
||||
\
|
||||
static inline void a_type##_set(a_type##_t *v, i_type i) \
|
||||
{ \
|
||||
return __ATOMIC_SET(&v->counter, i); \
|
||||
__ATOMIC_SET(&v->counter, i); \
|
||||
} \
|
||||
\
|
||||
static inline void a_type##_set_release(a_type##_t *v, i_type i) \
|
||||
{ \
|
||||
__ATOMIC_SET_RELEASE(&v->counter, i); \
|
||||
} \
|
||||
\
|
||||
static inline i_type a_type##_add_return(i_type i, a_type##_t *v) \
|
||||
@ -337,6 +300,7 @@ void atomic64_sub(s64, atomic64_t *);
|
||||
|
||||
s64 atomic64_xchg(atomic64_t *, s64);
|
||||
s64 atomic64_cmpxchg(atomic64_t *, s64, s64);
|
||||
bool atomic64_try_cmpxchg(atomic64_t *, s64 *, s64);
|
||||
|
||||
#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
|
||||
#define atomic64_inc(v) atomic64_add(1LL, (v))
|
||||
|
@ -62,6 +62,29 @@ static inline void bitmap_complement(unsigned long *dst, const unsigned long *sr
|
||||
dst[k] = ~src[k];
|
||||
}
|
||||
|
||||
static inline bool __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int bits)
|
||||
{
|
||||
unsigned int k;
|
||||
unsigned int lim = bits/BITS_PER_LONG;
|
||||
unsigned long result = 0;
|
||||
|
||||
for (k = 0; k < lim; k++)
|
||||
result |= (dst[k] = bitmap1[k] & ~bitmap2[k]);
|
||||
if (bits % BITS_PER_LONG)
|
||||
result |= (dst[k] = bitmap1[k] & ~bitmap2[k] &
|
||||
BITMAP_LAST_WORD_MASK(bits));
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
static inline bool bitmap_andnot(unsigned long *dst, const unsigned long *src1,
|
||||
const unsigned long *src2, unsigned int nbits)
|
||||
{
|
||||
if (small_const_nbits(nbits))
|
||||
return (*dst = *src1 & ~(*src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
|
||||
return __bitmap_andnot(dst, src1, src2, nbits);
|
||||
}
|
||||
|
||||
static inline void bitmap_zero(unsigned long *dst, int nbits)
|
||||
{
|
||||
memset(dst, 0, BITS_TO_LONGS(nbits) * sizeof(unsigned long));
|
||||
|
@ -6,9 +6,12 @@
|
||||
#define __LINUX_BLK_TYPES_H
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bvec.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rwsem.h>
|
||||
|
||||
struct bio_set;
|
||||
struct bio;
|
||||
@ -62,6 +65,8 @@ struct block_device {
|
||||
struct gendisk * bd_disk;
|
||||
struct gendisk __bd_disk;
|
||||
int bd_fd;
|
||||
|
||||
struct mutex bd_holder_lock;
|
||||
};
|
||||
|
||||
#define bdev_kobj(_bdev) (&((_bdev)->kobj))
|
||||
|
@ -65,7 +65,10 @@ unsigned bdev_logical_block_size(struct block_device *bdev);
|
||||
sector_t get_capacity(struct gendisk *disk);
|
||||
|
||||
struct blk_holder_ops {
|
||||
void (*mark_dead)(struct block_device *bdev);
|
||||
void (*mark_dead)(struct block_device *bdev, bool surprise);
|
||||
void (*sync)(struct block_device *bdev);
|
||||
int (*freeze)(struct block_device *bdev);
|
||||
int (*thaw)(struct block_device *bdev);
|
||||
};
|
||||
|
||||
static inline struct block_device *file_bdev(struct file *file)
|
||||
@ -80,8 +83,12 @@ int lookup_bdev(const char *path, dev_t *);
|
||||
|
||||
struct super_block {
|
||||
void *s_fs_info;
|
||||
struct rw_semaphore s_umount;
|
||||
};
|
||||
|
||||
static inline void evict_inodes(struct super_block *sb) {}
|
||||
static inline int sync_filesystem(struct super_block *) { return 0; }
|
||||
|
||||
/*
|
||||
* File types
|
||||
*
|
||||
|
@ -159,6 +159,7 @@ struct closure {
|
||||
#ifdef CONFIG_DEBUG_CLOSURES
|
||||
#define CLOSURE_MAGIC_DEAD 0xc054dead
|
||||
#define CLOSURE_MAGIC_ALIVE 0xc054a11e
|
||||
#define CLOSURE_MAGIC_STACK 0xc05451cc
|
||||
|
||||
unsigned int magic;
|
||||
struct list_head all;
|
||||
@ -284,6 +285,21 @@ static inline void closure_get(struct closure *cl)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* closure_get_not_zero
|
||||
*/
|
||||
static inline bool closure_get_not_zero(struct closure *cl)
|
||||
{
|
||||
unsigned old = atomic_read(&cl->remaining);
|
||||
do {
|
||||
if (!(old & CLOSURE_REMAINING_MASK))
|
||||
return false;
|
||||
|
||||
} while (!atomic_try_cmpxchg_acquire(&cl->remaining, &old, old + 1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* closure_init - Initialize a closure, setting the refcount to 1
|
||||
* @cl: closure to initialize
|
||||
@ -308,6 +324,18 @@ static inline void closure_init_stack(struct closure *cl)
|
||||
{
|
||||
memset(cl, 0, sizeof(struct closure));
|
||||
atomic_set(&cl->remaining, CLOSURE_REMAINING_INITIALIZER);
|
||||
#ifdef CONFIG_DEBUG_CLOSURES
|
||||
cl->magic = CLOSURE_MAGIC_STACK;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void closure_init_stack_release(struct closure *cl)
|
||||
{
|
||||
memset(cl, 0, sizeof(struct closure));
|
||||
atomic_set_release(&cl->remaining, CLOSURE_REMAINING_INITIALIZER);
|
||||
#ifdef CONFIG_DEBUG_CLOSURES
|
||||
cl->magic = CLOSURE_MAGIC_STACK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -355,6 +383,8 @@ do { \
|
||||
*/
|
||||
#define closure_return(_cl) continue_at((_cl), NULL, NULL)
|
||||
|
||||
void closure_return_sync(struct closure *cl);
|
||||
|
||||
/**
|
||||
* continue_at_nobarrier - jump to another function without barrier
|
||||
*
|
||||
@ -424,4 +454,39 @@ do { \
|
||||
__closure_wait_event(waitlist, _cond); \
|
||||
} while (0)
|
||||
|
||||
#define __closure_wait_event_timeout(waitlist, _cond, _until) \
|
||||
({ \
|
||||
struct closure cl; \
|
||||
long _t; \
|
||||
\
|
||||
closure_init_stack(&cl); \
|
||||
\
|
||||
while (1) { \
|
||||
closure_wait(waitlist, &cl); \
|
||||
if (_cond) { \
|
||||
_t = max_t(long, 1L, _until - jiffies); \
|
||||
break; \
|
||||
} \
|
||||
_t = max_t(long, 0L, _until - jiffies); \
|
||||
if (!_t) \
|
||||
break; \
|
||||
closure_sync_timeout(&cl, _t); \
|
||||
} \
|
||||
closure_wake_up(waitlist); \
|
||||
closure_sync(&cl); \
|
||||
_t; \
|
||||
})
|
||||
|
||||
/*
|
||||
* Returns 0 if timeout expired, remaining time in jiffies (at least 1) if
|
||||
* condition became true
|
||||
*/
|
||||
#define closure_wait_event_timeout(waitlist, _cond, _timeout) \
|
||||
({ \
|
||||
unsigned long _until = jiffies + _timeout; \
|
||||
(_cond) \
|
||||
? max_t(long, 1L, _until - jiffies) \
|
||||
: __closure_wait_event_timeout(waitlist, _cond, _until);\
|
||||
})
|
||||
|
||||
#endif /* _LINUX_CLOSURE_H */
|
||||
|
@ -67,6 +67,7 @@
|
||||
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
|
||||
#define fallthrough __attribute__((__fallthrough__))
|
||||
#define __noreturn __attribute__((__noreturn__))
|
||||
#define __no_kmsan_checks
|
||||
|
||||
#ifndef __counted_by
|
||||
#define __counted_by(nr)
|
||||
|
@ -1,7 +1,8 @@
|
||||
#ifndef _LINUX_CONSOLE_H_
|
||||
#define _LINUX_CONSOLE_H_
|
||||
|
||||
#define console_lock()
|
||||
#define console_unlock()
|
||||
#define console_lock() do {} while (0)
|
||||
#define console_trylock() true
|
||||
#define console_unlock() do {} while (0)
|
||||
|
||||
#endif /* _LINUX_CONSOLE_H */
|
||||
|
@ -9,4 +9,9 @@ struct dentry {
|
||||
struct inode *d_inode;
|
||||
};
|
||||
|
||||
static inline void shrink_dcache_sb(struct super_block *) {}
|
||||
|
||||
#define QSTR_INIT(n,l) { { { .len = l } }, .name = n }
|
||||
#define QSTR(n) (struct qstr)QSTR_INIT(n, strlen(n))
|
||||
|
||||
#endif /* __LINUX_DCACHE_H */
|
||||
|
20
include/linux/fs_parser.h
Normal file
20
include/linux/fs_parser.h
Normal file
@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* Filesystem parameter description and parser
|
||||
*
|
||||
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FS_PARSER_H
|
||||
#define _LINUX_FS_PARSER_H
|
||||
|
||||
struct constant_table {
|
||||
const char *name;
|
||||
int value;
|
||||
};
|
||||
|
||||
extern int lookup_constant(const struct constant_table tbl[], const char *name, int not_found);
|
||||
|
||||
extern const struct constant_table bool_names[];
|
||||
|
||||
#endif /* _LINUX_FS_PARSER_H */
|
@ -41,6 +41,7 @@
|
||||
#include <linux/limits.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct genradix_root;
|
||||
@ -48,10 +49,63 @@ struct genradix_root;
|
||||
#define GENRADIX_NODE_SHIFT 9
|
||||
#define GENRADIX_NODE_SIZE (1U << GENRADIX_NODE_SHIFT)
|
||||
|
||||
#define GENRADIX_ARY (GENRADIX_NODE_SIZE / sizeof(struct genradix_node *))
|
||||
#define GENRADIX_ARY_SHIFT ilog2(GENRADIX_ARY)
|
||||
|
||||
/* depth that's needed for a genradix that can address up to ULONG_MAX: */
|
||||
#define GENRADIX_MAX_DEPTH \
|
||||
DIV_ROUND_UP(BITS_PER_LONG - GENRADIX_NODE_SHIFT, GENRADIX_ARY_SHIFT)
|
||||
|
||||
#define GENRADIX_DEPTH_MASK \
|
||||
((unsigned long) (roundup_pow_of_two(GENRADIX_MAX_DEPTH + 1) - 1))
|
||||
|
||||
static inline int genradix_depth_shift(unsigned depth)
|
||||
{
|
||||
return GENRADIX_NODE_SHIFT + GENRADIX_ARY_SHIFT * depth;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns size (of data, in bytes) that a tree of a given depth holds:
|
||||
*/
|
||||
static inline size_t genradix_depth_size(unsigned depth)
|
||||
{
|
||||
return 1UL << genradix_depth_shift(depth);
|
||||
}
|
||||
|
||||
static inline unsigned genradix_root_to_depth(struct genradix_root *r)
|
||||
{
|
||||
return (unsigned long) r & GENRADIX_DEPTH_MASK;
|
||||
}
|
||||
|
||||
static inline struct genradix_node *genradix_root_to_node(struct genradix_root *r)
|
||||
{
|
||||
return (void *) ((unsigned long) r & ~GENRADIX_DEPTH_MASK);
|
||||
}
|
||||
|
||||
struct __genradix {
|
||||
struct genradix_root *root;
|
||||
};
|
||||
|
||||
struct genradix_node {
|
||||
union {
|
||||
/* Interior node: */
|
||||
struct genradix_node *children[GENRADIX_ARY];
|
||||
|
||||
/* Leaf: */
|
||||
u8 data[GENRADIX_NODE_SIZE];
|
||||
};
|
||||
};
|
||||
|
||||
static inline struct genradix_node *genradix_alloc_node(gfp_t gfp_mask)
|
||||
{
|
||||
return kzalloc(GENRADIX_NODE_SIZE, gfp_mask);
|
||||
}
|
||||
|
||||
static inline void genradix_free_node(struct genradix_node *node)
|
||||
{
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: currently, sizeof(_type) must not be larger than GENRADIX_NODE_SIZE:
|
||||
*/
|
||||
@ -128,6 +182,30 @@ static inline size_t __idx_to_offset(size_t idx, size_t obj_size)
|
||||
#define __genradix_idx_to_offset(_radix, _idx) \
|
||||
__idx_to_offset(_idx, __genradix_obj_size(_radix))
|
||||
|
||||
static inline void *__genradix_ptr_inlined(struct __genradix *radix, size_t offset)
|
||||
{
|
||||
struct genradix_root *r = READ_ONCE(radix->root);
|
||||
struct genradix_node *n = genradix_root_to_node(r);
|
||||
unsigned level = genradix_root_to_depth(r);
|
||||
unsigned shift = genradix_depth_shift(level);
|
||||
|
||||
if (unlikely(ilog2(offset) >= genradix_depth_shift(level)))
|
||||
return NULL;
|
||||
|
||||
while (n && shift > GENRADIX_NODE_SHIFT) {
|
||||
shift -= GENRADIX_ARY_SHIFT;
|
||||
n = n->children[offset >> shift];
|
||||
offset &= (1UL << shift) - 1;
|
||||
}
|
||||
|
||||
return n ? &n->data[offset] : NULL;
|
||||
}
|
||||
|
||||
#define genradix_ptr_inlined(_radix, _idx) \
|
||||
(__genradix_cast(_radix) \
|
||||
__genradix_ptr_inlined(&(_radix)->tree, \
|
||||
__genradix_idx_to_offset(_radix, _idx)))
|
||||
|
||||
void *__genradix_ptr(struct __genradix *, size_t);
|
||||
|
||||
/**
|
||||
@ -142,7 +220,24 @@ void *__genradix_ptr(struct __genradix *, size_t);
|
||||
__genradix_ptr(&(_radix)->tree, \
|
||||
__genradix_idx_to_offset(_radix, _idx)))
|
||||
|
||||
void *__genradix_ptr_alloc(struct __genradix *, size_t, gfp_t);
|
||||
void *__genradix_ptr_alloc(struct __genradix *, size_t,
|
||||
struct genradix_node **, gfp_t);
|
||||
|
||||
#define genradix_ptr_alloc_inlined(_radix, _idx, _gfp) \
|
||||
(__genradix_cast(_radix) \
|
||||
(__genradix_ptr_inlined(&(_radix)->tree, \
|
||||
__genradix_idx_to_offset(_radix, _idx)) ?: \
|
||||
__genradix_ptr_alloc(&(_radix)->tree, \
|
||||
__genradix_idx_to_offset(_radix, _idx), \
|
||||
NULL, _gfp)))
|
||||
|
||||
#define genradix_ptr_alloc_preallocated_inlined(_radix, _idx, _new_node, _gfp)\
|
||||
(__genradix_cast(_radix) \
|
||||
(__genradix_ptr_inlined(&(_radix)->tree, \
|
||||
__genradix_idx_to_offset(_radix, _idx)) ?: \
|
||||
__genradix_ptr_alloc(&(_radix)->tree, \
|
||||
__genradix_idx_to_offset(_radix, _idx), \
|
||||
_new_node, _gfp)))
|
||||
|
||||
/**
|
||||
* genradix_ptr_alloc - get a pointer to a genradix entry, allocating it
|
||||
@ -157,7 +252,13 @@ void *__genradix_ptr_alloc(struct __genradix *, size_t, gfp_t);
|
||||
(__genradix_cast(_radix) \
|
||||
__genradix_ptr_alloc(&(_radix)->tree, \
|
||||
__genradix_idx_to_offset(_radix, _idx), \
|
||||
_gfp))
|
||||
NULL, _gfp))
|
||||
|
||||
#define genradix_ptr_alloc_preallocated(_radix, _idx, _new_node, _gfp)\
|
||||
(__genradix_cast(_radix) \
|
||||
__genradix_ptr_alloc(&(_radix)->tree, \
|
||||
__genradix_idx_to_offset(_radix, _idx), \
|
||||
_new_node, _gfp))
|
||||
|
||||
struct genradix_iter {
|
||||
size_t offset;
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <linux/bug.h>
|
||||
#include <linux/byteorder.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/kmsan-checks.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/minmax.h>
|
||||
|
||||
|
@ -26,6 +26,7 @@ extern void kmemleak_free_part(const void *ptr, size_t size) __ref;
|
||||
extern void kmemleak_free_percpu(const void __percpu *ptr) __ref;
|
||||
extern void kmemleak_update_trace(const void *ptr) __ref;
|
||||
extern void kmemleak_not_leak(const void *ptr) __ref;
|
||||
extern void kmemleak_transient_leak(const void *ptr) __ref;
|
||||
extern void kmemleak_ignore(const void *ptr) __ref;
|
||||
extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref;
|
||||
extern void kmemleak_no_scan(const void *ptr) __ref;
|
||||
@ -93,6 +94,9 @@ static inline void kmemleak_update_trace(const void *ptr)
|
||||
static inline void kmemleak_not_leak(const void *ptr)
|
||||
{
|
||||
}
|
||||
static inline void kmemleak_transient_leak(const void *ptr)
|
||||
{
|
||||
}
|
||||
static inline void kmemleak_ignore(const void *ptr)
|
||||
{
|
||||
}
|
||||
|
98
include/linux/kmsan-checks.h
Normal file
98
include/linux/kmsan-checks.h
Normal file
@ -0,0 +1,98 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* KMSAN checks to be used for one-off annotations in subsystems.
|
||||
*
|
||||
* Copyright (C) 2017-2022 Google LLC
|
||||
* Author: Alexander Potapenko <glider@google.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_KMSAN_CHECKS_H
|
||||
#define _LINUX_KMSAN_CHECKS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef CONFIG_KMSAN
|
||||
|
||||
/**
|
||||
* kmsan_poison_memory() - Mark the memory range as uninitialized.
|
||||
* @address: address to start with.
|
||||
* @size: size of buffer to poison.
|
||||
* @flags: GFP flags for allocations done by this function.
|
||||
*
|
||||
* Until other data is written to this range, KMSAN will treat it as
|
||||
* uninitialized. Error reports for this memory will reference the call site of
|
||||
* kmsan_poison_memory() as origin.
|
||||
*/
|
||||
void kmsan_poison_memory(const void *address, size_t size, gfp_t flags);
|
||||
|
||||
/**
|
||||
* kmsan_unpoison_memory() - Mark the memory range as initialized.
|
||||
* @address: address to start with.
|
||||
* @size: size of buffer to unpoison.
|
||||
*
|
||||
* Until other data is written to this range, KMSAN will treat it as
|
||||
* initialized.
|
||||
*/
|
||||
void kmsan_unpoison_memory(const void *address, size_t size);
|
||||
|
||||
/**
|
||||
* kmsan_check_memory() - Check the memory range for being initialized.
|
||||
* @address: address to start with.
|
||||
* @size: size of buffer to check.
|
||||
*
|
||||
* If any piece of the given range is marked as uninitialized, KMSAN will report
|
||||
* an error.
|
||||
*/
|
||||
void kmsan_check_memory(const void *address, size_t size);
|
||||
|
||||
/**
|
||||
* kmsan_copy_to_user() - Notify KMSAN about a data transfer to userspace.
|
||||
* @to: destination address in the userspace.
|
||||
* @from: source address in the kernel.
|
||||
* @to_copy: number of bytes to copy.
|
||||
* @left: number of bytes not copied.
|
||||
*
|
||||
* If this is a real userspace data transfer, KMSAN checks the bytes that were
|
||||
* actually copied to ensure there was no information leak. If @to belongs to
|
||||
* the kernel space (which is possible for compat syscalls), KMSAN just copies
|
||||
* the metadata.
|
||||
*/
|
||||
void kmsan_copy_to_user(void __user *to, const void *from, size_t to_copy,
|
||||
size_t left);
|
||||
|
||||
/**
|
||||
* kmsan_memmove() - Notify KMSAN about a data copy within kernel.
|
||||
* @to: destination address in the kernel.
|
||||
* @from: source address in the kernel.
|
||||
* @size: number of bytes to copy.
|
||||
*
|
||||
* Invoked after non-instrumented version (e.g. implemented using assembly
|
||||
* code) of memmove()/memcpy() is called, in order to copy KMSAN's metadata.
|
||||
*/
|
||||
void kmsan_memmove(void *to, const void *from, size_t to_copy);
|
||||
|
||||
#else
|
||||
|
||||
static inline void kmsan_poison_memory(const void *address, size_t size,
|
||||
gfp_t flags)
|
||||
{
|
||||
}
|
||||
static inline void kmsan_unpoison_memory(const void *address, size_t size)
|
||||
{
|
||||
}
|
||||
static inline void kmsan_check_memory(const void *address, size_t size)
|
||||
{
|
||||
}
|
||||
static inline void kmsan_copy_to_user(void __user *to, const void *from,
|
||||
size_t to_copy, size_t left)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void kmsan_memmove(void *to, const void *from, size_t to_copy)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_KMSAN_CHECKS_H */
|
@ -20,6 +20,7 @@
|
||||
#include <linux/bug.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
@ -5,6 +5,8 @@ struct lock_class_key {};
|
||||
struct task_struct;
|
||||
|
||||
# define lock_acquire(l, s, t, r, c, n, i) do { } while (0)
|
||||
# define lock_acquire_exclusive(...) do { } while (0)
|
||||
# define lockdep_set_notrack_class(...) do { } while (0)
|
||||
# define lock_release(l, i) do { } while (0)
|
||||
# define lock_set_class(l, n, k, s, i) do { } while (0)
|
||||
# define lock_set_subclass(l, s, i) do { } while (0)
|
||||
|
@ -82,4 +82,71 @@ static inline s64 div_s64(s64 dividend, s32 divisor)
|
||||
return div_s64_rem(dividend, divisor, &remainder);
|
||||
}
|
||||
|
||||
#ifndef mul_u32_u32
|
||||
/*
|
||||
* Many a GCC version messes this up and generates a 64x64 mult :-(
|
||||
*/
|
||||
static inline u64 mul_u32_u32(u32 a, u32 b)
|
||||
{
|
||||
return (u64)a * b;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__)
|
||||
|
||||
#ifndef mul_u64_u64_shr
|
||||
static __always_inline u64 mul_u64_u64_shr(u64 a, u64 mul, unsigned int shift)
|
||||
{
|
||||
return (u64)(((unsigned __int128)a * mul) >> shift);
|
||||
}
|
||||
#endif /* mul_u64_u64_shr */
|
||||
|
||||
#else
|
||||
|
||||
#ifndef mul_u64_u64_shr
|
||||
static inline u64 mul_u64_u64_shr(u64 a, u64 b, unsigned int shift)
|
||||
{
|
||||
union {
|
||||
u64 ll;
|
||||
struct {
|
||||
#ifdef __BIG_ENDIAN
|
||||
u32 high, low;
|
||||
#else
|
||||
u32 low, high;
|
||||
#endif
|
||||
} l;
|
||||
} rl, rm, rn, rh, a0, b0;
|
||||
u64 c;
|
||||
|
||||
a0.ll = a;
|
||||
b0.ll = b;
|
||||
|
||||
rl.ll = mul_u32_u32(a0.l.low, b0.l.low);
|
||||
rm.ll = mul_u32_u32(a0.l.low, b0.l.high);
|
||||
rn.ll = mul_u32_u32(a0.l.high, b0.l.low);
|
||||
rh.ll = mul_u32_u32(a0.l.high, b0.l.high);
|
||||
|
||||
/*
|
||||
* Each of these lines computes a 64-bit intermediate result into "c",
|
||||
* starting at bits 32-95. The low 32-bits go into the result of the
|
||||
* multiplication, the high 32-bits are carried into the next step.
|
||||
*/
|
||||
rl.l.high = c = (u64)rl.l.high + rm.l.low + rn.l.low;
|
||||
rh.l.low = c = (c >> 32) + rm.l.high + rn.l.high + rh.l.low;
|
||||
rh.l.high = (c >> 32) + rh.l.high;
|
||||
|
||||
/*
|
||||
* The 128-bit result of the multiplication is in rl.ll and rh.ll,
|
||||
* shift it right and throw away the high part of the result.
|
||||
*/
|
||||
if (shift == 0)
|
||||
return rl.ll;
|
||||
if (shift < 64)
|
||||
return (rl.ll >> shift) | (rh.ll << (64 - shift));
|
||||
return rh.ll >> (shift & 63);
|
||||
}
|
||||
#endif /* mul_u64_u64_shr */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_MATH64_H */
|
||||
|
457
include/linux/min_heap.h
Normal file
457
include/linux/min_heap.h
Normal file
@ -0,0 +1,457 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_MIN_HEAP_H
|
||||
#define _LINUX_MIN_HEAP_H
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* Data structure to hold a min-heap.
|
||||
* @nr: Number of elements currently in the heap.
|
||||
* @size: Maximum number of elements that can be held in current storage.
|
||||
* @data: Pointer to the start of array holding the heap elements.
|
||||
* @preallocated: Start of the static preallocated array holding the heap elements.
|
||||
*/
|
||||
#define MIN_HEAP_PREALLOCATED(_type, _name, _nr) \
|
||||
struct _name { \
|
||||
size_t nr; \
|
||||
size_t size; \
|
||||
_type *data; \
|
||||
_type preallocated[_nr]; \
|
||||
}
|
||||
|
||||
#define DEFINE_MIN_HEAP(_type, _name) MIN_HEAP_PREALLOCATED(_type, _name, 0)
|
||||
|
||||
typedef DEFINE_MIN_HEAP(char, min_heap_char) min_heap_char;
|
||||
|
||||
#define __minheap_cast(_heap) (typeof((_heap)->data[0]) *)
|
||||
#define __minheap_obj_size(_heap) sizeof((_heap)->data[0])
|
||||
|
||||
/**
|
||||
* struct min_heap_callbacks - Data/functions to customise the min_heap.
|
||||
* @less: Partial order function for this heap.
|
||||
* @swp: Swap elements function.
|
||||
*/
|
||||
struct min_heap_callbacks {
|
||||
bool (*less)(const void *lhs, const void *rhs, void *args);
|
||||
void (*swp)(void *lhs, void *rhs, void *args);
|
||||
};
|
||||
|
||||
/**
|
||||
* is_aligned - is this pointer & size okay for word-wide copying?
|
||||
* @base: pointer to data
|
||||
* @size: size of each element
|
||||
* @align: required alignment (typically 4 or 8)
|
||||
*
|
||||
* Returns true if elements can be copied using word loads and stores.
|
||||
* The size must be a multiple of the alignment, and the base address must
|
||||
* be if we do not have CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS.
|
||||
*
|
||||
* For some reason, gcc doesn't know to optimize "if (a & mask || b & mask)"
|
||||
* to "if ((a | b) & mask)", so we do that by hand.
|
||||
*/
|
||||
__attribute_const__ __always_inline
|
||||
static bool is_aligned(const void *base, size_t size, unsigned char align)
|
||||
{
|
||||
unsigned char lsbits = (unsigned char)size;
|
||||
|
||||
(void)base;
|
||||
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||
lsbits |= (unsigned char)(uintptr_t)base;
|
||||
#endif
|
||||
return (lsbits & (align - 1)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* swap_words_32 - swap two elements in 32-bit chunks
|
||||
* @a: pointer to the first element to swap
|
||||
* @b: pointer to the second element to swap
|
||||
* @n: element size (must be a multiple of 4)
|
||||
*
|
||||
* Exchange the two objects in memory. This exploits base+index addressing,
|
||||
* which basically all CPUs have, to minimize loop overhead computations.
|
||||
*
|
||||
* For some reason, on x86 gcc 7.3.0 adds a redundant test of n at the
|
||||
* bottom of the loop, even though the zero flag is still valid from the
|
||||
* subtract (since the intervening mov instructions don't alter the flags).
|
||||
* Gcc 8.1.0 doesn't have that problem.
|
||||
*/
|
||||
static __always_inline
|
||||
void swap_words_32(void *a, void *b, size_t n)
|
||||
{
|
||||
do {
|
||||
u32 t = *(u32 *)(a + (n -= 4));
|
||||
*(u32 *)(a + n) = *(u32 *)(b + n);
|
||||
*(u32 *)(b + n) = t;
|
||||
} while (n);
|
||||
}
|
||||
|
||||
/**
|
||||
* swap_words_64 - swap two elements in 64-bit chunks
|
||||
* @a: pointer to the first element to swap
|
||||
* @b: pointer to the second element to swap
|
||||
* @n: element size (must be a multiple of 8)
|
||||
*
|
||||
* Exchange the two objects in memory. This exploits base+index
|
||||
* addressing, which basically all CPUs have, to minimize loop overhead
|
||||
* computations.
|
||||
*
|
||||
* We'd like to use 64-bit loads if possible. If they're not, emulating
|
||||
* one requires base+index+4 addressing which x86 has but most other
|
||||
* processors do not. If CONFIG_64BIT, we definitely have 64-bit loads,
|
||||
* but it's possible to have 64-bit loads without 64-bit pointers (e.g.
|
||||
* x32 ABI). Are there any cases the kernel needs to worry about?
|
||||
*/
|
||||
static __always_inline
|
||||
void swap_words_64(void *a, void *b, size_t n)
|
||||
{
|
||||
do {
|
||||
#ifdef CONFIG_64BIT
|
||||
u64 t = *(u64 *)(a + (n -= 8));
|
||||
*(u64 *)(a + n) = *(u64 *)(b + n);
|
||||
*(u64 *)(b + n) = t;
|
||||
#else
|
||||
/* Use two 32-bit transfers to avoid base+index+4 addressing */
|
||||
u32 t = *(u32 *)(a + (n -= 4));
|
||||
*(u32 *)(a + n) = *(u32 *)(b + n);
|
||||
*(u32 *)(b + n) = t;
|
||||
|
||||
t = *(u32 *)(a + (n -= 4));
|
||||
*(u32 *)(a + n) = *(u32 *)(b + n);
|
||||
*(u32 *)(b + n) = t;
|
||||
#endif
|
||||
} while (n);
|
||||
}
|
||||
|
||||
/**
|
||||
* swap_bytes - swap two elements a byte at a time
|
||||
* @a: pointer to the first element to swap
|
||||
* @b: pointer to the second element to swap
|
||||
* @n: element size
|
||||
*
|
||||
* This is the fallback if alignment doesn't allow using larger chunks.
|
||||
*/
|
||||
static __always_inline
|
||||
void swap_bytes(void *a, void *b, size_t n)
|
||||
{
|
||||
do {
|
||||
char t = ((char *)a)[--n];
|
||||
((char *)a)[n] = ((char *)b)[n];
|
||||
((char *)b)[n] = t;
|
||||
} while (n);
|
||||
}
|
||||
|
||||
/*
|
||||
* The values are arbitrary as long as they can't be confused with
|
||||
* a pointer, but small integers make for the smallest compare
|
||||
* instructions.
|
||||
*/
|
||||
#define SWAP_WORDS_64 ((void (*)(void *, void *, void *))0)
|
||||
#define SWAP_WORDS_32 ((void (*)(void *, void *, void *))1)
|
||||
#define SWAP_BYTES ((void (*)(void *, void *, void *))2)
|
||||
|
||||
/*
|
||||
* Selects the appropriate swap function based on the element size.
|
||||
*/
|
||||
static __always_inline
|
||||
void *select_swap_func(const void *base, size_t size)
|
||||
{
|
||||
if (is_aligned(base, size, 8))
|
||||
return SWAP_WORDS_64;
|
||||
else if (is_aligned(base, size, 4))
|
||||
return SWAP_WORDS_32;
|
||||
else
|
||||
return SWAP_BYTES;
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
void do_swap(void *a, void *b, size_t size, void (*swap_func)(void *lhs, void *rhs, void *args),
|
||||
void *priv)
|
||||
{
|
||||
if (swap_func == SWAP_WORDS_64)
|
||||
swap_words_64(a, b, size);
|
||||
else if (swap_func == SWAP_WORDS_32)
|
||||
swap_words_32(a, b, size);
|
||||
else if (swap_func == SWAP_BYTES)
|
||||
swap_bytes(a, b, size);
|
||||
else
|
||||
swap_func(a, b, priv);
|
||||
}
|
||||
|
||||
/**
|
||||
* parent - given the offset of the child, find the offset of the parent.
|
||||
* @i: the offset of the heap element whose parent is sought. Non-zero.
|
||||
* @lsbit: a precomputed 1-bit mask, equal to "size & -size"
|
||||
* @size: size of each element
|
||||
*
|
||||
* In terms of array indexes, the parent of element j = @i/@size is simply
|
||||
* (j-1)/2. But when working in byte offsets, we can't use implicit
|
||||
* truncation of integer divides.
|
||||
*
|
||||
* Fortunately, we only need one bit of the quotient, not the full divide.
|
||||
* @size has a least significant bit. That bit will be clear if @i is
|
||||
* an even multiple of @size, and set if it's an odd multiple.
|
||||
*
|
||||
* Logically, we're doing "if (i & lsbit) i -= size;", but since the
|
||||
* branch is unpredictable, it's done with a bit of clever branch-free
|
||||
* code instead.
|
||||
*/
|
||||
__attribute_const__ __always_inline
|
||||
static size_t parent(size_t i, unsigned int lsbit, size_t size)
|
||||
{
|
||||
i -= size;
|
||||
i -= size & -(i & lsbit);
|
||||
return i / 2;
|
||||
}
|
||||
|
||||
/* Initialize a min-heap. */
|
||||
static __always_inline
|
||||
void __min_heap_init_inline(min_heap_char *heap, void *data, int size)
|
||||
{
|
||||
heap->nr = 0;
|
||||
heap->size = size;
|
||||
if (data)
|
||||
heap->data = data;
|
||||
else
|
||||
heap->data = heap->preallocated;
|
||||
}
|
||||
|
||||
#define min_heap_init_inline(_heap, _data, _size) \
|
||||
__min_heap_init_inline((min_heap_char *)_heap, _data, _size)
|
||||
|
||||
/* Get the minimum element from the heap. */
|
||||
static __always_inline
|
||||
void *__min_heap_peek_inline(struct min_heap_char *heap)
|
||||
{
|
||||
return heap->nr ? heap->data : NULL;
|
||||
}
|
||||
|
||||
#define min_heap_peek_inline(_heap) \
|
||||
(__minheap_cast(_heap) __min_heap_peek_inline((min_heap_char *)_heap))
|
||||
|
||||
/* Check if the heap is full. */
|
||||
static __always_inline
|
||||
bool __min_heap_full_inline(min_heap_char *heap)
|
||||
{
|
||||
return heap->nr == heap->size;
|
||||
}
|
||||
|
||||
#define min_heap_full_inline(_heap) \
|
||||
__min_heap_full_inline((min_heap_char *)_heap)
|
||||
|
||||
/* Sift the element at pos down the heap. */
|
||||
static __always_inline
|
||||
void __min_heap_sift_down_inline(min_heap_char *heap, int pos, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args)
|
||||
{
|
||||
const unsigned long lsbit = elem_size & -elem_size;
|
||||
void *data = heap->data;
|
||||
void (*swp)(void *lhs, void *rhs, void *args) = func->swp;
|
||||
/* pre-scale counters for performance */
|
||||
size_t a = pos * elem_size;
|
||||
size_t b, c, d;
|
||||
size_t n = heap->nr * elem_size;
|
||||
|
||||
if (!swp)
|
||||
swp = select_swap_func(data, elem_size);
|
||||
|
||||
/* Find the sift-down path all the way to the leaves. */
|
||||
for (b = a; c = 2 * b + elem_size, (d = c + elem_size) < n;)
|
||||
b = func->less(data + c, data + d, args) ? c : d;
|
||||
|
||||
/* Special case for the last leaf with no sibling. */
|
||||
if (d == n)
|
||||
b = c;
|
||||
|
||||
/* Backtrack to the correct location. */
|
||||
while (b != a && func->less(data + a, data + b, args))
|
||||
b = parent(b, lsbit, elem_size);
|
||||
|
||||
/* Shift the element into its correct place. */
|
||||
c = b;
|
||||
while (b != a) {
|
||||
b = parent(b, lsbit, elem_size);
|
||||
do_swap(data + b, data + c, elem_size, swp, args);
|
||||
}
|
||||
}
|
||||
|
||||
#define min_heap_sift_down_inline(_heap, _pos, _func, _args) \
|
||||
__min_heap_sift_down_inline((min_heap_char *)_heap, _pos, __minheap_obj_size(_heap), \
|
||||
_func, _args)
|
||||
|
||||
/* Sift up ith element from the heap, O(log2(nr)). */
|
||||
static __always_inline
|
||||
void __min_heap_sift_up_inline(min_heap_char *heap, size_t elem_size, size_t idx,
|
||||
const struct min_heap_callbacks *func, void *args)
|
||||
{
|
||||
const unsigned long lsbit = elem_size & -elem_size;
|
||||
void *data = heap->data;
|
||||
void (*swp)(void *lhs, void *rhs, void *args) = func->swp;
|
||||
/* pre-scale counters for performance */
|
||||
size_t a = idx * elem_size, b;
|
||||
|
||||
if (!swp)
|
||||
swp = select_swap_func(data, elem_size);
|
||||
|
||||
while (a) {
|
||||
b = parent(a, lsbit, elem_size);
|
||||
if (func->less(data + b, data + a, args))
|
||||
break;
|
||||
do_swap(data + a, data + b, elem_size, swp, args);
|
||||
a = b;
|
||||
}
|
||||
}
|
||||
|
||||
#define min_heap_sift_up_inline(_heap, _idx, _func, _args) \
|
||||
__min_heap_sift_up_inline((min_heap_char *)_heap, __minheap_obj_size(_heap), _idx, \
|
||||
_func, _args)
|
||||
|
||||
/* Floyd's approach to heapification that is O(nr). */
|
||||
static __always_inline
|
||||
void __min_heapify_all_inline(min_heap_char *heap, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = heap->nr / 2 - 1; i >= 0; i--)
|
||||
__min_heap_sift_down_inline(heap, i, elem_size, func, args);
|
||||
}
|
||||
|
||||
#define min_heapify_all_inline(_heap, _func, _args) \
|
||||
__min_heapify_all_inline((min_heap_char *)_heap, __minheap_obj_size(_heap), _func, _args)
|
||||
|
||||
/* Remove minimum element from the heap, O(log2(nr)). */
|
||||
static __always_inline
|
||||
bool __min_heap_pop_inline(min_heap_char *heap, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args)
|
||||
{
|
||||
void *data = heap->data;
|
||||
|
||||
if (WARN_ONCE(heap->nr <= 0, "Popping an empty heap"))
|
||||
return false;
|
||||
|
||||
/* Place last element at the root (position 0) and then sift down. */
|
||||
heap->nr--;
|
||||
memcpy(data, data + (heap->nr * elem_size), elem_size);
|
||||
__min_heap_sift_down_inline(heap, 0, elem_size, func, args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define min_heap_pop_inline(_heap, _func, _args) \
|
||||
__min_heap_pop_inline((min_heap_char *)_heap, __minheap_obj_size(_heap), _func, _args)
|
||||
|
||||
/*
|
||||
* Remove the minimum element and then push the given element. The
|
||||
* implementation performs 1 sift (O(log2(nr))) and is therefore more
|
||||
* efficient than a pop followed by a push that does 2.
|
||||
*/
|
||||
static __always_inline
|
||||
void __min_heap_pop_push_inline(min_heap_char *heap, const void *element, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args)
|
||||
{
|
||||
memcpy(heap->data, element, elem_size);
|
||||
__min_heap_sift_down_inline(heap, 0, elem_size, func, args);
|
||||
}
|
||||
|
||||
#define min_heap_pop_push_inline(_heap, _element, _func, _args) \
|
||||
__min_heap_pop_push_inline((min_heap_char *)_heap, _element, __minheap_obj_size(_heap), \
|
||||
_func, _args)
|
||||
|
||||
/* Push an element on to the heap, O(log2(nr)). */
|
||||
static __always_inline
|
||||
bool __min_heap_push_inline(min_heap_char *heap, const void *element, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args)
|
||||
{
|
||||
void *data = heap->data;
|
||||
int pos;
|
||||
|
||||
if (WARN_ONCE(heap->nr >= heap->size, "Pushing on a full heap"))
|
||||
return false;
|
||||
|
||||
/* Place at the end of data. */
|
||||
pos = heap->nr;
|
||||
memcpy(data + (pos * elem_size), element, elem_size);
|
||||
heap->nr++;
|
||||
|
||||
/* Sift child at pos up. */
|
||||
__min_heap_sift_up_inline(heap, elem_size, pos, func, args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define min_heap_push_inline(_heap, _element, _func, _args) \
|
||||
__min_heap_push_inline((min_heap_char *)_heap, _element, __minheap_obj_size(_heap), \
|
||||
_func, _args)
|
||||
|
||||
/* Remove ith element from the heap, O(log2(nr)). */
|
||||
static __always_inline
|
||||
bool __min_heap_del_inline(min_heap_char *heap, size_t elem_size, size_t idx,
|
||||
const struct min_heap_callbacks *func, void *args)
|
||||
{
|
||||
void *data = heap->data;
|
||||
void (*swp)(void *lhs, void *rhs, void *args) = func->swp;
|
||||
|
||||
if (WARN_ONCE(heap->nr <= 0, "Popping an empty heap"))
|
||||
return false;
|
||||
|
||||
if (!swp)
|
||||
swp = select_swap_func(data, elem_size);
|
||||
|
||||
/* Place last element at the root (position 0) and then sift down. */
|
||||
heap->nr--;
|
||||
if (idx == heap->nr)
|
||||
return true;
|
||||
do_swap(data + (idx * elem_size), data + (heap->nr * elem_size), elem_size, swp, args);
|
||||
__min_heap_sift_up_inline(heap, elem_size, idx, func, args);
|
||||
__min_heap_sift_down_inline(heap, idx, elem_size, func, args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define min_heap_del_inline(_heap, _idx, _func, _args) \
|
||||
__min_heap_del_inline((min_heap_char *)_heap, __minheap_obj_size(_heap), _idx, \
|
||||
_func, _args)
|
||||
|
||||
void __min_heap_init(min_heap_char *heap, void *data, int size);
|
||||
void *__min_heap_peek(struct min_heap_char *heap);
|
||||
bool __min_heap_full(min_heap_char *heap);
|
||||
void __min_heap_sift_down(min_heap_char *heap, int pos, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args);
|
||||
void __min_heap_sift_up(min_heap_char *heap, size_t elem_size, size_t idx,
|
||||
const struct min_heap_callbacks *func, void *args);
|
||||
void __min_heapify_all(min_heap_char *heap, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args);
|
||||
bool __min_heap_pop(min_heap_char *heap, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args);
|
||||
void __min_heap_pop_push(min_heap_char *heap, const void *element, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args);
|
||||
bool __min_heap_push(min_heap_char *heap, const void *element, size_t elem_size,
|
||||
const struct min_heap_callbacks *func, void *args);
|
||||
bool __min_heap_del(min_heap_char *heap, size_t elem_size, size_t idx,
|
||||
const struct min_heap_callbacks *func, void *args);
|
||||
|
||||
#define min_heap_init(_heap, _data, _size) \
|
||||
__min_heap_init((min_heap_char *)_heap, _data, _size)
|
||||
#define min_heap_peek(_heap) \
|
||||
(__minheap_cast(_heap) __min_heap_peek((min_heap_char *)_heap))
|
||||
#define min_heap_full(_heap) \
|
||||
__min_heap_full((min_heap_char *)_heap)
|
||||
#define min_heap_sift_down(_heap, _pos, _func, _args) \
|
||||
__min_heap_sift_down((min_heap_char *)_heap, _pos, __minheap_obj_size(_heap), _func, _args)
|
||||
#define min_heap_sift_up(_heap, _idx, _func, _args) \
|
||||
__min_heap_sift_up((min_heap_char *)_heap, __minheap_obj_size(_heap), _idx, _func, _args)
|
||||
#define min_heapify_all(_heap, _func, _args) \
|
||||
__min_heapify_all((min_heap_char *)_heap, __minheap_obj_size(_heap), _func, _args)
|
||||
#define min_heap_pop(_heap, _func, _args) \
|
||||
__min_heap_pop((min_heap_char *)_heap, __minheap_obj_size(_heap), _func, _args)
|
||||
#define min_heap_pop_push(_heap, _element, _func, _args) \
|
||||
__min_heap_pop_push((min_heap_char *)_heap, _element, __minheap_obj_size(_heap), \
|
||||
_func, _args)
|
||||
#define min_heap_push(_heap, _element, _func, _args) \
|
||||
__min_heap_push((min_heap_char *)_heap, _element, __minheap_obj_size(_heap), _func, _args)
|
||||
#define min_heap_del(_heap, _idx, _func, _args) \
|
||||
__min_heap_del((min_heap_char *)_heap, __minheap_obj_size(_heap), _idx, _func, _args)
|
||||
|
||||
#endif /* _LINUX_MIN_HEAP_H */
|
@ -3,6 +3,8 @@
|
||||
#define _TOOLS_LINUX_MM_H
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct sysinfo {
|
||||
|
@ -38,11 +38,8 @@
|
||||
* Magic nums for obj red zoning.
|
||||
* Placed in the first word before and the first word after an obj.
|
||||
*/
|
||||
#define RED_INACTIVE 0x09F911029D74E35BULL /* when obj is inactive */
|
||||
#define RED_ACTIVE 0xD84156C5635688C0ULL /* when obj is active */
|
||||
|
||||
#define SLUB_RED_INACTIVE 0xbb
|
||||
#define SLUB_RED_ACTIVE 0xcc
|
||||
#define SLUB_RED_INACTIVE 0xbb /* when obj is inactive */
|
||||
#define SLUB_RED_ACTIVE 0xcc /* when obj is active */
|
||||
|
||||
/* ...and for poisoning */
|
||||
#define POISON_INUSE 0x5a /* for use-uninitialised poisoning */
|
||||
@ -52,12 +49,6 @@
|
||||
/********** arch/$ARCH/mm/init.c **********/
|
||||
#define POISON_FREE_INITMEM 0xcc
|
||||
|
||||
/********** arch/ia64/hp/common/sba_iommu.c **********/
|
||||
/*
|
||||
* arch/ia64/hp/common/sba_iommu.c uses a 16-byte poison string with a
|
||||
* value of "SBAIOMMU POISON\0" for spill-over poisoning.
|
||||
*/
|
||||
|
||||
/********** fs/jbd/journal.c **********/
|
||||
#define JBD_POISON_FREE 0x5b
|
||||
#define JBD2_POISON_FREE 0x5c
|
||||
|
@ -9,7 +9,9 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/math64.h>
|
||||
|
||||
#ifdef SYS_getrandom
|
||||
static inline int getrandom(void *buf, size_t buflen, unsigned int flags)
|
||||
@ -67,4 +69,24 @@ static inline u32 get_random_u32_below(u32 ceil)
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 __get_random_u32_below(u32 ceil)
|
||||
{
|
||||
return get_random_u32_below(ceil);
|
||||
}
|
||||
|
||||
static inline u64 get_random_u64_below(u64 ceil)
|
||||
{
|
||||
if (ceil <= 1)
|
||||
return 0;
|
||||
if (ceil <= U32_MAX)
|
||||
return get_random_u32_below(ceil);
|
||||
|
||||
for (;;) {
|
||||
u64 rand = get_random_u64();
|
||||
u64 mult = ceil * rand;
|
||||
if (likely(mult >= -ceil % ceil))
|
||||
return mul_u64_u64_shr(ceil, rand, 64);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _LINUX_RANDOM_H */
|
||||
|
@ -60,10 +60,13 @@
|
||||
#define PF_FROZEN 0x00010000 /* frozen for system suspend */
|
||||
#define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */
|
||||
#define PF_KSWAPD 0x00040000 /* I am kswapd */
|
||||
#define PF_MEMALLOC_NOFS 0x00040000 /* All allocations inherit GFP_NOFS. See memalloc_nfs_save() */
|
||||
#define PF_MEMALLOC_NOIO 0x00080000 /* Allocating memory without IO involved */
|
||||
#define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */
|
||||
#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
|
||||
#define PF_RANDOMIZE 0x00400000 /* randomize virtual address space */
|
||||
#define PF_MEMALLOC_NORECLAIM 0x00800000 /* All allocation requests will clear __GFP_DIRECT_RECLAIM */
|
||||
#define PF_MEMALLOC_NOWARN 0x01000000 /* All allocation requests will inherit __GFP_NOWARN */
|
||||
#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */
|
||||
#define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */
|
||||
#define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */
|
||||
@ -94,6 +97,11 @@ struct task_struct {
|
||||
struct signal_struct {
|
||||
struct rw_semaphore exec_update_lock;
|
||||
} *signal, _signal;
|
||||
|
||||
struct {
|
||||
u64 sum_exec_runtime;
|
||||
u64 exec_start;
|
||||
} se;
|
||||
};
|
||||
|
||||
extern __thread struct task_struct *current;
|
||||
|
6
include/linux/sched/sysctl.h
Normal file
6
include/linux/sched/sysctl.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __TOOLS_LINUX_SCHED_SYSCTL_H
|
||||
#define __TOOLS_LINUX_SCHED_SYSCTL_H
|
||||
|
||||
#define sysctl_hung_task_timeout_secs (HZ * 10)
|
||||
|
||||
#endif /* __TOOLS_LINUX_SCHED_SYSCTL_H */
|
@ -18,6 +18,7 @@
|
||||
#define alloc_hooks(_do, ...) _do
|
||||
|
||||
#define ARCH_KMALLOC_MINALIGN 16
|
||||
#define ARCH_SLAB_MINALIGN 16
|
||||
#define KMALLOC_MAX_SIZE SIZE_MAX
|
||||
|
||||
#define MAX_PAGE_ORDER 10
|
||||
@ -102,12 +103,17 @@ static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)
|
||||
((size) != 0 && (n) > SIZE_MAX / (size) \
|
||||
? NULL : kmalloc((n) * (size), flags))
|
||||
|
||||
#define kvcalloc(n, size, flags) kvmalloc_array(n, size, flags|__GFP_ZERO)
|
||||
|
||||
#define kvmalloc_array_noprof(...) kvmalloc_array(__VA_ARGS__)
|
||||
|
||||
#define kcalloc(n, size, flags) kmalloc_array(n, size, flags|__GFP_ZERO)
|
||||
|
||||
#define kfree(p) free((void *) p)
|
||||
#define kzfree(p) free((void *) p)
|
||||
|
||||
#define kvmalloc(size, flags) kmalloc(size, flags)
|
||||
#define kvmalloc_noprof(size, flags) kmalloc(size, flags)
|
||||
#define kvzalloc(size, flags) kzalloc(size, flags)
|
||||
#define kvfree(p) kfree(p)
|
||||
|
||||
@ -271,6 +277,8 @@ static inline void *vmalloc(unsigned long size)
|
||||
return __vmalloc(size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
#define vmalloc_noprof(...) vmalloc(__VA_ARGS__)
|
||||
|
||||
static inline void *vzalloc(unsigned long size)
|
||||
{
|
||||
return __vmalloc(size, GFP_KERNEL|__GFP_ZERO);
|
||||
|
@ -1,6 +1,17 @@
|
||||
#ifndef __TOOLS_LINUX_SRCU_H
|
||||
#define __TOOLS_LINUX_SRCU_H
|
||||
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
#define NUM_ACTIVE_RCU_POLL_OLDSTATE 2
|
||||
|
||||
typedef void (*rcu_callback_t)(struct rcu_head *head);
|
||||
|
||||
static inline struct urcu_gp_poll_state get_state_synchronize_rcu()
|
||||
{
|
||||
return start_poll_synchronize_rcu();
|
||||
}
|
||||
|
||||
struct srcu_struct {
|
||||
};
|
||||
|
||||
@ -11,25 +22,33 @@ static inline int srcu_read_lock(struct srcu_struct *ssp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool poll_state_synchronize_srcu(struct srcu_struct *ssp, unsigned long cookie)
|
||||
static inline bool poll_state_synchronize_srcu(struct srcu_struct *ssp, struct urcu_gp_poll_state cookie)
|
||||
{
|
||||
return false;
|
||||
return poll_state_synchronize_rcu(cookie);
|
||||
}
|
||||
|
||||
static inline unsigned long start_poll_synchronize_srcu(struct srcu_struct *ssp)
|
||||
static inline struct urcu_gp_poll_state start_poll_synchronize_srcu(struct srcu_struct *ssp)
|
||||
{
|
||||
return 0;
|
||||
return start_poll_synchronize_rcu();
|
||||
}
|
||||
|
||||
static inline unsigned long get_state_synchronize_srcu(struct srcu_struct *ssp)
|
||||
static inline struct urcu_gp_poll_state get_state_synchronize_srcu(struct srcu_struct *ssp)
|
||||
{
|
||||
return 0;
|
||||
return get_state_synchronize_rcu();
|
||||
}
|
||||
|
||||
static inline void synchronize_srcu_expedited(struct srcu_struct *ssp) {}
|
||||
|
||||
static inline void srcu_barrier(struct srcu_struct *ssp) {}
|
||||
|
||||
static inline void cleanup_srcu_struct(struct srcu_struct *ssp) {}
|
||||
|
||||
static inline void call_srcu(struct srcu_struct *ssp, struct rcu_head *rhp,
|
||||
rcu_callback_t func)
|
||||
{
|
||||
call_rcu(rhp, func);
|
||||
}
|
||||
|
||||
static inline int init_srcu_struct(struct srcu_struct *ssp)
|
||||
{
|
||||
return 0;
|
||||
|
85
include/linux/string_choices.h
Normal file
85
include/linux/string_choices.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_STRING_CHOICES_H_
|
||||
#define _LINUX_STRING_CHOICES_H_
|
||||
|
||||
/*
|
||||
* Here provide a series of helpers in the str_$TRUE_$FALSE format (you can
|
||||
* also expand some helpers as needed), where $TRUE and $FALSE are their
|
||||
* corresponding literal strings. These helpers can be used in the printing
|
||||
* and also in other places where constant strings are required. Using these
|
||||
* helpers offers the following benefits:
|
||||
* 1) Reducing the hardcoding of strings, which makes the code more elegant
|
||||
* through these simple literal-meaning helpers.
|
||||
* 2) Unifying the output, which prevents the same string from being printed
|
||||
* in various forms, such as enable/disable, enabled/disabled, en/dis.
|
||||
* 3) Deduping by the linker, which results in a smaller binary file.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
static inline const char *str_enable_disable(bool v)
|
||||
{
|
||||
return v ? "enable" : "disable";
|
||||
}
|
||||
#define str_disable_enable(v) str_enable_disable(!(v))
|
||||
|
||||
static inline const char *str_enabled_disabled(bool v)
|
||||
{
|
||||
return v ? "enabled" : "disabled";
|
||||
}
|
||||
#define str_disabled_enabled(v) str_enabled_disabled(!(v))
|
||||
|
||||
static inline const char *str_hi_lo(bool v)
|
||||
{
|
||||
return v ? "hi" : "lo";
|
||||
}
|
||||
#define str_lo_hi(v) str_hi_lo(!(v))
|
||||
|
||||
static inline const char *str_high_low(bool v)
|
||||
{
|
||||
return v ? "high" : "low";
|
||||
}
|
||||
#define str_low_high(v) str_high_low(!(v))
|
||||
|
||||
static inline const char *str_read_write(bool v)
|
||||
{
|
||||
return v ? "read" : "write";
|
||||
}
|
||||
#define str_write_read(v) str_read_write(!(v))
|
||||
|
||||
static inline const char *str_on_off(bool v)
|
||||
{
|
||||
return v ? "on" : "off";
|
||||
}
|
||||
#define str_off_on(v) str_on_off(!(v))
|
||||
|
||||
static inline const char *str_yes_no(bool v)
|
||||
{
|
||||
return v ? "yes" : "no";
|
||||
}
|
||||
#define str_no_yes(v) str_yes_no(!(v))
|
||||
|
||||
static inline const char *str_up_down(bool v)
|
||||
{
|
||||
return v ? "up" : "down";
|
||||
}
|
||||
#define str_down_up(v) str_up_down(!(v))
|
||||
|
||||
static inline const char *str_true_false(bool v)
|
||||
{
|
||||
return v ? "true" : "false";
|
||||
}
|
||||
#define str_false_true(v) str_true_false(!(v))
|
||||
|
||||
/**
|
||||
* str_plural - Return the simple pluralization based on English counts
|
||||
* @num: Number used for deciding pluralization
|
||||
*
|
||||
* If @num is 1, returns empty string, otherwise returns "s".
|
||||
*/
|
||||
static inline const char *str_plural(size_t num)
|
||||
{
|
||||
return num == 1 ? "" : "s";
|
||||
}
|
||||
|
||||
#endif
|
7
include/linux/swap.h
Normal file
7
include/linux/swap.h
Normal file
@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_SWAP_H
|
||||
#define _LINUX_SWAP_H
|
||||
|
||||
static inline void mm_account_reclaimed_pages(unsigned long pages) {}
|
||||
|
||||
#endif /* _LINUX_SWAP_H */
|
@ -44,6 +44,20 @@ static inline struct timespec timespec_trunc(struct timespec t, unsigned gran)
|
||||
return t;
|
||||
}
|
||||
|
||||
static inline void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec)
|
||||
{
|
||||
while (nsec >= NSEC_PER_SEC) {
|
||||
nsec -= NSEC_PER_SEC;
|
||||
++sec;
|
||||
}
|
||||
while (nsec < 0) {
|
||||
nsec += NSEC_PER_SEC;
|
||||
--sec;
|
||||
}
|
||||
ts->tv_sec = sec;
|
||||
ts->tv_nsec = nsec;
|
||||
}
|
||||
|
||||
#define ns_to_timespec64 ns_to_timespec
|
||||
#define timespec64_to_ns timespec_to_ns
|
||||
#define timespec64_trunc timespec_trunc
|
||||
|
@ -37,6 +37,8 @@ typedef unsigned gfp_t;
|
||||
#define __GFP_NOWARN 0
|
||||
#define __GFP_NORETRY 0
|
||||
#define __GFP_NOFAIL 0
|
||||
#define __GFP_ACCOUNT 0
|
||||
#define __GFP_RECLAIMABLE 0
|
||||
#define __GFP_ZERO 1
|
||||
#define GFP_KERNEL 2
|
||||
|
||||
|
1
include/linux/unaligned.h
Normal file
1
include/linux/unaligned.h
Normal file
@ -0,0 +1 @@
|
||||
#include <asm/unaligned.h>
|
@ -96,6 +96,7 @@ do { \
|
||||
#define wait_event_freezable(wq, condition) ({wait_event(wq, condition); 0; })
|
||||
#define wait_event_killable(wq, condition) ({wait_event(wq, condition); 0; })
|
||||
#define wait_event_interruptible(wq, condition) ({wait_event(wq, condition); 0; })
|
||||
#define wait_event_state(wq, condition, state) ({wait_event(wq, condition); 0; })
|
||||
|
||||
#define __wait_event_timeout(wq, condition, timeout) \
|
||||
___wait_event(wq, ___wait_cond_timeout(condition), \
|
||||
|
@ -151,7 +151,7 @@ extern void workqueue_set_max_active(struct workqueue_struct *wq,
|
||||
extern bool current_is_workqueue_rescuer(void);
|
||||
extern bool workqueue_congested(int cpu, struct workqueue_struct *wq);
|
||||
extern unsigned int work_busy(struct work_struct *work);
|
||||
extern __printf(1, 2) void set_worker_desc(const char *fmt, ...);
|
||||
static inline __printf(1, 2) void set_worker_desc(const char *fmt, ...) {}
|
||||
extern void print_worker_info(const char *log_lvl, struct task_struct *task);
|
||||
extern void show_workqueue_state(void);
|
||||
|
||||
|
@ -47,6 +47,12 @@ struct xattr_handler {
|
||||
size_t size, int flags);
|
||||
};
|
||||
|
||||
static inline bool xattr_handler_can_list(const struct xattr_handler *handler,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
return handler && (!handler->list || handler->list(dentry));
|
||||
}
|
||||
|
||||
const char *xattr_full_name(const struct xattr_handler *, const char *);
|
||||
|
||||
struct xattr {
|
||||
|
@ -184,11 +184,6 @@ invalid:
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
#define acl_for_each_entry(acl, acl_e) \
|
||||
for (acl_e = acl->a_entries; \
|
||||
acl_e < acl->a_entries + acl->a_count; \
|
||||
acl_e++)
|
||||
|
||||
/*
|
||||
* Convert from in-memory to filesystem representation.
|
||||
*/
|
||||
@ -199,11 +194,11 @@ bch2_acl_to_xattr(struct btree_trans *trans,
|
||||
{
|
||||
struct bkey_i_xattr *xattr;
|
||||
bch_acl_header *acl_header;
|
||||
const struct posix_acl_entry *acl_e;
|
||||
const struct posix_acl_entry *acl_e, *pe;
|
||||
void *outptr;
|
||||
unsigned nr_short = 0, nr_long = 0, acl_len, u64s;
|
||||
|
||||
acl_for_each_entry(acl, acl_e) {
|
||||
FOREACH_ACL_ENTRY(acl_e, acl, pe) {
|
||||
switch (acl_e->e_tag) {
|
||||
case ACL_USER:
|
||||
case ACL_GROUP:
|
||||
@ -241,7 +236,7 @@ bch2_acl_to_xattr(struct btree_trans *trans,
|
||||
|
||||
outptr = (void *) acl_header + sizeof(*acl_header);
|
||||
|
||||
acl_for_each_entry(acl, acl_e) {
|
||||
FOREACH_ACL_ENTRY(acl_e, acl, pe) {
|
||||
bch_acl_entry *entry = outptr;
|
||||
|
||||
entry->e_tag = cpu_to_le16(acl_e->e_tag);
|
||||
@ -272,16 +267,19 @@ bch2_acl_to_xattr(struct btree_trans *trans,
|
||||
return xattr;
|
||||
}
|
||||
|
||||
struct posix_acl *bch2_get_acl(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, int type)
|
||||
struct posix_acl *bch2_get_acl(struct inode *vinode, int type, bool rcu)
|
||||
{
|
||||
struct bch_inode_info *inode = to_bch_ei(dentry->d_inode);
|
||||
struct bch_inode_info *inode = to_bch_ei(vinode);
|
||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||
struct bch_hash_info hash = bch2_hash_info_init(c, &inode->ei_inode);
|
||||
struct xattr_search_key search = X_SEARCH(acl_to_xattr_type(type), "", 0);
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
struct btree_iter iter = { NULL };
|
||||
struct posix_acl *acl = NULL;
|
||||
|
||||
if (rcu)
|
||||
return ERR_PTR(-ECHILD);
|
||||
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
retry:
|
||||
bch2_trans_begin(trans);
|
||||
|
||||
@ -346,7 +344,6 @@ int bch2_set_acl(struct mnt_idmap *idmap,
|
||||
{
|
||||
struct bch_inode_info *inode = to_bch_ei(dentry->d_inode);
|
||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
struct btree_iter inode_iter = { NULL };
|
||||
struct bch_inode_unpacked inode_u;
|
||||
struct posix_acl *acl;
|
||||
@ -354,11 +351,12 @@ int bch2_set_acl(struct mnt_idmap *idmap,
|
||||
int ret;
|
||||
|
||||
mutex_lock(&inode->ei_update_lock);
|
||||
struct btree_trans *trans = bch2_trans_get(c);
|
||||
retry:
|
||||
bch2_trans_begin(trans);
|
||||
acl = _acl;
|
||||
|
||||
ret = bch2_subvol_is_ro_trans(trans, inode->ei_subvol) ?:
|
||||
ret = bch2_subvol_is_ro_trans(trans, inode->ei_inum.subvol) ?:
|
||||
bch2_inode_peek(trans, &inode_iter, &inode_u, inode_inum(inode),
|
||||
BTREE_ITER_intent);
|
||||
if (ret)
|
||||
@ -394,8 +392,8 @@ btree_err:
|
||||
|
||||
set_cached_acl(&inode->v, type, acl);
|
||||
err:
|
||||
mutex_unlock(&inode->ei_update_lock);
|
||||
bch2_trans_put(trans);
|
||||
mutex_unlock(&inode->ei_update_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ void bch2_acl_to_text(struct printbuf *, const void *, size_t);
|
||||
|
||||
#ifdef CONFIG_BCACHEFS_POSIX_ACL
|
||||
|
||||
struct posix_acl *bch2_get_acl(struct mnt_idmap *, struct dentry *, int);
|
||||
struct posix_acl *bch2_get_acl(struct inode *, int, bool);
|
||||
|
||||
int bch2_set_acl_trans(struct btree_trans *, subvol_inum,
|
||||
struct bch_inode_unpacked *,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,15 +8,13 @@
|
||||
#include "debug.h"
|
||||
#include "super.h"
|
||||
|
||||
enum bch_validate_flags;
|
||||
|
||||
/* How out of date a pointer gen is allowed to be: */
|
||||
#define BUCKET_GC_GEN_MAX 96U
|
||||
|
||||
static inline bool bch2_dev_bucket_exists(struct bch_fs *c, struct bpos pos)
|
||||
{
|
||||
rcu_read_lock();
|
||||
struct bch_dev *ca = bch2_dev_rcu(c, pos.inode);
|
||||
struct bch_dev *ca = bch2_dev_rcu_noerror(c, pos.inode);
|
||||
bool ret = ca && bucket_valid(ca, pos.offset);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
@ -82,6 +80,14 @@ static inline bool bucket_data_type_mismatch(enum bch_data_type bucket,
|
||||
bucket_data_type(bucket) != bucket_data_type(ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* It is my general preference to use unsigned types for unsigned quantities -
|
||||
* however, these helpers are used in disk accounting calculations run by
|
||||
* triggers where the output will be negated and added to an s64. unsigned is
|
||||
* right out even though all these quantities will fit in 32 bits, since it
|
||||
* won't be sign extended correctly; u64 will negate "correctly", but s64 is the
|
||||
* simpler option here.
|
||||
*/
|
||||
static inline s64 bch2_bucket_sectors_total(struct bch_alloc_v4 a)
|
||||
{
|
||||
return a.stripe_sectors + a.dirty_sectors + a.cached_sectors;
|
||||
@ -125,7 +131,7 @@ static inline enum bch_data_type alloc_data_type(struct bch_alloc_v4 a,
|
||||
if (a.stripe)
|
||||
return data_type == BCH_DATA_parity ? data_type : BCH_DATA_stripe;
|
||||
if (bch2_bucket_sectors_dirty(a))
|
||||
return data_type;
|
||||
return bucket_data_type(data_type);
|
||||
if (a.cached_sectors)
|
||||
return BCH_DATA_cached;
|
||||
if (BCH_ALLOC_V4_NEED_DISCARD(&a))
|
||||
@ -142,7 +148,9 @@ static inline void alloc_data_type_set(struct bch_alloc_v4 *a, enum bch_data_typ
|
||||
|
||||
static inline u64 alloc_lru_idx_read(struct bch_alloc_v4 a)
|
||||
{
|
||||
return a.data_type == BCH_DATA_cached ? a.io_time[READ] : 0;
|
||||
return a.data_type == BCH_DATA_cached
|
||||
? a.io_time[READ] & LRU_TIME_MAX
|
||||
: 0;
|
||||
}
|
||||
|
||||
#define DATA_TYPES_MOVABLE \
|
||||
@ -158,6 +166,9 @@ static inline bool data_type_movable(enum bch_data_type type)
|
||||
static inline u64 alloc_lru_idx_fragmentation(struct bch_alloc_v4 a,
|
||||
struct bch_dev *ca)
|
||||
{
|
||||
if (a.data_type >= BCH_DATA_NR)
|
||||
return 0;
|
||||
|
||||
if (!data_type_movable(a.data_type) ||
|
||||
!bch2_bucket_sectors_fragmented(ca, a))
|
||||
return 0;
|
||||
@ -166,8 +177,8 @@ static inline u64 alloc_lru_idx_fragmentation(struct bch_alloc_v4 a,
|
||||
* avoid overflowing LRU_TIME_BITS on a corrupted fs, when
|
||||
* bucket_sectors_dirty is (much) bigger than bucket_size
|
||||
*/
|
||||
u64 d = min(bch2_bucket_sectors_dirty(a),
|
||||
ca->mi.bucket_size);
|
||||
u64 d = min_t(s64, bch2_bucket_sectors_dirty(a),
|
||||
ca->mi.bucket_size);
|
||||
|
||||
return div_u64(d * (1ULL << 31), ca->mi.bucket_size);
|
||||
}
|
||||
@ -206,7 +217,8 @@ static inline void set_alloc_v4_u64s(struct bkey_i_alloc_v4 *a)
|
||||
struct bkey_i_alloc_v4 *
|
||||
bch2_trans_start_alloc_update_noupdate(struct btree_trans *, struct btree_iter *, struct bpos);
|
||||
struct bkey_i_alloc_v4 *
|
||||
bch2_trans_start_alloc_update(struct btree_trans *, struct bpos);
|
||||
bch2_trans_start_alloc_update(struct btree_trans *, struct bpos,
|
||||
enum btree_iter_update_trigger_flags);
|
||||
|
||||
void __bch2_alloc_to_v4(struct bkey_s_c, struct bch_alloc_v4 *);
|
||||
|
||||
@ -231,52 +243,52 @@ struct bkey_i_alloc_v4 *bch2_alloc_to_v4_mut(struct btree_trans *, struct bkey_s
|
||||
|
||||
int bch2_bucket_io_time_reset(struct btree_trans *, unsigned, size_t, int);
|
||||
|
||||
int bch2_alloc_v1_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_alloc_v2_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_alloc_v3_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_alloc_v4_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_alloc_v1_validate(struct bch_fs *, struct bkey_s_c,
|
||||
struct bkey_validate_context);
|
||||
int bch2_alloc_v2_validate(struct bch_fs *, struct bkey_s_c,
|
||||
struct bkey_validate_context);
|
||||
int bch2_alloc_v3_validate(struct bch_fs *, struct bkey_s_c,
|
||||
struct bkey_validate_context);
|
||||
int bch2_alloc_v4_validate(struct bch_fs *, struct bkey_s_c,
|
||||
struct bkey_validate_context);
|
||||
void bch2_alloc_v4_swab(struct bkey_s);
|
||||
void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
#define bch2_bkey_ops_alloc ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_alloc_v1_invalid, \
|
||||
.key_validate = bch2_alloc_v1_validate, \
|
||||
.val_to_text = bch2_alloc_to_text, \
|
||||
.trigger = bch2_trigger_alloc, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_alloc_v2 ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_alloc_v2_invalid, \
|
||||
.key_validate = bch2_alloc_v2_validate, \
|
||||
.val_to_text = bch2_alloc_to_text, \
|
||||
.trigger = bch2_trigger_alloc, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_alloc_v3 ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_alloc_v3_invalid, \
|
||||
.key_validate = bch2_alloc_v3_validate, \
|
||||
.val_to_text = bch2_alloc_to_text, \
|
||||
.trigger = bch2_trigger_alloc, \
|
||||
.min_val_size = 16, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_alloc_v4 ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_alloc_v4_invalid, \
|
||||
.key_validate = bch2_alloc_v4_validate, \
|
||||
.val_to_text = bch2_alloc_to_text, \
|
||||
.swab = bch2_alloc_v4_swab, \
|
||||
.trigger = bch2_trigger_alloc, \
|
||||
.min_val_size = 48, \
|
||||
})
|
||||
|
||||
int bch2_bucket_gens_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_bucket_gens_validate(struct bch_fs *, struct bkey_s_c,
|
||||
struct bkey_validate_context);
|
||||
void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
#define bch2_bkey_ops_bucket_gens ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_bucket_gens_invalid, \
|
||||
.key_validate = bch2_bucket_gens_validate, \
|
||||
.val_to_text = bch2_bucket_gens_to_text, \
|
||||
})
|
||||
|
||||
@ -297,8 +309,11 @@ int bch2_alloc_key_to_dev_counters(struct btree_trans *, struct bch_dev *,
|
||||
int bch2_trigger_alloc(struct btree_trans *, enum btree_id, unsigned,
|
||||
struct bkey_s_c, struct bkey_s,
|
||||
enum btree_iter_update_trigger_flags);
|
||||
|
||||
int bch2_check_discard_freespace_key(struct btree_trans *, struct btree_iter *, u8 *, bool);
|
||||
int bch2_check_alloc_info(struct bch_fs *);
|
||||
int bch2_check_alloc_to_lru_refs(struct bch_fs *);
|
||||
void bch2_dev_do_discards(struct bch_dev *);
|
||||
void bch2_do_discards(struct bch_fs *);
|
||||
|
||||
static inline u64 should_invalidate_buckets(struct bch_dev *ca,
|
||||
@ -313,6 +328,7 @@ static inline u64 should_invalidate_buckets(struct bch_dev *ca,
|
||||
return clamp_t(s64, want_free - free, 0, u.d[BCH_DATA_cached].buckets);
|
||||
}
|
||||
|
||||
void bch2_dev_do_invalidates(struct bch_dev *);
|
||||
void bch2_do_invalidates(struct bch_fs *);
|
||||
|
||||
static inline struct bch_backpointer *alloc_v4_backpointers(struct bch_alloc_v4 *a)
|
||||
@ -329,6 +345,7 @@ static inline const struct bch_backpointer *alloc_v4_backpointers_c(const struct
|
||||
|
||||
int bch2_dev_freespace_init(struct bch_fs *, struct bch_dev *, u64, u64);
|
||||
int bch2_fs_freespace_init(struct bch_fs *);
|
||||
int bch2_dev_remove_alloc(struct bch_fs *, struct bch_dev *);
|
||||
|
||||
void bch2_recalc_capacity(struct bch_fs *);
|
||||
u64 bch2_min_rw_member_capacity(struct bch_fs *);
|
||||
@ -336,7 +353,9 @@ u64 bch2_min_rw_member_capacity(struct bch_fs *);
|
||||
void bch2_dev_allocator_remove(struct bch_fs *, struct bch_dev *);
|
||||
void bch2_dev_allocator_add(struct bch_fs *, struct bch_dev *);
|
||||
|
||||
void bch2_fs_allocator_background_exit(struct bch_fs *);
|
||||
void bch2_dev_allocator_background_exit(struct bch_dev *);
|
||||
void bch2_dev_allocator_background_init(struct bch_dev *);
|
||||
|
||||
void bch2_fs_allocator_background_init(struct bch_fs *);
|
||||
|
||||
#endif /* _BCACHEFS_ALLOC_BACKGROUND_H */
|
||||
|
@ -58,7 +58,7 @@ LE32_BITMASK(BCH_ALLOC_V3_NEED_INC_GEN,struct bch_alloc_v3, flags, 1, 2)
|
||||
|
||||
struct bch_alloc_v4 {
|
||||
struct bch_val v;
|
||||
__u64 journal_seq;
|
||||
__u64 journal_seq_nonempty;
|
||||
__u32 flags;
|
||||
__u8 gen;
|
||||
__u8 oldest_gen;
|
||||
@ -69,7 +69,8 @@ struct bch_alloc_v4 {
|
||||
__u64 io_time[2];
|
||||
__u32 stripe;
|
||||
__u32 nr_external_backpointers;
|
||||
__u64 fragmentation_lru;
|
||||
/* end of fields in original version of alloc_v4 */
|
||||
__u64 journal_seq_empty;
|
||||
__u32 stripe_sectors;
|
||||
__u32 pad;
|
||||
} __packed __aligned(8);
|
||||
|
@ -107,14 +107,10 @@ void __bch2_open_bucket_put(struct bch_fs *c, struct open_bucket *ob)
|
||||
return;
|
||||
}
|
||||
|
||||
percpu_down_read(&c->mark_lock);
|
||||
spin_lock(&ob->lock);
|
||||
|
||||
ob->valid = false;
|
||||
ob->data_type = 0;
|
||||
|
||||
spin_unlock(&ob->lock);
|
||||
percpu_up_read(&c->mark_lock);
|
||||
|
||||
spin_lock(&c->freelist_lock);
|
||||
bch2_open_bucket_hash_remove(c, ob);
|
||||
@ -131,14 +127,14 @@ void __bch2_open_bucket_put(struct bch_fs *c, struct open_bucket *ob)
|
||||
|
||||
void bch2_open_bucket_write_error(struct bch_fs *c,
|
||||
struct open_buckets *obs,
|
||||
unsigned dev)
|
||||
unsigned dev, int err)
|
||||
{
|
||||
struct open_bucket *ob;
|
||||
unsigned i;
|
||||
|
||||
open_bucket_for_each(c, obs, ob, i)
|
||||
if (ob->dev == dev && ob->ec)
|
||||
bch2_ec_bucket_cancel(c, ob);
|
||||
bch2_ec_bucket_cancel(c, ob, err);
|
||||
}
|
||||
|
||||
static struct open_bucket *bch2_open_bucket_alloc(struct bch_fs *c)
|
||||
@ -156,12 +152,24 @@ static struct open_bucket *bch2_open_bucket_alloc(struct bch_fs *c)
|
||||
return ob;
|
||||
}
|
||||
|
||||
static inline bool is_superblock_bucket(struct bch_fs *c, struct bch_dev *ca, u64 b)
|
||||
{
|
||||
if (c->curr_recovery_pass > BCH_RECOVERY_PASS_trans_mark_dev_sbs)
|
||||
return false;
|
||||
|
||||
return bch2_is_superblock_bucket(ca, b);
|
||||
}
|
||||
|
||||
static void open_bucket_free_unused(struct bch_fs *c, struct open_bucket *ob)
|
||||
{
|
||||
BUG_ON(c->open_buckets_partial_nr >=
|
||||
ARRAY_SIZE(c->open_buckets_partial));
|
||||
|
||||
spin_lock(&c->freelist_lock);
|
||||
rcu_read_lock();
|
||||
bch2_dev_rcu(c, ob->dev)->nr_partial_buckets++;
|
||||
rcu_read_unlock();
|
||||
|
||||
ob->on_partial_list = true;
|
||||
c->open_buckets_partial[c->open_buckets_partial_nr++] =
|
||||
ob - c->open_buckets;
|
||||
@ -171,70 +179,50 @@ static void open_bucket_free_unused(struct bch_fs *c, struct open_bucket *ob)
|
||||
closure_wake_up(&c->freelist_wait);
|
||||
}
|
||||
|
||||
/* _only_ for allocating the journal on a new device: */
|
||||
long bch2_bucket_alloc_new_fs(struct bch_dev *ca)
|
||||
static inline bool may_alloc_bucket(struct bch_fs *c,
|
||||
struct bpos bucket,
|
||||
struct bucket_alloc_state *s)
|
||||
{
|
||||
while (ca->new_fs_bucket_idx < ca->mi.nbuckets) {
|
||||
u64 b = ca->new_fs_bucket_idx++;
|
||||
|
||||
if (!is_superblock_bucket(ca, b) &&
|
||||
(!ca->buckets_nouse || !test_bit(b, ca->buckets_nouse)))
|
||||
return b;
|
||||
if (bch2_bucket_is_open(c, bucket.inode, bucket.offset)) {
|
||||
s->skipped_open++;
|
||||
return false;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline unsigned open_buckets_reserved(enum bch_watermark watermark)
|
||||
{
|
||||
switch (watermark) {
|
||||
case BCH_WATERMARK_interior_updates:
|
||||
return 0;
|
||||
case BCH_WATERMARK_reclaim:
|
||||
return OPEN_BUCKETS_COUNT / 6;
|
||||
case BCH_WATERMARK_btree:
|
||||
case BCH_WATERMARK_btree_copygc:
|
||||
return OPEN_BUCKETS_COUNT / 4;
|
||||
case BCH_WATERMARK_copygc:
|
||||
return OPEN_BUCKETS_COUNT / 3;
|
||||
default:
|
||||
return OPEN_BUCKETS_COUNT / 2;
|
||||
u64 journal_seq_ready =
|
||||
bch2_bucket_journal_seq_ready(&c->buckets_waiting_for_journal,
|
||||
bucket.inode, bucket.offset);
|
||||
if (journal_seq_ready > c->journal.flushed_seq_ondisk) {
|
||||
if (journal_seq_ready > c->journal.flushing_seq)
|
||||
s->need_journal_commit++;
|
||||
s->skipped_need_journal_commit++;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bch2_bucket_nocow_is_locked(&c->nocow_locks, bucket)) {
|
||||
s->skipped_nocow++;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
|
||||
u64 bucket,
|
||||
u64 bucket, u8 gen,
|
||||
enum bch_watermark watermark,
|
||||
const struct bch_alloc_v4 *a,
|
||||
struct bucket_alloc_state *s,
|
||||
struct closure *cl)
|
||||
{
|
||||
struct open_bucket *ob;
|
||||
if (unlikely(is_superblock_bucket(c, ca, bucket)))
|
||||
return NULL;
|
||||
|
||||
if (unlikely(ca->buckets_nouse && test_bit(bucket, ca->buckets_nouse))) {
|
||||
s->skipped_nouse++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bch2_bucket_is_open(c, ca->dev_idx, bucket)) {
|
||||
s->skipped_open++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bch2_bucket_needs_journal_commit(&c->buckets_waiting_for_journal,
|
||||
c->journal.flushed_seq_ondisk, ca->dev_idx, bucket)) {
|
||||
s->skipped_need_journal_commit++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bch2_bucket_nocow_is_locked(&c->nocow_locks, POS(ca->dev_idx, bucket))) {
|
||||
s->skipped_nocow++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spin_lock(&c->freelist_lock);
|
||||
|
||||
if (unlikely(c->open_buckets_nr_free <= open_buckets_reserved(watermark))) {
|
||||
if (unlikely(c->open_buckets_nr_free <= bch2_open_buckets_reserved(watermark))) {
|
||||
if (cl)
|
||||
closure_wait(&c->open_buckets_wait, cl);
|
||||
|
||||
@ -250,14 +238,13 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ob = bch2_open_bucket_alloc(c);
|
||||
struct open_bucket *ob = bch2_open_bucket_alloc(c);
|
||||
|
||||
spin_lock(&ob->lock);
|
||||
|
||||
ob->valid = true;
|
||||
ob->sectors_free = ca->mi.bucket_size;
|
||||
ob->dev = ca->dev_idx;
|
||||
ob->gen = a->gen;
|
||||
ob->gen = gen;
|
||||
ob->bucket = bucket;
|
||||
spin_unlock(&ob->lock);
|
||||
|
||||
@ -272,111 +259,29 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
|
||||
}
|
||||
|
||||
static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bch_dev *ca,
|
||||
enum bch_watermark watermark, u64 free_entry,
|
||||
enum bch_watermark watermark,
|
||||
struct bucket_alloc_state *s,
|
||||
struct bkey_s_c freespace_k,
|
||||
struct btree_iter *freespace_iter,
|
||||
struct closure *cl)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter iter = { NULL };
|
||||
struct bkey_s_c k;
|
||||
struct open_bucket *ob;
|
||||
struct bch_alloc_v4 a_convert;
|
||||
const struct bch_alloc_v4 *a;
|
||||
u64 b = free_entry & ~(~0ULL << 56);
|
||||
unsigned genbits = free_entry >> 56;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
int ret;
|
||||
u64 b = freespace_iter->pos.offset & ~(~0ULL << 56);
|
||||
|
||||
if (b < ca->mi.first_bucket || b >= ca->mi.nbuckets) {
|
||||
prt_printf(&buf, "freespace btree has bucket outside allowed range %u-%llu\n"
|
||||
" freespace key ",
|
||||
ca->mi.first_bucket, ca->mi.nbuckets);
|
||||
bch2_bkey_val_to_text(&buf, c, freespace_k);
|
||||
bch2_trans_inconsistent(trans, "%s", buf.buf);
|
||||
ob = ERR_PTR(-EIO);
|
||||
goto err;
|
||||
}
|
||||
if (!may_alloc_bucket(c, POS(ca->dev_idx, b), s))
|
||||
return NULL;
|
||||
|
||||
k = bch2_bkey_get_iter(trans, &iter,
|
||||
BTREE_ID_alloc, POS(ca->dev_idx, b),
|
||||
BTREE_ITER_cached);
|
||||
ret = bkey_err(k);
|
||||
if (ret) {
|
||||
ob = ERR_PTR(ret);
|
||||
goto err;
|
||||
}
|
||||
u8 gen;
|
||||
int ret = bch2_check_discard_freespace_key(trans, freespace_iter, &gen, true);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
a = bch2_alloc_to_v4(k, &a_convert);
|
||||
|
||||
if (a->data_type != BCH_DATA_free) {
|
||||
if (c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_alloc_info) {
|
||||
ob = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
prt_printf(&buf, "non free bucket in freespace btree\n"
|
||||
" freespace key ");
|
||||
bch2_bkey_val_to_text(&buf, c, freespace_k);
|
||||
prt_printf(&buf, "\n ");
|
||||
bch2_bkey_val_to_text(&buf, c, k);
|
||||
bch2_trans_inconsistent(trans, "%s", buf.buf);
|
||||
ob = ERR_PTR(-EIO);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (genbits != (alloc_freespace_genbits(*a) >> 56) &&
|
||||
c->curr_recovery_pass > BCH_RECOVERY_PASS_check_alloc_info) {
|
||||
prt_printf(&buf, "bucket in freespace btree with wrong genbits (got %u should be %llu)\n"
|
||||
" freespace key ",
|
||||
genbits, alloc_freespace_genbits(*a) >> 56);
|
||||
bch2_bkey_val_to_text(&buf, c, freespace_k);
|
||||
prt_printf(&buf, "\n ");
|
||||
bch2_bkey_val_to_text(&buf, c, k);
|
||||
bch2_trans_inconsistent(trans, "%s", buf.buf);
|
||||
ob = ERR_PTR(-EIO);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_extents_to_backpointers) {
|
||||
struct bch_backpointer bp;
|
||||
struct bpos bp_pos = POS_MIN;
|
||||
|
||||
ret = bch2_get_next_backpointer(trans, ca, POS(ca->dev_idx, b), -1,
|
||||
&bp_pos, &bp,
|
||||
BTREE_ITER_nopreserve);
|
||||
if (ret) {
|
||||
ob = ERR_PTR(ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!bkey_eq(bp_pos, POS_MAX)) {
|
||||
/*
|
||||
* Bucket may have data in it - we don't call
|
||||
* bc2h_trans_inconnsistent() because fsck hasn't
|
||||
* finished yet
|
||||
*/
|
||||
ob = NULL;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ob = __try_alloc_bucket(c, ca, b, watermark, a, s, cl);
|
||||
if (!ob)
|
||||
bch2_set_btree_iter_dontneed(&iter);
|
||||
err:
|
||||
if (iter.path)
|
||||
bch2_set_btree_iter_dontneed(&iter);
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
printbuf_exit(&buf);
|
||||
return ob;
|
||||
return __try_alloc_bucket(c, ca, b, gen, watermark, s, cl);
|
||||
}
|
||||
|
||||
/*
|
||||
* This path is for before the freespace btree is initialized:
|
||||
*
|
||||
* If ca->new_fs_bucket_idx is nonzero, we haven't yet marked superblock &
|
||||
* journal buckets - journal buckets will be < ca->new_fs_bucket_idx
|
||||
*/
|
||||
static noinline struct open_bucket *
|
||||
bch2_bucket_alloc_early(struct btree_trans *trans,
|
||||
@ -385,10 +290,11 @@ bch2_bucket_alloc_early(struct btree_trans *trans,
|
||||
struct bucket_alloc_state *s,
|
||||
struct closure *cl)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter iter, citer;
|
||||
struct bkey_s_c k, ck;
|
||||
struct open_bucket *ob = NULL;
|
||||
u64 first_bucket = max_t(u64, ca->mi.first_bucket, ca->new_fs_bucket_idx);
|
||||
u64 first_bucket = ca->mi.first_bucket;
|
||||
u64 *dev_alloc_cursor = &ca->alloc_cursor[s->btree_bitmap];
|
||||
u64 alloc_start = max(first_bucket, *dev_alloc_cursor);
|
||||
u64 alloc_cursor = alloc_start;
|
||||
@ -411,10 +317,6 @@ again:
|
||||
if (bkey_ge(k.k->p, POS(ca->dev_idx, ca->mi.nbuckets)))
|
||||
break;
|
||||
|
||||
if (ca->new_fs_bucket_idx &&
|
||||
is_superblock_bucket(ca, k.k->p.offset))
|
||||
continue;
|
||||
|
||||
if (s->btree_bitmap != BTREE_BITMAP_ANY &&
|
||||
s->btree_bitmap != bch2_dev_btree_bitmap_marked_sectors(ca,
|
||||
bucket_to_sector(ca, bucket), ca->mi.bucket_size)) {
|
||||
@ -448,7 +350,10 @@ again:
|
||||
|
||||
s->buckets_seen++;
|
||||
|
||||
ob = __try_alloc_bucket(trans->c, ca, k.k->p.offset, watermark, a, s, cl);
|
||||
ob = may_alloc_bucket(c, k.k->p, s)
|
||||
? __try_alloc_bucket(c, ca, k.k->p.offset, a->gen,
|
||||
watermark, s, cl)
|
||||
: NULL;
|
||||
next:
|
||||
bch2_set_btree_iter_dontneed(&citer);
|
||||
bch2_trans_iter_exit(trans, &citer);
|
||||
@ -485,26 +390,21 @@ static struct open_bucket *bch2_bucket_alloc_freelist(struct btree_trans *trans,
|
||||
u64 alloc_start = max_t(u64, ca->mi.first_bucket, READ_ONCE(*dev_alloc_cursor));
|
||||
u64 alloc_cursor = alloc_start;
|
||||
int ret;
|
||||
|
||||
BUG_ON(ca->new_fs_bucket_idx);
|
||||
again:
|
||||
for_each_btree_key_norestart(trans, iter, BTREE_ID_freespace,
|
||||
POS(ca->dev_idx, alloc_cursor), 0, k, ret) {
|
||||
if (k.k->p.inode != ca->dev_idx)
|
||||
break;
|
||||
|
||||
for (alloc_cursor = max(alloc_cursor, bkey_start_offset(k.k));
|
||||
alloc_cursor < k.k->p.offset;
|
||||
alloc_cursor++) {
|
||||
ret = btree_trans_too_many_iters(trans);
|
||||
if (ret) {
|
||||
ob = ERR_PTR(ret);
|
||||
break;
|
||||
}
|
||||
for_each_btree_key_max_norestart(trans, iter, BTREE_ID_freespace,
|
||||
POS(ca->dev_idx, alloc_cursor),
|
||||
POS(ca->dev_idx, U64_MAX),
|
||||
0, k, ret) {
|
||||
/*
|
||||
* peek normally dosen't trim extents - they can span iter.pos,
|
||||
* which is not what we want here:
|
||||
*/
|
||||
iter.k.size = iter.k.p.offset - iter.pos.offset;
|
||||
|
||||
while (iter.k.size) {
|
||||
s->buckets_seen++;
|
||||
|
||||
u64 bucket = alloc_cursor & ~(~0ULL << 56);
|
||||
u64 bucket = iter.pos.offset & ~(~0ULL << 56);
|
||||
if (s->btree_bitmap != BTREE_BITMAP_ANY &&
|
||||
s->btree_bitmap != bch2_dev_btree_bitmap_marked_sectors(ca,
|
||||
bucket_to_sector(ca, bucket), ca->mi.bucket_size)) {
|
||||
@ -513,32 +413,36 @@ again:
|
||||
goto fail;
|
||||
|
||||
bucket = sector_to_bucket(ca,
|
||||
round_up(bucket_to_sector(ca, bucket) + 1,
|
||||
round_up(bucket_to_sector(ca, bucket + 1),
|
||||
1ULL << ca->mi.btree_bitmap_shift));
|
||||
u64 genbits = alloc_cursor >> 56;
|
||||
alloc_cursor = bucket | (genbits << 56);
|
||||
alloc_cursor = bucket|(iter.pos.offset & (~0ULL << 56));
|
||||
|
||||
if (alloc_cursor > k.k->p.offset)
|
||||
bch2_btree_iter_set_pos(&iter, POS(ca->dev_idx, alloc_cursor));
|
||||
bch2_btree_iter_set_pos(&iter, POS(ca->dev_idx, alloc_cursor));
|
||||
s->skipped_mi_btree_bitmap++;
|
||||
continue;
|
||||
goto next;
|
||||
}
|
||||
|
||||
ob = try_alloc_bucket(trans, ca, watermark,
|
||||
alloc_cursor, s, k, cl);
|
||||
ob = try_alloc_bucket(trans, ca, watermark, s, &iter, cl);
|
||||
if (ob) {
|
||||
if (!IS_ERR(ob))
|
||||
*dev_alloc_cursor = iter.pos.offset;
|
||||
bch2_set_btree_iter_dontneed(&iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.k.size--;
|
||||
iter.pos.offset++;
|
||||
}
|
||||
next:
|
||||
if (ob || ret)
|
||||
break;
|
||||
}
|
||||
fail:
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
|
||||
if (!ob && ret)
|
||||
BUG_ON(ob && ret);
|
||||
|
||||
if (ret)
|
||||
ob = ERR_PTR(ret);
|
||||
|
||||
if (!ob && alloc_start > ca->mi.first_bucket) {
|
||||
@ -546,8 +450,6 @@ fail:
|
||||
goto again;
|
||||
}
|
||||
|
||||
*dev_alloc_cursor = alloc_cursor;
|
||||
|
||||
return ob;
|
||||
}
|
||||
|
||||
@ -597,6 +499,7 @@ static noinline void trace_bucket_alloc2(struct bch_fs *c, struct bch_dev *ca,
|
||||
* @watermark: how important is this allocation?
|
||||
* @data_type: BCH_DATA_journal, btree, user...
|
||||
* @cl: if not NULL, closure to be used to wait if buckets not available
|
||||
* @nowait: if true, do not wait for buckets to become available
|
||||
* @usage: for secondarily also returning the current device usage
|
||||
*
|
||||
* Returns: an open_bucket on success, or an ERR_PTR() on failure.
|
||||
@ -606,6 +509,7 @@ static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
|
||||
enum bch_watermark watermark,
|
||||
enum bch_data_type data_type,
|
||||
struct closure *cl,
|
||||
bool nowait,
|
||||
struct bch_dev_usage *usage)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
@ -615,21 +519,25 @@ static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
|
||||
struct bucket_alloc_state s = {
|
||||
.btree_bitmap = data_type == BCH_DATA_btree,
|
||||
};
|
||||
bool waiting = false;
|
||||
bool waiting = nowait;
|
||||
again:
|
||||
bch2_dev_usage_read_fast(ca, usage);
|
||||
avail = dev_buckets_free(ca, *usage, watermark);
|
||||
|
||||
if (usage->d[BCH_DATA_need_discard].buckets > avail)
|
||||
bch2_do_discards(c);
|
||||
bch2_dev_do_discards(ca);
|
||||
|
||||
if (usage->d[BCH_DATA_need_gc_gens].buckets > avail)
|
||||
bch2_gc_gens_async(c);
|
||||
|
||||
if (should_invalidate_buckets(ca, *usage))
|
||||
bch2_do_invalidates(c);
|
||||
bch2_dev_do_invalidates(ca);
|
||||
|
||||
if (!avail) {
|
||||
if (watermark > BCH_WATERMARK_normal &&
|
||||
c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_allocations)
|
||||
goto alloc;
|
||||
|
||||
if (cl && !waiting) {
|
||||
closure_wait(&c->freelist_wait, cl);
|
||||
waiting = true;
|
||||
@ -649,7 +557,7 @@ alloc:
|
||||
? bch2_bucket_alloc_freelist(trans, ca, watermark, &s, cl)
|
||||
: bch2_bucket_alloc_early(trans, ca, watermark, &s, cl);
|
||||
|
||||
if (s.skipped_need_journal_commit * 2 > avail)
|
||||
if (s.need_journal_commit * 2 > avail)
|
||||
bch2_journal_flush_async(&c->journal, NULL);
|
||||
|
||||
if (!ob && s.btree_bitmap != BTREE_BITMAP_ANY) {
|
||||
@ -689,9 +597,9 @@ struct open_bucket *bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca,
|
||||
struct bch_dev_usage usage;
|
||||
struct open_bucket *ob;
|
||||
|
||||
bch2_trans_do(c, NULL, NULL, 0,
|
||||
bch2_trans_do(c,
|
||||
PTR_ERR_OR_ZERO(ob = bch2_bucket_alloc_trans(trans, ca, watermark,
|
||||
data_type, cl, &usage)));
|
||||
data_type, cl, false, &usage)));
|
||||
return ob;
|
||||
}
|
||||
|
||||
@ -712,9 +620,9 @@ struct dev_alloc_list bch2_dev_alloc_list(struct bch_fs *c,
|
||||
unsigned i;
|
||||
|
||||
for_each_set_bit(i, devs->d, BCH_SB_MEMBERS_MAX)
|
||||
ret.devs[ret.nr++] = i;
|
||||
ret.data[ret.nr++] = i;
|
||||
|
||||
bubble_sort(ret.devs, ret.nr, dev_stripe_cmp);
|
||||
bubble_sort(ret.data, ret.nr, dev_stripe_cmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -723,7 +631,7 @@ static inline void bch2_dev_stripe_increment_inlined(struct bch_dev *ca,
|
||||
struct bch_dev_usage *usage)
|
||||
{
|
||||
u64 *v = stripe->next_alloc + ca->dev_idx;
|
||||
u64 free_space = dev_buckets_available(ca, BCH_WATERMARK_normal);
|
||||
u64 free_space = __dev_buckets_available(ca, *usage, BCH_WATERMARK_normal);
|
||||
u64 free_space_inv = free_space
|
||||
? div64_u64(1ULL << 48, free_space)
|
||||
: 1ULL << 48;
|
||||
@ -754,7 +662,6 @@ static int add_new_bucket(struct bch_fs *c,
|
||||
unsigned nr_replicas,
|
||||
unsigned *nr_effective,
|
||||
bool *have_cache,
|
||||
unsigned flags,
|
||||
struct open_bucket *ob)
|
||||
{
|
||||
unsigned durability = ob_dev(c, ob)->mi.durability;
|
||||
@ -781,24 +688,19 @@ int bch2_bucket_alloc_set_trans(struct btree_trans *trans,
|
||||
unsigned nr_replicas,
|
||||
unsigned *nr_effective,
|
||||
bool *have_cache,
|
||||
unsigned flags,
|
||||
enum bch_write_flags flags,
|
||||
enum bch_data_type data_type,
|
||||
enum bch_watermark watermark,
|
||||
struct closure *cl)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct dev_alloc_list devs_sorted =
|
||||
bch2_dev_alloc_list(c, stripe, devs_may_alloc);
|
||||
int ret = -BCH_ERR_insufficient_devices;
|
||||
|
||||
BUG_ON(*nr_effective >= nr_replicas);
|
||||
|
||||
for (unsigned i = 0; i < devs_sorted.nr; i++) {
|
||||
struct bch_dev_usage usage;
|
||||
struct open_bucket *ob;
|
||||
|
||||
unsigned dev = devs_sorted.devs[i];
|
||||
struct bch_dev *ca = bch2_dev_tryget_noerror(c, dev);
|
||||
struct dev_alloc_list devs_sorted = bch2_dev_alloc_list(c, stripe, devs_may_alloc);
|
||||
darray_for_each(devs_sorted, i) {
|
||||
struct bch_dev *ca = bch2_dev_tryget_noerror(c, *i);
|
||||
if (!ca)
|
||||
continue;
|
||||
|
||||
@ -807,7 +709,9 @@ int bch2_bucket_alloc_set_trans(struct btree_trans *trans,
|
||||
continue;
|
||||
}
|
||||
|
||||
ob = bch2_bucket_alloc_trans(trans, ca, watermark, data_type, cl, &usage);
|
||||
struct bch_dev_usage usage;
|
||||
struct open_bucket *ob = bch2_bucket_alloc_trans(trans, ca, watermark, data_type,
|
||||
cl, flags & BCH_WRITE_alloc_nowait, &usage);
|
||||
if (!IS_ERR(ob))
|
||||
bch2_dev_stripe_increment_inlined(ca, stripe, &usage);
|
||||
bch2_dev_put(ca);
|
||||
@ -821,7 +725,7 @@ int bch2_bucket_alloc_set_trans(struct btree_trans *trans,
|
||||
|
||||
if (add_new_bucket(c, ptrs, devs_may_alloc,
|
||||
nr_replicas, nr_effective,
|
||||
have_cache, flags, ob)) {
|
||||
have_cache, ob)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
@ -847,14 +751,10 @@ static int bucket_alloc_from_stripe(struct btree_trans *trans,
|
||||
unsigned *nr_effective,
|
||||
bool *have_cache,
|
||||
enum bch_watermark watermark,
|
||||
unsigned flags,
|
||||
enum bch_write_flags flags,
|
||||
struct closure *cl)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct dev_alloc_list devs_sorted;
|
||||
struct ec_stripe_head *h;
|
||||
struct open_bucket *ob;
|
||||
unsigned i, ec_idx;
|
||||
int ret = 0;
|
||||
|
||||
if (nr_replicas < 2)
|
||||
@ -863,34 +763,32 @@ static int bucket_alloc_from_stripe(struct btree_trans *trans,
|
||||
if (ec_open_bucket(c, ptrs))
|
||||
return 0;
|
||||
|
||||
h = bch2_ec_stripe_head_get(trans, target, 0, nr_replicas - 1, watermark, cl);
|
||||
struct ec_stripe_head *h =
|
||||
bch2_ec_stripe_head_get(trans, target, 0, nr_replicas - 1, watermark, cl);
|
||||
if (IS_ERR(h))
|
||||
return PTR_ERR(h);
|
||||
if (!h)
|
||||
return 0;
|
||||
|
||||
devs_sorted = bch2_dev_alloc_list(c, &wp->stripe, devs_may_alloc);
|
||||
|
||||
for (i = 0; i < devs_sorted.nr; i++)
|
||||
for (ec_idx = 0; ec_idx < h->s->nr_data; ec_idx++) {
|
||||
struct dev_alloc_list devs_sorted = bch2_dev_alloc_list(c, &wp->stripe, devs_may_alloc);
|
||||
darray_for_each(devs_sorted, i)
|
||||
for (unsigned ec_idx = 0; ec_idx < h->s->nr_data; ec_idx++) {
|
||||
if (!h->s->blocks[ec_idx])
|
||||
continue;
|
||||
|
||||
ob = c->open_buckets + h->s->blocks[ec_idx];
|
||||
if (ob->dev == devs_sorted.devs[i] &&
|
||||
!test_and_set_bit(ec_idx, h->s->blocks_allocated))
|
||||
goto got_bucket;
|
||||
}
|
||||
goto out_put_head;
|
||||
got_bucket:
|
||||
ob->ec_idx = ec_idx;
|
||||
ob->ec = h->s;
|
||||
ec_stripe_new_get(h->s, STRIPE_REF_io);
|
||||
struct open_bucket *ob = c->open_buckets + h->s->blocks[ec_idx];
|
||||
if (ob->dev == *i && !test_and_set_bit(ec_idx, h->s->blocks_allocated)) {
|
||||
ob->ec_idx = ec_idx;
|
||||
ob->ec = h->s;
|
||||
ec_stripe_new_get(h->s, STRIPE_REF_io);
|
||||
|
||||
ret = add_new_bucket(c, ptrs, devs_may_alloc,
|
||||
nr_replicas, nr_effective,
|
||||
have_cache, flags, ob);
|
||||
out_put_head:
|
||||
ret = add_new_bucket(c, ptrs, devs_may_alloc,
|
||||
nr_replicas, nr_effective,
|
||||
have_cache, ob);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
bch2_ec_stripe_head_put(c, h);
|
||||
return ret;
|
||||
}
|
||||
@ -928,7 +826,7 @@ static int bucket_alloc_set_writepoint(struct bch_fs *c,
|
||||
unsigned nr_replicas,
|
||||
unsigned *nr_effective,
|
||||
bool *have_cache,
|
||||
bool ec, unsigned flags)
|
||||
bool ec)
|
||||
{
|
||||
struct open_buckets ptrs_skip = { .nr = 0 };
|
||||
struct open_bucket *ob;
|
||||
@ -940,7 +838,7 @@ static int bucket_alloc_set_writepoint(struct bch_fs *c,
|
||||
have_cache, ec, ob))
|
||||
ret = add_new_bucket(c, ptrs, devs_may_alloc,
|
||||
nr_replicas, nr_effective,
|
||||
have_cache, flags, ob);
|
||||
have_cache, ob);
|
||||
else
|
||||
ob_push(c, &ptrs_skip, ob);
|
||||
}
|
||||
@ -956,8 +854,7 @@ static int bucket_alloc_set_partial(struct bch_fs *c,
|
||||
unsigned nr_replicas,
|
||||
unsigned *nr_effective,
|
||||
bool *have_cache, bool ec,
|
||||
enum bch_watermark watermark,
|
||||
unsigned flags)
|
||||
enum bch_watermark watermark)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
@ -978,7 +875,7 @@ static int bucket_alloc_set_partial(struct bch_fs *c,
|
||||
u64 avail;
|
||||
|
||||
bch2_dev_usage_read_fast(ca, &usage);
|
||||
avail = dev_buckets_free(ca, usage, watermark);
|
||||
avail = dev_buckets_free(ca, usage, watermark) + ca->nr_partial_buckets;
|
||||
if (!avail)
|
||||
continue;
|
||||
|
||||
@ -987,9 +884,13 @@ static int bucket_alloc_set_partial(struct bch_fs *c,
|
||||
i);
|
||||
ob->on_partial_list = false;
|
||||
|
||||
rcu_read_lock();
|
||||
bch2_dev_rcu(c, ob->dev)->nr_partial_buckets--;
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = add_new_bucket(c, ptrs, devs_may_alloc,
|
||||
nr_replicas, nr_effective,
|
||||
have_cache, flags, ob);
|
||||
have_cache, ob);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
@ -1009,7 +910,7 @@ static int __open_bucket_add_buckets(struct btree_trans *trans,
|
||||
unsigned *nr_effective,
|
||||
bool *have_cache,
|
||||
enum bch_watermark watermark,
|
||||
unsigned flags,
|
||||
enum bch_write_flags flags,
|
||||
struct closure *_cl)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
@ -1028,18 +929,15 @@ static int __open_bucket_add_buckets(struct btree_trans *trans,
|
||||
open_bucket_for_each(c, ptrs, ob, i)
|
||||
__clear_bit(ob->dev, devs.d);
|
||||
|
||||
if (erasure_code && ec_open_bucket(c, ptrs))
|
||||
return 0;
|
||||
|
||||
ret = bucket_alloc_set_writepoint(c, ptrs, wp, &devs,
|
||||
nr_replicas, nr_effective,
|
||||
have_cache, erasure_code, flags);
|
||||
have_cache, erasure_code);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bucket_alloc_set_partial(c, ptrs, wp, &devs,
|
||||
nr_replicas, nr_effective,
|
||||
have_cache, erasure_code, watermark, flags);
|
||||
have_cache, erasure_code, watermark);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1080,12 +978,12 @@ static int open_bucket_add_buckets(struct btree_trans *trans,
|
||||
unsigned *nr_effective,
|
||||
bool *have_cache,
|
||||
enum bch_watermark watermark,
|
||||
unsigned flags,
|
||||
enum bch_write_flags flags,
|
||||
struct closure *cl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (erasure_code) {
|
||||
if (erasure_code && !ec_open_bucket(trans->c, ptrs)) {
|
||||
ret = __open_bucket_add_buckets(trans, ptrs, wp,
|
||||
devs_have, target, erasure_code,
|
||||
nr_replicas, nr_effective, have_cache,
|
||||
@ -1200,7 +1098,13 @@ void bch2_open_buckets_stop(struct bch_fs *c, struct bch_dev *ca,
|
||||
--c->open_buckets_partial_nr;
|
||||
swap(c->open_buckets_partial[i],
|
||||
c->open_buckets_partial[c->open_buckets_partial_nr]);
|
||||
|
||||
ob->on_partial_list = false;
|
||||
|
||||
rcu_read_lock();
|
||||
bch2_dev_rcu(c, ob->dev)->nr_partial_buckets--;
|
||||
rcu_read_unlock();
|
||||
|
||||
spin_unlock(&c->freelist_lock);
|
||||
bch2_open_bucket_put(c, ob);
|
||||
spin_lock(&c->freelist_lock);
|
||||
@ -1382,7 +1286,7 @@ int bch2_alloc_sectors_start_trans(struct btree_trans *trans,
|
||||
unsigned nr_replicas,
|
||||
unsigned nr_replicas_required,
|
||||
enum bch_watermark watermark,
|
||||
unsigned flags,
|
||||
enum bch_write_flags flags,
|
||||
struct closure *cl,
|
||||
struct write_point **wp_ret)
|
||||
{
|
||||
@ -1398,8 +1302,6 @@ int bch2_alloc_sectors_start_trans(struct btree_trans *trans,
|
||||
if (!IS_ENABLED(CONFIG_BCACHEFS_ERASURE_CODING))
|
||||
erasure_code = false;
|
||||
|
||||
BUG_ON(flags & BCH_WRITE_ONLY_SPECIFIED_DEVS);
|
||||
|
||||
BUG_ON(!nr_replicas || !nr_replicas_required);
|
||||
retry:
|
||||
ptrs.nr = 0;
|
||||
@ -1417,7 +1319,7 @@ retry:
|
||||
if (wp->data_type != BCH_DATA_user)
|
||||
have_cache = true;
|
||||
|
||||
if (target && !(flags & BCH_WRITE_ONLY_SPECIFIED_DEVS)) {
|
||||
if (target && !(flags & BCH_WRITE_only_specified_devs)) {
|
||||
ret = open_bucket_add_buckets(trans, &ptrs, wp, devs_have,
|
||||
target, erasure_code,
|
||||
nr_replicas, &nr_effective,
|
||||
@ -1504,11 +1406,12 @@ err:
|
||||
try_decrease_writepoints(trans, write_points_nr))
|
||||
goto retry;
|
||||
|
||||
if (bch2_err_matches(ret, BCH_ERR_open_buckets_empty) ||
|
||||
if (cl && bch2_err_matches(ret, BCH_ERR_open_buckets_empty))
|
||||
ret = -BCH_ERR_bucket_alloc_blocked;
|
||||
|
||||
if (cl && !(flags & BCH_WRITE_alloc_nowait) &&
|
||||
bch2_err_matches(ret, BCH_ERR_freelist_empty))
|
||||
return cl
|
||||
? -BCH_ERR_bucket_alloc_blocked
|
||||
: -BCH_ERR_ENOSPC_bucket_alloc;
|
||||
ret = -BCH_ERR_bucket_alloc_blocked;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1589,7 +1492,7 @@ void bch2_fs_allocator_foreground_init(struct bch_fs *c)
|
||||
}
|
||||
}
|
||||
|
||||
static void bch2_open_bucket_to_text(struct printbuf *out, struct bch_fs *c, struct open_bucket *ob)
|
||||
void bch2_open_bucket_to_text(struct printbuf *out, struct bch_fs *c, struct open_bucket *ob)
|
||||
{
|
||||
struct bch_dev *ca = ob_dev(c, ob);
|
||||
unsigned data_type = ob->data_type;
|
||||
@ -1609,7 +1512,8 @@ static void bch2_open_bucket_to_text(struct printbuf *out, struct bch_fs *c, str
|
||||
prt_newline(out);
|
||||
}
|
||||
|
||||
void bch2_open_buckets_to_text(struct printbuf *out, struct bch_fs *c)
|
||||
void bch2_open_buckets_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
struct bch_dev *ca)
|
||||
{
|
||||
struct open_bucket *ob;
|
||||
|
||||
@ -1619,7 +1523,7 @@ void bch2_open_buckets_to_text(struct printbuf *out, struct bch_fs *c)
|
||||
ob < c->open_buckets + ARRAY_SIZE(c->open_buckets);
|
||||
ob++) {
|
||||
spin_lock(&ob->lock);
|
||||
if (ob->valid && !ob->on_partial_list)
|
||||
if (ob->valid && (!ca || ob->dev == ca->dev_idx))
|
||||
bch2_open_bucket_to_text(out, c, ob);
|
||||
spin_unlock(&ob->lock);
|
||||
}
|
||||
@ -1703,8 +1607,11 @@ void bch2_fs_alloc_debug_to_text(struct printbuf *out, struct bch_fs *c)
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(c->open_buckets); i++)
|
||||
nr[c->open_buckets[i].data_type]++;
|
||||
|
||||
printbuf_tabstops_reset(out);
|
||||
printbuf_tabstop_push(out, 24);
|
||||
|
||||
prt_printf(out, "capacity\t%llu\n", c->capacity);
|
||||
prt_printf(out, "reserved\t%llu\n", c->reserved);
|
||||
prt_printf(out, "hidden\t%llu\n", percpu_u64_get(&c->usage->hidden));
|
||||
prt_printf(out, "btree\t%llu\n", percpu_u64_get(&c->usage->btree));
|
||||
prt_printf(out, "data\t%llu\n", percpu_u64_get(&c->usage->data));
|
||||
@ -1734,13 +1641,7 @@ void bch2_dev_alloc_debug_to_text(struct printbuf *out, struct bch_dev *ca)
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(c->open_buckets); i++)
|
||||
nr[c->open_buckets[i].data_type]++;
|
||||
|
||||
printbuf_tabstop_push(out, 12);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
|
||||
bch2_dev_usage_to_text(out, &stats);
|
||||
bch2_dev_usage_to_text(out, ca, &stats);
|
||||
|
||||
prt_newline(out);
|
||||
|
||||
@ -1758,11 +1659,12 @@ void bch2_dev_alloc_debug_to_text(struct printbuf *out, struct bch_dev *ca)
|
||||
prt_printf(out, "buckets to invalidate\t%llu\r\n", should_invalidate_buckets(ca, stats));
|
||||
}
|
||||
|
||||
void bch2_print_allocator_stuck(struct bch_fs *c)
|
||||
static noinline void bch2_print_allocator_stuck(struct bch_fs *c)
|
||||
{
|
||||
struct printbuf buf = PRINTBUF;
|
||||
|
||||
prt_printf(&buf, "Allocator stuck? Waited for 10 seconds\n");
|
||||
prt_printf(&buf, "Allocator stuck? Waited for %u seconds\n",
|
||||
c->opts.allocator_stuck_timeout);
|
||||
|
||||
prt_printf(&buf, "Allocator debug:\n");
|
||||
printbuf_indent_add(&buf, 2);
|
||||
@ -1792,3 +1694,24 @@ void bch2_print_allocator_stuck(struct bch_fs *c)
|
||||
bch2_print_string_as_lines(KERN_ERR, buf.buf);
|
||||
printbuf_exit(&buf);
|
||||
}
|
||||
|
||||
static inline unsigned allocator_wait_timeout(struct bch_fs *c)
|
||||
{
|
||||
if (c->allocator_last_stuck &&
|
||||
time_after(c->allocator_last_stuck + HZ * 60 * 2, jiffies))
|
||||
return 0;
|
||||
|
||||
return c->opts.allocator_stuck_timeout * HZ;
|
||||
}
|
||||
|
||||
void __bch2_wait_on_allocator(struct bch_fs *c, struct closure *cl)
|
||||
{
|
||||
unsigned t = allocator_wait_timeout(c);
|
||||
|
||||
if (t && closure_sync_timeout(cl, t)) {
|
||||
c->allocator_last_stuck = jiffies;
|
||||
bch2_print_allocator_stuck(c);
|
||||
}
|
||||
|
||||
closure_sync(cl);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ void bch2_reset_alloc_cursors(struct bch_fs *);
|
||||
|
||||
struct dev_alloc_list {
|
||||
unsigned nr;
|
||||
u8 devs[BCH_SB_MEMBERS_MAX];
|
||||
u8 data[BCH_SB_MEMBERS_MAX];
|
||||
};
|
||||
|
||||
struct dev_alloc_list bch2_dev_alloc_list(struct bch_fs *,
|
||||
@ -28,13 +28,28 @@ struct dev_alloc_list bch2_dev_alloc_list(struct bch_fs *,
|
||||
struct bch_devs_mask *);
|
||||
void bch2_dev_stripe_increment(struct bch_dev *, struct dev_stripe_state *);
|
||||
|
||||
long bch2_bucket_alloc_new_fs(struct bch_dev *);
|
||||
|
||||
static inline struct bch_dev *ob_dev(struct bch_fs *c, struct open_bucket *ob)
|
||||
{
|
||||
return bch2_dev_have_ref(c, ob->dev);
|
||||
}
|
||||
|
||||
static inline unsigned bch2_open_buckets_reserved(enum bch_watermark watermark)
|
||||
{
|
||||
switch (watermark) {
|
||||
case BCH_WATERMARK_interior_updates:
|
||||
return 0;
|
||||
case BCH_WATERMARK_reclaim:
|
||||
return OPEN_BUCKETS_COUNT / 6;
|
||||
case BCH_WATERMARK_btree:
|
||||
case BCH_WATERMARK_btree_copygc:
|
||||
return OPEN_BUCKETS_COUNT / 4;
|
||||
case BCH_WATERMARK_copygc:
|
||||
return OPEN_BUCKETS_COUNT / 3;
|
||||
default:
|
||||
return OPEN_BUCKETS_COUNT / 2;
|
||||
}
|
||||
}
|
||||
|
||||
struct open_bucket *bch2_bucket_alloc(struct bch_fs *, struct bch_dev *,
|
||||
enum bch_watermark, enum bch_data_type,
|
||||
struct closure *);
|
||||
@ -67,7 +82,7 @@ static inline struct open_bucket *ec_open_bucket(struct bch_fs *c,
|
||||
}
|
||||
|
||||
void bch2_open_bucket_write_error(struct bch_fs *,
|
||||
struct open_buckets *, unsigned);
|
||||
struct open_buckets *, unsigned, int);
|
||||
|
||||
void __bch2_open_bucket_put(struct bch_fs *, struct open_bucket *);
|
||||
|
||||
@ -155,9 +170,10 @@ static inline bool bch2_bucket_is_open_safe(struct bch_fs *c, unsigned dev, u64
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum bch_write_flags;
|
||||
int bch2_bucket_alloc_set_trans(struct btree_trans *, struct open_buckets *,
|
||||
struct dev_stripe_state *, struct bch_devs_mask *,
|
||||
unsigned, unsigned *, bool *, unsigned,
|
||||
unsigned, unsigned *, bool *, enum bch_write_flags,
|
||||
enum bch_data_type, enum bch_watermark,
|
||||
struct closure *);
|
||||
|
||||
@ -167,7 +183,7 @@ int bch2_alloc_sectors_start_trans(struct btree_trans *,
|
||||
struct bch_devs_list *,
|
||||
unsigned, unsigned,
|
||||
enum bch_watermark,
|
||||
unsigned,
|
||||
enum bch_write_flags,
|
||||
struct closure *,
|
||||
struct write_point **);
|
||||
|
||||
@ -222,7 +238,8 @@ static inline struct write_point_specifier writepoint_ptr(struct write_point *wp
|
||||
|
||||
void bch2_fs_allocator_foreground_init(struct bch_fs *);
|
||||
|
||||
void bch2_open_buckets_to_text(struct printbuf *, struct bch_fs *);
|
||||
void bch2_open_bucket_to_text(struct printbuf *, struct bch_fs *, struct open_bucket *);
|
||||
void bch2_open_buckets_to_text(struct printbuf *, struct bch_fs *, struct bch_dev *);
|
||||
void bch2_open_buckets_partial_to_text(struct printbuf *, struct bch_fs *);
|
||||
|
||||
void bch2_write_points_to_text(struct printbuf *, struct bch_fs *);
|
||||
@ -230,6 +247,11 @@ void bch2_write_points_to_text(struct printbuf *, struct bch_fs *);
|
||||
void bch2_fs_alloc_debug_to_text(struct printbuf *, struct bch_fs *);
|
||||
void bch2_dev_alloc_debug_to_text(struct printbuf *, struct bch_dev *);
|
||||
|
||||
void bch2_print_allocator_stuck(struct bch_fs *);
|
||||
void __bch2_wait_on_allocator(struct bch_fs *, struct closure *);
|
||||
static inline void bch2_wait_on_allocator(struct bch_fs *c, struct closure *cl)
|
||||
{
|
||||
if (cl->closure_get_happened)
|
||||
__bch2_wait_on_allocator(c, cl);
|
||||
}
|
||||
|
||||
#endif /* _BCACHEFS_ALLOC_FOREGROUND_H */
|
||||
|
@ -18,6 +18,7 @@ struct bucket_alloc_state {
|
||||
u64 buckets_seen;
|
||||
u64 skipped_open;
|
||||
u64 skipped_need_journal_commit;
|
||||
u64 need_journal_commit;
|
||||
u64 skipped_nocow;
|
||||
u64 skipped_nouse;
|
||||
u64 skipped_mi_btree_bitmap;
|
||||
@ -89,6 +90,7 @@ struct dev_stripe_state {
|
||||
x(stopped) \
|
||||
x(waiting_io) \
|
||||
x(waiting_work) \
|
||||
x(runnable) \
|
||||
x(running)
|
||||
|
||||
enum write_point_state {
|
||||
@ -124,6 +126,7 @@ struct write_point {
|
||||
enum write_point_state state;
|
||||
u64 last_state_change;
|
||||
u64 time[WRITE_POINT_STATE_NR];
|
||||
u64 last_runtime;
|
||||
} __aligned(SMP_CACHE_BYTES);
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user