mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-04-01 00:00:03 +03:00
Compare commits
312 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 | ||
|
dd275b1c5f | ||
|
41df701a08 | ||
|
f72ded6a4f | ||
|
e4271d7a3e | ||
|
87ab1fd7ed | ||
|
c909480560 | ||
|
33ce7dd90c | ||
|
a87faa2e30 | ||
|
d915c62f17 | ||
|
fc06a0ea5e | ||
|
b46d3a2710 | ||
|
ab83e348fb | ||
|
3a4a096cd2 | ||
|
ed675b8d64 | ||
|
d750b2b98b | ||
|
f3ab07db73 | ||
|
8bc27da705 | ||
|
a2a0d53945 | ||
|
786e507c2e | ||
|
e743caf71c | ||
|
c20f323fdb | ||
|
2a15fc0445 | ||
|
990437ad13 | ||
|
c2354f0326 | ||
|
b42b5b4065 | ||
|
e1fa076a86 | ||
|
0d570e822b | ||
|
0916d38664 | ||
|
da5435b0cc | ||
|
7d79fba1af | ||
|
d456f9e97a | ||
|
30e16b5e15 | ||
|
fac7cce224 | ||
|
587f7f5a47 | ||
|
cafd2226a2 | ||
|
697c79fa7c | ||
|
4676269d2d | ||
|
617ba1380b | ||
|
e739da5da8 | ||
|
af05a54922 | ||
|
8cd17b40df | ||
|
96a346254d | ||
|
15e3c90584 | ||
|
0ca3233518 | ||
|
20f7954cdb | ||
|
9ec185437d | ||
|
96843fc95d | ||
|
781ea5d40f | ||
|
31066e17e8 | ||
|
d42a097280 | ||
|
22495e0d31 | ||
|
25bce91b4b | ||
|
21b1111b59 | ||
|
de6e8ac230 | ||
|
3016a7dbbd | ||
|
c3c7dacab2 | ||
|
18f9526c45 | ||
|
0c39011ae0 | ||
|
cd94eda1d8 | ||
|
a0bbe712c0 | ||
|
c36b96d4dc | ||
|
d43fbfd642 | ||
|
7f15685517 | ||
|
b362f12add | ||
|
422ae1f1a7 | ||
|
bf2c0c8852 | ||
|
ce01c61ba5 | ||
|
0e414b462f | ||
|
7efaf45d78 | ||
|
067e072465 | ||
|
9bb2977a1a | ||
|
5a3011c48e | ||
|
aa985e6a44 | ||
|
5b216318b8 | ||
|
6ba303e8bf | ||
|
80167bf0a8 | ||
|
1e35104d31 | ||
|
7bf821f3f9 | ||
|
ff44b8b96d | ||
|
9cd7440649 | ||
|
3f531df2b3 | ||
|
72ad5766bd | ||
|
cd198e2b8e | ||
|
88aa61eb95 | ||
|
45c8cc32a3 | ||
|
0f5c8e0407 | ||
|
368cdb8796 | ||
|
f40361c34f | ||
|
764031a4aa | ||
|
7d795ddb25 | ||
|
56a9580aeb | ||
|
2e316499df | ||
|
cc16402e4f | ||
|
0fcdd67bf0 | ||
|
5e9d1953a2 | ||
|
eccefb381d | ||
|
b91647aab8 | ||
|
e94c985640 | ||
|
04a31f10e0 | ||
|
683710c068 | ||
|
3882d1b1e4 | ||
|
3488d4f15f | ||
|
3ac510f6a4 | ||
|
477670f481 | ||
|
5531accc97 | ||
|
128b569155 | ||
|
3d63b901c6 | ||
|
761ef99f91 | ||
|
1fb1898b24 | ||
|
52904aa886 | ||
|
2b8a0f0caf | ||
|
578f32a96e | ||
|
a739671c0b | ||
|
b832e3b2f7 | ||
|
efbe47e2b4 | ||
|
b9e48edba7 | ||
|
ec2d118738 | ||
|
b3677f3040 | ||
|
b8b36900f8 | ||
|
0e0aa31912 | ||
|
ad41c2fb76 |
.bcachefs_revision.editorconfig
.github/workflows
.gitignoreCargo.lockCargo.tomlINSTALL.mdMakefileMakefile.compilerarch/etc
bcachefs.8bch_bindgen
build.nixc_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
ccan/compiler
debian
default.nixdoc
flake.lockflake.nixinclude
crypto
linux
@ -1 +1 @@
|
||||
10ca1f99f8c99a3d992b686cdc29d427807070e5
|
||||
7fdc3fa3cb5fb561f5945b4de418d48d1a726a8d
|
||||
|
@ -1,6 +1,34 @@
|
||||
indent_style = tab
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 8
|
||||
indent_style = tab
|
||||
insert_final_newline = true
|
||||
max_line_length = 80
|
||||
tab_width = 8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[.git/**]
|
||||
max_line_length = 72
|
||||
|
||||
[*.nix]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.y{,a}ml]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[Cargo.toml]
|
||||
indent_style = space
|
||||
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
|
||||
|
21
.github/workflows/nix-flake-update.yml
vendored
Normal file
21
.github/workflows/nix-flake-update.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: update-flake-lock
|
||||
on:
|
||||
workflow_dispatch: # allows manual triggering
|
||||
schedule:
|
||||
- cron: '0 0 1 * *' # Run monthly
|
||||
push:
|
||||
paths:
|
||||
- 'flake.nix'
|
||||
jobs:
|
||||
lockfile:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v27
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Update flake.lock
|
||||
uses: DeterminateSystems/update-flake-lock@v21
|
31
.github/workflows/nix-flake.yml
vendored
Normal file
31
.github/workflows/nix-flake.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
name: Nix Flake actions
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
nix-matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- 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 }}'
|
21
.github/workflows/nixos.yml
vendored
21
.github/workflows/nixos.yml
vendored
@ -1,21 +0,0 @@
|
||||
name: "NixOS-Tests"
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
jobs:
|
||||
nixos-flake-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v23
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: cachix/cachix-action@v12
|
||||
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
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,12 +10,11 @@ TAGS
|
||||
cscope*
|
||||
bcachefs-tools
|
||||
compile_commands.json
|
||||
tests/test_helper
|
||||
tests/__pycache__/
|
||||
|
||||
# dot-files that we don't want to ignore
|
||||
!.gitignore
|
||||
!.github/dependabot.yml
|
||||
!.github/workflows/
|
||||
!.editorconfig
|
||||
|
||||
bcachefs-principles-of-operation.*
|
||||
|
433
Cargo.lock
generated
433
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,33 +62,30 @@ 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",
|
||||
"uuid",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -98,8 +96,6 @@ dependencies = [
|
||||
"bindgen",
|
||||
"bitfield",
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"memoffset",
|
||||
"paste",
|
||||
"pkg-config",
|
||||
"uuid",
|
||||
@ -107,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",
|
||||
@ -142,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]]
|
||||
@ -178,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",
|
||||
@ -189,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",
|
||||
@ -199,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",
|
||||
@ -212,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",
|
||||
@ -233,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"
|
||||
@ -272,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",
|
||||
@ -298,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"
|
||||
@ -311,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"
|
||||
@ -322,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"
|
||||
@ -334,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]]
|
||||
@ -360,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"
|
||||
@ -403,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",
|
||||
@ -431,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",
|
||||
@ -461,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",
|
||||
@ -472,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"
|
||||
@ -505,17 +476,23 @@ 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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
@ -524,15 +501,37 @@ 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.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[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",
|
||||
@ -541,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]]
|
||||
@ -562,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"
|
||||
@ -612,134 +611,104 @@ 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"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
26
Cargo.toml
26
Cargo.toml
@ -1,17 +1,23 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
default-members = [".", "bch_bindgen"]
|
||||
|
||||
[package]
|
||||
name = "bcachefs-tools"
|
||||
version = "0.3.1"
|
||||
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,6 +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"
|
||||
|
28
INSTALL.md
28
INSTALL.md
@ -17,8 +17,9 @@ Build dependencies:
|
||||
* zlib1g
|
||||
|
||||
In addition a recent Rust toolchain is required (rustc, cargo), either by using
|
||||
[rustup](https://rustup.rs/) or make sure to use a distribution where rustc (>=1.65)
|
||||
is available.
|
||||
[rustup](https://rustup.rs/) or make sure to use a distribution where a recent
|
||||
enough rustc is available. Please check `rust-version` in `Cargo.toml` to see
|
||||
the minimum supported Rust version (MSRV).
|
||||
|
||||
``` shell
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
|
||||
@ -33,12 +34,24 @@ apt install -y pkg-config libaio-dev libblkid-dev libkeyutils-dev \
|
||||
python3 python3-docutils libclang-dev debhelper dh-python
|
||||
```
|
||||
|
||||
Fedora: install the "Development tools" group along with:
|
||||
Starting from Debian Trixie and Ubuntu 23.10, you will additionally need:
|
||||
```shell
|
||||
dnf install -y libaio-devel libsodium-devel \
|
||||
apt install -y systemd-dev
|
||||
```
|
||||
|
||||
Fedora: install build dependencies either with `dnf builddep bcachefs-tools` or with:
|
||||
```shell
|
||||
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.
|
||||
@ -74,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):
|
||||
|
||||
|
32
Makefile
32
Makefile
@ -1,4 +1,4 @@
|
||||
VERSION=1.7.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)
|
||||
|
||||
@ -254,6 +255,7 @@ update-bcachefs-sources:
|
||||
test -d libbcachefs || mkdir libbcachefs
|
||||
cp $(LINUX_DIR)/fs/bcachefs/*.[ch] libbcachefs/
|
||||
git add libbcachefs/*.[ch]
|
||||
git rm -f libbcachefs/mean_and_variance_test.c
|
||||
cp $(LINUX_DIR)/include/linux/closure.h include/linux/
|
||||
git add include/linux/closure.h
|
||||
cp $(LINUX_DIR)/lib/closure.c linux/
|
||||
@ -293,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=""
|
10
bcachefs.8
10
bcachefs.8
@ -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
|
||||
@ -497,7 +497,7 @@ Resize journal on a device
|
||||
Create a new subvolume
|
||||
.It Ic subvolume delete Oo Ar options Oc Ar path
|
||||
Delete an existing subvolume
|
||||
.It Ic subvolume delete Oo Ar options Oc Ar source dest
|
||||
.It Ic subvolume snapshot Oo Ar options Oc Ar source dest
|
||||
Create a snapshot of
|
||||
.Ar source
|
||||
at
|
||||
@ -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"
|
||||
|
||||
|
@ -29,8 +29,7 @@ fn main() {
|
||||
.to_string(),
|
||||
)
|
||||
.clang_args(
|
||||
urcu
|
||||
.include_paths
|
||||
urcu.include_paths
|
||||
.iter()
|
||||
.map(|p| format!("-I{}", p.display())),
|
||||
)
|
||||
@ -64,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_.*")
|
||||
|
@ -1,3 +0,0 @@
|
||||
# Default settings, i.e. idiomatic rust
|
||||
edition = "2021"
|
||||
newline_style = "Unix"
|
@ -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,12 +61,15 @@ impl bch_sb {
|
||||
uuid::Uuid::from_bytes(self.user_uuid.b)
|
||||
}
|
||||
|
||||
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],
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use crate::btree::BtreeIter;
|
||||
use crate::c;
|
||||
use crate::fs::Fs;
|
||||
use crate::btree::BtreeIter;
|
||||
use crate::printbuf_to_formatter;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::transmute;
|
||||
|
||||
pub struct BkeySC<'a> {
|
||||
pub k: &'a c::bkey,
|
||||
pub v: &'a c::bch_val,
|
||||
pub(crate) iter: PhantomData<&'a mut BtreeIter<'a>>
|
||||
pub k: &'a c::bkey,
|
||||
pub v: &'a c::bch_val,
|
||||
pub(crate) iter: PhantomData<&'a mut BtreeIter<'a>>,
|
||||
}
|
||||
|
||||
pub enum BkeyValC<'a> {
|
||||
@ -49,59 +49,66 @@ pub enum BkeyValC<'a> {
|
||||
snapshot_tree(&'a c::bch_snapshot_tree),
|
||||
logged_op_truncate(&'a c::bch_logged_op_truncate),
|
||||
logged_op_finsert(&'a c::bch_logged_op_finsert),
|
||||
accounting(&'a c::bch_accounting),
|
||||
inode_alloc_cursor(&'a c::bch_inode_alloc_cursor),
|
||||
}
|
||||
|
||||
impl<'a, 'b> BkeySC<'a> {
|
||||
unsafe fn to_raw(&self) -> c::bkey_s_c {
|
||||
c::bkey_s_c { k: self.k, v: self.v }
|
||||
c::bkey_s_c {
|
||||
k: self.k,
|
||||
v: self.v,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_text(&'a self, fs: &'b Fs) -> BkeySCToText<'a, 'b> {
|
||||
BkeySCToText { k: self, fs }
|
||||
}
|
||||
|
||||
pub fn v(&'a self) -> BkeyValC {
|
||||
pub fn v(&'a self) -> BkeyValC<'a> {
|
||||
unsafe {
|
||||
let ty: c::bch_bkey_type = transmute(self.k.type_ as u32);
|
||||
|
||||
use c::bch_bkey_type::*;
|
||||
use BkeyValC::*;
|
||||
match ty {
|
||||
KEY_TYPE_deleted => deleted,
|
||||
KEY_TYPE_whiteout => whiteout,
|
||||
KEY_TYPE_error => error,
|
||||
KEY_TYPE_cookie => cookie(transmute(self.v)),
|
||||
KEY_TYPE_hash_whiteout => hash_whiteout(transmute(self.v)),
|
||||
KEY_TYPE_btree_ptr => btree_ptr(transmute(self.v)),
|
||||
KEY_TYPE_extent => extent(transmute(self.v)),
|
||||
KEY_TYPE_reservation => reservation(transmute(self.v)),
|
||||
KEY_TYPE_inode => inode(transmute(self.v)),
|
||||
KEY_TYPE_inode_generation => inode_generation(transmute(self.v)),
|
||||
KEY_TYPE_dirent => dirent(transmute(self.v)),
|
||||
KEY_TYPE_xattr => xattr(transmute(self.v)),
|
||||
KEY_TYPE_alloc => alloc(transmute(self.v)),
|
||||
KEY_TYPE_quota => quota(transmute(self.v)),
|
||||
KEY_TYPE_stripe => stripe(transmute(self.v)),
|
||||
KEY_TYPE_reflink_p => reflink_p(transmute(self.v)),
|
||||
KEY_TYPE_reflink_v => reflink_v(transmute(self.v)),
|
||||
KEY_TYPE_inline_data => inline_data(transmute(self.v)),
|
||||
KEY_TYPE_btree_ptr_v2 => btree_ptr_v2(transmute(self.v)),
|
||||
KEY_TYPE_indirect_inline_data => indirect_inline_data(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v2 => alloc_v2(transmute(self.v)),
|
||||
KEY_TYPE_subvolume => subvolume(transmute(self.v)),
|
||||
KEY_TYPE_snapshot => snapshot(transmute(self.v)),
|
||||
KEY_TYPE_inode_v2 => inode_v2(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v3 => inode_v3(transmute(self.v)),
|
||||
KEY_TYPE_set => set,
|
||||
KEY_TYPE_lru => lru(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v4 => alloc_v4(transmute(self.v)),
|
||||
KEY_TYPE_backpointer => backpointer(transmute(self.v)),
|
||||
KEY_TYPE_inode_v3 => inode_v3(transmute(self.v)),
|
||||
KEY_TYPE_bucket_gens => bucket_gens(transmute(self.v)),
|
||||
KEY_TYPE_snapshot_tree => snapshot_tree(transmute(self.v)),
|
||||
KEY_TYPE_logged_op_truncate => logged_op_truncate(transmute(self.v)),
|
||||
KEY_TYPE_logged_op_finsert => logged_op_finsert(transmute(self.v)),
|
||||
KEY_TYPE_MAX => unreachable!(),
|
||||
KEY_TYPE_deleted => deleted,
|
||||
KEY_TYPE_whiteout => whiteout,
|
||||
KEY_TYPE_error => error,
|
||||
KEY_TYPE_cookie => cookie(transmute(self.v)),
|
||||
KEY_TYPE_hash_whiteout => hash_whiteout(transmute(self.v)),
|
||||
KEY_TYPE_btree_ptr => btree_ptr(transmute(self.v)),
|
||||
KEY_TYPE_extent => extent(transmute(self.v)),
|
||||
KEY_TYPE_reservation => reservation(transmute(self.v)),
|
||||
KEY_TYPE_inode => inode(transmute(self.v)),
|
||||
KEY_TYPE_inode_generation => inode_generation(transmute(self.v)),
|
||||
KEY_TYPE_dirent => dirent(transmute(self.v)),
|
||||
KEY_TYPE_xattr => xattr(transmute(self.v)),
|
||||
KEY_TYPE_alloc => alloc(transmute(self.v)),
|
||||
KEY_TYPE_quota => quota(transmute(self.v)),
|
||||
KEY_TYPE_stripe => stripe(transmute(self.v)),
|
||||
KEY_TYPE_reflink_p => reflink_p(transmute(self.v)),
|
||||
KEY_TYPE_reflink_v => reflink_v(transmute(self.v)),
|
||||
KEY_TYPE_inline_data => inline_data(transmute(self.v)),
|
||||
KEY_TYPE_btree_ptr_v2 => btree_ptr_v2(transmute(self.v)),
|
||||
KEY_TYPE_indirect_inline_data => indirect_inline_data(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v2 => alloc_v2(transmute(self.v)),
|
||||
KEY_TYPE_subvolume => subvolume(transmute(self.v)),
|
||||
KEY_TYPE_snapshot => snapshot(transmute(self.v)),
|
||||
KEY_TYPE_inode_v2 => inode_v2(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v3 => inode_v3(transmute(self.v)),
|
||||
KEY_TYPE_set => set,
|
||||
KEY_TYPE_lru => lru(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v4 => alloc_v4(transmute(self.v)),
|
||||
KEY_TYPE_backpointer => backpointer(transmute(self.v)),
|
||||
KEY_TYPE_inode_v3 => inode_v3(transmute(self.v)),
|
||||
KEY_TYPE_bucket_gens => bucket_gens(transmute(self.v)),
|
||||
KEY_TYPE_snapshot_tree => snapshot_tree(transmute(self.v)),
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,7 +116,11 @@ impl<'a, 'b> BkeySC<'a> {
|
||||
|
||||
impl<'a> From<&'a c::bkey_i> for BkeySC<'a> {
|
||||
fn from(k: &'a c::bkey_i) -> Self {
|
||||
BkeySC { k: &k.k, v: &k.v, iter: PhantomData }
|
||||
BkeySC {
|
||||
k: &k.k,
|
||||
v: &k.v,
|
||||
iter: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +132,9 @@ pub struct BkeySCToText<'a, 'b> {
|
||||
impl<'a, 'b> fmt::Display for BkeySCToText<'a, 'b> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
unsafe {
|
||||
printbuf_to_formatter(f, |buf| c::bch2_bkey_val_to_text(buf, self.fs.raw, self.k.to_raw()))
|
||||
printbuf_to_formatter(f, |buf| {
|
||||
c::bch2_bkey_val_to_text(buf, self.fs.raw, self.k.to_raw())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,26 @@
|
||||
use crate::SPOS_MAX;
|
||||
use crate::c;
|
||||
use crate::bkey::BkeySC;
|
||||
use crate::fs::Fs;
|
||||
use crate::c;
|
||||
use crate::errcode::{bch_errcode, errptr_to_result_c};
|
||||
use crate::fs::Fs;
|
||||
use crate::printbuf_to_formatter;
|
||||
use crate::SPOS_MAX;
|
||||
use bitflags::bitflags;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use bitflags::bitflags;
|
||||
|
||||
pub struct BtreeTrans<'f> {
|
||||
raw: *mut c::btree_trans,
|
||||
fs: PhantomData<&'f Fs>
|
||||
raw: *mut c::btree_trans,
|
||||
fs: PhantomData<&'f Fs>,
|
||||
}
|
||||
|
||||
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), fs: PhantomData }
|
||||
BtreeTrans {
|
||||
raw: &mut *c::__bch2_trans_get(fs.raw, 0),
|
||||
fs: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -25,36 +28,41 @@ impl<'f> BtreeTrans<'f> {
|
||||
impl<'f> Drop for BtreeTrans<'f> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::bch2_trans_put(&mut *self.raw) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct BtreeIterFlags: u16 {
|
||||
const SLOTS = c::BTREE_ITER_SLOTS as u16;
|
||||
const INTENT = c::BTREE_ITER_INTENT as u16;
|
||||
const PREFETCH = c::BTREE_ITER_PREFETCH as u16;
|
||||
const IS_EXTENTS = c::BTREE_ITER_IS_EXTENTS as u16;
|
||||
const NOT_EXTENTS = c::BTREE_ITER_NOT_EXTENTS as u16;
|
||||
const CACHED = c::BTREE_ITER_CACHED as u16;
|
||||
const KEY_CACHED = c::BTREE_ITER_WITH_KEY_CACHE as u16;
|
||||
const WITH_UPDATES = c::BTREE_ITER_WITH_UPDATES as u16;
|
||||
const WITH_JOURNAL = c::BTREE_ITER_WITH_JOURNAL as u16;
|
||||
const __ALL_SNAPSHOTS = c::__BTREE_ITER_ALL_SNAPSHOTS as u16;
|
||||
const ALL_SNAPSHOTS = c::BTREE_ITER_ALL_SNAPSHOTS as u16;
|
||||
const FILTER_SNAPSHOTS = c::BTREE_ITER_FILTER_SNAPSHOTS as u16;
|
||||
const NOPRESERVE = c::BTREE_ITER_NOPRESERVE as u16;
|
||||
const CACHED_NOFILL = c::BTREE_ITER_CACHED_NOFILL as u16;
|
||||
const KEY_CACHE_FILL = c::BTREE_ITER_KEY_CACHE_FILL as u16;
|
||||
const SLOTS = c::btree_iter_update_trigger_flags::BTREE_ITER_slots as u16;
|
||||
const INTENT = c::btree_iter_update_trigger_flags::BTREE_ITER_intent as u16;
|
||||
const PREFETCH = c::btree_iter_update_trigger_flags::BTREE_ITER_prefetch as u16;
|
||||
const IS_EXTENTS = c::btree_iter_update_trigger_flags::BTREE_ITER_is_extents as u16;
|
||||
const NOT_EXTENTS = c::btree_iter_update_trigger_flags::BTREE_ITER_not_extents as u16;
|
||||
const CACHED = c::btree_iter_update_trigger_flags::BTREE_ITER_cached as u16;
|
||||
const KEY_CACHED = c::btree_iter_update_trigger_flags::BTREE_ITER_with_key_cache as u16;
|
||||
const WITH_UPDATES = c::btree_iter_update_trigger_flags::BTREE_ITER_with_updates as u16;
|
||||
const WITH_JOURNAL = c::btree_iter_update_trigger_flags::BTREE_ITER_with_journal as u16;
|
||||
const SNAPSHOT_FIELD = c::btree_iter_update_trigger_flags::BTREE_ITER_snapshot_field as u16;
|
||||
const ALL_SNAPSHOTS = c::btree_iter_update_trigger_flags::BTREE_ITER_all_snapshots as u16;
|
||||
const FILTER_SNAPSHOTS = c::btree_iter_update_trigger_flags::BTREE_ITER_filter_snapshots as u16;
|
||||
const NOPRESERVE = c::btree_iter_update_trigger_flags::BTREE_ITER_nopreserve as u16;
|
||||
const CACHED_NOFILL = c::btree_iter_update_trigger_flags::BTREE_ITER_cached_nofill as u16;
|
||||
const KEY_CACHE_FILL = c::btree_iter_update_trigger_flags::BTREE_ITER_key_cache_fill as u16;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BtreeIter<'t> {
|
||||
raw: c::btree_iter,
|
||||
trans: PhantomData<&'t BtreeTrans<'t>>,
|
||||
raw: c::btree_iter,
|
||||
trans: PhantomData<&'t BtreeTrans<'t>>,
|
||||
}
|
||||
|
||||
impl<'t> BtreeIter<'t> {
|
||||
pub fn new(trans: &'t BtreeTrans<'t>, btree: c::btree_id, pos: c::bpos, flags: BtreeIterFlags) -> BtreeIter<'t> {
|
||||
pub fn new(
|
||||
trans: &'t BtreeTrans<'t>,
|
||||
btree: c::btree_id,
|
||||
pos: c::bpos,
|
||||
flags: BtreeIterFlags,
|
||||
) -> BtreeIter<'t> {
|
||||
unsafe {
|
||||
let mut iter: MaybeUninit<c::btree_iter> = MaybeUninit::uninit();
|
||||
|
||||
@ -63,30 +71,52 @@ impl<'t> BtreeIter<'t> {
|
||||
iter.as_mut_ptr(),
|
||||
btree,
|
||||
pos,
|
||||
flags.bits as u32);
|
||||
flags.bits as u32,
|
||||
);
|
||||
|
||||
BtreeIter { raw: iter.assume_init(), trans: PhantomData }
|
||||
BtreeIter {
|
||||
raw: iter.assume_init(),
|
||||
trans: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
errptr_to_result_c(k.k)
|
||||
.map(|_| if !k.k.is_null() { Some(BkeySC { k: &*k.k, v: &*k.v, iter: PhantomData }) } else { None } )
|
||||
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 {
|
||||
k: &*k.k,
|
||||
v: &*k.v,
|
||||
iter: PhantomData,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek(&mut self) -> Result<Option<BkeySC>, bch_errcode> {
|
||||
self.peek_upto(SPOS_MAX)
|
||||
self.peek_max(SPOS_MAX)
|
||||
}
|
||||
|
||||
pub fn peek_and_restart(&mut self) -> Result<Option<BkeySC>, bch_errcode> {
|
||||
unsafe {
|
||||
let k = c::bch2_btree_iter_peek_and_restart_outlined(&mut self.raw);
|
||||
|
||||
errptr_to_result_c(k.k)
|
||||
.map(|_| if !k.k.is_null() { Some(BkeySC{ k: &*k.k, v: &*k.v, iter: PhantomData }) } else { None } )
|
||||
errptr_to_result_c(k.k).map(|_| {
|
||||
if !k.k.is_null() {
|
||||
Some(BkeySC {
|
||||
k: &*k.k,
|
||||
v: &*k.v,
|
||||
iter: PhantomData,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,21 +130,23 @@ impl<'t> BtreeIter<'t> {
|
||||
impl<'t> Drop for BtreeIter<'t> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::bch2_trans_iter_exit(self.raw.trans, &mut self.raw) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BtreeNodeIter<'t> {
|
||||
raw: c::btree_iter,
|
||||
trans: PhantomData<&'t BtreeTrans<'t>>,
|
||||
raw: c::btree_iter,
|
||||
trans: PhantomData<&'t BtreeTrans<'t>>,
|
||||
}
|
||||
|
||||
impl<'t> BtreeNodeIter<'t> {
|
||||
pub fn new(trans: &'t BtreeTrans<'t>,
|
||||
btree: c::btree_id,
|
||||
pos: c::bpos,
|
||||
pub fn new(
|
||||
trans: &'t BtreeTrans<'t>,
|
||||
btree: c::btree_id,
|
||||
pos: c::bpos,
|
||||
locks_want: u32,
|
||||
depth: u32,
|
||||
flags: BtreeIterFlags) -> BtreeNodeIter {
|
||||
depth: u32,
|
||||
flags: BtreeIterFlags,
|
||||
) -> BtreeNodeIter<'t> {
|
||||
unsafe {
|
||||
let mut iter: MaybeUninit<c::btree_iter> = MaybeUninit::uninit();
|
||||
c::bch2_trans_node_iter_init(
|
||||
@ -124,9 +156,13 @@ impl<'t> BtreeNodeIter<'t> {
|
||||
pos,
|
||||
locks_want,
|
||||
depth,
|
||||
flags.bits as u32);
|
||||
flags.bits as u32,
|
||||
);
|
||||
|
||||
BtreeNodeIter { raw: iter.assume_init(), trans: PhantomData }
|
||||
BtreeNodeIter {
|
||||
raw: iter.assume_init(),
|
||||
trans: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,7 +197,7 @@ impl<'t> BtreeNodeIter<'t> {
|
||||
impl<'t> Drop for BtreeNodeIter<'t> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::bch2_trans_iter_exit(self.raw.trans, &mut self.raw) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, 'f> c::btree {
|
||||
@ -175,23 +211,27 @@ impl<'b, 'f> c::btree {
|
||||
}
|
||||
|
||||
pub struct BtreeNodeToText<'b, 'f> {
|
||||
b: &'b c::btree,
|
||||
fs: &'f Fs,
|
||||
b: &'b c::btree,
|
||||
fs: &'f Fs,
|
||||
}
|
||||
|
||||
impl<'b, 'f> fmt::Display for BtreeNodeToText<'b, 'f> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
printbuf_to_formatter(f, |buf| unsafe { c::bch2_btree_node_to_text(buf, self.fs.raw, self.b) })
|
||||
printbuf_to_formatter(f, |buf| unsafe {
|
||||
c::bch2_btree_node_to_text(buf, self.fs.raw, self.b)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BtreeNodeOndiskToText<'b, 'f> {
|
||||
b: &'b c::btree,
|
||||
fs: &'f Fs,
|
||||
b: &'b c::btree,
|
||||
fs: &'f Fs,
|
||||
}
|
||||
|
||||
impl<'b, 'f> fmt::Display for BtreeNodeOndiskToText<'b, 'f> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
printbuf_to_formatter(f, |buf| unsafe { c::bch2_btree_node_ondisk_to_text(buf, self.fs.raw, self.b) })
|
||||
printbuf_to_formatter(f, |buf| unsafe {
|
||||
c::bch2_btree_node_ondisk_to_text(buf, self.fs.raw, self.b)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::c;
|
||||
use crate::errcode::{bch_errcode, errptr_to_result};
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::path::PathBuf;
|
||||
use crate::c;
|
||||
use crate::errcode::{bch_errcode, errptr_to_result};
|
||||
|
||||
pub struct Fs {
|
||||
pub raw: *mut c::bch_fs,
|
||||
@ -10,18 +10,19 @@ pub struct Fs {
|
||||
|
||||
impl Fs {
|
||||
pub fn open(devs: &Vec<PathBuf>, opts: c::bch_opts) -> Result<Fs, bch_errcode> {
|
||||
let devs: Vec<_> = devs.iter()
|
||||
let devs: Vec<_> = devs
|
||||
.iter()
|
||||
.map(|i| CString::new(i.as_os_str().as_bytes()).unwrap().into_raw())
|
||||
.collect();
|
||||
|
||||
let ret = unsafe { c::bch2_fs_open(devs[..].as_ptr(), devs.len() as u32, opts) };
|
||||
|
||||
errptr_to_result(ret).map(|fs| Fs { raw: fs})
|
||||
errptr_to_result(ret).map(|fs| Fs { raw: fs })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Fs {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::bch2_fs_stop(self.raw) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
pub mod bcachefs;
|
||||
pub mod btree;
|
||||
pub mod bkey;
|
||||
pub mod btree;
|
||||
pub mod errcode;
|
||||
pub mod keyutils;
|
||||
pub mod sb_io;
|
||||
pub mod fs;
|
||||
pub mod keyutils;
|
||||
pub mod opts;
|
||||
pub mod sb_io;
|
||||
pub use paste::paste;
|
||||
|
||||
pub mod c {
|
||||
@ -15,15 +15,19 @@ pub mod c {
|
||||
use c::bpos as Bpos;
|
||||
|
||||
pub const fn spos(inode: u64, offset: u64, snapshot: u32) -> Bpos {
|
||||
Bpos { inode, offset, snapshot }
|
||||
Bpos {
|
||||
inode,
|
||||
offset,
|
||||
snapshot,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn pos(inode: u64, offset: u64) -> Bpos {
|
||||
spos(inode, offset, 0)
|
||||
}
|
||||
|
||||
pub const POS_MIN: Bpos = spos(0, 0, 0);
|
||||
pub const POS_MAX: Bpos = spos(u64::MAX, u64::MAX, 0);
|
||||
pub const POS_MIN: Bpos = spos(0, 0, 0);
|
||||
pub const POS_MAX: Bpos = spos(u64::MAX, u64::MAX, 0);
|
||||
pub const SPOS_MAX: Bpos = spos(u64::MAX, u64::MAX, u32::MAX);
|
||||
|
||||
use std::cmp::Ordering;
|
||||
@ -44,14 +48,15 @@ impl PartialOrd for Bpos {
|
||||
|
||||
impl Ord for Bpos {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let l_inode = self.inode;
|
||||
let r_inode = other.inode;
|
||||
let l_offset = self.offset;
|
||||
let r_offset = other.offset;
|
||||
let l_snapshot = self.snapshot;
|
||||
let r_snapshot = other.snapshot;
|
||||
let l_inode = self.inode;
|
||||
let r_inode = other.inode;
|
||||
let l_offset = self.offset;
|
||||
let r_offset = other.offset;
|
||||
let l_snapshot = self.snapshot;
|
||||
let r_snapshot = other.snapshot;
|
||||
|
||||
l_inode.cmp(&r_inode)
|
||||
l_inode
|
||||
.cmp(&r_inode)
|
||||
.then(l_offset.cmp(&r_offset))
|
||||
.then(l_snapshot.cmp(&r_snapshot))
|
||||
}
|
||||
@ -68,9 +73,9 @@ impl fmt::Display for c::btree_id {
|
||||
}
|
||||
}
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::ffi::CString;
|
||||
use std::{path::Path,os::unix::ffi::OsStrExt};
|
||||
use std::str::FromStr;
|
||||
use std::{os::unix::ffi::OsStrExt, path::Path};
|
||||
|
||||
pub fn path_to_cstr<P: AsRef<Path>>(p: P) -> CString {
|
||||
CString::new(p.as_ref().as_os_str().as_bytes()).unwrap()
|
||||
@ -79,29 +84,60 @@ pub fn path_to_cstr<P: AsRef<Path>>(p: P) -> CString {
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InvalidBtreeId;
|
||||
pub enum BchToolsErr {
|
||||
InvalidBtreeId,
|
||||
InvalidBkeyType,
|
||||
InvalidBpos,
|
||||
}
|
||||
|
||||
impl fmt::Display for InvalidBtreeId {
|
||||
impl fmt::Display for BchToolsErr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "invalid btree id")
|
||||
match self {
|
||||
BchToolsErr::InvalidBtreeId => write!(f, "invalid btree id"),
|
||||
BchToolsErr::InvalidBkeyType => write!(f, "invalid bkey type"),
|
||||
BchToolsErr::InvalidBpos => write!(f, "invalid bpos"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for InvalidBtreeId {
|
||||
}
|
||||
impl Error for BchToolsErr {}
|
||||
|
||||
impl FromStr for c::btree_id {
|
||||
type Err = InvalidBtreeId;
|
||||
type Err = BchToolsErr;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = CString::new(s).unwrap();
|
||||
let p = s.as_ptr();
|
||||
|
||||
let v = unsafe {c::match_string(c::__bch2_btree_ids[..].as_ptr(), (-(1 as isize)) as usize, p)};
|
||||
let v = unsafe {
|
||||
c::match_string(
|
||||
c::__bch2_btree_ids[..].as_ptr(),
|
||||
(-(1 as isize)) as usize,
|
||||
p,
|
||||
)
|
||||
};
|
||||
if v >= 0 {
|
||||
Ok(unsafe { std::mem::transmute(v) })
|
||||
} else {
|
||||
Err(InvalidBtreeId)
|
||||
Err(BchToolsErr::InvalidBtreeId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for c::bch_bkey_type {
|
||||
type Err = BchToolsErr;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = CString::new(s).unwrap();
|
||||
let p = s.as_ptr();
|
||||
|
||||
let v = unsafe {
|
||||
c::match_string(c::bch2_bkey_types[..].as_ptr(), (-(1 as isize)) as usize, p)
|
||||
};
|
||||
if v >= 0 {
|
||||
Ok(unsafe { std::mem::transmute(v) })
|
||||
} else {
|
||||
Err(BchToolsErr::InvalidBkeyType)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,7 +154,7 @@ impl c::printbuf {
|
||||
impl Drop for c::printbuf {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::bch2_printbuf_exit(self) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Bpos {
|
||||
@ -126,7 +162,7 @@ impl fmt::Display for Bpos {
|
||||
let mut buf = c::printbuf::new();
|
||||
|
||||
unsafe { c::bch2_bpos_to_text(&mut buf, *self) };
|
||||
|
||||
|
||||
let s = unsafe { CStr::from_ptr(buf.buf) };
|
||||
let s = s.to_str().unwrap();
|
||||
write!(f, "{}", s)
|
||||
@ -134,7 +170,7 @@ impl fmt::Display for Bpos {
|
||||
}
|
||||
|
||||
impl FromStr for c::bpos {
|
||||
type Err = InvalidBtreeId;
|
||||
type Err = BchToolsErr;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s == "POS_MIN" {
|
||||
@ -150,20 +186,26 @@ impl FromStr for c::bpos {
|
||||
}
|
||||
|
||||
let mut fields = s.split(':');
|
||||
let ino_str = fields.next().ok_or(InvalidBtreeId)?;
|
||||
let off_str = fields.next().ok_or(InvalidBtreeId)?;
|
||||
let ino_str = fields.next().ok_or(BchToolsErr::InvalidBpos)?;
|
||||
let off_str = fields.next().ok_or(BchToolsErr::InvalidBpos)?;
|
||||
let snp_str = fields.next();
|
||||
|
||||
let ino: u64 = ino_str.parse().map_err(|_| InvalidBtreeId)?;
|
||||
let off: u64 = off_str.parse().map_err(|_| InvalidBtreeId)?;
|
||||
let snp: u32 = snp_str.map(|s| s.parse().ok()).flatten().unwrap_or(0);
|
||||
let ino: u64 = ino_str.parse().map_err(|_| BchToolsErr::InvalidBpos)?;
|
||||
let off: u64 = off_str.parse().map_err(|_| BchToolsErr::InvalidBpos)?;
|
||||
let snp: u32 = snp_str.map(|s| s.parse().ok()).flatten().unwrap_or(0);
|
||||
|
||||
Ok(c::bpos { inode: ino, offset: off, snapshot: snp })
|
||||
Ok(c::bpos {
|
||||
inode: ino,
|
||||
offset: off,
|
||||
snapshot: snp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn printbuf_to_formatter<F>(f: &mut fmt::Formatter<'_>, func: F) -> fmt::Result
|
||||
where F: Fn(*mut c::printbuf) {
|
||||
where
|
||||
F: Fn(*mut c::printbuf),
|
||||
{
|
||||
let mut buf = c::printbuf::new();
|
||||
|
||||
func(&mut buf);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
use anyhow::anyhow;
|
||||
use crate::path_to_cstr;
|
||||
use crate::bcachefs;
|
||||
use crate::bcachefs::*;
|
||||
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,
|
||||
@ -11,7 +13,8 @@ pub fn read_super_opts(
|
||||
let path = path_to_cstr(path);
|
||||
let mut sb = std::mem::MaybeUninit::zeroed();
|
||||
|
||||
let ret = unsafe { crate::bcachefs::bch2_read_super(path.as_ptr(), &mut opts, sb.as_mut_ptr()) };
|
||||
let ret =
|
||||
unsafe { crate::bcachefs::bch2_read_super(path.as_ptr(), &mut opts, sb.as_mut_ptr()) };
|
||||
|
||||
if ret != 0 {
|
||||
let err: bch_errcode = unsafe { ::std::mem::transmute(ret) };
|
||||
@ -33,7 +36,9 @@ pub fn read_super_silent(
|
||||
let path = path_to_cstr(path);
|
||||
let mut sb = std::mem::MaybeUninit::zeroed();
|
||||
|
||||
let ret = unsafe { crate::bcachefs::bch2_read_super_silent(path.as_ptr(), &mut opts, sb.as_mut_ptr()) };
|
||||
let ret = unsafe {
|
||||
crate::bcachefs::bch2_read_super_silent(path.as_ptr(), &mut opts, sb.as_mut_ptr())
|
||||
};
|
||||
|
||||
if ret != 0 {
|
||||
let err: bch_errcode = unsafe { ::std::mem::transmute(ret) };
|
||||
|
56
build.nix
56
build.nix
@ -1,56 +0,0 @@
|
||||
{ lib, stdenv, pkg-config, attr, libuuid, libsodium, keyutils, liburcu, zlib
|
||||
, libaio, udev, zstd, lz4, nix-gitignore, rustPlatform, rustc, cargo, fuse3
|
||||
, fuseSupport ? false, }:
|
||||
let
|
||||
src = nix-gitignore.gitignoreSource [ ] ./.;
|
||||
|
||||
commit = lib.strings.substring 0 7 (builtins.readFile ./.bcachefs_revision);
|
||||
version = "git-${commit}";
|
||||
in stdenv.mkDerivation {
|
||||
inherit src version;
|
||||
|
||||
pname = "bcachefs-tools";
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkg-config
|
||||
cargo
|
||||
rustc
|
||||
rustPlatform.cargoSetupHook
|
||||
rustPlatform.bindgenHook
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
libaio
|
||||
keyutils # libkeyutils
|
||||
lz4 # liblz4
|
||||
|
||||
libsodium
|
||||
liburcu
|
||||
libuuid
|
||||
zstd # libzstd
|
||||
zlib # zlib1g
|
||||
attr
|
||||
udev
|
||||
] ++ lib.optional fuseSupport fuse3;
|
||||
|
||||
${if fuseSupport then "BCACHEFS_FUSE" else null} = "1";
|
||||
|
||||
cargoRoot = ".";
|
||||
# when git-based crates are updated, run:
|
||||
# nix run github:Mic92/nix-update -- --version=skip --flake default
|
||||
# to update the hashes
|
||||
cargoDeps = rustPlatform.importCargoLock {
|
||||
lockFile = "${src}/Cargo.lock";
|
||||
};
|
||||
|
||||
makeFlags = [ "DESTDIR=${placeholder "out"}" "PREFIX=" "VERSION=${commit}" ];
|
||||
|
||||
dontStrip = true;
|
||||
checkPhase = "./target/release/bcachefs version";
|
||||
doCheck = true;
|
||||
|
||||
meta = {
|
||||
mainProgram = "bcachefs";
|
||||
license = lib.licenses.gpl2Only;
|
||||
};
|
||||
}
|
@ -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, "t: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;
|
||||
|
@ -30,6 +30,15 @@ static void dump_usage(void)
|
||||
"Report bugs to <linux-bcachefs@vger.kernel.org>");
|
||||
}
|
||||
|
||||
static void dump_node(struct bch_fs *c, struct bch_dev *ca, struct bkey_s_c k, ranges *data)
|
||||
{
|
||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
||||
|
||||
bkey_for_each_ptr(ptrs, ptr)
|
||||
if (ptr->dev == ca->dev_idx)
|
||||
range_add(data, ptr->offset << 9, c->opts.btree_node_size);
|
||||
}
|
||||
|
||||
static void dump_one_device(struct bch_fs *c, struct bch_dev *ca, int fd,
|
||||
bool entire_journal)
|
||||
{
|
||||
@ -60,42 +69,25 @@ 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 bkey_ptrs_c ptrs;
|
||||
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) {
|
||||
ptrs = bch2_bkey_ptrs_c(k);
|
||||
|
||||
bkey_for_each_ptr(ptrs, ptr)
|
||||
if (ptr->dev == ca->dev_idx)
|
||||
range_add(&data,
|
||||
ptr->offset << 9,
|
||||
btree_ptr_sectors_written(&b->key));
|
||||
}
|
||||
}
|
||||
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;
|
||||
if (!btree_node_fake(b)) {
|
||||
ptrs = bch2_bkey_ptrs_c(bkey_i_to_s_c(&b->key));
|
||||
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);
|
||||
|
||||
bkey_for_each_ptr(ptrs, ptr)
|
||||
if (ptr->dev == ca->dev_idx)
|
||||
range_add(&data,
|
||||
ptr->offset << 9,
|
||||
btree_ptr_sectors_written(&b->key));
|
||||
}
|
||||
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
bch2_trans_put(trans);
|
||||
}
|
||||
|
||||
@ -120,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);
|
||||
@ -159,7 +152,7 @@ int cmd_dump(int argc, char *argv[])
|
||||
if (IS_ERR(c))
|
||||
die("error opening devices: %s", bch2_err_str(PTR_ERR(c)));
|
||||
|
||||
down_read(&c->gc_lock);
|
||||
down_read(&c->state_lock);
|
||||
|
||||
for_each_online_member(c, ca)
|
||||
nr_devices++;
|
||||
@ -182,7 +175,7 @@ int cmd_dump(int argc, char *argv[])
|
||||
close(fd);
|
||||
}
|
||||
|
||||
up_read(&c->gc_lock);
|
||||
up_read(&c->state_lock);
|
||||
|
||||
bch2_fs_stop(c);
|
||||
return 0;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "cmds.h"
|
||||
#include "posix_to_bcachefs.h"
|
||||
#include "libbcachefs.h"
|
||||
#include "crypto.h"
|
||||
#include "libbcachefs/errcode.h"
|
||||
@ -38,40 +39,38 @@ 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) \
|
||||
x('f', force, no_argument) \
|
||||
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"
|
||||
" -U, --uuid=uuid\n"
|
||||
" --superblock_size=size\n"
|
||||
" --source=path Initialize the bcachefs filesystem from this root directory\n"
|
||||
"\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"
|
||||
@ -113,26 +112,69 @@ u64 read_flag_list_or_die(char *opt, const char * const list[],
|
||||
return v;
|
||||
}
|
||||
|
||||
void build_fs(struct bch_fs *c, const char *src_path)
|
||||
{
|
||||
struct copy_fs_state s = {};
|
||||
int src_fd = xopen(src_path, O_RDONLY|O_NOATIME);
|
||||
struct stat stat = xfstat(src_fd);
|
||||
|
||||
if (!S_ISDIR(stat.st_mode))
|
||||
die("%s is not a directory", src_path);
|
||||
|
||||
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();
|
||||
|
||||
while ((opt = getopt_long(argc, argv,
|
||||
"-L:U:g:fqhv",
|
||||
format_opts,
|
||||
NULL)) != -1)
|
||||
switch (opt) {
|
||||
if (getenv("BCACHEFS_KERNEL_ONLY"))
|
||||
initialize = false;
|
||||
|
||||
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 ||
|
||||
@ -142,6 +184,9 @@ int cmd_format(int argc, char *argv[])
|
||||
opt_set(fs_opts, metadata_replicas, v);
|
||||
opt_set(fs_opts, data_replicas, v);
|
||||
break;
|
||||
case O_source:
|
||||
opts.source = optarg;
|
||||
break;
|
||||
case O_encrypted:
|
||||
opts.encrypted = true;
|
||||
break;
|
||||
@ -162,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;
|
||||
@ -172,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;
|
||||
@ -209,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:
|
||||
@ -218,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");
|
||||
@ -248,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) {
|
||||
@ -274,6 +297,12 @@ int cmd_format(int argc, char *argv[])
|
||||
|
||||
darray_exit(&devices);
|
||||
|
||||
/* don't skip initialization when we have to build an image from a source */
|
||||
if (opts.source && !initialize) {
|
||||
printf("Warning: Forcing the initialization because the source flag was supplied\n");
|
||||
initialize = 1;
|
||||
}
|
||||
|
||||
if (initialize) {
|
||||
struct bch_opts mount_opts = bch2_opts_empty();
|
||||
|
||||
@ -291,6 +320,11 @@ int cmd_format(int argc, char *argv[])
|
||||
die("error opening %s: %s", device_paths.data[0],
|
||||
bch2_err_str(PTR_ERR(c)));
|
||||
|
||||
if (opts.source) {
|
||||
build_fs(c, opts.source);
|
||||
}
|
||||
|
||||
|
||||
bch2_fs_stop(c);
|
||||
}
|
||||
|
||||
@ -401,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;
|
||||
}
|
||||
|
302
c_src/cmd_fs.c
302
c_src/cmd_fs.c
@ -9,6 +9,7 @@
|
||||
|
||||
#include "libbcachefs/bcachefs_ioctl.h"
|
||||
#include "libbcachefs/buckets.h"
|
||||
#include "libbcachefs/disk_accounting.h"
|
||||
#include "libbcachefs/opts.h"
|
||||
#include "libbcachefs/super-io.h"
|
||||
|
||||
@ -121,19 +122,50 @@ 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)
|
||||
static void devs_usage_to_text(struct printbuf *out,
|
||||
struct bchfs_handle fs,
|
||||
dev_names dev_names)
|
||||
{
|
||||
darray_for_each(*dev_names, dev)
|
||||
if (dev->idx == idx)
|
||||
return dev;
|
||||
return NULL;
|
||||
sort(dev_names.data, dev_names.nr,
|
||||
sizeof(dev_names.data[0]), dev_by_label_cmp, NULL);
|
||||
|
||||
printbuf_tabstops_reset(out);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 20);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 14);
|
||||
|
||||
darray_for_each(dev_names, dev)
|
||||
dev_usage_to_text(out, fs, dev);
|
||||
|
||||
darray_for_each(dev_names, dev) {
|
||||
free(dev->dev);
|
||||
free(dev->label);
|
||||
}
|
||||
}
|
||||
|
||||
static void persistent_reserved_to_text(struct printbuf *out,
|
||||
unsigned nr_replicas, s64 sectors)
|
||||
{
|
||||
if (!sectors)
|
||||
return;
|
||||
|
||||
prt_str(out, "reserved:");
|
||||
prt_tab(out);
|
||||
prt_printf(out, "%u/%u ", 1, nr_replicas);
|
||||
prt_tab(out);
|
||||
prt_str(out, "[] ");
|
||||
prt_units_u64(out, sectors << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
}
|
||||
|
||||
static void replicas_usage_to_text(struct printbuf *out,
|
||||
const struct bch_replicas_usage *r,
|
||||
const struct bch_replicas_entry_v1 *r,
|
||||
s64 sectors,
|
||||
dev_names *dev_names)
|
||||
{
|
||||
if (!r->sectors)
|
||||
if (!sectors)
|
||||
return;
|
||||
|
||||
char devs[4096], *d = devs;
|
||||
@ -141,11 +173,11 @@ static void replicas_usage_to_text(struct printbuf *out,
|
||||
|
||||
unsigned durability = 0;
|
||||
|
||||
for (unsigned i = 0; i < r->r.nr_devs; i++) {
|
||||
unsigned dev_idx = r->r.devs[i];
|
||||
for (unsigned i = 0; i < r->nr_devs; i++) {
|
||||
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++ = ' ';
|
||||
@ -157,11 +189,11 @@ static void replicas_usage_to_text(struct printbuf *out,
|
||||
*d++ = ']';
|
||||
*d++ = '\0';
|
||||
|
||||
bch2_prt_data_type(out, r->r.data_type);
|
||||
bch2_prt_data_type(out, r->data_type);
|
||||
prt_char(out, ':');
|
||||
prt_tab(out);
|
||||
|
||||
prt_printf(out, "%u/%u ", r->r.nr_required, r->r.nr_devs);
|
||||
prt_printf(out, "%u/%u ", r->nr_required, r->nr_devs);
|
||||
prt_tab(out);
|
||||
|
||||
prt_printf(out, "%u ", durability);
|
||||
@ -170,7 +202,7 @@ static void replicas_usage_to_text(struct printbuf *out,
|
||||
prt_printf(out, "%s ", devs);
|
||||
prt_tab(out);
|
||||
|
||||
prt_units_u64(out, r->sectors << 9);
|
||||
prt_units_u64(out, sectors << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
}
|
||||
@ -181,14 +213,190 @@ static void replicas_usage_to_text(struct printbuf *out,
|
||||
_r = replicas_usage_next(_r), \
|
||||
BUG_ON((void *) _r > (void *) (_u)->replicas + (_u)->replica_entries_bytes))
|
||||
|
||||
static void fs_usage_to_text(struct printbuf *out, const char *path)
|
||||
typedef DARRAY(struct bkey_i_accounting *) darray_accounting_p;
|
||||
|
||||
static int accounting_p_cmp(const void *_l, const void *_r)
|
||||
{
|
||||
unsigned i;
|
||||
const struct bkey_i_accounting * const *l = _l;
|
||||
const struct bkey_i_accounting * const *r = _r;
|
||||
|
||||
struct bchfs_handle fs = bcache_fs_open(path);
|
||||
struct bpos lp = (*l)->k.p, rp = (*r)->k.p;
|
||||
|
||||
dev_names dev_names = bchu_fs_get_devices(fs);
|
||||
return bpos_cmp(lp, rp);
|
||||
}
|
||||
|
||||
static void accounting_sort(darray_accounting_p *sorted,
|
||||
struct bch_ioctl_query_accounting *in)
|
||||
{
|
||||
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)))
|
||||
if (darray_push(sorted, a))
|
||||
die("memory allocation failure");
|
||||
|
||||
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)
|
||||
{
|
||||
struct bch_ioctl_query_accounting *a =
|
||||
bchu_fs_accounting(fs,
|
||||
BIT(BCH_DISK_ACCOUNTING_persistent_reserved)|
|
||||
BIT(BCH_DISK_ACCOUNTING_replicas)|
|
||||
BIT(BCH_DISK_ACCOUNTING_compression)|
|
||||
BIT(BCH_DISK_ACCOUNTING_btree)|
|
||||
BIT(BCH_DISK_ACCOUNTING_rebalance_work));
|
||||
if (!a)
|
||||
return -1;
|
||||
|
||||
accounting_swab_if_old(a);
|
||||
|
||||
darray_accounting_p a_sorted = {};
|
||||
|
||||
accounting_sort(&a_sorted, a);
|
||||
|
||||
prt_str(out, "Filesystem: ");
|
||||
pr_uuid(out, fs.uuid.b);
|
||||
prt_newline(out);
|
||||
|
||||
printbuf_tabstops_reset(out);
|
||||
printbuf_tabstop_push(out, 20);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
|
||||
prt_str(out, "Size:");
|
||||
prt_tab(out);
|
||||
prt_units_u64(out, a->capacity << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
|
||||
prt_str(out, "Used:");
|
||||
prt_tab(out);
|
||||
prt_units_u64(out, a->used << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
|
||||
prt_str(out, "Online reserved:");
|
||||
prt_tab(out);
|
||||
prt_units_u64(out, a->online_reserved << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
|
||||
prt_newline(out);
|
||||
|
||||
printbuf_tabstops_reset(out);
|
||||
|
||||
printbuf_tabstop_push(out, 16);
|
||||
prt_str(out, "Data type");
|
||||
prt_tab(out);
|
||||
|
||||
printbuf_tabstop_push(out, 16);
|
||||
prt_str(out, "Required/total");
|
||||
prt_tab(out);
|
||||
|
||||
printbuf_tabstop_push(out, 14);
|
||||
prt_str(out, "Durability");
|
||||
prt_tab(out);
|
||||
|
||||
printbuf_tabstop_push(out, 14);
|
||||
prt_str(out, "Devices");
|
||||
prt_newline(out);
|
||||
|
||||
printbuf_tabstop_push(out, 14);
|
||||
|
||||
unsigned prev_type = 0;
|
||||
|
||||
darray_for_each(a_sorted, i) {
|
||||
struct bkey_i_accounting *a = *i;
|
||||
|
||||
struct disk_accounting_pos acc_k;
|
||||
bpos_to_disk_accounting_pos(&acc_k, a->k.p);
|
||||
|
||||
bool new_type = acc_k.type != prev_type;
|
||||
prev_type = acc_k.type;
|
||||
|
||||
switch (acc_k.type) {
|
||||
case BCH_DISK_ACCOUNTING_persistent_reserved:
|
||||
persistent_reserved_to_text(out,
|
||||
acc_k.persistent_reserved.nr_replicas,
|
||||
a->v.d[0]);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_replicas:
|
||||
replicas_usage_to_text(out, &acc_k.replicas, a->v.d[0], &dev_names);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_compression:
|
||||
if (new_type) {
|
||||
prt_printf(out, "\nCompression:\n");
|
||||
printbuf_tabstops_reset(out);
|
||||
printbuf_tabstop_push(out, 12);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 24);
|
||||
prt_printf(out, "type\tcompressed\runcompressed\raverage extent size\r\n");
|
||||
}
|
||||
|
||||
u64 nr_extents = a->v.d[0];
|
||||
u64 sectors_uncompressed = a->v.d[1];
|
||||
u64 sectors_compressed = a->v.d[2];
|
||||
|
||||
bch2_prt_compression_type(out, acc_k.compression.type);
|
||||
prt_tab(out);
|
||||
|
||||
prt_human_readable_u64(out, sectors_compressed << 9);
|
||||
prt_tab_rjust(out);
|
||||
|
||||
prt_human_readable_u64(out, sectors_uncompressed << 9);
|
||||
prt_tab_rjust(out);
|
||||
|
||||
prt_human_readable_u64(out, nr_extents
|
||||
? div_u64(sectors_uncompressed << 9, nr_extents)
|
||||
: 0);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_btree:
|
||||
if (new_type) {
|
||||
prt_printf(out, "\nBtree usage:\n");
|
||||
printbuf_tabstops_reset(out);
|
||||
printbuf_tabstop_push(out, 12);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
}
|
||||
prt_printf(out, "%s:\t", bch2_btree_id_str(acc_k.btree.id));
|
||||
prt_units_u64(out, a->v.d[0] << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_rebalance_work:
|
||||
if (new_type)
|
||||
prt_printf(out, "\nPending rebalance work:\n");
|
||||
prt_units_u64(out, a->v.d[0] << 9);
|
||||
prt_newline(out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
darray_exit(&a_sorted);
|
||||
free(a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fs_usage_v0_to_text(struct printbuf *out,
|
||||
struct bchfs_handle fs,
|
||||
dev_names dev_names)
|
||||
{
|
||||
struct bch_ioctl_fs_usage *u = bchu_fs_usage(fs);
|
||||
|
||||
prt_str(out, "Filesystem: ");
|
||||
@ -239,63 +447,63 @@ static void fs_usage_to_text(struct printbuf *out, const char *path)
|
||||
|
||||
printbuf_tabstop_push(out, 14);
|
||||
|
||||
for (i = 0; i < BCH_REPLICAS_MAX; i++) {
|
||||
if (!u->persistent_reserved[i])
|
||||
continue;
|
||||
|
||||
prt_str(out, "reserved:");
|
||||
prt_tab(out);
|
||||
prt_printf(out, "%u/%u ", 1, i);
|
||||
prt_tab(out);
|
||||
prt_str(out, "[] ");
|
||||
prt_units_u64(out, u->persistent_reserved[i] << 9);
|
||||
prt_tab_rjust(out);
|
||||
prt_newline(out);
|
||||
}
|
||||
for (unsigned i = 0; i < BCH_REPLICAS_MAX; i++)
|
||||
persistent_reserved_to_text(out, i, u->persistent_reserved[i]);
|
||||
|
||||
struct bch_replicas_usage *r;
|
||||
|
||||
for_each_usage_replica(u, r)
|
||||
if (r->r.data_type < BCH_DATA_user)
|
||||
replicas_usage_to_text(out, r, &dev_names);
|
||||
replicas_usage_to_text(out, &r->r, r->sectors, &dev_names);
|
||||
|
||||
for_each_usage_replica(u, r)
|
||||
if (r->r.data_type == BCH_DATA_user &&
|
||||
r->r.nr_required <= 1)
|
||||
replicas_usage_to_text(out, r, &dev_names);
|
||||
replicas_usage_to_text(out, &r->r, r->sectors, &dev_names);
|
||||
|
||||
for_each_usage_replica(u, r)
|
||||
if (r->r.data_type == BCH_DATA_user &&
|
||||
r->r.nr_required > 1)
|
||||
replicas_usage_to_text(out, r, &dev_names);
|
||||
replicas_usage_to_text(out, &r->r, r->sectors, &dev_names);
|
||||
|
||||
for_each_usage_replica(u, r)
|
||||
if (r->r.data_type > BCH_DATA_user)
|
||||
replicas_usage_to_text(out, r, &dev_names);
|
||||
replicas_usage_to_text(out, &r->r, r->sectors, &dev_names);
|
||||
|
||||
free(u);
|
||||
}
|
||||
|
||||
sort(dev_names.data, dev_names.nr,
|
||||
sizeof(dev_names.data[0]), dev_by_label_cmp, NULL);
|
||||
static void fs_usage_to_text(struct printbuf *out, const char *path)
|
||||
{
|
||||
struct bchfs_handle fs = bcache_fs_open(path);
|
||||
|
||||
printbuf_tabstops_reset(out);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 20);
|
||||
printbuf_tabstop_push(out, 16);
|
||||
printbuf_tabstop_push(out, 14);
|
||||
dev_names dev_names = bchu_fs_get_devices(fs);
|
||||
|
||||
darray_for_each(dev_names, dev)
|
||||
dev_usage_to_text(out, fs, dev);
|
||||
if (!fs_usage_v1_to_text(out, fs, dev_names))
|
||||
goto devs;
|
||||
|
||||
fs_usage_v0_to_text(out, fs, dev_names);
|
||||
devs:
|
||||
devs_usage_to_text(out, fs, dev_names);
|
||||
|
||||
darray_for_each(dev_names, dev) {
|
||||
free(dev->dev);
|
||||
free(dev->label);
|
||||
}
|
||||
darray_exit(&dev_names);
|
||||
|
||||
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"
|
||||
|
122
c_src/cmd_fsck.c
122
c_src/cmd_fsck.c
@ -1,4 +1,5 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
@ -20,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"
|
||||
@ -60,14 +60,18 @@ static int splice_fd_to_stdinout(int fd)
|
||||
setnonblocking(STDIN_FILENO);
|
||||
setnonblocking(fd);
|
||||
|
||||
bool stdin_closed = false;
|
||||
|
||||
while (true) {
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
FD_SET(fd, &fds);
|
||||
if (!stdin_closed)
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
|
||||
select(fd + 1, &fds, NULL, NULL, NULL);
|
||||
if (select(fd + 1, &fds, NULL, NULL, NULL) < 0)
|
||||
die("select error: %m");
|
||||
|
||||
int r = do_splice(fd, STDOUT_FILENO);
|
||||
if (r < 0)
|
||||
@ -78,21 +82,25 @@ static int splice_fd_to_stdinout(int fd)
|
||||
r = do_splice(STDIN_FILENO, fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r)
|
||||
stdin_closed = true;
|
||||
}
|
||||
|
||||
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)
|
||||
die("BCH_IOCTL_FSCK_ONLINE error: %s", bch2_err_str(fsck_fd));
|
||||
die("BCH_IOCTL_FSCK_ONLINE error: %s", bch2_err_str(errno));
|
||||
|
||||
return splice_fd_to_stdinout(fsck_fd);
|
||||
}
|
||||
@ -106,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;
|
||||
@ -151,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' },
|
||||
@ -165,16 +211,22 @@ int cmd_fsck(int argc, char *argv[])
|
||||
int opt, ret = 0;
|
||||
struct printbuf opts_str = PRINTBUF;
|
||||
|
||||
if (getenv("BCACHEFS_KERNEL_ONLY"))
|
||||
kernel = true;
|
||||
|
||||
append_opt(&opts_str, "degraded");
|
||||
append_opt(&opts_str, "fsck");
|
||||
append_opt(&opts_str, "fix_errors=ask");
|
||||
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");
|
||||
@ -192,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;
|
||||
@ -217,42 +266,63 @@ 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)) {
|
||||
printf("Running fsck online\n");
|
||||
return fsck_online(*i, opts_str.buf);
|
||||
}
|
||||
|
||||
int kernel_probed = kernel;
|
||||
if (kernel_probed < 0)
|
||||
kernel_probed = should_use_kernel_fsck(devs);
|
||||
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
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;
|
||||
|
||||
if (fsck_fd < 0)
|
||||
die("BCH_IOCTL_FSCK_OFFLINE error: %s", bch2_err_str(fsck_fd));
|
||||
die("BCH_IOCTL_FSCK_OFFLINE error: %s", bch2_err_str(errno));
|
||||
|
||||
ret = splice_fd_to_stdinout(fsck_fd);
|
||||
} else {
|
||||
userland_fsck:
|
||||
ret = bch2_parse_mount_opts(NULL, &opts, 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;
|
||||
|
||||
darray_for_each(devs, i)
|
||||
if (dev_mounted(*i))
|
||||
return fsck_online(*i);
|
||||
|
||||
struct bch_fs *c = bch2_fs_open(devs.data, devs.nr, opts);
|
||||
if (IS_ERR(c))
|
||||
exit(8);
|
||||
|
@ -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;
|
||||
@ -191,7 +188,7 @@ retry:
|
||||
bch2_trans_begin(trans);
|
||||
now = bch2_current_time(c);
|
||||
|
||||
ret = bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_INTENT);
|
||||
ret = bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -544,7 +540,7 @@ retry:
|
||||
bch2_trans_begin(trans);
|
||||
now = bch2_current_time(c);
|
||||
|
||||
ret = bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_INTENT);
|
||||
ret = bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@ -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 */
|
||||
|
@ -66,7 +66,7 @@ int cmd_unlock(int argc, char *argv[])
|
||||
if (ret)
|
||||
die("Error opening %s: %s", dev, bch2_err_str(ret));
|
||||
|
||||
if (!bch2_sb_is_encrypted_and_locked(sb.sb))
|
||||
if (!bch2_sb_is_encrypted(sb.sb))
|
||||
die("%s is not encrypted", dev);
|
||||
|
||||
if (check)
|
||||
@ -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,44 +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 = bch_dev_bkey_exists(c, ptr->dev);
|
||||
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);
|
||||
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,10 +272,12 @@ 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);
|
||||
opt_set(opts, nochanges, true);
|
||||
opt_set(opts, norecovery, true);
|
||||
opt_set(opts, read_only, true);
|
||||
@ -227,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':
|
||||
@ -238,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"));
|
||||
@ -262,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;
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
@ -20,27 +18,18 @@
|
||||
#include "cmds.h"
|
||||
#include "crypto.h"
|
||||
#include "libbcachefs.h"
|
||||
#include "posix_to_bcachefs.h"
|
||||
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/generic-radix-tree.h>
|
||||
#include <linux/xattr.h>
|
||||
#include "libbcachefs/bcachefs.h"
|
||||
#include "libbcachefs/alloc_background.h"
|
||||
#include "libbcachefs/alloc_foreground.h"
|
||||
#include "libbcachefs/btree_update.h"
|
||||
#include "libbcachefs/buckets.h"
|
||||
#include "libbcachefs/dirent.h"
|
||||
#include "libbcachefs/errcode.h"
|
||||
#include "libbcachefs/fs-common.h"
|
||||
#include "libbcachefs/inode.h"
|
||||
#include "libbcachefs/io_write.h"
|
||||
#include "libbcachefs/replicas.h"
|
||||
#include "libbcachefs/str_hash.h"
|
||||
#include "libbcachefs/super.h"
|
||||
#include "libbcachefs/xattr.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)
|
||||
{
|
||||
@ -117,403 +106,6 @@ static void mark_unreserved_space(struct bch_fs *c, ranges extents)
|
||||
}
|
||||
}
|
||||
|
||||
static void update_inode(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *inode)
|
||||
{
|
||||
struct bkey_inode_buf packed;
|
||||
int ret;
|
||||
|
||||
bch2_inode_pack(&packed, inode);
|
||||
packed.inode.k.p.snapshot = U32_MAX;
|
||||
ret = bch2_btree_insert(c, BTREE_ID_inodes, &packed.inode.k_i,
|
||||
NULL, 0);
|
||||
if (ret)
|
||||
die("error updating inode: %s", bch2_err_str(ret));
|
||||
}
|
||||
|
||||
static void create_link(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *parent,
|
||||
const char *name, u64 inum, mode_t mode)
|
||||
{
|
||||
struct qstr qstr = QSTR(name);
|
||||
struct bch_inode_unpacked parent_u;
|
||||
struct bch_inode_unpacked inode;
|
||||
|
||||
int ret = bch2_trans_do(c, NULL, NULL, 0,
|
||||
bch2_link_trans(trans,
|
||||
(subvol_inum) { 1, parent->bi_inum }, &parent_u,
|
||||
(subvol_inum) { 1, inum }, &inode, &qstr));
|
||||
if (ret)
|
||||
die("error creating hardlink: %s", bch2_err_str(ret));
|
||||
}
|
||||
|
||||
static struct bch_inode_unpacked create_file(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *parent,
|
||||
const char *name,
|
||||
uid_t uid, gid_t gid,
|
||||
mode_t mode, dev_t rdev)
|
||||
{
|
||||
struct qstr qstr = QSTR(name);
|
||||
struct bch_inode_unpacked new_inode;
|
||||
|
||||
bch2_inode_init_early(c, &new_inode);
|
||||
|
||||
int ret = bch2_trans_do(c, NULL, NULL, 0,
|
||||
bch2_create_trans(trans,
|
||||
(subvol_inum) { 1, parent->bi_inum }, parent,
|
||||
&new_inode, &qstr,
|
||||
uid, gid, mode, rdev, NULL, NULL,
|
||||
(subvol_inum) {}, 0));
|
||||
if (ret)
|
||||
die("error creating %s: %s", name, bch2_err_str(ret));
|
||||
|
||||
return new_inode;
|
||||
}
|
||||
|
||||
#define for_each_xattr_handler(handlers, handler) \
|
||||
if (handlers) \
|
||||
for ((handler) = *(handlers)++; \
|
||||
(handler) != NULL; \
|
||||
(handler) = *(handlers)++)
|
||||
|
||||
static const struct xattr_handler *xattr_resolve_name(char **name)
|
||||
{
|
||||
const struct xattr_handler **handlers = bch2_xattr_handlers;
|
||||
const struct xattr_handler *handler;
|
||||
|
||||
for_each_xattr_handler(handlers, handler) {
|
||||
char *n;
|
||||
|
||||
n = strcmp_prefix(*name, xattr_prefix(handler));
|
||||
if (n) {
|
||||
if (!handler->prefix ^ !*n) {
|
||||
if (*n)
|
||||
continue;
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
*name = n;
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static void copy_times(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
struct stat *src)
|
||||
{
|
||||
dst->bi_atime = timespec_to_bch2_time(c, src->st_atim);
|
||||
dst->bi_mtime = timespec_to_bch2_time(c, src->st_mtim);
|
||||
dst->bi_ctime = timespec_to_bch2_time(c, src->st_ctim);
|
||||
}
|
||||
|
||||
static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
char *src)
|
||||
{
|
||||
struct bch_hash_info hash_info = bch2_hash_info_init(c, dst);
|
||||
|
||||
char attrs[XATTR_LIST_MAX];
|
||||
ssize_t attrs_size = llistxattr(src, attrs, sizeof(attrs));
|
||||
if (attrs_size < 0)
|
||||
die("listxattr error: %m");
|
||||
|
||||
char *next, *attr;
|
||||
for (attr = attrs;
|
||||
attr < attrs + attrs_size;
|
||||
attr = next) {
|
||||
next = attr + strlen(attr) + 1;
|
||||
|
||||
char val[XATTR_SIZE_MAX];
|
||||
ssize_t val_size = lgetxattr(src, attr, val, sizeof(val));
|
||||
|
||||
if (val_size < 0)
|
||||
die("error getting xattr val: %m");
|
||||
|
||||
const struct xattr_handler *h = xattr_resolve_name(&attr);
|
||||
struct bch_inode_unpacked inode_u;
|
||||
|
||||
int ret = bch2_trans_do(c, NULL, NULL, 0,
|
||||
bch2_xattr_set(trans,
|
||||
(subvol_inum) { 1, dst->bi_inum },
|
||||
&inode_u, &hash_info, attr,
|
||||
val, val_size, h->flags, 0));
|
||||
if (ret < 0)
|
||||
die("error creating xattr: %s", bch2_err_str(ret));
|
||||
}
|
||||
}
|
||||
|
||||
#define WRITE_DATA_BUF (1 << 20)
|
||||
|
||||
static char buf[WRITE_DATA_BUF] __aligned(PAGE_SIZE);
|
||||
|
||||
static void write_data(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *dst_inode,
|
||||
u64 dst_offset, void *buf, size_t len)
|
||||
{
|
||||
struct bch_write_op op;
|
||||
struct bio_vec bv[WRITE_DATA_BUF / PAGE_SIZE];
|
||||
|
||||
BUG_ON(dst_offset & (block_bytes(c) - 1));
|
||||
BUG_ON(len & (block_bytes(c) - 1));
|
||||
BUG_ON(len > WRITE_DATA_BUF);
|
||||
|
||||
bio_init(&op.wbio.bio, NULL, bv, ARRAY_SIZE(bv), 0);
|
||||
bch2_bio_map(&op.wbio.bio, buf, len);
|
||||
|
||||
bch2_write_op_init(&op, c, bch2_opts_to_inode_opts(c->opts));
|
||||
op.write_point = writepoint_hashed(0);
|
||||
op.nr_replicas = 1;
|
||||
op.subvol = 1;
|
||||
op.pos = SPOS(dst_inode->bi_inum, dst_offset >> 9, U32_MAX);
|
||||
op.flags |= BCH_WRITE_SYNC;
|
||||
|
||||
int ret = bch2_disk_reservation_get(c, &op.res, len >> 9,
|
||||
c->opts.data_replicas, 0);
|
||||
if (ret)
|
||||
die("error reserving space in new filesystem: %s", bch2_err_str(ret));
|
||||
|
||||
closure_call(&op.cl, bch2_write, NULL, NULL);
|
||||
|
||||
BUG_ON(!(op.flags & BCH_WRITE_DONE));
|
||||
dst_inode->bi_sectors += len >> 9;
|
||||
|
||||
if (op.error)
|
||||
die("write error: %s", bch2_err_str(op.error));
|
||||
}
|
||||
|
||||
static void copy_data(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *dst_inode,
|
||||
int src_fd, u64 start, u64 end)
|
||||
{
|
||||
while (start < end) {
|
||||
unsigned len = min_t(u64, end - start, sizeof(buf));
|
||||
unsigned pad = round_up(len, block_bytes(c)) - len;
|
||||
|
||||
xpread(src_fd, buf, len, start);
|
||||
memset(buf + len, 0, pad);
|
||||
|
||||
write_data(c, dst_inode, start, buf, len + pad);
|
||||
start += len;
|
||||
}
|
||||
}
|
||||
|
||||
static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
u64 logical, u64 physical, u64 length)
|
||||
{
|
||||
struct bch_dev *ca = c->devs[0];
|
||||
|
||||
BUG_ON(logical & (block_bytes(c) - 1));
|
||||
BUG_ON(physical & (block_bytes(c) - 1));
|
||||
BUG_ON(length & (block_bytes(c) - 1));
|
||||
|
||||
logical >>= 9;
|
||||
physical >>= 9;
|
||||
length >>= 9;
|
||||
|
||||
BUG_ON(physical + length > bucket_to_sector(ca, ca->mi.nbuckets));
|
||||
|
||||
while (length) {
|
||||
struct bkey_i_extent *e;
|
||||
BKEY_PADDED_ONSTACK(k, BKEY_EXTENT_VAL_U64s_MAX) k;
|
||||
u64 b = sector_to_bucket(ca, physical);
|
||||
struct disk_reservation res;
|
||||
unsigned sectors;
|
||||
int ret;
|
||||
|
||||
sectors = min(ca->mi.bucket_size -
|
||||
(physical & (ca->mi.bucket_size - 1)),
|
||||
length);
|
||||
|
||||
e = bkey_extent_init(&k.k);
|
||||
e->k.p.inode = dst->bi_inum;
|
||||
e->k.p.offset = logical + sectors;
|
||||
e->k.p.snapshot = U32_MAX;
|
||||
e->k.size = sectors;
|
||||
bch2_bkey_append_ptr(&e->k_i, (struct bch_extent_ptr) {
|
||||
.offset = physical,
|
||||
.dev = 0,
|
||||
.gen = *bucket_gen(ca, b),
|
||||
});
|
||||
|
||||
ret = bch2_disk_reservation_get(c, &res, sectors, 1,
|
||||
BCH_DISK_RESERVATION_NOFAIL);
|
||||
if (ret)
|
||||
die("error reserving space in new filesystem: %s",
|
||||
bch2_err_str(ret));
|
||||
|
||||
ret = bch2_btree_insert(c, BTREE_ID_extents, &e->k_i, &res, 0);
|
||||
if (ret)
|
||||
die("btree insert error %s", bch2_err_str(ret));
|
||||
|
||||
bch2_disk_reservation_put(c, &res);
|
||||
|
||||
dst->bi_sectors += sectors;
|
||||
logical += sectors;
|
||||
physical += sectors;
|
||||
length -= sectors;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_link(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
char *src)
|
||||
{
|
||||
ssize_t ret = readlink(src, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
die("readlink error: %m");
|
||||
|
||||
write_data(c, dst, 0, buf, round_up(ret, block_bytes(c)));
|
||||
}
|
||||
|
||||
static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
int src_fd, u64 src_size,
|
||||
char *src_path, ranges *extents)
|
||||
{
|
||||
struct fiemap_iter iter;
|
||||
struct fiemap_extent e;
|
||||
|
||||
fiemap_for_each(src_fd, iter, e)
|
||||
if (e.fe_flags & FIEMAP_EXTENT_UNKNOWN) {
|
||||
fsync(src_fd);
|
||||
break;
|
||||
}
|
||||
fiemap_iter_exit(&iter);
|
||||
|
||||
fiemap_for_each(src_fd, iter, e) {
|
||||
u64 src_max = roundup(src_size, block_bytes(c));
|
||||
|
||||
e.fe_length = min(e.fe_length, src_max - e.fe_logical);
|
||||
|
||||
if ((e.fe_logical & (block_bytes(c) - 1)) ||
|
||||
(e.fe_length & (block_bytes(c) - 1)))
|
||||
die("Unaligned extent in %s - can't handle", src_path);
|
||||
|
||||
if (e.fe_flags & (FIEMAP_EXTENT_UNKNOWN|
|
||||
FIEMAP_EXTENT_ENCODED|
|
||||
FIEMAP_EXTENT_NOT_ALIGNED|
|
||||
FIEMAP_EXTENT_DATA_INLINE)) {
|
||||
copy_data(c, dst, src_fd, e.fe_logical,
|
||||
min(src_size - e.fe_logical,
|
||||
e.fe_length));
|
||||
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) {
|
||||
copy_data(c, dst, src_fd, e.fe_logical,
|
||||
min(src_size - e.fe_logical,
|
||||
e.fe_length));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((e.fe_physical & (block_bytes(c) - 1)))
|
||||
die("Unaligned extent in %s - can't handle", src_path);
|
||||
|
||||
range_add(extents, e.fe_physical, e.fe_length);
|
||||
link_data(c, dst, e.fe_logical, e.fe_physical, e.fe_length);
|
||||
}
|
||||
fiemap_iter_exit(&iter);
|
||||
}
|
||||
|
||||
struct copy_fs_state {
|
||||
u64 bcachefs_inum;
|
||||
dev_t dev;
|
||||
|
||||
GENRADIX(u64) hardlinks;
|
||||
ranges extents;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
DIR *dir = fdopendir(src_fd);
|
||||
struct dirent *d;
|
||||
|
||||
while ((errno = 0), (d = readdir(dir))) {
|
||||
struct bch_inode_unpacked inode;
|
||||
int fd;
|
||||
|
||||
if (fchdir(src_fd))
|
||||
die("chdir error: %m");
|
||||
|
||||
struct stat stat =
|
||||
xfstatat(src_fd, d->d_name, AT_SYMLINK_NOFOLLOW);
|
||||
|
||||
if (!strcmp(d->d_name, ".") ||
|
||||
!strcmp(d->d_name, "..") ||
|
||||
!strcmp(d->d_name, "lost+found") ||
|
||||
stat.st_ino == s->bcachefs_inum)
|
||||
continue;
|
||||
|
||||
char *child_path = mprintf("%s/%s", src_path, d->d_name);
|
||||
|
||||
if (stat.st_dev != s->dev)
|
||||
die("%s does not have correct st_dev!", child_path);
|
||||
|
||||
u64 *dst_inum = S_ISREG(stat.st_mode)
|
||||
? genradix_ptr_alloc(&s->hardlinks, stat.st_ino, GFP_KERNEL)
|
||||
: NULL;
|
||||
|
||||
if (dst_inum && *dst_inum) {
|
||||
create_link(c, dst, d->d_name, *dst_inum, S_IFREG);
|
||||
goto next;
|
||||
}
|
||||
|
||||
inode = create_file(c, dst, d->d_name,
|
||||
stat.st_uid, stat.st_gid,
|
||||
stat.st_mode, stat.st_rdev);
|
||||
|
||||
if (dst_inum)
|
||||
*dst_inum = inode.bi_inum;
|
||||
|
||||
copy_times(c, &inode, &stat);
|
||||
copy_xattrs(c, &inode, d->d_name);
|
||||
|
||||
/* copy xattrs */
|
||||
|
||||
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);
|
||||
close(fd);
|
||||
break;
|
||||
case DT_REG:
|
||||
inode.bi_size = stat.st_size;
|
||||
|
||||
fd = xopen(d->d_name, O_RDONLY|O_NOATIME);
|
||||
copy_file(c, &inode, fd, stat.st_size,
|
||||
child_path, &s->extents);
|
||||
close(fd);
|
||||
break;
|
||||
case DT_LNK:
|
||||
inode.bi_size = stat.st_size;
|
||||
|
||||
copy_link(c, &inode, d->d_name);
|
||||
break;
|
||||
case DT_FIFO:
|
||||
case DT_CHR:
|
||||
case DT_BLK:
|
||||
case DT_SOCK:
|
||||
case DT_WHT:
|
||||
/* nothing else to copy for these: */
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
update_inode(c, &inode);
|
||||
next:
|
||||
free(child_path);
|
||||
}
|
||||
|
||||
if (errno)
|
||||
die("readdir error: %m");
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static ranges reserve_new_fs_space(const char *file_path, unsigned block_size,
|
||||
u64 size, u64 *bcachefs_inum, dev_t dev,
|
||||
bool force)
|
||||
@ -561,71 +153,15 @@ static ranges reserve_new_fs_space(const char *file_path, unsigned block_size,
|
||||
return extents;
|
||||
}
|
||||
|
||||
static void reserve_old_fs_space(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *root_inode,
|
||||
ranges *extents)
|
||||
{
|
||||
struct bch_dev *ca = c->devs[0];
|
||||
struct bch_inode_unpacked dst;
|
||||
struct hole_iter iter;
|
||||
struct range i;
|
||||
|
||||
dst = create_file(c, root_inode, "old_migrated_filesystem",
|
||||
0, 0, S_IFREG|0400, 0);
|
||||
dst.bi_size = bucket_to_sector(ca, ca->mi.nbuckets) << 9;
|
||||
|
||||
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);
|
||||
|
||||
update_inode(c, &dst);
|
||||
}
|
||||
|
||||
static void copy_fs(struct bch_fs *c, int src_fd, const char *src_path,
|
||||
u64 bcachefs_inum, ranges *extents)
|
||||
{
|
||||
syncfs(src_fd);
|
||||
|
||||
struct bch_inode_unpacked root_inode;
|
||||
int ret = bch2_inode_find_by_inum(c, (subvol_inum) { 1, BCACHEFS_ROOT_INO },
|
||||
&root_inode);
|
||||
if (ret)
|
||||
die("error looking up root directory: %s", bch2_err_str(ret));
|
||||
|
||||
if (fchdir(src_fd))
|
||||
die("chdir error: %m");
|
||||
|
||||
struct stat stat = xfstat(src_fd);
|
||||
copy_times(c, &root_inode, &stat);
|
||||
copy_xattrs(c, &root_inode, ".");
|
||||
|
||||
struct copy_fs_state s = {
|
||||
.bcachefs_inum = bcachefs_inum,
|
||||
.dev = stat.st_dev,
|
||||
.extents = *extents,
|
||||
};
|
||||
|
||||
/* now, copy: */
|
||||
copy_dir(&s, c, &root_inode, src_fd, src_path);
|
||||
|
||||
reserve_old_fs_space(c, &root_inode, &s.extents);
|
||||
|
||||
update_inode(c, &root_inode);
|
||||
|
||||
darray_exit(&s.extents);
|
||||
genradix_free(&s.hardlinks);
|
||||
}
|
||||
|
||||
static void find_superblock_space(ranges extents,
|
||||
struct format_opts opts,
|
||||
struct dev_opts *dev)
|
||||
{
|
||||
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) {
|
||||
@ -673,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)
|
||||
@ -712,26 +253,38 @@ 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, buckets_nouse, 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)));
|
||||
|
||||
ret = bch2_buckets_nouse_alloc(c);
|
||||
if (ret)
|
||||
die("Error allocating buckets_nouse: %s", bch2_err_str(ret));
|
||||
|
||||
mark_unreserved_space(c, extents);
|
||||
|
||||
ret = bch2_fs_start(c);
|
||||
if (ret)
|
||||
die("Error starting new filesystem: %s", bch2_err_str(ret));
|
||||
|
||||
copy_fs(c, fs_fd, fs_path, bcachefs_inum, &extents);
|
||||
struct copy_fs_state s = {
|
||||
.bcachefs_inum = bcachefs_inum,
|
||||
.dev = stat.st_dev,
|
||||
.extents = extents,
|
||||
.type = BCH_MIGRATE_migrate,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
@ -754,12 +307,12 @@ static int migrate_fs(const char *fs_path,
|
||||
"superblock at the default offset and finish the migration run\n"
|
||||
" bcachefs migrate-superblock -d %s -o %llu\n"
|
||||
"\n"
|
||||
"The new filesystem will have a file at /old_migrated_filestem\n"
|
||||
"The new filesystem will have a file at /old_migrated_filesystem\n"
|
||||
"referencing all disk space that might be used by the existing\n"
|
||||
"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;
|
||||
}
|
||||
|
||||
@ -823,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)
|
||||
@ -832,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;
|
||||
@ -844,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[]);
|
||||
|
@ -101,7 +101,7 @@ struct bch_key derive_passphrase(struct bch_sb_field_crypt *crypt,
|
||||
return key;
|
||||
}
|
||||
|
||||
bool bch2_sb_is_encrypted_and_locked(struct bch_sb *sb)
|
||||
bool bch2_sb_is_encrypted(struct bch_sb *sb)
|
||||
{
|
||||
struct bch_sb_field_crypt *crypt;
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
@ -12,11 +12,14 @@ char *read_passphrase(const char *);
|
||||
char *read_passphrase_twice(const char *);
|
||||
|
||||
struct bch_key derive_passphrase(struct bch_sb_field_crypt *, const char *);
|
||||
bool bch2_sb_is_encrypted_and_locked(struct bch_sb *);
|
||||
bool bch2_sb_is_encrypted(struct bch_sb *);
|
||||
void bch2_passphrase_check(struct bch_sb *, const char *,
|
||||
struct bch_key *, struct bch_encrypted_key *);
|
||||
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)
|
||||
{
|
||||
@ -638,7 +757,7 @@ struct bch_opts bch2_parse_opts(struct bch_opt_strs strs)
|
||||
ret = bch2_opt_parse(NULL,
|
||||
&bch2_opt_table[i],
|
||||
strs.by_id[i], &v, &err);
|
||||
if (ret < 0)
|
||||
if (ret < 0 && ret != -BCH_ERR_option_needs_open_fs)
|
||||
die("Invalid option %s", err.buf);
|
||||
|
||||
bch2_opt_set_by_id(&opts, i, v);
|
||||
@ -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;
|
||||
}
|
||||
|
@ -4,8 +4,10 @@
|
||||
#include <linux/uuid.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libbcachefs/bcachefs.h"
|
||||
#include "libbcachefs/bcachefs_format.h"
|
||||
#include "libbcachefs/bcachefs_ioctl.h"
|
||||
#include "libbcachefs/inode.h"
|
||||
#include "libbcachefs/opts.h"
|
||||
#include "libbcachefs/vstructs.h"
|
||||
#include "tools-util.h"
|
||||
@ -26,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);
|
||||
@ -37,16 +42,21 @@ struct format_opts {
|
||||
unsigned superblock_size;
|
||||
bool encrypted;
|
||||
char *passphrase;
|
||||
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,
|
||||
};
|
||||
}
|
||||
@ -55,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);
|
||||
@ -94,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)
|
||||
@ -168,6 +185,35 @@ static inline struct bch_ioctl_fs_usage *bchu_fs_usage(struct bchfs_handle fs)
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct bch_ioctl_query_accounting *bchu_fs_accounting(struct bchfs_handle fs,
|
||||
unsigned typemask)
|
||||
{
|
||||
unsigned accounting_u64s = 128;
|
||||
struct bch_ioctl_query_accounting *ret = NULL;
|
||||
|
||||
while (1) {
|
||||
ret = xrealloc(ret, sizeof(*ret) + accounting_u64s * sizeof(u64));
|
||||
|
||||
memset(ret, 0, sizeof(*ret));
|
||||
|
||||
ret->accounting_u64s = accounting_u64s;
|
||||
ret->accounting_types_mask = typemask;
|
||||
|
||||
if (!ioctl(fs.ioctl_fd, BCH_IOCTL_QUERY_ACCOUNTING, ret))
|
||||
return ret;
|
||||
|
||||
if (errno == ENOTTY)
|
||||
return NULL;
|
||||
|
||||
if (errno == ERANGE) {
|
||||
accounting_u64s *= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
die("BCH_IOCTL_USAGE error: %m");
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct bch_ioctl_dev_usage_v2 *bchu_dev_usage(struct bchfs_handle fs,
|
||||
unsigned idx)
|
||||
{
|
||||
@ -264,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 */
|
||||
|
468
c_src/posix_to_bcachefs.c
Normal file
468
c_src/posix_to_bcachefs.c
Normal file
@ -0,0 +1,468 @@
|
||||
#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/io_write.h"
|
||||
#include "libbcachefs/namei.h"
|
||||
#include "libbcachefs/str_hash.h"
|
||||
#include "libbcachefs/xattr.h"
|
||||
|
||||
void update_inode(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *inode)
|
||||
{
|
||||
struct bkey_inode_buf packed;
|
||||
int ret;
|
||||
|
||||
bch2_inode_pack(&packed, inode);
|
||||
packed.inode.k.p.snapshot = U32_MAX;
|
||||
ret = bch2_btree_insert(c, BTREE_ID_inodes, &packed.inode.k_i,
|
||||
NULL, 0, BTREE_ITER_cached);
|
||||
if (ret)
|
||||
die("error updating inode: %s", bch2_err_str(ret));
|
||||
}
|
||||
|
||||
void create_link(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *parent,
|
||||
const char *name, u64 inum, mode_t mode)
|
||||
{
|
||||
struct qstr qstr = QSTR(name);
|
||||
struct bch_inode_unpacked parent_u;
|
||||
struct bch_inode_unpacked inode;
|
||||
|
||||
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));
|
||||
if (ret)
|
||||
die("error creating hardlink: %s", bch2_err_str(ret));
|
||||
}
|
||||
|
||||
struct bch_inode_unpacked create_file(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *parent,
|
||||
const char *name,
|
||||
uid_t uid, gid_t gid,
|
||||
mode_t mode, dev_t rdev)
|
||||
{
|
||||
struct qstr qstr = QSTR(name);
|
||||
struct bch_inode_unpacked new_inode;
|
||||
|
||||
bch2_inode_init_early(c, &new_inode);
|
||||
|
||||
int ret = bch2_trans_commit_do(c, NULL, NULL, 0,
|
||||
bch2_create_trans(trans,
|
||||
(subvol_inum) { 1, parent->bi_inum }, parent,
|
||||
&new_inode, &qstr,
|
||||
uid, gid, mode, rdev, NULL, NULL,
|
||||
(subvol_inum) {}, 0));
|
||||
if (ret)
|
||||
die("error creating %s: %s", name, bch2_err_str(ret));
|
||||
|
||||
return new_inode;
|
||||
}
|
||||
|
||||
#define for_each_xattr_handler(handlers, handler) \
|
||||
if (handlers) \
|
||||
for ((handler) = *(handlers)++; \
|
||||
(handler) != NULL; \
|
||||
(handler) = *(handlers)++)
|
||||
|
||||
static const struct xattr_handler *xattr_resolve_name(char **name)
|
||||
{
|
||||
const struct xattr_handler * const *handlers = bch2_xattr_handlers;
|
||||
const struct xattr_handler *handler;
|
||||
|
||||
for_each_xattr_handler(handlers, handler) {
|
||||
char *n;
|
||||
|
||||
n = strcmp_prefix(*name, xattr_prefix(handler));
|
||||
if (n) {
|
||||
if (!handler->prefix ^ !*n) {
|
||||
if (*n)
|
||||
continue;
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
*name = n;
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
void copy_times(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
struct stat *src)
|
||||
{
|
||||
dst->bi_atime = timespec_to_bch2_time(c, src->st_atim);
|
||||
dst->bi_mtime = timespec_to_bch2_time(c, src->st_mtim);
|
||||
dst->bi_ctime = timespec_to_bch2_time(c, src->st_ctim);
|
||||
}
|
||||
|
||||
void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
char *src)
|
||||
{
|
||||
struct bch_hash_info hash_info = bch2_hash_info_init(c, dst);
|
||||
|
||||
char attrs[XATTR_LIST_MAX];
|
||||
ssize_t attrs_size = llistxattr(src, attrs, sizeof(attrs));
|
||||
if (attrs_size < 0)
|
||||
die("listxattr error: %m");
|
||||
|
||||
char *next, *attr;
|
||||
for (attr = attrs;
|
||||
attr < attrs + attrs_size;
|
||||
attr = next) {
|
||||
next = attr + strlen(attr) + 1;
|
||||
|
||||
char val[XATTR_SIZE_MAX];
|
||||
ssize_t val_size = lgetxattr(src, attr, val, sizeof(val));
|
||||
|
||||
if (val_size < 0)
|
||||
die("error getting xattr val: %m");
|
||||
|
||||
const struct xattr_handler *h = xattr_resolve_name(&attr);
|
||||
if (IS_ERR(h))
|
||||
continue;
|
||||
|
||||
int ret = bch2_trans_commit_do(c, NULL, NULL, 0,
|
||||
bch2_xattr_set(trans,
|
||||
(subvol_inum) { 1, dst->bi_inum },
|
||||
dst, &hash_info, attr,
|
||||
val, val_size, h->flags, 0));
|
||||
if (ret < 0)
|
||||
die("error creating xattr: %s", bch2_err_str(ret));
|
||||
}
|
||||
}
|
||||
|
||||
#define WRITE_DATA_BUF (1 << 20)
|
||||
|
||||
static char buf[WRITE_DATA_BUF] __aligned(PAGE_SIZE);
|
||||
|
||||
static void write_data(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *dst_inode,
|
||||
u64 dst_offset, void *buf, size_t len)
|
||||
{
|
||||
struct bch_write_op op;
|
||||
struct bio_vec bv[WRITE_DATA_BUF / PAGE_SIZE];
|
||||
|
||||
BUG_ON(dst_offset & (block_bytes(c) - 1));
|
||||
BUG_ON(len & (block_bytes(c) - 1));
|
||||
BUG_ON(len > WRITE_DATA_BUF);
|
||||
|
||||
bio_init(&op.wbio.bio, NULL, bv, ARRAY_SIZE(bv), 0);
|
||||
bch2_bio_map(&op.wbio.bio, buf, len);
|
||||
|
||||
bch2_write_op_init(&op, c, bch2_opts_to_inode_opts(c->opts));
|
||||
op.write_point = writepoint_hashed(0);
|
||||
op.nr_replicas = 1;
|
||||
op.subvol = 1;
|
||||
op.pos = SPOS(dst_inode->bi_inum, dst_offset >> 9, U32_MAX);
|
||||
op.flags |= BCH_WRITE_sync;
|
||||
|
||||
int ret = bch2_disk_reservation_get(c, &op.res, len >> 9,
|
||||
c->opts.data_replicas, 0);
|
||||
if (ret)
|
||||
die("error reserving space in new filesystem: %s", bch2_err_str(ret));
|
||||
|
||||
closure_call(&op.cl, bch2_write, NULL, NULL);
|
||||
|
||||
BUG_ON(!(op.flags & BCH_WRITE_submitted));
|
||||
dst_inode->bi_sectors += len >> 9;
|
||||
|
||||
if (op.error)
|
||||
die("write error: %s", bch2_err_str(op.error));
|
||||
}
|
||||
|
||||
void copy_data(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *dst_inode,
|
||||
int src_fd, u64 start, u64 end)
|
||||
{
|
||||
while (start < end) {
|
||||
unsigned len = min_t(u64, end - start, sizeof(buf));
|
||||
unsigned pad = round_up(len, block_bytes(c)) - len;
|
||||
|
||||
xpread(src_fd, buf, len, start);
|
||||
memset(buf + len, 0, pad);
|
||||
|
||||
write_data(c, dst_inode, start, buf, len + pad);
|
||||
start += len;
|
||||
}
|
||||
}
|
||||
|
||||
static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
u64 logical, u64 physical, u64 length)
|
||||
{
|
||||
struct bch_dev *ca = c->devs[0];
|
||||
|
||||
BUG_ON(logical & (block_bytes(c) - 1));
|
||||
BUG_ON(physical & (block_bytes(c) - 1));
|
||||
BUG_ON(length & (block_bytes(c) - 1));
|
||||
|
||||
logical >>= 9;
|
||||
physical >>= 9;
|
||||
length >>= 9;
|
||||
|
||||
BUG_ON(physical + length > bucket_to_sector(ca, ca->mi.nbuckets));
|
||||
|
||||
while (length) {
|
||||
struct bkey_i_extent *e;
|
||||
BKEY_PADDED_ONSTACK(k, BKEY_EXTENT_VAL_U64s_MAX) k;
|
||||
u64 b = sector_to_bucket(ca, physical);
|
||||
struct disk_reservation res;
|
||||
unsigned sectors;
|
||||
int ret;
|
||||
|
||||
sectors = min(ca->mi.bucket_size -
|
||||
(physical & (ca->mi.bucket_size - 1)),
|
||||
length);
|
||||
|
||||
e = bkey_extent_init(&k.k);
|
||||
e->k.p.inode = dst->bi_inum;
|
||||
e->k.p.offset = logical + sectors;
|
||||
e->k.p.snapshot = U32_MAX;
|
||||
e->k.size = sectors;
|
||||
bch2_bkey_append_ptr(&e->k_i, (struct bch_extent_ptr) {
|
||||
.offset = physical,
|
||||
.dev = 0,
|
||||
.gen = *bucket_gen(ca, b),
|
||||
});
|
||||
|
||||
ret = bch2_disk_reservation_get(c, &res, sectors, 1,
|
||||
BCH_DISK_RESERVATION_NOFAIL);
|
||||
if (ret)
|
||||
die("error reserving space in new filesystem: %s",
|
||||
bch2_err_str(ret));
|
||||
|
||||
ret = bch2_btree_insert(c, BTREE_ID_extents, &e->k_i, &res, 0, 0);
|
||||
if (ret)
|
||||
die("btree insert error %s", bch2_err_str(ret));
|
||||
|
||||
bch2_disk_reservation_put(c, &res);
|
||||
|
||||
dst->bi_sectors += sectors;
|
||||
logical += sectors;
|
||||
physical += sectors;
|
||||
length -= sectors;
|
||||
}
|
||||
}
|
||||
|
||||
void copy_link(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
char *src)
|
||||
{
|
||||
ssize_t i;
|
||||
ssize_t ret = readlink(src, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
die("readlink error: %m");
|
||||
|
||||
for (i = ret; i < round_up(ret, block_bytes(c)); i++)
|
||||
buf[i] = 0;
|
||||
|
||||
write_data(c, dst, 0, buf, round_up(ret, block_bytes(c)));
|
||||
}
|
||||
|
||||
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,
|
||||
u64 reserve_start)
|
||||
{
|
||||
struct fiemap_iter iter;
|
||||
struct fiemap_extent e;
|
||||
|
||||
fiemap_for_each(src_fd, iter, e)
|
||||
if (e.fe_flags & FIEMAP_EXTENT_UNKNOWN) {
|
||||
fsync(src_fd);
|
||||
break;
|
||||
}
|
||||
fiemap_iter_exit(&iter);
|
||||
|
||||
fiemap_for_each(src_fd, iter, e) {
|
||||
u64 src_max = roundup(src_size, block_bytes(c));
|
||||
|
||||
e.fe_length = min(e.fe_length, src_max - e.fe_logical);
|
||||
|
||||
if ((e.fe_logical & (block_bytes(c) - 1)) ||
|
||||
(e.fe_length & (block_bytes(c) - 1)))
|
||||
die("Unaligned extent in %s - can't handle", src_path);
|
||||
|
||||
if (BCH_MIGRATE_copy == s->type || (e.fe_flags & (FIEMAP_EXTENT_UNKNOWN|
|
||||
FIEMAP_EXTENT_ENCODED|
|
||||
FIEMAP_EXTENT_NOT_ALIGNED|
|
||||
FIEMAP_EXTENT_DATA_INLINE))) {
|
||||
copy_data(c, dst, src_fd, e.fe_logical,
|
||||
e.fe_logical + min(src_size - e.fe_logical,
|
||||
e.fe_length));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((e.fe_physical & (block_bytes(c) - 1)))
|
||||
die("Unaligned extent in %s - can't handle", src_path);
|
||||
|
||||
range_add(&s->extents, e.fe_physical, e.fe_length);
|
||||
link_data(c, dst, e.fe_logical, e.fe_physical, e.fe_length);
|
||||
}
|
||||
fiemap_iter_exit(&iter);
|
||||
}
|
||||
|
||||
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,
|
||||
u64 reserve_start)
|
||||
{
|
||||
DIR *dir = fdopendir(src_fd);
|
||||
struct dirent *d;
|
||||
|
||||
while ((errno = 0), (d = readdir(dir))) {
|
||||
struct bch_inode_unpacked inode;
|
||||
int fd;
|
||||
|
||||
if (fchdir(src_fd))
|
||||
die("chdir error: %m");
|
||||
|
||||
struct stat stat =
|
||||
xfstatat(src_fd, d->d_name, AT_SYMLINK_NOFOLLOW);
|
||||
|
||||
if (!strcmp(d->d_name, ".") ||
|
||||
!strcmp(d->d_name, "..") ||
|
||||
!strcmp(d->d_name, "lost+found"))
|
||||
continue;
|
||||
|
||||
if (BCH_MIGRATE_migrate == s->type && stat.st_ino == s->bcachefs_inum)
|
||||
continue;
|
||||
|
||||
char *child_path = mprintf("%s/%s", src_path, d->d_name);
|
||||
|
||||
if (s->type == BCH_MIGRATE_migrate && stat.st_dev != s->dev)
|
||||
die("%s does not have correct st_dev!", child_path);
|
||||
|
||||
u64 *dst_inum = S_ISREG(stat.st_mode)
|
||||
? genradix_ptr_alloc(&s->hardlinks, stat.st_ino, GFP_KERNEL)
|
||||
: NULL;
|
||||
|
||||
if (dst_inum && *dst_inum) {
|
||||
create_link(c, dst, d->d_name, *dst_inum, S_IFREG);
|
||||
goto next;
|
||||
}
|
||||
|
||||
inode = create_file(c, dst, d->d_name,
|
||||
stat.st_uid, stat.st_gid,
|
||||
stat.st_mode, stat.st_rdev);
|
||||
|
||||
if (dst_inum)
|
||||
*dst_inum = inode.bi_inum;
|
||||
|
||||
copy_xattrs(c, &inode, d->d_name);
|
||||
|
||||
/* copy xattrs */
|
||||
|
||||
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, reserve_start);
|
||||
close(fd);
|
||||
break;
|
||||
case DT_REG:
|
||||
inode.bi_size = stat.st_size;
|
||||
|
||||
fd = xopen(d->d_name, O_RDONLY|O_NOATIME);
|
||||
copy_file(c, &inode, fd, stat.st_size,
|
||||
child_path, s, reserve_start);
|
||||
close(fd);
|
||||
break;
|
||||
case DT_LNK:
|
||||
inode.bi_size = stat.st_size;
|
||||
|
||||
copy_link(c, &inode, d->d_name);
|
||||
break;
|
||||
case DT_FIFO:
|
||||
case DT_CHR:
|
||||
case DT_BLK:
|
||||
case DT_SOCK:
|
||||
case DT_WHT:
|
||||
/* nothing else to copy for these: */
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
copy_times(c, &inode, &stat);
|
||||
update_inode(c, &inode);
|
||||
next:
|
||||
free(child_path);
|
||||
}
|
||||
|
||||
if (errno)
|
||||
die("readdir error: %m");
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static void reserve_old_fs_space(struct bch_fs *c,
|
||||
struct bch_inode_unpacked *root_inode,
|
||||
ranges *extents,
|
||||
u64 reserve_start)
|
||||
{
|
||||
struct bch_dev *ca = c->devs[0];
|
||||
struct bch_inode_unpacked dst;
|
||||
struct hole_iter iter;
|
||||
struct range i;
|
||||
|
||||
dst = create_file(c, root_inode, "old_migrated_filesystem",
|
||||
0, 0, S_IFREG|0400, 0);
|
||||
dst.bi_size = bucket_to_sector(ca, ca->mi.nbuckets) << 9;
|
||||
|
||||
ranges_sort_merge(extents);
|
||||
|
||||
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, u64 reserve_start)
|
||||
{
|
||||
syncfs(src_fd);
|
||||
|
||||
struct bch_inode_unpacked root_inode;
|
||||
int ret = bch2_inode_find_by_inum(c, (subvol_inum) { 1, BCACHEFS_ROOT_INO },
|
||||
&root_inode);
|
||||
if (ret)
|
||||
die("error looking up root directory: %s", bch2_err_str(ret));
|
||||
|
||||
if (fchdir(src_fd))
|
||||
die("chdir error: %m");
|
||||
|
||||
struct stat stat = xfstat(src_fd);
|
||||
copy_times(c, &root_inode, &stat);
|
||||
copy_xattrs(c, &root_inode, ".");
|
||||
|
||||
|
||||
/* now, copy: */
|
||||
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_start);
|
||||
|
||||
update_inode(c, &root_inode);
|
||||
|
||||
if (BCH_MIGRATE_migrate == s->type)
|
||||
darray_exit(&s->extents);
|
||||
|
||||
genradix_free(&s->hardlinks);
|
||||
}
|
54
c_src/posix_to_bcachefs.h
Normal file
54
c_src/posix_to_bcachefs.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _POSIX_TO_BCACHEFS_H
|
||||
#define _POSIX_TO_BCACHEFS_H
|
||||
|
||||
/*
|
||||
* This header exports the functionality needed for copying data from existing
|
||||
* posix compliant filesystems to bcachefs. There are two use cases:
|
||||
* 1. Creating a new bcachefs filesystem using `bcachefs format`, we can
|
||||
* specify a source directory tree which will be copied over the new
|
||||
* bcachefs filesytem.
|
||||
* 2. Migrating an existing filesystem in place, with `bcachefs migrate`.
|
||||
* This will allocate space for the bcachefs metadata, but the actual data
|
||||
* represented by the extents will not be duplicated. The bcachefs metadata
|
||||
* will simply point to the existing extents.
|
||||
*
|
||||
* To avoid code duplication, `copy_fs` deals with both cases. See the function
|
||||
* documentation for more details.
|
||||
*/
|
||||
|
||||
#include "libbcachefs.h"
|
||||
|
||||
enum bch_migrate_type {
|
||||
BCH_MIGRATE_copy,
|
||||
BCH_MIGRATE_migrate
|
||||
};
|
||||
|
||||
/*
|
||||
* The migrate action uses all the fields in this struct.
|
||||
* The copy action only uses the `hardlinks` field. Since `hardlinks` is
|
||||
* initialized with zeroes, an empty `copy_fs_state` struct can be passed.
|
||||
*/
|
||||
struct copy_fs_state {
|
||||
u64 bcachefs_inum;
|
||||
dev_t dev;
|
||||
|
||||
GENRADIX(u64) hardlinks;
|
||||
ranges extents;
|
||||
enum bch_migrate_type type;
|
||||
};
|
||||
|
||||
/*
|
||||
* The `copy_fs` function is used for both copying a directory tree to a new
|
||||
* bcachefs filesystem and migrating an existing one, depending on the value
|
||||
* from the `type` field in `copy_fs_state` struct.
|
||||
*
|
||||
* In case of copy, an empty `copy_fs_state` structure is passed to `copy_fs`
|
||||
* (only the `hardlinks` field is used, and that is initialized with zeroes).
|
||||
*
|
||||
* In the migrate case, all the fields from `copy_fs_state` need to be
|
||||
* 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, 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;
|
||||
@ -271,7 +289,7 @@ void ranges_sort_merge(ranges *r)
|
||||
|
||||
/* Merge contiguous ranges: */
|
||||
darray_for_each(*r, i) {
|
||||
struct range *t = tmp.nr ? &tmp.data[tmp.nr - 1] : NULL;
|
||||
struct range *t = tmp.nr ? &tmp.data[tmp.nr - 1] : NULL;
|
||||
|
||||
if (t && t->end >= i->start)
|
||||
t->end = max(t->end, i->end);
|
||||
@ -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 */
|
||||
|
@ -97,7 +97,7 @@
|
||||
* UNNEEDED - a variable/function may not be needed
|
||||
*
|
||||
* This suppresses warnings about unused variables or functions, but tells
|
||||
* the compiler that if it is unused it need not emit it into the source code.
|
||||
* the compiler that if it is unused it needs not emit it into the source code.
|
||||
*
|
||||
* Example:
|
||||
* // With some preprocessor options, this is unnecessary.
|
||||
|
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 compatability.
|
||||
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
|
||||
|
15
default.nix
15
default.nix
@ -1,6 +1,9 @@
|
||||
(import (let lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||
in fetchTarball {
|
||||
url =
|
||||
"https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||
}) { src = ./.; }).defaultNix
|
||||
(import (
|
||||
let
|
||||
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||
in
|
||||
fetchTarball {
|
||||
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||
}
|
||||
) { src = ./.; }).defaultNix
|
||||
|
@ -388,13 +388,13 @@ limitation being disk space.
|
||||
The following subcommands exist for managing subvolumes and snapshots:
|
||||
\begin{itemize}
|
||||
\item \texttt{bcachefs subvolume create}: Create a new, empty subvolume
|
||||
\item \texttt{bcachefs subvolume destroy}: Delete an existing subvolume
|
||||
\item \texttt{bcachefs subvolume delete}: Delete an existing subvolume
|
||||
or snapshot
|
||||
\item \texttt{bcachefs subvolume snapshot}: Create a snapshot of an
|
||||
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.
|
||||
|
||||
@ -464,7 +464,7 @@ The \texttt{-o verbose} enables additional log output during the mount process.
|
||||
|
||||
It is possible to run fsck either in userspace with the \texttt{bcachefs fsck}
|
||||
subcommand (also available as \texttt{fsck.bcachefs}, or in the kernel while
|
||||
mounting by specifying the \texttt{-o fsck} mount option. In either case the
|
||||
mounting by specifying the \texttt{-o fsck} mount option). In either case the
|
||||
exact same fsck implementation is being run, only the environment is different.
|
||||
Running fsck in the kernel at mount time has the advantage of somewhat better
|
||||
performance, while running in userspace has the ability to be stopped with
|
||||
@ -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.
|
||||
|
||||
@ -528,7 +528,7 @@ filesystem:
|
||||
\begin{itemize}
|
||||
\item \texttt{bcachefs device add}: Formats and adds a new device to an
|
||||
existing filesystem.
|
||||
\item \texttt{bcachefs device remove}: Permenantly removes a device from
|
||||
\item \texttt{bcachefs device remove}: Permanently removes a device from
|
||||
an existing filesystem.
|
||||
\item \texttt{bcachefs device online}: Connects a device to a running
|
||||
filesystem that was mounted without it (i.e. in degraded mode)
|
||||
@ -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:
|
||||
|
||||
@ -912,7 +912,7 @@ quantiles for latency/duration in the
|
||||
\end{itemize}
|
||||
|
||||
\item \texttt{btree\_key\_cache} \\
|
||||
Prints infromation on the btree key cache: number of freed keys
|
||||
Prints information on the btree key cache: number of freed keys
|
||||
(which must wait for a sRCU barrier to complete before being
|
||||
freed), number of cached keys, and number of dirty keys.
|
||||
|
||||
@ -1036,7 +1036,7 @@ listing btree nodes and contents, but for offline filesystems.
|
||||
\subsubsection{bcachefs list\_journal}
|
||||
|
||||
This subcommand lists the contents of the journal, which primarily records btree
|
||||
updates ordered by when they occured.
|
||||
updates ordered by when they occurred.
|
||||
|
||||
\subsubsection{bcachefs dump}
|
||||
|
||||
@ -1052,7 +1052,7 @@ This section documents bcachefs-specific ioctls:
|
||||
|
||||
\begin{description}
|
||||
\item \texttt{BCH\_IOCTL\_QUERY\_UUID} \\
|
||||
Returs the UUID of the filesystem: used to find the sysfs
|
||||
Returns the UUID of the filesystem: used to find the sysfs
|
||||
directory given a path to a mounted filesystem.
|
||||
|
||||
\item \texttt{BCH\_IOCTL\_FS\_USAGE} \\
|
||||
@ -1102,7 +1102,7 @@ This section documents bcachefs-specific ioctls:
|
||||
\item \texttt{BCH\_IOCTL\_DISK\_RESIZE\_JOURNAL} \\
|
||||
\item \texttt{BCH\_IOCTL\_DATA} \\
|
||||
Starts a data job, which walks all data and/or metadata in a
|
||||
filesystem performing, performaing some operation on each btree
|
||||
filesystem performing, performing some operations on each btree
|
||||
node and extent. Returns a file descriptor which can be read
|
||||
from to get the current status of the job, and closing the file
|
||||
descriptor (i.e. on process exit stops the data job.
|
||||
@ -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,14 +49,14 @@ 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
|
||||
----------------------
|
||||
|
||||
Configuration options that point to targets (i.e. a disk or group of disks) may
|
||||
be passed either a device (i.e. /dev/sda), or a label. Labels are assigned to
|
||||
disks (and need not be unique), and these labels form a nested heirarchy: this
|
||||
disks (and need not be unique), and these labels form a nested hierarchy: this
|
||||
allows disks to be grouped together and referred to either individually or as a
|
||||
group.
|
||||
|
||||
@ -86,7 +87,7 @@ The foreground_target option is used to direct writes from applications. The
|
||||
background_target option, if set, will cause data to be moved to that target in
|
||||
the background by the rebalance thread some time after it has been initially
|
||||
written - leaving behind the original copy, but marking it cached so that it can
|
||||
be discarded by the allocator. The promote_target will will cause reads to write
|
||||
be discarded by the allocator. The promote_target will cause reads to write
|
||||
a cached copy of the data being read to that target, if it doesn't exist.
|
||||
|
||||
Together, these options can be used for writeback caching, like so:
|
||||
|
137
flake.lock
generated
137
flake.lock
generated
@ -1,13 +1,28 @@
|
||||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1742394900,
|
||||
"narHash": "sha256-vVOAp9ahvnU+fQoKd4SEXB2JG2wbENkpqcwlkIXgUC0=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "70947c1908108c0c551ddfd73d4f750ff2ea67cd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"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": {
|
||||
@ -16,13 +31,51 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741352980,
|
||||
"narHash": "sha256-+u2UunDA4Cl5Fci3m7S643HzKmIDAe+fiXrLqYsR2fs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "f4330d22f1c5d2ba72d3d22df5597d123fdb60a9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"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": 1698924604,
|
||||
"narHash": "sha256-GCFbkl2tj8fEZBZCw3Tc0AkGo0v+YrQlohhEGJ/X4s0=",
|
||||
"lastModified": 1742422364,
|
||||
"narHash": "sha256-mNqIplmEohk5jRkqYqG19GA8MbQ/D4gQSK0Mu4LvfRQ=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "fa804edfb7869c9fb230e174182a8a1a7e512c40",
|
||||
"rev": "a84ebe20c6bc2ecbcfb000a50776219f48d134cc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -32,43 +85,69 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1740877520,
|
||||
"narHash": "sha256-oiwv/ZK/2FhGxrCkQkB83i7GnWXPPLzoqFHpDD3uYpk=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "147dee35aab2193b174e4c0868bd80ead5ce755c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-parts": "flake-parts",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"utils": "utils"
|
||||
"rust-overlay": "rust-overlay",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"lastModified": 1742524367,
|
||||
"narHash": "sha256-KzTwk/5ETJavJZYV1DEWdCx05M4duFCxCpRbQSKWpng=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "70bf752d176b2ce07417e346d85486acea9040ef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742370146,
|
||||
"narHash": "sha256-XRE8hL4vKIQyVMDXykFh4ceo3KSpuJF3ts8GKwh5bIU=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "adc195eef5da3606891cedf80c0d9ce2d3190808",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
|
349
flake.nix
349
flake.nix
@ -1,40 +1,327 @@
|
||||
{
|
||||
description = "Userspace tools for bcachefs";
|
||||
|
||||
# Nixpkgs / NixOS version to use.
|
||||
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
inputs.utils.url = "github:numtide/flake-utils";
|
||||
inputs.flake-compat = {
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
|
||||
treefmt-nix = {
|
||||
url = "github:numtide/treefmt-nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
crane.url = "github:ipetkov/crane";
|
||||
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
flake-compat = {
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
nix-github-actions = {
|
||||
url = "github:nix-community/nix-github-actions";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, utils, ... }:
|
||||
{
|
||||
overlays.default = final: prev: {
|
||||
bcachefs = final.callPackage ./build.nix { };
|
||||
outputs =
|
||||
inputs@{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-parts,
|
||||
treefmt-nix,
|
||||
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 ];
|
||||
|
||||
flake = {
|
||||
githubActions = nix-github-actions.lib.mkGithubMatrix {
|
||||
# github actions supports fewer architectures
|
||||
checks = nixpkgs.lib.getAttrs [ "aarch64-linux" "x86_64-linux" ] self.checks;
|
||||
};
|
||||
};
|
||||
} // utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ self.overlays.default ];
|
||||
};
|
||||
in {
|
||||
packages = {
|
||||
inherit (pkgs) bcachefs;
|
||||
bcachefs-fuse = pkgs.bcachefs.override { fuseSupport = true; };
|
||||
default = pkgs.bcachefs;
|
||||
};
|
||||
|
||||
formatter = pkgs.nixfmt;
|
||||
inherit systems;
|
||||
|
||||
devShells.default = pkgs.callPackage ({ mkShell, rustc, cargo, gnumake
|
||||
, gcc, clang, pkg-config, libuuid, libsodium, keyutils, liburcu, zlib
|
||||
, libaio, zstd, lz4, udev, bcachefs }:
|
||||
mkShell {
|
||||
LIBCLANG_PATH = "${clang.cc.lib}/lib";
|
||||
inherit (bcachefs) nativeBuildInputs buildInputs;
|
||||
}) { };
|
||||
});
|
||||
perSystem =
|
||||
{
|
||||
self',
|
||||
config,
|
||||
lib,
|
||||
system,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (builtins) readFile split;
|
||||
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);
|
||||
|
||||
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}";
|
||||
|
||||
mkCommon =
|
||||
{
|
||||
crane,
|
||||
pkgs,
|
||||
rustVersion ? "latest",
|
||||
|
||||
# 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; };
|
||||
|
||||
mkPackage =
|
||||
{ common, name }:
|
||||
common.craneLib.buildPackage (
|
||||
common.args
|
||||
// {
|
||||
inherit (common) cargoArtifacts;
|
||||
pname = name;
|
||||
|
||||
enableParallelBuilding = true;
|
||||
buildPhaseCargoCommand = ''
|
||||
make ''${enableParallelBuilding:+-j''${NIX_BUILD_CORES}} $makeFlags
|
||||
'';
|
||||
doNotPostBuildInstallCargoBinaries = true;
|
||||
installPhaseCommand = ''
|
||||
make ''${enableParallelBuilding:+-j''${NIX_BUILD_CORES}} $makeFlags install
|
||||
'';
|
||||
|
||||
doInstallCheck = true;
|
||||
installCheckPhase = ''
|
||||
runHook preInstallCheck
|
||||
|
||||
test "$($out/bin/bcachefs version)" = "${version}"
|
||||
|
||||
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 =
|
||||
let
|
||||
inherit (cargoToml.package) name;
|
||||
in
|
||||
(mkPackages name systems)
|
||||
// {
|
||||
${name} = config.packages."${name}-${system}";
|
||||
"${name}-fuse" = config.packages."${name}-fuse-${system}";
|
||||
default = config.packages.${name};
|
||||
};
|
||||
|
||||
checks = {
|
||||
inherit (config.packages)
|
||||
bcachefs-tools
|
||||
bcachefs-tools-fuse
|
||||
bcachefs-tools-fuse-i686-linux
|
||||
;
|
||||
|
||||
cargo-clippy = common.craneLib.cargoClippy (
|
||||
common.args
|
||||
// {
|
||||
inherit (common) cargoArtifacts;
|
||||
cargoClippyExtraArgs = "--all-targets --all-features -- --deny warnings";
|
||||
}
|
||||
);
|
||||
|
||||
# we have to build our own `craneLib.cargoTest`
|
||||
cargo-test = common.craneLib.mkCargoDerivation (
|
||||
common.args
|
||||
// {
|
||||
inherit (common) 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 = [
|
||||
config.packages.default
|
||||
config.treefmt.build.devShell
|
||||
];
|
||||
|
||||
# here go packages that aren't required for builds but are used for
|
||||
# development, and might need to be version matched with build
|
||||
# dependencies (e.g. clippy or rust-analyzer).
|
||||
packages = with pkgs; [
|
||||
bear
|
||||
cargo-audit
|
||||
cargo-outdated
|
||||
clang-tools
|
||||
(rust-bin.stable.latest.minimal.override {
|
||||
extensions = [
|
||||
"rust-analyzer"
|
||||
"rust-src"
|
||||
];
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
treefmt.config = {
|
||||
projectRootFile = "flake.nix";
|
||||
flakeCheck = false;
|
||||
|
||||
programs = {
|
||||
nixfmt.enable = true;
|
||||
rustfmt.edition = rustfmtToml.edition;
|
||||
rustfmt.enable = true;
|
||||
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
|
||||
|
@ -112,6 +112,8 @@ static inline void skcipher_request_set_sync_tfm(struct skcipher_request *req,
|
||||
skcipher_request_set_tfm(req, &tfm->base);
|
||||
}
|
||||
|
||||
#define skcipher_request_set_callback(...) do {} while (0)
|
||||
|
||||
static inline void skcipher_request_set_crypt(
|
||||
struct skcipher_request *req,
|
||||
struct scatterlist *src, struct scatterlist *dst,
|
||||
|
@ -16,55 +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 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_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); \
|
||||
@ -91,7 +67,7 @@ typedef struct {
|
||||
\
|
||||
__atomic_compare_exchange_n((p), &__old, new, false, \
|
||||
__ATOMIC_RELEASE, \
|
||||
__ATOMIC_RELEASE); \
|
||||
__ATOMIC_RELAXED); \
|
||||
__old; \
|
||||
})
|
||||
|
||||
@ -101,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) \
|
||||
@ -170,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) \
|
||||
@ -281,6 +260,11 @@ static inline i_type a_type##_cmpxchg(a_type##_t *v, i_type old, i_type new)\
|
||||
return cmpxchg(&v->counter, old, new); \
|
||||
} \
|
||||
\
|
||||
static inline bool a_type##_try_cmpxchg(a_type##_t *v, i_type *old, i_type new)\
|
||||
{ \
|
||||
return try_cmpxchg(&v->counter, old, new); \
|
||||
} \
|
||||
\
|
||||
static inline i_type a_type##_cmpxchg_acquire(a_type##_t *v, i_type old, i_type new)\
|
||||
{ \
|
||||
return cmpxchg_acquire(&v->counter, old, new); \
|
||||
@ -316,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)
|
||||
@ -73,15 +76,19 @@ static inline struct block_device *file_bdev(struct file *file)
|
||||
return container_of(file->f_inode, struct block_device, __bd_inode);
|
||||
}
|
||||
|
||||
void fput(struct file *);
|
||||
void bdev_fput(struct file *);
|
||||
struct file *bdev_file_open_by_path(const char *, blk_mode_t, void *,
|
||||
const struct blk_holder_ops *);
|
||||
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;
|
||||
@ -194,6 +195,18 @@ static inline void closure_sync(struct closure *cl)
|
||||
__closure_sync(cl);
|
||||
}
|
||||
|
||||
int __closure_sync_timeout(struct closure *cl, unsigned long timeout);
|
||||
|
||||
static inline int closure_sync_timeout(struct closure *cl, unsigned long timeout)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_CLOSURES
|
||||
BUG_ON(closure_nr_remaining(cl) != 1 && !cl->closure_get_happened);
|
||||
#endif
|
||||
return cl->closure_get_happened
|
||||
? __closure_sync_timeout(cl, timeout)
|
||||
: 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_CLOSURES
|
||||
|
||||
void closure_debug_create(struct closure *cl);
|
||||
@ -272,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
|
||||
@ -296,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
|
||||
}
|
||||
|
||||
/**
|
||||
@ -343,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
|
||||
*
|
||||
@ -412,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;
|
||||
@ -176,6 +184,8 @@ static inline void ktime_get_coarse_real_ts64(struct timespec64 *ts)
|
||||
#define current_kernel_time64() current_kernel_time()
|
||||
#define CURRENT_TIME (current_kernel_time())
|
||||
|
||||
#define sched_annotate_sleep() do {} while (0)
|
||||
|
||||
static inline unsigned int stack_trace_save_tsk(struct task_struct *task,
|
||||
unsigned long *store, unsigned int size,
|
||||
unsigned int skipnr)
|
||||
|
@ -4,28 +4,123 @@
|
||||
#define PF_MEMALLOC 0x00000800 /* Allocating memory */
|
||||
#define PF_MEMALLOC_NOFS 0x00040000 /* All allocation requests will inherit GFP_NOFS */
|
||||
|
||||
/**
|
||||
* memalloc_flags_save - Add a PF_* flag to current->flags, save old value
|
||||
*
|
||||
* This allows PF_* flags to be conveniently added, irrespective of current
|
||||
* value, and then the old version restored with memalloc_flags_restore().
|
||||
*/
|
||||
static inline unsigned memalloc_flags_save(unsigned flags)
|
||||
{
|
||||
unsigned oldflags = ~current->flags & flags;
|
||||
current->flags |= flags;
|
||||
return oldflags;
|
||||
}
|
||||
|
||||
static inline void memalloc_flags_restore(unsigned flags)
|
||||
{
|
||||
current->flags &= ~flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* memalloc_noio_save - Marks implicit GFP_NOIO allocation scope.
|
||||
*
|
||||
* This functions marks the beginning of the GFP_NOIO allocation scope.
|
||||
* All further allocations will implicitly drop __GFP_IO flag and so
|
||||
* they are safe for the IO critical section from the allocation recursion
|
||||
* point of view. Use memalloc_noio_restore to end the scope with flags
|
||||
* returned by this function.
|
||||
*
|
||||
* Context: This function is safe to be used from any context.
|
||||
* Return: The saved flags to be passed to memalloc_noio_restore.
|
||||
*/
|
||||
static inline unsigned int memalloc_noio_save(void)
|
||||
{
|
||||
return memalloc_flags_save(PF_MEMALLOC_NOIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* memalloc_noio_restore - Ends the implicit GFP_NOIO scope.
|
||||
* @flags: Flags to restore.
|
||||
*
|
||||
* Ends the implicit GFP_NOIO scope started by memalloc_noio_save function.
|
||||
* Always make sure that the given flags is the return value from the
|
||||
* pairing memalloc_noio_save call.
|
||||
*/
|
||||
static inline void memalloc_noio_restore(unsigned int flags)
|
||||
{
|
||||
memalloc_flags_restore(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* memalloc_nofs_save - Marks implicit GFP_NOFS allocation scope.
|
||||
*
|
||||
* This functions marks the beginning of the GFP_NOFS allocation scope.
|
||||
* All further allocations will implicitly drop __GFP_FS flag and so
|
||||
* they are safe for the FS critical section from the allocation recursion
|
||||
* point of view. Use memalloc_nofs_restore to end the scope with flags
|
||||
* returned by this function.
|
||||
*
|
||||
* Context: This function is safe to be used from any context.
|
||||
* Return: The saved flags to be passed to memalloc_nofs_restore.
|
||||
*/
|
||||
static inline unsigned int memalloc_nofs_save(void)
|
||||
{
|
||||
unsigned int flags = current->flags & PF_MEMALLOC_NOFS;
|
||||
current->flags |= PF_MEMALLOC_NOFS;
|
||||
return flags;
|
||||
return memalloc_flags_save(PF_MEMALLOC_NOFS);
|
||||
}
|
||||
|
||||
/**
|
||||
* memalloc_nofs_restore - Ends the implicit GFP_NOFS scope.
|
||||
* @flags: Flags to restore.
|
||||
*
|
||||
* Ends the implicit GFP_NOFS scope started by memalloc_nofs_save function.
|
||||
* Always make sure that the given flags is the return value from the
|
||||
* pairing memalloc_nofs_save call.
|
||||
*/
|
||||
static inline void memalloc_nofs_restore(unsigned int flags)
|
||||
{
|
||||
current->flags = (current->flags & ~PF_MEMALLOC_NOFS) | flags;
|
||||
memalloc_flags_restore(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* memalloc_noreclaim_save - Marks implicit __GFP_MEMALLOC scope.
|
||||
*
|
||||
* This function marks the beginning of the __GFP_MEMALLOC allocation scope.
|
||||
* All further allocations will implicitly add the __GFP_MEMALLOC flag, which
|
||||
* prevents entering reclaim and allows access to all memory reserves. This
|
||||
* should only be used when the caller guarantees the allocation will allow more
|
||||
* memory to be freed very shortly, i.e. it needs to allocate some memory in
|
||||
* the process of freeing memory, and cannot reclaim due to potential recursion.
|
||||
*
|
||||
* Users of this scope have to be extremely careful to not deplete the reserves
|
||||
* completely and implement a throttling mechanism which controls the
|
||||
* consumption of the reserve based on the amount of freed memory. Usage of a
|
||||
* pre-allocated pool (e.g. mempool) should be always considered before using
|
||||
* this scope.
|
||||
*
|
||||
* Individual allocations under the scope can opt out using __GFP_NOMEMALLOC
|
||||
*
|
||||
* Context: This function should not be used in an interrupt context as that one
|
||||
* does not give PF_MEMALLOC access to reserves.
|
||||
* See __gfp_pfmemalloc_flags().
|
||||
* Return: The saved flags to be passed to memalloc_noreclaim_restore.
|
||||
*/
|
||||
static inline unsigned int memalloc_noreclaim_save(void)
|
||||
{
|
||||
unsigned int flags = current->flags & PF_MEMALLOC;
|
||||
current->flags |= PF_MEMALLOC;
|
||||
return flags;
|
||||
return memalloc_flags_save(PF_MEMALLOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* memalloc_noreclaim_restore - Ends the implicit __GFP_MEMALLOC scope.
|
||||
* @flags: Flags to restore.
|
||||
*
|
||||
* Ends the implicit __GFP_MEMALLOC scope started by memalloc_noreclaim_save
|
||||
* function. Always make sure that the given flags is the return value from the
|
||||
* pairing memalloc_noreclaim_save call.
|
||||
*/
|
||||
static inline void memalloc_noreclaim_restore(unsigned int flags)
|
||||
{
|
||||
current->flags = (current->flags & ~PF_MEMALLOC) | flags;
|
||||
memalloc_flags_restore(flags);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_SCHED_MM_H */
|
||||
|
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,8 +18,11 @@
|
||||
#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
|
||||
|
||||
static inline size_t kmalloc_size_roundup(size_t s)
|
||||
{
|
||||
return roundup_pow_of_two(s);
|
||||
@ -100,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(p)
|
||||
#define kzfree(p) free(p)
|
||||
#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)
|
||||
|
||||
@ -269,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,18 +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 struct urcu_gp_poll_state get_state_synchronize_srcu(struct srcu_struct *ssp)
|
||||
{
|
||||
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;
|
||||
|
@ -10,6 +10,7 @@ extern ssize_t strscpy(char *dest, const char *src, size_t count);
|
||||
extern char *strim(char *);
|
||||
extern void memzero_explicit(void *, size_t);
|
||||
int match_string(const char * const *, size_t, const char *);
|
||||
extern void * memscan(void *,int, size_t);
|
||||
|
||||
#define kstrndup(s, n, gfp) strndup(s, n)
|
||||
#define kstrdup(s, gfp) strdup(s)
|
||||
|
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), \
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user