mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-23 19:04:45 +03:00
Compare commits
443 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef686e96ec | |||
| 7a41ef240a | |||
| 72d16a9b49 | |||
| 54c358c3f2 | |||
| 560e9fc817 | |||
| d642efe83c | |||
| 51e313f610 | |||
| 327f12c291 | |||
| 5d4f7e7566 | |||
| abd0b59e48 | |||
| 6b9d0eda75 | |||
| 744cdfd93b | |||
| 36d50b60d8 | |||
| 0c4f86be74 | |||
| 88be308b2f | |||
| d6dc79eabc | |||
| 900a444107 | |||
| 1885e5ebab | |||
| 1ad8fcc054 | |||
| 05c96b438a | |||
| ccf6d0a59b | |||
| 61ae6c99f7 | |||
| e9353bc2ef | |||
| 87d93731e7 | |||
| bd197378e7 | |||
| cd2bb9ca44 | |||
| 52d9bc7174 | |||
| 6905f6b2c1 | |||
| cfc82609a2 | |||
| e26776f14c | |||
| e68e938f54 | |||
| ab2110e3e2 | |||
| a909190683 | |||
| 073f3c7826 | |||
| 5072f37419 | |||
| 332cd2e313 | |||
| ac6f332154 | |||
| f14b6f2302 | |||
| bfb2928490 | |||
| ecb1b1a31d | |||
| 412b69dfab | |||
| d014da0032 | |||
| 8f93ab53d4 | |||
| 88891b804b | |||
| 87b5e7fb1d | |||
| 5722dce473 | |||
| 91d5ac85c0 | |||
| fd8ccce07b | |||
| c2a3bcc91d | |||
| d1277e2a13 | |||
| a59bf29606 | |||
| 28fdc5f811 | |||
| a78a93e67e | |||
| 9a68ceba10 | |||
| 3c7ad493a6 | |||
| faad85637b | |||
| 501da8d433 | |||
| 30620ad8e1 | |||
| 1d65d1a597 | |||
| edf3d7aa43 | |||
| 9755cdfd89 | |||
| f36e8118fd | |||
| e69f73c5cf | |||
| 3430eced80 | |||
| 0839934d84 | |||
| f831d1377f | |||
| a559c3d0f4 | |||
| 95e29a7275 | |||
| 85890d54d9 | |||
| 12e25a6ec3 | |||
| 57490d5e13 | |||
| 214196e9f5 | |||
| 932d471bec | |||
| 77cba40b85 | |||
| 18d069a20f | |||
| dfc25ea91c | |||
| 7428adc6b7 | |||
| 30782f2ff5 | |||
| 43efd5625b | |||
| 87a520c4e7 | |||
| d02bcae0c4 | |||
| d9bcadc6ba | |||
| 67819ea28d | |||
| 79430bf34b | |||
| cabc605aa7 | |||
| 0740d41e9b | |||
| 16e8e24f9c | |||
| bc5afff351 | |||
| 825d8e1b0f | |||
| f7797f3f5e | |||
| 2439e95f36 | |||
| de722e55ca | |||
| acb4e7b0e1 | |||
| 5a397fda09 | |||
| 525a7037c7 | |||
| 789f3d0e56 | |||
| 5d946dfa1c | |||
| cd80d6d355 | |||
| 140584bfff | |||
| 8773e29c23 | |||
| bb21c0aa3b | |||
| 455ea5bb1f | |||
| 7126b0e5ed | |||
| 7ca0ef36e1 | |||
| 0d6186cff3 | |||
| 6f349d33a5 | |||
| 226d362b12 | |||
| 497fc5fb06 | |||
| abb485a34a | |||
| 0ccffb2634 | |||
| 26cb87d22d | |||
| 43dbfa3921 | |||
| 395583e38e | |||
| 818bc70c32 | |||
| 6150fbe67f | |||
| 458bb8c8a1 | |||
| cda6fdd500 | |||
| df8271301e | |||
| e219935f10 | |||
| bb9104f1e8 | |||
| 94b240bae0 | |||
| e93203e004 | |||
| ccb453acd0 | |||
| 6c1989923e | |||
| a0eb5a77a0 | |||
| fe77c48320 | |||
| db9b29895e | |||
| 4d4dd76f0f | |||
| 286c7f75bb | |||
| 403703d57a | |||
| f17c843eff | |||
| f6440fa094 | |||
| 62f9691e10 | |||
| 73e26fdc09 | |||
| 65a89d9f49 | |||
| 8829ba19b7 | |||
| 642d86af0d | |||
| 07ca7592ad | |||
| fb0d807477 | |||
| 858ea8861c | |||
| 549841ef9a | |||
| 96f322e7e2 | |||
| d022406a14 | |||
| a1a1386965 | |||
| 43eaef6de8 | |||
| 5bc4c39d70 | |||
| 756e28be51 | |||
| 039a810491 | |||
| bfb7b9613a | |||
| 3e33897bec | |||
| 0f3b928e85 | |||
| 12fec4a147 | |||
| 7930a5ee65 | |||
| be94a3de0f | |||
| db83b3abe9 | |||
| 55fd8ceab6 | |||
| e269e1c07a | |||
| 81f981cd82 | |||
| 3790aa8176 | |||
| 4e1d1b4b92 | |||
| c32c475363 | |||
| dd487640b2 | |||
| acb39fc9a4 | |||
| 6539bf71fe | |||
| 32a78e579d | |||
| fb7aa3c9b2 | |||
| 4016ad705b | |||
| 59570a05d8 | |||
| 88ae76a4e0 | |||
| 88d7da62b5 | |||
| 6410ee4a94 | |||
| a296875da0 | |||
| 921ec61b77 | |||
| fcd9966ed9 | |||
| a2621753b2 | |||
| e888f28988 | |||
| 305510fd33 | |||
| 67cff6e4c1 | |||
| 944180ab50 | |||
| 3075b29ca8 | |||
| e1d9228b08 | |||
| afaf9414ff | |||
| cee725c9bd | |||
| 03ad94a3b2 | |||
| 7a7e101437 | |||
| 401ba57ccd | |||
| 188950df9e | |||
| 58bc86c5cb | |||
| 7cf4cd8246 | |||
| 783be694f1 | |||
| af5626ac27 | |||
| cc1f85be8b | |||
| 9585538d0e | |||
| 86e74dc162 | |||
| b3d723fb0e | |||
| 3d40b65540 | |||
| fa7b558bef | |||
| a103ae446e | |||
| 2ab24dfded | |||
| 489633d99a | |||
| ee49d9e02b | |||
| 1fbda9caee | |||
| 42bdfd3b36 | |||
| 900480bd96 | |||
| 058b6fd069 | |||
| 8847b06bf6 | |||
| 21adfb031c | |||
| ae2cfdf8a7 | |||
| 20e4513c56 | |||
| f217a2b902 | |||
| aa5b9e1d7c | |||
| fb3ad5d24e | |||
| de2ac3f700 | |||
| f9688b21d7 | |||
| fad85e52e5 | |||
| 038aaec1cd | |||
| 94ca328fb3 | |||
| 65c4c9a233 | |||
| 07ca433973 | |||
| f21d1f8fad | |||
| ee8794195b | |||
| 0ef4def852 | |||
| aa51adf0a2 | |||
| 1d02bdee6c | |||
| 2080c4f27e | |||
| 49ba502f99 | |||
| 7735c9addf | |||
| ed02d603a1 | |||
| 529469769f | |||
| 3b854534f0 | |||
| dcbf847493 | |||
| 2757204434 | |||
| 24a6f83847 | |||
| 2c36eb763f | |||
| a4ab0c607e | |||
| a3a4b8def7 | |||
| 14bdf57a99 | |||
| 45061cc797 | |||
| cb01817f22 | |||
| 1c4ccfb34e | |||
| 056287e3f7 | |||
| ccfa35c6f9 | |||
| 8471f71132 | |||
| 813185d141 | |||
| be12087783 | |||
| 4f9014b70b | |||
| 043ef5c25e | |||
| c06118e0b1 | |||
| 5f24bd11ee | |||
| f6f3089cf6 | |||
| a09aeb9fc4 | |||
| e4257ed76d | |||
| c4a5e3b90f | |||
| d02fc15ba1 | |||
| 435dc4baab | |||
| 04177b9c3f | |||
| 4a87c280dc | |||
| d237d9a918 | |||
| 2132ae465d | |||
| 87f01fc158 | |||
| 995b80fa3a | |||
| d842f99c6b | |||
| 8cad25a39c | |||
| c00bb5f4ea | |||
| d33cbbbf93 | |||
| a4efa59a94 | |||
| cb4d3fb737 | |||
| 4a2e9811e9 | |||
| 050dfc5045 | |||
| b49118220c | |||
| 806dda56ce | |||
| 97f5cfea77 | |||
| 5ecbea67eb | |||
| 957b4e9fbd | |||
| ef648fec0e | |||
| e518548e17 | |||
| 1f442afa41 | |||
| 62d549d757 | |||
| ab9011e79b | |||
| b42f36f0b0 | |||
| a30fed54f4 | |||
| e767b1cacc | |||
| d2090becab | |||
| 54f10674f3 | |||
| f8460e7e62 | |||
| 45479eb1de | |||
| aaeffd09bf | |||
| 0c270bb6c4 | |||
| c2c643256c | |||
| 896d0f0906 | |||
| ef525e0841 | |||
| 00a27515f0 | |||
| 52f1ef3b2d | |||
| c6b0680d9b | |||
| 2c37e1416b | |||
| 6e4845aee3 | |||
| 48cf7d674a | |||
| ca54e52122 | |||
| c3ae9321bf | |||
| 2dd2e49cc7 | |||
| 8a1b26eb54 | |||
| 7e76d21bc8 | |||
| e579a4ed0f | |||
| 6867d00403 | |||
| 0dc6fb730f | |||
| f5bffd3748 | |||
| 07c7899a37 | |||
| 79bfba2fa8 | |||
| 73511e3dde | |||
| 3b79394bc9 | |||
| 4df31aa98c | |||
| aeeada355c | |||
| 0905a4fe9b | |||
| 3ba6774e58 | |||
| 26e9c479b5 | |||
| db75854cbb | |||
| bd565f3e24 | |||
| 3c4e580e9a | |||
| b3f4436d37 | |||
| 05f8be3b49 | |||
| d8091c9294 | |||
| 05613fa7a3 | |||
| 725c9e22ca | |||
| fbfc7e843a | |||
| faa62966b1 | |||
| be28cdd1c3 | |||
| 7f0b3fa042 | |||
| f40a1ad9e0 | |||
| 9cf33c99fc | |||
| a51019f4ec | |||
| c71847b77b | |||
| 5c6d3c21b1 | |||
| 5e7198b873 | |||
| 46c71074ca | |||
| 35ba2ca5b7 | |||
| cbcb88dff8 | |||
| 0df5b5737c | |||
| 102a1db6b2 | |||
| 25e44a17ff | |||
| 718d20ed93 | |||
| 18fea82b89 | |||
| cfb602125e | |||
| 106627caa7 | |||
| d6bee967ed | |||
| 47e3dba972 | |||
| a09e3a8594 | |||
| 5573cbea9a | |||
| fc5966589b | |||
| 5d61d6e8dd | |||
| 775afc4dcd | |||
| 7ce9da0bea | |||
| e58dee8cae | |||
| 83b5a22d86 | |||
| 13c38c4c45 | |||
| fdbec0423b | |||
| 9f29a4d972 | |||
| ced5f71eec | |||
| e5a4f9cfc4 | |||
| 1579483a86 | |||
| edd23dba81 | |||
| 7b353d2c8c | |||
| b37efb872b | |||
| d8a81c3d3c | |||
| 875307b6a1 | |||
| 626abe164d | |||
| ba28919168 | |||
| c70c6e004e | |||
| 227273efa4 | |||
| b199e62d17 | |||
| b9d18bdbdc | |||
| e651a5b233 | |||
| 723726ae7d | |||
| aba5b019cb | |||
| f664153078 | |||
| 4ce06f940e | |||
| 5899ea5a77 | |||
| 56e69c1e9c | |||
| dacb4f6a61 | |||
| 66ccc9b75f | |||
| 7b86ad215e | |||
| aa7817c151 | |||
| 3902eaf9ed | |||
| 2cec08a1f0 | |||
| 0968d689a2 | |||
| 1ce90aa441 | |||
| c9eab8257d | |||
| df39626fdd | |||
| 083ddb7714 | |||
| 7bc2d04398 | |||
| 84d9492e52 | |||
| c8bbb0c93d | |||
| ae93e46716 | |||
| 645ca45a13 | |||
| 29bc31f62f | |||
| 17e2fd3bfd | |||
| 55de40fe47 | |||
| 9cea5f0d69 | |||
| 78d84f56d1 | |||
| 127daad223 | |||
| b155a243a6 | |||
| ac71835706 | |||
| 3625a0131a | |||
| 0b5a4c4d6b | |||
| ee73a8ff3d | |||
| c0234eab65 | |||
| dd34e6cdd9 | |||
| e9c1fa0cc1 | |||
| 18524b936d | |||
| 8afac5dc55 | |||
| bd724261d2 | |||
| a1e03186fd | |||
| e28635396a | |||
| 36f36610c3 | |||
| fd20a81b9a | |||
| ef8a6fe9fe | |||
| 7c36a9e24a | |||
| da81d91d48 | |||
| ecd3976f5b | |||
| 76a157f004 | |||
| 6512c18fe1 | |||
| f5ddb3b481 | |||
| d6a779a278 | |||
| bbba0b7f93 | |||
| 8a06356e24 | |||
| b73a8b1dc2 | |||
| baed4fbacb | |||
| f4c8e9c69b | |||
| 8639ca86da | |||
| c6ee83893e | |||
| 0fba4d138c | |||
| 6bf3f4dfe5 | |||
| fa0cd2d16f | |||
| a00c61db44 | |||
| c2068750d7 | |||
| af424d8a1a | |||
| 1ac6248312 | |||
| 77b01f53e7 | |||
| 57fc3987a0 | |||
| 4f6167deb5 | |||
| 79d6a1b1da | |||
| 510179f086 | |||
| cb16a5e043 | |||
| 3ca31bd0c6 |
-21
@@ -1,21 +0,0 @@
|
||||
env:
|
||||
CIRRUS_CLONE_DEPTH: 1
|
||||
ARCH: amd64
|
||||
|
||||
build_task:
|
||||
matrix:
|
||||
freebsd_instance:
|
||||
image_family: freebsd-12-4
|
||||
freebsd_instance:
|
||||
image_family: freebsd-13-2
|
||||
freebsd_instance:
|
||||
image_family: freebsd-14-0-snap
|
||||
prepare_script:
|
||||
- pkg install -y autoconf automake libtool gettext-runtime gmake ksh93 py39-packaging py39-cffi py39-sysctl
|
||||
configure_script:
|
||||
- env MAKE=gmake ./autogen.sh
|
||||
- env MAKE=gmake ./configure --with-config="user" --with-python=3.9
|
||||
build_script:
|
||||
- gmake -j `sysctl -n kern.smp.cpus`
|
||||
install_script:
|
||||
- gmake install
|
||||
+11
-7
@@ -145,18 +145,22 @@ Once everything is in good shape and the details have been worked out you can re
|
||||
Any required reviews can then be finalized and the pull request merged.
|
||||
|
||||
#### Tests and Benchmarks
|
||||
* Every pull request is tested using a GitHub Actions workflow on multiple platforms by running the [zfs-tests.sh and zloop.sh](
|
||||
* Every pull request will by tested by the buildbot on multiple platforms by running the [zfs-tests.sh and zloop.sh](
|
||||
https://openzfs.github.io/openzfs-docs/Developer%20Resources/Building%20ZFS.html#running-zloop-sh-and-zfs-tests-sh) test suites.
|
||||
`.github/workflows/scripts/generate-ci-type.py` is used to determine whether the pull request is nonbehavior, i.e., not introducing behavior changes of any code, configuration or tests. If so, the CI will run on fewer platforms and only essential sanity tests will run. You can always override this by adding `ZFS-CI-Type` line to your commit message:
|
||||
* If your last commit (or `HEAD` in git terms) contains a line `ZFS-CI-Type: quick`, quick mode is forced regardless of what files are changed.
|
||||
* Otherwise, if any commit in a PR contains a line `ZFS-CI-Type: full`, full mode is forced.
|
||||
* To verify your changes conform to the [style guidelines](
|
||||
https://github.com/openzfs/zfs/blob/master/.github/CONTRIBUTING.md#style-guides
|
||||
), please run `make checkstyle` and resolve any warnings.
|
||||
* Code analysis is performed by [CodeQL](https://codeql.github.com/) for each pull request.
|
||||
* Test cases should be provided when appropriate. This includes making sure new features have adequate code coverage.
|
||||
* Static code analysis of each pull request is performed by the buildbot; run `make lint` to check your changes.
|
||||
* Test cases should be provided when appropriate.
|
||||
This includes making sure new features have adequate code coverage.
|
||||
* If your pull request improves performance, please include some benchmarks.
|
||||
* The pull request must pass all CI checks before being accepted.
|
||||
* The pull request must pass all required [ZFS
|
||||
Buildbot](http://build.zfsonlinux.org/) builders before
|
||||
being accepted. If you are experiencing intermittent TEST
|
||||
builder failures, you may be experiencing a [test suite
|
||||
issue](https://github.com/openzfs/zfs/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Test+Suite%22).
|
||||
There are also various [buildbot options](https://openzfs.github.io/openzfs-docs/Developer%20Resources/Buildbot%20Options.html)
|
||||
to control how changes are tested.
|
||||
|
||||
### Testing
|
||||
All help is appreciated! If you're in a position to run the latest code
|
||||
|
||||
@@ -25,16 +25,14 @@ Type | Version/Name
|
||||
--- | ---
|
||||
Distribution Name |
|
||||
Distribution Version |
|
||||
Kernel Version |
|
||||
Linux Kernel |
|
||||
Architecture |
|
||||
OpenZFS Version |
|
||||
ZFS Version |
|
||||
SPL Version |
|
||||
<!--
|
||||
Command to find OpenZFS version:
|
||||
zfs version
|
||||
|
||||
Commands to find kernel version:
|
||||
uname -r # Linux
|
||||
freebsd-version -r # FreeBSD
|
||||
Commands to find ZFS/SPL versions:
|
||||
modinfo zfs | grep -iw version
|
||||
modinfo spl | grep -iw version
|
||||
-->
|
||||
|
||||
### Describe the problem you're observing
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: OpenZFS Questions
|
||||
url: https://github.com/openzfs/zfs/discussions/new
|
||||
about: Ask the community for help
|
||||
- name: OpenZFS Community Support Mailing list (Linux)
|
||||
url: https://zfsonlinux.topicbox.com/groups/zfs-discuss
|
||||
about: Get community support for OpenZFS on Linux
|
||||
@@ -10,5 +7,5 @@ contact_links:
|
||||
url: https://lists.freebsd.org/mailman/listinfo/freebsd-fs
|
||||
about: Get community support for OpenZFS on FreeBSD
|
||||
- name: OpenZFS on IRC
|
||||
url: https://web.libera.chat/#openzfs
|
||||
url: https://webchat.freenode.net/#openzfs
|
||||
about: Use IRC to get community support for OpenZFS
|
||||
|
||||
@@ -14,7 +14,7 @@ Please check our issue tracker before opening a new feature request.
|
||||
Filling out the following template will help other contributors better understand your proposed feature.
|
||||
-->
|
||||
|
||||
### Describe the feature you would like to see added to OpenZFS
|
||||
### Describe the feature would like to see added to OpenZFS
|
||||
|
||||
<!--
|
||||
Provide a clear and concise description of the feature.
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
name: Code Question
|
||||
about: Ask a question about the code
|
||||
title: ''
|
||||
labels: 'Type: Question'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for taking an interest in the OpenZFS codebase.
|
||||
|
||||
Please be aware that most questions are preferably asked in the mailing list first.
|
||||
This form is primarily meant for asking questions about the code itself.
|
||||
|
||||
Please also check our issue tracker before opening a new question.
|
||||
Filling out the following template will help other contributors better understand your question.
|
||||
-->
|
||||
|
||||
### Ask your question!
|
||||
|
||||
<!--
|
||||
Please provide a clear and concise question.
|
||||
-->
|
||||
|
||||
### Which portion of the codebase does your question involve?
|
||||
|
||||
<!--
|
||||
Optional: Please describe what portion of the codebase your issue involved.
|
||||
Example: "Testsuite", "Buildbots", "CLI", a code snippet etc.
|
||||
-->
|
||||
|
||||
### Additional context
|
||||
|
||||
<!--
|
||||
Any additional information you want to add?
|
||||
-->
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
<!--- Provide a general summary of your changes in the Title above -->
|
||||
|
||||
<!---
|
||||
Documentation on ZFS Buildbot options can be found at
|
||||
https://openzfs.github.io/openzfs-docs/Developer%20Resources/Buildbot%20Options.html
|
||||
-->
|
||||
|
||||
### Motivation and Context
|
||||
<!--- Why is this change required? What problem does it solve? -->
|
||||
<!--- If it fixes an open issue, please link to the issue here. -->
|
||||
@@ -22,17 +27,15 @@
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Performance enhancement (non-breaking change which improves efficiency)
|
||||
- [ ] Code cleanup (non-breaking change which makes code smaller or more readable)
|
||||
- [ ] Quality assurance (non-breaking change which makes the code more robust against bugs)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||
- [ ] Library ABI change (libzfs, libzfs\_core, libnvpair, libuutil and libzfsbootenv)
|
||||
- [ ] Documentation (a change to man pages or other documentation)
|
||||
|
||||
### Checklist:
|
||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||
- [ ] My code follows the OpenZFS [code style requirements](https://github.com/openzfs/zfs/blob/master/.github/CONTRIBUTING.md#coding-conventions).
|
||||
- [ ] My code follows the ZFS on Linux [code style requirements](https://github.com/zfsonlinux/zfs/blob/master/.github/CONTRIBUTING.md#coding-conventions).
|
||||
- [ ] I have updated the documentation accordingly.
|
||||
- [ ] I have read the [**contributing** document](https://github.com/openzfs/zfs/blob/master/.github/CONTRIBUTING.md).
|
||||
- [ ] I have added [tests](https://github.com/openzfs/zfs/tree/master/tests) to cover my changes.
|
||||
- [ ] I have read the [**contributing** document](https://github.com/zfsonlinux/zfs/blob/master/.github/CONTRIBUTING.md).
|
||||
- [ ] I have added [tests](https://github.com/zfsonlinux/zfs/tree/master/tests) to cover my changes.
|
||||
- [ ] I have run the ZFS Test Suite with this change applied.
|
||||
- [ ] All commit messages are properly formatted and contain [`Signed-off-by`](https://github.com/openzfs/zfs/blob/master/.github/CONTRIBUTING.md#signed-off-by).
|
||||
- [ ] All commit messages are properly formatted and contain [`Signed-off-by`](https://github.com/zfsonlinux/zfs/blob/master/.github/CONTRIBUTING.md#signed-off-by).
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
name: "Custom CodeQL Analysis"
|
||||
|
||||
queries:
|
||||
- uses: ./.github/codeql/custom-queries/cpp/deprecatedFunctionUsage.ql
|
||||
- uses: ./.github/codeql/custom-queries/cpp/dslDatasetHoldReleMismatch.ql
|
||||
@@ -1,4 +0,0 @@
|
||||
name: "Custom CodeQL Analysis"
|
||||
|
||||
paths-ignore:
|
||||
- tests
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* @name Deprecated function usage detection
|
||||
* @description Detects functions whose usage is banned from the OpenZFS
|
||||
* codebase due to QA concerns.
|
||||
* @kind problem
|
||||
* @severity error
|
||||
* @id cpp/deprecated-function-usage
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
predicate isDeprecatedFunction(Function f) {
|
||||
f.getName() = "strtok" or
|
||||
f.getName() = "__xpg_basename" or
|
||||
f.getName() = "basename" or
|
||||
f.getName() = "dirname" or
|
||||
f.getName() = "bcopy" or
|
||||
f.getName() = "bcmp" or
|
||||
f.getName() = "bzero" or
|
||||
f.getName() = "asctime" or
|
||||
f.getName() = "asctime_r" or
|
||||
f.getName() = "gmtime" or
|
||||
f.getName() = "localtime" or
|
||||
f.getName() = "strncpy"
|
||||
|
||||
}
|
||||
|
||||
string getReplacementMessage(Function f) {
|
||||
if f.getName() = "strtok" then
|
||||
result = "Use strtok_r(3) instead!"
|
||||
else if f.getName() = "__xpg_basename" then
|
||||
result = "basename(3) is underspecified. Use zfs_basename() instead!"
|
||||
else if f.getName() = "basename" then
|
||||
result = "basename(3) is underspecified. Use zfs_basename() instead!"
|
||||
else if f.getName() = "dirname" then
|
||||
result = "dirname(3) is underspecified. Use zfs_dirnamelen() instead!"
|
||||
else if f.getName() = "bcopy" then
|
||||
result = "bcopy(3) is deprecated. Use memcpy(3)/memmove(3) instead!"
|
||||
else if f.getName() = "bcmp" then
|
||||
result = "bcmp(3) is deprecated. Use memcmp(3) instead!"
|
||||
else if f.getName() = "bzero" then
|
||||
result = "bzero(3) is deprecated. Use memset(3) instead!"
|
||||
else if f.getName() = "asctime" then
|
||||
result = "Use strftime(3) instead!"
|
||||
else if f.getName() = "asctime_r" then
|
||||
result = "Use strftime(3) instead!"
|
||||
else if f.getName() = "gmtime" then
|
||||
result = "gmtime(3) isn't thread-safe. Use gmtime_r(3) instead!"
|
||||
else if f.getName() = "localtime" then
|
||||
result = "localtime(3) isn't thread-safe. Use localtime_r(3) instead!"
|
||||
else
|
||||
result = "strncpy(3) is deprecated. Use strlcpy(3) instead!"
|
||||
}
|
||||
|
||||
from FunctionCall fc, Function f
|
||||
where
|
||||
fc.getTarget() = f and
|
||||
isDeprecatedFunction(f)
|
||||
select fc, getReplacementMessage(f)
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* @name Detect mismatched dsl_dataset_hold/_rele pairs
|
||||
* @description Flags instances of issue #12014 where
|
||||
* - a dataset held with dsl_dataset_hold_obj() ends up in dsl_dataset_rele_flags(), or
|
||||
* - a dataset held with dsl_dataset_hold_obj_flags() ends up in dsl_dataset_rele().
|
||||
* @kind problem
|
||||
* @severity error
|
||||
* @tags correctness
|
||||
* @id cpp/dslDatasetHoldReleMismatch
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
from Variable ds, Call holdCall, Call releCall, string message
|
||||
where
|
||||
ds.getType().toString() = "dsl_dataset_t *" and
|
||||
holdCall.getASuccessor*() = releCall and
|
||||
(
|
||||
(holdCall.getTarget().getName() = "dsl_dataset_hold_obj_flags" and
|
||||
holdCall.getArgument(4).(AddressOfExpr).getOperand().(VariableAccess).getTarget() = ds and
|
||||
releCall.getTarget().getName() = "dsl_dataset_rele" and
|
||||
releCall.getArgument(0).(VariableAccess).getTarget() = ds and
|
||||
message = "Held with dsl_dataset_hold_obj_flags but released with dsl_dataset_rele")
|
||||
or
|
||||
(holdCall.getTarget().getName() = "dsl_dataset_hold_obj" and
|
||||
holdCall.getArgument(3).(AddressOfExpr).getOperand().(VariableAccess).getTarget() = ds and
|
||||
releCall.getTarget().getName() = "dsl_dataset_rele_flags" and
|
||||
releCall.getArgument(0).(VariableAccess).getTarget() = ds and
|
||||
message = "Held with dsl_dataset_hold_obj but released with dsl_dataset_rele_flags")
|
||||
)
|
||||
select releCall,
|
||||
"Mismatched release: held with $@ but released with " + releCall.getTarget().getName() + " for dataset $@",
|
||||
holdCall, holdCall.getTarget().getName(),
|
||||
ds, ds.toString()
|
||||
@@ -1,4 +0,0 @@
|
||||
name: openzfs-cpp-queries
|
||||
version: 0.0.0
|
||||
libraryPathDependencies: codeql-cpp
|
||||
suites: openzfs-cpp-suite
|
||||
@@ -1,13 +0,0 @@
|
||||
# Configuration for probot-no-response - https://github.com/probot/no-response
|
||||
|
||||
# Number of days of inactivity before an Issue is closed for lack of response
|
||||
daysUntilClose: 31
|
||||
# Label requiring a response
|
||||
responseRequiredLabel: "Status: Feedback requested"
|
||||
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been automatically closed because there has been no response
|
||||
to our request for more information from the original author. With only the
|
||||
information that is currently in the issue, we don't have enough information
|
||||
to take action. Please reach out if you have or find the answers we need so
|
||||
that we can investigate further.
|
||||
+1
-10
@@ -7,14 +7,7 @@ only: issues
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- "Type: Feature"
|
||||
- "Bot: Not Stale"
|
||||
- "Status: Work in Progress"
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: true
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: true
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: true
|
||||
- "Type: Understood"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: "Status: Stale"
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
@@ -22,5 +15,3 @@ markComment: >
|
||||
This issue has been automatically marked as "stale" because it has not had
|
||||
any activity for a while. It will be closed in 90 days if no further activity occurs.
|
||||
Thank you for your contributions.
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 6
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
|
||||
## The testings are done this way
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph CleanUp and Summary
|
||||
CleanUp+Summary
|
||||
end
|
||||
|
||||
subgraph Functional Testings
|
||||
sanity-checks-20.04
|
||||
zloop-checks-20.04
|
||||
functional-testing-20.04-->Part1-20.04
|
||||
functional-testing-20.04-->Part2-20.04
|
||||
functional-testing-20.04-->Part3-20.04
|
||||
functional-testing-20.04-->Part4-20.04
|
||||
functional-testing-22.04-->Part1-22.04
|
||||
functional-testing-22.04-->Part2-22.04
|
||||
functional-testing-22.04-->Part3-22.04
|
||||
functional-testing-22.04-->Part4-22.04
|
||||
sanity-checks-22.04
|
||||
zloop-checks-22.04
|
||||
end
|
||||
|
||||
subgraph Code Checking + Building
|
||||
Build-Ubuntu-20.04
|
||||
codeql.yml
|
||||
checkstyle.yml
|
||||
Build-Ubuntu-22.04
|
||||
end
|
||||
|
||||
Build-Ubuntu-20.04-->sanity-checks-20.04
|
||||
Build-Ubuntu-20.04-->zloop-checks-20.04
|
||||
Build-Ubuntu-20.04-->functional-testing-20.04
|
||||
Build-Ubuntu-22.04-->sanity-checks-22.04
|
||||
Build-Ubuntu-22.04-->zloop-checks-22.04
|
||||
Build-Ubuntu-22.04-->functional-testing-22.04
|
||||
|
||||
sanity-checks-20.04-->CleanUp+Summary
|
||||
Part1-20.04-->CleanUp+Summary
|
||||
Part2-20.04-->CleanUp+Summary
|
||||
Part3-20.04-->CleanUp+Summary
|
||||
Part4-20.04-->CleanUp+Summary
|
||||
Part1-22.04-->CleanUp+Summary
|
||||
Part2-22.04-->CleanUp+Summary
|
||||
Part3-22.04-->CleanUp+Summary
|
||||
Part4-22.04-->CleanUp+Summary
|
||||
sanity-checks-22.04-->CleanUp+Summary
|
||||
```
|
||||
|
||||
|
||||
1) build zfs modules for Ubuntu 20.04 and 22.04 (~15m)
|
||||
2) 2x zloop test (~10m) + 2x sanity test (~25m)
|
||||
3) 4x functional testings in parts 1..4 (each ~1h)
|
||||
4) cleanup and create summary
|
||||
- content of summary depends on the results of the steps
|
||||
|
||||
When everything runs fine, the full run should be done in
|
||||
about 2 hours.
|
||||
|
||||
The codeql.yml and checkstyle.yml are not part in this circle.
|
||||
@@ -4,61 +4,33 @@ on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
checkstyle:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# for x in lxd core20 snapd; do sudo snap remove $x; done
|
||||
sudo apt-get purge -y snapd google-chrome-stable firefox
|
||||
ONLY_DEPS=1 .github/workflows/scripts/qemu-3-deps-vm.sh ubuntu22
|
||||
sudo apt-get install -y cppcheck devscripts mandoc pax-utils shellcheck
|
||||
sudo python -m pipx install --quiet flake8
|
||||
# confirm that the tools are installed
|
||||
# the build system doesn't fail when they are not
|
||||
checkbashisms --version
|
||||
cppcheck --version
|
||||
flake8 --version
|
||||
scanelf --version
|
||||
shellcheck --version
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes -qq build-essential autoconf libtool gawk alien fakeroot linux-headers-$(uname -r)
|
||||
sudo apt-get install --yes -qq zlib1g-dev uuid-dev libattr1-dev libblkid-dev libselinux-dev libudev-dev libssl-dev python-dev python-setuptools python-cffi python3 python3-dev python3-setuptools python3-cffi
|
||||
# packages for tests
|
||||
sudo apt-get install --yes -qq parted lsscsi ksh attr acl nfs-kernel-server fio
|
||||
sudo apt-get install --yes -qq mandoc cppcheck pax-utils abigail-tools # devscripts - enable then bashisms fixed
|
||||
sudo -E pip --quiet install flake8
|
||||
- name: Prepare
|
||||
run: |
|
||||
sed -i '/DEBUG_CFLAGS="-Werror"/s/^/#/' config/zfs-build.m4
|
||||
./autogen.sh
|
||||
- name: Configure
|
||||
run: |
|
||||
sh ./autogen.sh
|
||||
./configure
|
||||
- name: Make
|
||||
run: |
|
||||
make -j$(nproc) --no-print-directory --silent
|
||||
- name: Checkstyle
|
||||
run: |
|
||||
make -j$(nproc) --no-print-directory --silent checkstyle
|
||||
make checkstyle
|
||||
- name: Lint
|
||||
run: |
|
||||
make -j$(nproc) --no-print-directory --silent lint
|
||||
make lint
|
||||
- name: CheckABI
|
||||
id: CheckABI
|
||||
run: |
|
||||
docker run -v $PWD:/source ghcr.io/openzfs/libabigail make -j$(nproc) --no-print-directory --silent checkabi
|
||||
- name: StoreABI
|
||||
if: failure() && steps.CheckABI.outcome == 'failure'
|
||||
run: |
|
||||
docker run -v $PWD:/source ghcr.io/openzfs/libabigail make -j$(nproc) --no-print-directory --silent storeabi
|
||||
- name: Prepare artifacts
|
||||
if: failure() && steps.CheckABI.outcome == 'failure'
|
||||
run: |
|
||||
find -name *.abi | tar -cf abi_files.tar -T -
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: failure() && steps.CheckABI.outcome == 'failure'
|
||||
with:
|
||||
name: New ABI files (use only if you're sure about interface changes)
|
||||
path: abi_files.tar
|
||||
make -j$(nproc)
|
||||
make checkabi
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp', 'python' ]
|
||||
|
||||
steps:
|
||||
- name: Set make jobs
|
||||
run: |
|
||||
echo "MAKEFLAGS=-j$(nproc)" >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
config-file: .github/codeql-${{ matrix.language }}.yml
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -1,49 +0,0 @@
|
||||
name: labels
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [ opened, synchronize, reopened, converted_to_draft, ready_for_review ]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
open:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'opened' && github.event.pull_request.draft }}
|
||||
steps:
|
||||
- env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ISSUE: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $ISSUE --add-label "Status: Work in Progress"
|
||||
|
||||
push:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'synchronize' || github.event.action == 'reopened' }}
|
||||
steps:
|
||||
- env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ISSUE: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $ISSUE --remove-label "Status: Accepted,Status: Inactive,Status: Revision Needed,Status: Stale"
|
||||
|
||||
draft:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'converted_to_draft' }}
|
||||
steps:
|
||||
- env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ISSUE: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $ISSUE --remove-label "Status: Accepted,Status: Code Review Needed,Status: Inactive,Status: Revision Needed,Status: Stale" --add-label "Status: Work in Progress"
|
||||
|
||||
rfr:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.action == 'ready_for_review' }}
|
||||
steps:
|
||||
- env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ISSUE: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr edit $ISSUE --remove-label "Status: Accepted,Status: Inactive,Status: Revision Needed,Status: Stale,Status: Work in Progress" --add-label "Status: Code Review Needed"
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
Workflow for each operating system:
|
||||
- install qemu on the github runner
|
||||
- download current cloud image of operating system
|
||||
- start and init that image via cloud-init
|
||||
- install dependencies and poweroff system
|
||||
- start system and build openzfs and then poweroff again
|
||||
- clone build system and start 2 instances of it
|
||||
- run functional testings and complete in around 3h
|
||||
- when tests are done, do some logfile preparing
|
||||
- show detailed results for each system
|
||||
- in the end, generate the job summary
|
||||
|
||||
/TR 14.09.2024
|
||||
@@ -1,112 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Determine the CI type based on the change list and commit message.
|
||||
|
||||
Prints "quick" if (explicity required by user):
|
||||
- the *last* commit message contains 'ZFS-CI-Type: quick'
|
||||
or if (heuristics):
|
||||
- the files changed are not in the list of specified directories, and
|
||||
- all commit messages do not contain 'ZFS-CI-Type: (full|linux|freebsd)'
|
||||
|
||||
Otherwise prints "full".
|
||||
"""
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
"""
|
||||
Patterns of files that are not considered to trigger full CI.
|
||||
Note: not using pathlib.Path.match() because it does not support '**'
|
||||
"""
|
||||
FULL_RUN_IGNORE_REGEX = list(map(re.compile, [
|
||||
r'.*\.md',
|
||||
r'.*\.gitignore'
|
||||
]))
|
||||
|
||||
"""
|
||||
Patterns of files that are considered to trigger full CI.
|
||||
"""
|
||||
FULL_RUN_REGEX = list(map(re.compile, [
|
||||
r'\.github/workflows/scripts/.*',
|
||||
r'cmd.*',
|
||||
r'configs/.*',
|
||||
r'META',
|
||||
r'.*\.am',
|
||||
r'.*\.m4',
|
||||
r'autogen\.sh',
|
||||
r'configure\.ac',
|
||||
r'copy-builtin',
|
||||
r'contrib',
|
||||
r'etc',
|
||||
r'include',
|
||||
r'lib/.*',
|
||||
r'module/.*',
|
||||
r'scripts/.*',
|
||||
r'tests/.*',
|
||||
r'udev/.*'
|
||||
]))
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
prog = sys.argv[0]
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print(f'Usage: {prog} <head_ref> <base_ref>')
|
||||
sys.exit(1)
|
||||
|
||||
head, base = sys.argv[1:3]
|
||||
|
||||
def output_type(type, reason):
|
||||
print(f'{prog}: will run {type} CI: {reason}', file=sys.stderr)
|
||||
print(type)
|
||||
sys.exit(0)
|
||||
|
||||
# check last (HEAD) commit message
|
||||
last_commit_message_raw = subprocess.run([
|
||||
'git', 'show', '-s', '--format=%B', head
|
||||
], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
for line in last_commit_message_raw.stdout.decode().splitlines():
|
||||
if line.strip().lower() == 'zfs-ci-type: quick':
|
||||
output_type('quick', f'requested by HEAD commit {head}')
|
||||
|
||||
# check all commit messages
|
||||
all_commit_message_raw = subprocess.run([
|
||||
'git', 'show', '-s',
|
||||
'--format=ZFS-CI-Commit: %H%n%B', f'{head}...{base}'
|
||||
], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
all_commit_message = all_commit_message_raw.stdout.decode().splitlines()
|
||||
|
||||
commit_ref = head
|
||||
for line in all_commit_message:
|
||||
if line.startswith('ZFS-CI-Commit:'):
|
||||
commit_ref = line.lstrip('ZFS-CI-Commit:').rstrip()
|
||||
if line.strip().lower() == 'zfs-ci-type: freebsd':
|
||||
output_type('freebsd', f'requested by commit {commit_ref}')
|
||||
if line.strip().lower() == 'zfs-ci-type: linux':
|
||||
output_type('linux', f'requested by commit {commit_ref}')
|
||||
if line.strip().lower() == 'zfs-ci-type: full':
|
||||
output_type('full', f'requested by commit {commit_ref}')
|
||||
|
||||
# check changed files
|
||||
changed_files_raw = subprocess.run([
|
||||
'git', 'diff', '--name-only', head, base
|
||||
], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
changed_files = changed_files_raw.stdout.decode().splitlines()
|
||||
|
||||
for f in changed_files:
|
||||
for r in FULL_RUN_IGNORE_REGEX:
|
||||
if r.match(f):
|
||||
break
|
||||
else:
|
||||
for r in FULL_RUN_REGEX:
|
||||
if r.match(f):
|
||||
output_type(
|
||||
'full',
|
||||
f'changed file "{f}" matches pattern "{r.pattern}"'
|
||||
)
|
||||
|
||||
# catch-all
|
||||
output_type('quick', 'no changed file matches full CI patterns')
|
||||
@@ -1,109 +0,0 @@
|
||||
#!/bin/awk -f
|
||||
#
|
||||
# Merge multiple ZTS tests results summaries into a single summary. This is
|
||||
# needed when you're running different parts of ZTS on different tests
|
||||
# runners or VMs.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# ./merge_summary.awk summary1.txt [summary2.txt] [summary3.txt] ...
|
||||
#
|
||||
# or:
|
||||
#
|
||||
# cat summary*.txt | ./merge_summary.awk
|
||||
#
|
||||
BEGIN {
|
||||
i=-1
|
||||
pass=0
|
||||
fail=0
|
||||
skip=0
|
||||
state=""
|
||||
cl=0
|
||||
el=0
|
||||
upl=0
|
||||
ul=0
|
||||
|
||||
# Total seconds of tests runtime
|
||||
total=0;
|
||||
}
|
||||
|
||||
# Skip empty lines
|
||||
/^\s*$/{next}
|
||||
|
||||
# Skip Configuration and Test lines
|
||||
/^Test:/{state=""; next}
|
||||
/Configuration/{state="";next}
|
||||
|
||||
# When we see "test-runner.py" stop saving config lines, and
|
||||
# save test runner lines
|
||||
/test-runner.py/{state="testrunner"; runner=runner$0"\n"; next}
|
||||
|
||||
# We need to differentiate the PASS counts from test result lines that start
|
||||
# with PASS, like:
|
||||
#
|
||||
# PASS mv_files/setup
|
||||
#
|
||||
# Use state="pass_count" to differentiate
|
||||
#
|
||||
/Results Summary/{state="pass_count"; next}
|
||||
/PASS/{ if (state=="pass_count") {pass += $2}}
|
||||
/FAIL/{ if (state=="pass_count") {fail += $2}}
|
||||
/SKIP/{ if (state=="pass_count") {skip += $2}}
|
||||
/Running Time/{
|
||||
state="";
|
||||
running[i]=$3;
|
||||
split($3, arr, ":")
|
||||
total += arr[1] * 60 * 60;
|
||||
total += arr[2] * 60;
|
||||
total += arr[3]
|
||||
next;
|
||||
}
|
||||
|
||||
/Tests with results other than PASS that are expected/{state="expected_lines"; next}
|
||||
/Tests with result of PASS that are unexpected/{state="unexpected_pass_lines"; next}
|
||||
/Tests with results other than PASS that are unexpected/{state="unexpected_lines"; next}
|
||||
{
|
||||
if (state == "expected_lines") {
|
||||
expected_lines[el] = $0
|
||||
el++
|
||||
}
|
||||
|
||||
if (state == "unexpected_pass_lines") {
|
||||
unexpected_pass_lines[upl] = $0
|
||||
upl++
|
||||
}
|
||||
if (state == "unexpected_lines") {
|
||||
unexpected_lines[ul] = $0
|
||||
ul++
|
||||
}
|
||||
}
|
||||
|
||||
# Reproduce summary
|
||||
END {
|
||||
print runner;
|
||||
print "\nResults Summary"
|
||||
print "PASS\t"pass
|
||||
print "FAIL\t"fail
|
||||
print "SKIP\t"skip
|
||||
print ""
|
||||
print "Running Time:\t"strftime("%T", total, 1)
|
||||
if (pass+fail+skip > 0) {
|
||||
percent_passed=(pass/(pass+fail+skip) * 100)
|
||||
}
|
||||
printf "Percent passed:\t%3.2f%", percent_passed
|
||||
|
||||
print "\n\nTests with results other than PASS that are expected:"
|
||||
asort(expected_lines, sorted)
|
||||
for (j in sorted)
|
||||
print sorted[j]
|
||||
|
||||
print "\n\nTests with result of PASS that are unexpected:"
|
||||
asort(unexpected_pass_lines, sorted)
|
||||
for (j in sorted)
|
||||
print sorted[j]
|
||||
|
||||
print "\n\nTests with results other than PASS that are unexpected:"
|
||||
asort(unexpected_lines, sorted)
|
||||
for (j in sorted)
|
||||
print sorted[j]
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 1) setup qemu instance on action runner
|
||||
######################################################################
|
||||
|
||||
set -eu
|
||||
|
||||
# We've been seeing this script take over 15min to run. This may or
|
||||
# may not be normal. Just to get a little more insight, print out
|
||||
# a message to stdout with the top running process, and do this every
|
||||
# 30 seconds. We can delete this watchdog later once we get a better
|
||||
# handle on what the timeout value should be.
|
||||
(while [ 1 ] ; do sleep 30 && echo "[watchdog: $(ps -eo cmd --sort=-pcpu | head -n 2 | tail -n 1)}')]"; done) &
|
||||
|
||||
# install needed packages
|
||||
export DEBIAN_FRONTEND="noninteractive"
|
||||
sudo apt-get -y update
|
||||
sudo apt-get install -y axel cloud-image-utils daemonize guestfs-tools \
|
||||
virt-manager linux-modules-extra-$(uname -r) zfsutils-linux
|
||||
|
||||
# generate ssh keys
|
||||
rm -f ~/.ssh/id_ed25519
|
||||
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -q -N ""
|
||||
|
||||
# not needed
|
||||
sudo systemctl stop docker.socket
|
||||
sudo systemctl stop multipathd.socket
|
||||
|
||||
# remove default swapfile and /mnt
|
||||
sudo swapoff -a
|
||||
sudo umount -l /mnt
|
||||
DISK="/dev/disk/cloud/azure_resource-part1"
|
||||
sudo sed -e "s|^$DISK.*||g" -i /etc/fstab
|
||||
sudo wipefs -aq $DISK
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
sudo modprobe loop
|
||||
sudo modprobe zfs
|
||||
|
||||
# partition the disk as needed
|
||||
DISK="/dev/disk/cloud/azure_resource"
|
||||
sudo sgdisk --zap-all $DISK
|
||||
sudo sgdisk -p \
|
||||
-n 1:0:+16G -c 1:"swap" \
|
||||
-n 2:0:0 -c 2:"tests" \
|
||||
$DISK
|
||||
sync
|
||||
sleep 1
|
||||
|
||||
# swap with same size as RAM (16GiB)
|
||||
sudo mkswap $DISK-part1
|
||||
sudo swapon $DISK-part1
|
||||
|
||||
# JBOD 2xdisk for OpenZFS storage (test vm's)
|
||||
SSD1="$DISK-part2"
|
||||
sudo fallocate -l 12G /test.ssd2
|
||||
SSD2=$(sudo losetup -b 4096 -f /test.ssd2 --show)
|
||||
|
||||
# adjust zfs module parameter and create pool
|
||||
exec 1>/dev/null
|
||||
ARC_MIN=$((1024*1024*256))
|
||||
ARC_MAX=$((1024*1024*512))
|
||||
echo $ARC_MIN | sudo tee /sys/module/zfs/parameters/zfs_arc_min
|
||||
echo $ARC_MAX | sudo tee /sys/module/zfs/parameters/zfs_arc_max
|
||||
echo 1 | sudo tee /sys/module/zfs/parameters/zvol_use_blk_mq
|
||||
sudo zpool create -f -o ashift=12 zpool $SSD1 $SSD2 -O relatime=off \
|
||||
-O atime=off -O xattr=sa -O compression=lz4 -O sync=disabled \
|
||||
-O redundant_metadata=none -O mountpoint=/mnt/tests
|
||||
|
||||
# no need for some scheduler
|
||||
for i in /sys/block/s*/queue/scheduler; do
|
||||
echo "none" | sudo tee $i
|
||||
done
|
||||
|
||||
# Kill off our watchdog
|
||||
kill $(jobs -p)
|
||||
@@ -1,314 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 2) start qemu with some operating system, init via cloud-init
|
||||
######################################################################
|
||||
|
||||
set -eu
|
||||
|
||||
# short name used in zfs-qemu.yml
|
||||
OS="$1"
|
||||
|
||||
# OS variant (virt-install --os-variant list)
|
||||
OSv=$OS
|
||||
|
||||
# FreeBSD urls's
|
||||
FREEBSD_REL="https://download.freebsd.org/releases/CI-IMAGES"
|
||||
FREEBSD_SNAP="https://download.freebsd.org/snapshots/CI-IMAGES"
|
||||
URLxz=""
|
||||
|
||||
# Ubuntu mirrors
|
||||
UBMIRROR="https://cloud-images.ubuntu.com"
|
||||
#UBMIRROR="https://mirrors.cloud.tencent.com/ubuntu-cloud-images"
|
||||
#UBMIRROR="https://mirror.citrahost.com/ubuntu-cloud-images"
|
||||
|
||||
# default nic model for vm's
|
||||
NIC="virtio"
|
||||
|
||||
# additional options for virt-install
|
||||
OPTS[0]=""
|
||||
OPTS[1]=""
|
||||
|
||||
case "$OS" in
|
||||
almalinux8)
|
||||
OSNAME="AlmaLinux 8"
|
||||
URL="https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/AlmaLinux-8-GenericCloud-latest.x86_64.qcow2"
|
||||
;;
|
||||
almalinux9)
|
||||
OSNAME="AlmaLinux 9"
|
||||
URL="https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2"
|
||||
;;
|
||||
almalinux10)
|
||||
OSNAME="AlmaLinux 10"
|
||||
OSv="almalinux9"
|
||||
URL="https://repo.almalinux.org/almalinux/10/cloud/x86_64/images/AlmaLinux-10-GenericCloud-latest.x86_64.qcow2"
|
||||
;;
|
||||
archlinux)
|
||||
OSNAME="Archlinux"
|
||||
URL="https://geo.mirror.pkgbuild.com/images/latest/Arch-Linux-x86_64-cloudimg.qcow2"
|
||||
;;
|
||||
centos-stream9)
|
||||
OSNAME="CentOS Stream 9"
|
||||
URL="https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2"
|
||||
;;
|
||||
centos-stream10)
|
||||
OSNAME="CentOS Stream 10"
|
||||
OSv="centos-stream9"
|
||||
URL="https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-10-latest.x86_64.qcow2"
|
||||
;;
|
||||
debian11)
|
||||
OSNAME="Debian 11"
|
||||
URL="https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.qcow2"
|
||||
;;
|
||||
debian12)
|
||||
OSNAME="Debian 12"
|
||||
URL="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
|
||||
;;
|
||||
debian13)
|
||||
OSNAME="Debian 13"
|
||||
# TODO: Overwrite OSv to debian13 for virt-install until it's added to osinfo
|
||||
OSv="debian12"
|
||||
URL="https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2"
|
||||
OPTS[0]="--boot"
|
||||
OPTS[1]="uefi=on"
|
||||
;;
|
||||
fedora41)
|
||||
OSNAME="Fedora 41"
|
||||
OSv="fedora-unknown"
|
||||
URL="https://download.fedoraproject.org/pub/fedora/linux/releases/41/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-41-1.4.x86_64.qcow2"
|
||||
;;
|
||||
fedora42)
|
||||
OSNAME="Fedora 42"
|
||||
OSv="fedora-unknown"
|
||||
URL="https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2"
|
||||
;;
|
||||
fedora43)
|
||||
OSNAME="Fedora 43"
|
||||
OSv="fedora-unknown"
|
||||
URL="https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2"
|
||||
;;
|
||||
freebsd13-5r)
|
||||
FreeBSD="13.5-RELEASE"
|
||||
OSNAME="FreeBSD $FreeBSD"
|
||||
OSv="freebsd13.0"
|
||||
URLxz="$FREEBSD_REL/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI.raw.xz"
|
||||
KSRC="$FREEBSD_REL/../amd64/$FreeBSD/src.txz"
|
||||
NIC="rtl8139"
|
||||
;;
|
||||
freebsd14-2r)
|
||||
FreeBSD="14.2-RELEASE"
|
||||
OSNAME="FreeBSD $FreeBSD"
|
||||
OSv="freebsd14.0"
|
||||
URLxz="$FREEBSD_REL/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI.raw.xz"
|
||||
KSRC="$FREEBSD_REL/../amd64/$FreeBSD/src.txz"
|
||||
;;
|
||||
freebsd14-3r)
|
||||
FreeBSD="14.3-RELEASE"
|
||||
OSNAME="FreeBSD $FreeBSD"
|
||||
OSv="freebsd14.0"
|
||||
URLxz="$FREEBSD_REL/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI.raw.xz"
|
||||
KSRC="$FREEBSD_REL/../amd64/$FreeBSD/src.txz"
|
||||
;;
|
||||
freebsd13-5s)
|
||||
FreeBSD="13.5-STABLE"
|
||||
OSNAME="FreeBSD $FreeBSD"
|
||||
OSv="freebsd13.0"
|
||||
URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI.raw.xz"
|
||||
KSRC="$FREEBSD_SNAP/../amd64/$FreeBSD/src.txz"
|
||||
NIC="rtl8139"
|
||||
;;
|
||||
freebsd14-3s)
|
||||
FreeBSD="14.3-STABLE"
|
||||
OSNAME="FreeBSD $FreeBSD"
|
||||
OSv="freebsd14.0"
|
||||
URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz"
|
||||
KSRC="$FREEBSD_SNAP/../amd64/$FreeBSD/src.txz"
|
||||
;;
|
||||
freebsd15-0s)
|
||||
FreeBSD="15.0-STABLE"
|
||||
OSNAME="FreeBSD $FreeBSD"
|
||||
OSv="freebsd14.0"
|
||||
URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz"
|
||||
KSRC="$FREEBSD_SNAP/../amd64/$FreeBSD/src.txz"
|
||||
;;
|
||||
freebsd16-0c)
|
||||
FreeBSD="16.0-CURRENT"
|
||||
OSNAME="FreeBSD $FreeBSD"
|
||||
OSv="freebsd14.0"
|
||||
URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz"
|
||||
KSRC="$FREEBSD_SNAP/../amd64/$FreeBSD/src.txz"
|
||||
;;
|
||||
tumbleweed)
|
||||
OSNAME="openSUSE Tumbleweed"
|
||||
OSv="opensusetumbleweed"
|
||||
MIRROR="http://opensuse-mirror-gce-us.susecloud.net"
|
||||
URL="$MIRROR/tumbleweed/appliances/openSUSE-MicroOS.x86_64-OpenStack-Cloud.qcow2"
|
||||
;;
|
||||
ubuntu22)
|
||||
OSNAME="Ubuntu 22.04"
|
||||
OSv="ubuntu22.04"
|
||||
URL="$UBMIRROR/jammy/current/jammy-server-cloudimg-amd64.img"
|
||||
;;
|
||||
ubuntu24)
|
||||
OSNAME="Ubuntu 24.04"
|
||||
OSv="ubuntu24.04"
|
||||
URL="$UBMIRROR/noble/current/noble-server-cloudimg-amd64.img"
|
||||
;;
|
||||
*)
|
||||
echo "Wrong value for OS variable!"
|
||||
exit 111
|
||||
;;
|
||||
esac
|
||||
|
||||
# environment file
|
||||
ENV="/var/tmp/env.txt"
|
||||
echo "ENV=$ENV" >> $ENV
|
||||
|
||||
# result path
|
||||
echo 'RESPATH="/var/tmp/test_results"' >> $ENV
|
||||
|
||||
# FreeBSD 13 has problems with: e1000 and virtio
|
||||
echo "NIC=$NIC" >> $ENV
|
||||
|
||||
# freebsd15 -> used in zfs-qemu.yml
|
||||
echo "OS=$OS" >> $ENV
|
||||
|
||||
# freebsd14.0 -> used for virt-install
|
||||
echo "OSv=\"$OSv\"" >> $ENV
|
||||
|
||||
# FreeBSD 15 (Current) -> used for summary
|
||||
echo "OSNAME=\"$OSNAME\"" >> $ENV
|
||||
|
||||
# default vm count for testings
|
||||
VMs=2
|
||||
echo "VMs=\"$VMs\"" >> $ENV
|
||||
|
||||
# default cpu count for testing vm's
|
||||
CPU=2
|
||||
echo "CPU=\"$CPU\"" >> $ENV
|
||||
|
||||
sudo mkdir -p "/mnt/tests"
|
||||
sudo chown -R $(whoami) /mnt/tests
|
||||
|
||||
DISK="/dev/zvol/zpool/openzfs"
|
||||
sudo zfs create -ps -b 64k -V 80g zpool/openzfs
|
||||
while true; do test -b $DISK && break; sleep 1; done
|
||||
|
||||
# we are downloading via axel, curl and wget are mostly slower and
|
||||
# require more return value checking
|
||||
IMG="/mnt/tests/cloud-image"
|
||||
if [ ! -z "$URLxz" ]; then
|
||||
echo "Loading $URLxz ..."
|
||||
time axel -q -o "$IMG" "$URLxz"
|
||||
echo "Loading $KSRC ..."
|
||||
time axel -q -o ~/src.txz $KSRC
|
||||
else
|
||||
echo "Loading $URL ..."
|
||||
time axel -q -o "$IMG" "$URL"
|
||||
fi
|
||||
|
||||
echo "Importing VM image to zvol..."
|
||||
if [ ! -z "$URLxz" ]; then
|
||||
xzcat -T0 $IMG | sudo dd of=$DISK bs=4M
|
||||
else
|
||||
sudo qemu-img dd -f qcow2 -O raw if=$IMG of=$DISK bs=4M
|
||||
fi
|
||||
rm -f $IMG
|
||||
|
||||
PUBKEY=$(cat ~/.ssh/id_ed25519.pub)
|
||||
if [ ${OS:0:7} != "freebsd" ]; then
|
||||
cat <<EOF > /tmp/user-data
|
||||
#cloud-config
|
||||
|
||||
hostname: $OS
|
||||
|
||||
users:
|
||||
- name: root
|
||||
shell: $BASH
|
||||
- name: zfs
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
shell: $BASH
|
||||
ssh_authorized_keys:
|
||||
- $PUBKEY
|
||||
|
||||
growpart:
|
||||
mode: auto
|
||||
devices: ['/']
|
||||
ignore_growroot_disabled: false
|
||||
EOF
|
||||
else
|
||||
cat <<EOF > /tmp/user-data
|
||||
#cloud-config
|
||||
|
||||
hostname: $OS
|
||||
|
||||
# minimized config without sudo for nuageinit of FreeBSD
|
||||
growpart:
|
||||
mode: auto
|
||||
devices: ['/']
|
||||
ignore_growroot_disabled: false
|
||||
EOF
|
||||
fi
|
||||
|
||||
sudo virsh net-update default add ip-dhcp-host \
|
||||
"<host mac='52:54:00:83:79:00' ip='192.168.122.10'/>" --live --config
|
||||
|
||||
sudo virt-install \
|
||||
--os-variant $OSv \
|
||||
--name "openzfs" \
|
||||
--cpu host-passthrough \
|
||||
--virt-type=kvm --hvm \
|
||||
--vcpus=4,sockets=1 \
|
||||
--memory $((1024*12)) \
|
||||
--memballoon model=virtio \
|
||||
--graphics none \
|
||||
--network bridge=virbr0,model=$NIC,mac='52:54:00:83:79:00' \
|
||||
--cloud-init user-data=/tmp/user-data \
|
||||
--disk $DISK,bus=virtio,cache=none,format=raw,driver.discard=unmap \
|
||||
--import --noautoconsole ${OPTS[0]} ${OPTS[1]} >/dev/null
|
||||
|
||||
# Give the VMs hostnames so we don't have to refer to them with
|
||||
# hardcoded IP addresses.
|
||||
#
|
||||
# vm0: Initial VM we install dependencies and build ZFS on.
|
||||
# vm1..2 Testing VMs
|
||||
for ((i=0; i<=VMs; i++)); do
|
||||
echo "192.168.122.1$i vm$i" | sudo tee -a /etc/hosts
|
||||
done
|
||||
|
||||
# in case the directory isn't there already
|
||||
mkdir -p $HOME/.ssh
|
||||
|
||||
cat <<EOF >> $HOME/.ssh/config
|
||||
# no questions please
|
||||
StrictHostKeyChecking no
|
||||
|
||||
# small timeout, used in while loops later
|
||||
ConnectTimeout 1
|
||||
EOF
|
||||
|
||||
if [ ${OS:0:7} != "freebsd" ]; then
|
||||
# enable KSM on Linux
|
||||
sudo virsh dommemstat --domain "openzfs" --period 5
|
||||
sudo virsh node-memory-tune 100 50 1
|
||||
echo 1 | sudo tee /sys/kernel/mm/ksm/run > /dev/null
|
||||
else
|
||||
# on FreeBSD we need some more init stuff, because of nuageinit
|
||||
BASH="/usr/local/bin/bash"
|
||||
while pidof /usr/bin/qemu-system-x86_64 >/dev/null; do
|
||||
ssh 2>/dev/null root@vm0 "uname -a" && break
|
||||
done
|
||||
ssh root@vm0 "env IGNORE_OSVERSION=yes pkg install -y bash ca_root_nss git qemu-guest-agent python3 py311-cloud-init"
|
||||
ssh root@vm0 "chsh -s $BASH root"
|
||||
ssh root@vm0 'sysrc qemu_guest_agent_enable="YES"'
|
||||
ssh root@vm0 'sysrc cloudinit_enable="YES"'
|
||||
ssh root@vm0 "pw add user zfs -w no -s $BASH"
|
||||
ssh root@vm0 'mkdir -p ~zfs/.ssh'
|
||||
ssh root@vm0 'echo "zfs ALL=(ALL:ALL) NOPASSWD: ALL" >> /usr/local/etc/sudoers'
|
||||
ssh root@vm0 'echo "PubkeyAuthentication yes" >> /etc/ssh/sshd_config'
|
||||
scp ~/.ssh/id_ed25519.pub "root@vm0:~zfs/.ssh/authorized_keys"
|
||||
ssh root@vm0 'chown -R zfs ~zfs'
|
||||
ssh root@vm0 'service sshd restart'
|
||||
scp ~/src.txz "root@vm0:/tmp/src.txz"
|
||||
ssh root@vm0 'tar -C / -zxf /tmp/src.txz'
|
||||
fi
|
||||
@@ -1,262 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 3) install dependencies for compiling and loading
|
||||
#
|
||||
# $1: OS name (like 'fedora41')
|
||||
# $2: (optional) Experimental Fedora kernel version, like "6.14" to
|
||||
# install instead of Fedora defaults.
|
||||
######################################################################
|
||||
|
||||
set -eu
|
||||
|
||||
function archlinux() {
|
||||
echo "##[group]Running pacman -Syu"
|
||||
sudo btrfs filesystem resize max /
|
||||
sudo pacman -Syu --noconfirm
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Install Development Tools"
|
||||
sudo pacman -Sy --noconfirm base-devel bc cpio cryptsetup dhclient dkms \
|
||||
fakeroot fio gdb inetutils jq less linux linux-headers lsscsi nfs-utils \
|
||||
parted pax perf python-packaging python-setuptools qemu-guest-agent ksh \
|
||||
samba strace sysstat rng-tools rsync wget xxhash
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
function debian() {
|
||||
export DEBIAN_FRONTEND="noninteractive"
|
||||
|
||||
echo "##[group]Running apt-get update+upgrade"
|
||||
sudo sed -i '/[[:alpha:]]-backports/d' /etc/apt/sources.list
|
||||
sudo apt-get update -y
|
||||
sudo apt-get upgrade -y
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Install Development Tools"
|
||||
sudo apt-get install -y \
|
||||
acl alien attr autoconf bc cpio cryptsetup curl dbench dh-python dkms \
|
||||
fakeroot fio gdb gdebi git ksh lcov isc-dhcp-client jq libacl1-dev \
|
||||
libaio-dev libattr1-dev libblkid-dev libcurl4-openssl-dev libdevmapper-dev \
|
||||
libelf-dev libffi-dev libmount-dev libpam0g-dev libselinux-dev libssl-dev \
|
||||
libtool libtool-bin libudev-dev libunwind-dev linux-headers-$(uname -r) \
|
||||
lsscsi nfs-kernel-server pamtester parted python3 python3-all-dev \
|
||||
python3-cffi python3-dev python3-distlib python3-packaging libtirpc-dev \
|
||||
python3-setuptools python3-sphinx qemu-guest-agent rng-tools rpm2cpio \
|
||||
rsync samba strace sysstat uuid-dev watchdog wget xfslibs-dev xxhash \
|
||||
zlib1g-dev
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
function freebsd() {
|
||||
export ASSUME_ALWAYS_YES="YES"
|
||||
|
||||
echo "##[group]Install Development Tools"
|
||||
sudo pkg install -y autoconf automake autotools base64 checkbashisms fio \
|
||||
gdb gettext gettext-runtime git gmake gsed jq ksh lcov libtool lscpu \
|
||||
pkgconf python python3 pamtester pamtester qemu-guest-agent rsync xxhash
|
||||
sudo pkg install -xy \
|
||||
'^samba4[[:digit:]]+$' \
|
||||
'^py3[[:digit:]]+-cffi$' \
|
||||
'^py3[[:digit:]]+-sysctl$' \
|
||||
'^py3[[:digit:]]+-setuptools$' \
|
||||
'^py3[[:digit:]]+-packaging$'
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
# common packages for: almalinux, centos, redhat
|
||||
function rhel() {
|
||||
echo "##[group]Running dnf update"
|
||||
echo "max_parallel_downloads=10" | sudo -E tee -a /etc/dnf/dnf.conf
|
||||
sudo dnf clean all
|
||||
sudo dnf update -y --setopt=fastestmirror=1 --refresh
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Install Development Tools"
|
||||
|
||||
# Alma wants "Development Tools", Fedora 41 wants "development-tools"
|
||||
if ! sudo dnf group install -y "Development Tools" ; then
|
||||
echo "Trying 'development-tools' instead of 'Development Tools'"
|
||||
sudo dnf group install -y development-tools
|
||||
fi
|
||||
|
||||
sudo dnf install -y \
|
||||
acl attr bc bzip2 cryptsetup curl dbench dkms elfutils-libelf-devel fio \
|
||||
gdb git jq kernel-rpm-macros ksh libacl-devel libaio-devel \
|
||||
libargon2-devel libattr-devel libblkid-devel libcurl-devel libffi-devel \
|
||||
ncompress libselinux-devel libtirpc-devel libtool libudev-devel \
|
||||
libuuid-devel lsscsi mdadm nfs-utils openssl-devel pam-devel pamtester \
|
||||
parted perf python3 python3-cffi python3-devel python3-packaging \
|
||||
kernel-devel python3-setuptools qemu-guest-agent rng-tools rpcgen \
|
||||
rpm-build rsync samba strace sysstat systemd watchdog wget xfsprogs-devel \
|
||||
xxhash zlib-devel
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
function tumbleweed() {
|
||||
echo "##[group]Running zypper is TODO!"
|
||||
sleep 23456
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
# $1: Kernel version to install (like '6.14rc7')
|
||||
function install_fedora_experimental_kernel {
|
||||
|
||||
our_version="$1"
|
||||
sudo dnf -y copr enable @kernel-vanilla/stable
|
||||
sudo dnf -y copr enable @kernel-vanilla/mainline
|
||||
all="$(sudo dnf list --showduplicates kernel-* python3-perf* perf* bpftool*)"
|
||||
echo "Available versions:"
|
||||
echo "$all"
|
||||
|
||||
# You can have a bunch of minor variants of the version we want '6.14'.
|
||||
# Pick the newest variant (sorted by version number).
|
||||
specific_version=$(echo "$all" | grep $our_version | awk '{print $2}' | sort -V | tail -n 1)
|
||||
list="$(echo "$all" | grep $specific_version | grep -Ev 'kernel-rt|kernel-selftests|kernel-debuginfo' | sed 's/.x86_64//g' | awk '{print $1"-"$2}')"
|
||||
sudo dnf install -y $list
|
||||
sudo dnf -y copr disable @kernel-vanilla/stable
|
||||
sudo dnf -y copr disable @kernel-vanilla/mainline
|
||||
}
|
||||
|
||||
# Install dependencies
|
||||
case "$1" in
|
||||
almalinux8)
|
||||
echo "##[group]Enable epel and powertools repositories"
|
||||
sudo dnf config-manager -y --set-enabled powertools
|
||||
sudo dnf install -y epel-release
|
||||
echo "##[endgroup]"
|
||||
rhel
|
||||
echo "##[group]Install kernel-abi-whitelists"
|
||||
sudo dnf install -y kernel-abi-whitelists
|
||||
echo "##[endgroup]"
|
||||
;;
|
||||
almalinux9|almalinux10|centos-stream9|centos-stream10)
|
||||
echo "##[group]Enable epel and crb repositories"
|
||||
sudo dnf config-manager -y --set-enabled crb
|
||||
sudo dnf install -y epel-release
|
||||
echo "##[endgroup]"
|
||||
rhel
|
||||
echo "##[group]Install kernel-abi-stablelists"
|
||||
sudo dnf install -y kernel-abi-stablelists
|
||||
echo "##[endgroup]"
|
||||
;;
|
||||
archlinux)
|
||||
archlinux
|
||||
;;
|
||||
debian*)
|
||||
echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections
|
||||
debian
|
||||
echo "##[group]Install Debian specific"
|
||||
sudo apt-get install -yq linux-perf dh-sequence-dkms
|
||||
echo "##[endgroup]"
|
||||
;;
|
||||
fedora*)
|
||||
rhel
|
||||
sudo dnf install -y libunwind-devel
|
||||
|
||||
# Fedora 42+ moves /usr/bin/script from 'util-linux' to 'util-linux-script'
|
||||
sudo dnf install -y util-linux-script || true
|
||||
|
||||
# Optional: Install an experimental kernel ($2 = kernel version)
|
||||
if [ -n "${2:-}" ] ; then
|
||||
install_fedora_experimental_kernel "$2"
|
||||
fi
|
||||
;;
|
||||
freebsd*)
|
||||
freebsd
|
||||
;;
|
||||
tumbleweed)
|
||||
tumbleweed
|
||||
;;
|
||||
ubuntu*)
|
||||
debian
|
||||
echo "##[group]Install Ubuntu specific"
|
||||
sudo apt-get install -yq linux-tools-common libtirpc-dev \
|
||||
linux-modules-extra-$(uname -r)
|
||||
sudo apt-get install -yq dh-sequence-dkms
|
||||
echo "##[endgroup]"
|
||||
echo "##[group]Delete Ubuntu OpenZFS modules"
|
||||
for i in $(find /lib/modules -name zfs -type d); do sudo rm -rvf $i; done
|
||||
echo "##[endgroup]"
|
||||
;;
|
||||
esac
|
||||
|
||||
# This script is used for checkstyle + zloop deps also.
|
||||
# Install only the needed packages and exit - when used this way.
|
||||
test -z "${ONLY_DEPS:-}" || exit 0
|
||||
|
||||
# Start services
|
||||
echo "##[group]Enable services"
|
||||
case "$1" in
|
||||
freebsd*)
|
||||
# add virtio things
|
||||
echo 'virtio_load="YES"' | sudo -E tee -a /boot/loader.conf
|
||||
for i in balloon blk console random scsi; do
|
||||
echo "virtio_${i}_load=\"YES\"" | sudo -E tee -a /boot/loader.conf
|
||||
done
|
||||
echo "fdescfs /dev/fd fdescfs rw 0 0" | sudo -E tee -a /etc/fstab
|
||||
sudo -E mount /dev/fd
|
||||
sudo -E touch /etc/zfs/exports
|
||||
sudo -E sysrc mountd_flags="/etc/zfs/exports"
|
||||
echo '[global]' | sudo -E tee /usr/local/etc/smb4.conf >/dev/null
|
||||
sudo -E service nfsd enable
|
||||
sudo -E service qemu-guest-agent enable
|
||||
sudo -E service samba_server enable
|
||||
;;
|
||||
debian*|ubuntu*)
|
||||
sudo -E systemctl enable nfs-kernel-server
|
||||
sudo -E systemctl enable qemu-guest-agent
|
||||
sudo -E systemctl enable smbd
|
||||
;;
|
||||
*)
|
||||
# All other linux distros
|
||||
sudo -E systemctl enable nfs-server
|
||||
sudo -E systemctl enable qemu-guest-agent
|
||||
sudo -E systemctl enable smb
|
||||
;;
|
||||
esac
|
||||
echo "##[endgroup]"
|
||||
|
||||
# Setup Kernel cmdline
|
||||
CMDLINE="console=tty0 console=ttyS0,115200n8"
|
||||
CMDLINE="$CMDLINE selinux=0"
|
||||
CMDLINE="$CMDLINE random.trust_cpu=on"
|
||||
CMDLINE="$CMDLINE no_timer_check"
|
||||
case "$1" in
|
||||
almalinux*|centos*|fedora*)
|
||||
GRUB_CFG="/boot/grub2/grub.cfg"
|
||||
GRUB_MKCONFIG="grub2-mkconfig"
|
||||
CMDLINE="$CMDLINE biosdevname=0 net.ifnames=0"
|
||||
echo 'GRUB_SERIAL_COMMAND="serial --speed=115200"' \
|
||||
| sudo tee -a /etc/default/grub >/dev/null
|
||||
;;
|
||||
ubuntu24)
|
||||
GRUB_CFG="/boot/grub/grub.cfg"
|
||||
GRUB_MKCONFIG="grub-mkconfig"
|
||||
echo 'GRUB_DISABLE_OS_PROBER="false"' \
|
||||
| sudo tee -a /etc/default/grub >/dev/null
|
||||
;;
|
||||
*)
|
||||
GRUB_CFG="/boot/grub/grub.cfg"
|
||||
GRUB_MKCONFIG="grub-mkconfig"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$1" in
|
||||
archlinux|freebsd*)
|
||||
true
|
||||
;;
|
||||
*)
|
||||
echo "##[group]Edit kernel cmdline"
|
||||
sudo sed -i -e '/^GRUB_CMDLINE_LINUX/d' /etc/default/grub || true
|
||||
echo "GRUB_CMDLINE_LINUX=\"$CMDLINE\"" \
|
||||
| sudo tee -a /etc/default/grub >/dev/null
|
||||
sudo $GRUB_MKCONFIG -o $GRUB_CFG
|
||||
echo "##[endgroup]"
|
||||
;;
|
||||
esac
|
||||
|
||||
# reset cloud-init configuration and poweroff
|
||||
sudo cloud-init clean --logs
|
||||
sleep 2 && sudo poweroff &
|
||||
exit 0
|
||||
@@ -1,28 +0,0 @@
|
||||
######################################################################
|
||||
# 3) Wait for VM to boot from previous step and launch dependencies
|
||||
# script on it.
|
||||
#
|
||||
# $1: OS name (like 'fedora41')
|
||||
# $2: (optional) Experimental kernel version to install on fedora,
|
||||
# like "6.14".
|
||||
######################################################################
|
||||
|
||||
.github/workflows/scripts/qemu-wait-for-vm.sh vm0
|
||||
|
||||
# SPECIAL CASE:
|
||||
#
|
||||
# If the user passed in an experimental kernel version to test on Fedora,
|
||||
# we need to update the kernel version in zfs's META file to allow the
|
||||
# build to happen. We update our local copy of META here, since we know
|
||||
# it will be rsync'd up in the next step.
|
||||
if [ -n "${2:-}" ] ; then
|
||||
sed -i -E 's/Linux-Maximum: .+/Linux-Maximum: 99.99/g' META
|
||||
fi
|
||||
|
||||
scp .github/workflows/scripts/qemu-3-deps-vm.sh zfs@vm0:qemu-3-deps-vm.sh
|
||||
PID=`pidof /usr/bin/qemu-system-x86_64`
|
||||
ssh zfs@vm0 '$HOME/qemu-3-deps-vm.sh' "$@"
|
||||
# wait for poweroff to succeed
|
||||
tail --pid=$PID -f /dev/null
|
||||
sleep 5 # avoid this: "error: Domain is already active"
|
||||
rm -f $HOME/.ssh/known_hosts
|
||||
@@ -1,396 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 4) configure and build openzfs modules. This is run on the VMs.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# qemu-4-build-vm.sh OS [--enable-debug][--dkms][--patch-level NUM]
|
||||
# [--poweroff][--release][--repo][--tarball]
|
||||
#
|
||||
# OS: OS name like 'fedora41'
|
||||
# --enable-debug: Build RPMs with '--enable-debug' (for testing)
|
||||
# --dkms: Build DKMS RPMs as well
|
||||
# --patch-level NUM: Use a custom patch level number for packages.
|
||||
# --poweroff: Power-off the VM after building
|
||||
# --release Build zfs-release*.rpm as well
|
||||
# --repo After building everything, copy RPMs into /tmp/repo
|
||||
# in the ZFS RPM repository file structure. Also
|
||||
# copy tarballs if they were built.
|
||||
# --tarball: Also build a tarball of ZFS source
|
||||
######################################################################
|
||||
|
||||
ENABLE_DEBUG=""
|
||||
DKMS=""
|
||||
PATCH_LEVEL=""
|
||||
POWEROFF=""
|
||||
RELEASE=""
|
||||
REPO=""
|
||||
TARBALL=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--enable-debug)
|
||||
ENABLE_DEBUG=1
|
||||
shift
|
||||
;;
|
||||
--dkms)
|
||||
DKMS=1
|
||||
shift
|
||||
;;
|
||||
--patch-level)
|
||||
PATCH_LEVEL=$2
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--poweroff)
|
||||
POWEROFF=1
|
||||
shift
|
||||
;;
|
||||
--release)
|
||||
RELEASE=1
|
||||
shift
|
||||
;;
|
||||
--repo)
|
||||
REPO=1
|
||||
shift
|
||||
;;
|
||||
--tarball)
|
||||
TARBALL=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
OS=$1
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -eu
|
||||
|
||||
function run() {
|
||||
LOG="/var/tmp/build-stderr.txt"
|
||||
echo "****************************************************"
|
||||
echo "$(date) ($*)"
|
||||
echo "****************************************************"
|
||||
($@ || echo $? > /tmp/rv) 3>&1 1>&2 2>&3 | stdbuf -eL -oL tee -a $LOG
|
||||
if [ -f /tmp/rv ]; then
|
||||
RV=$(cat /tmp/rv)
|
||||
echo "****************************************************"
|
||||
echo "exit with value=$RV ($*)"
|
||||
echo "****************************************************"
|
||||
echo 1 > /var/tmp/build-exitcode.txt
|
||||
exit $RV
|
||||
fi
|
||||
}
|
||||
|
||||
# Look at the RPMs in the current directory and copy/move them to
|
||||
# /tmp/repo, using the directory structure we use for the ZFS RPM repos.
|
||||
#
|
||||
# For example:
|
||||
# /tmp/repo/epel-testing/9.5
|
||||
# /tmp/repo/epel-testing/9.5/SRPMS
|
||||
# /tmp/repo/epel-testing/9.5/SRPMS/zfs-2.3.99-1.el9.src.rpm
|
||||
# /tmp/repo/epel-testing/9.5/SRPMS/zfs-kmod-2.3.99-1.el9.src.rpm
|
||||
# /tmp/repo/epel-testing/9.5/kmod
|
||||
# /tmp/repo/epel-testing/9.5/kmod/x86_64
|
||||
# /tmp/repo/epel-testing/9.5/kmod/x86_64/debug
|
||||
# /tmp/repo/epel-testing/9.5/kmod/x86_64/debug/kmod-zfs-debuginfo-2.3.99-1.el9.x86_64.rpm
|
||||
# /tmp/repo/epel-testing/9.5/kmod/x86_64/debug/libnvpair3-debuginfo-2.3.99-1.el9.x86_64.rpm
|
||||
# /tmp/repo/epel-testing/9.5/kmod/x86_64/debug/libuutil3-debuginfo-2.3.99-1.el9.x86_64.rpm
|
||||
# ...
|
||||
function copy_rpms_to_repo {
|
||||
# Pick a RPM to query. It doesn't matter which one - we just want to extract
|
||||
# the 'Build Host' value from it.
|
||||
rpm=$(ls zfs-*.rpm | head -n 1)
|
||||
|
||||
# Get zfs version '2.2.99'
|
||||
zfs_ver=$(rpm -qpi $rpm | awk '/Version/{print $3}')
|
||||
|
||||
# Get "2.1" or "2.2"
|
||||
zfs_major=$(echo $zfs_ver | grep -Eo [0-9]+\.[0-9]+)
|
||||
|
||||
# Get 'almalinux9.5' or 'fedora41' type string
|
||||
build_host=$(rpm -qpi $rpm | awk '/Build Host/{print $4}')
|
||||
|
||||
# Get '9.5' or '41' OS version
|
||||
os_ver=$(echo $build_host | grep -Eo '[0-9\.]+$')
|
||||
|
||||
# Our ZFS version and OS name will determine which repo the RPMs
|
||||
# will go in (regular or testing). Fedora always gets the newest
|
||||
# releases, and Alma gets the older releases.
|
||||
case $build_host in
|
||||
almalinux*)
|
||||
case $zfs_major in
|
||||
2.2)
|
||||
d="epel"
|
||||
;;
|
||||
*)
|
||||
d="epel-testing"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
fedora*)
|
||||
d="fedora"
|
||||
;;
|
||||
esac
|
||||
|
||||
prefix=/tmp/repo
|
||||
dst="$prefix/$d/$os_ver"
|
||||
|
||||
# Special case: move zfs-release*.rpm out of the way first (if we built them).
|
||||
# This will make filtering the other RPMs easier.
|
||||
mkdir -p $dst
|
||||
mv zfs-release*.rpm $dst || true
|
||||
|
||||
# Copy source RPMs
|
||||
mkdir -p $dst/SRPMS
|
||||
cp $(ls *.src.rpm) $dst/SRPMS/
|
||||
|
||||
if [[ "$build_host" =~ "almalinux" ]] ; then
|
||||
# Copy kmods+userspace
|
||||
mkdir -p $dst/kmod/x86_64/debug
|
||||
cp $(ls *.rpm | grep -Ev 'src.rpm|dkms|debuginfo') $dst/kmod/x86_64
|
||||
cp *debuginfo*.rpm $dst/kmod/x86_64/debug
|
||||
fi
|
||||
|
||||
if [ -n "$DKMS" ] ; then
|
||||
# Copy dkms+userspace
|
||||
mkdir -p $dst/x86_64
|
||||
cp $(ls *.rpm | grep -Ev 'src.rpm|kmod|debuginfo') $dst/x86_64
|
||||
fi
|
||||
|
||||
# Copy debug
|
||||
mkdir -p $dst/x86_64/debug
|
||||
cp $(ls *debuginfo*.rpm | grep -v kmod) $dst/x86_64/debug
|
||||
}
|
||||
|
||||
function freebsd() {
|
||||
extra="${1:-}"
|
||||
|
||||
export MAKE="gmake"
|
||||
echo "##[group]Autogen.sh"
|
||||
run ./autogen.sh
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Configure"
|
||||
run ./configure \
|
||||
--prefix=/usr/local \
|
||||
--with-libintl-prefix=/usr/local \
|
||||
--enable-pyzfs \
|
||||
--enable-debuginfo $extra
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Build"
|
||||
run gmake -j$(sysctl -n hw.ncpu)
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Install"
|
||||
run sudo gmake install
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
function linux() {
|
||||
extra="${1:-}"
|
||||
|
||||
echo "##[group]Autogen.sh"
|
||||
run ./autogen.sh
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Configure"
|
||||
run ./configure \
|
||||
--prefix=/usr \
|
||||
--enable-pyzfs \
|
||||
--enable-debuginfo $extra
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Build"
|
||||
run make -j$(nproc)
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Install"
|
||||
run sudo make install
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
function rpm_build_and_install() {
|
||||
extra="${1:-}"
|
||||
|
||||
# Build RPMs with XZ compression by default (since gzip decompression is slow)
|
||||
echo "%_binary_payload w7.xzdio" >> ~/.rpmmacros
|
||||
|
||||
echo "##[group]Autogen.sh"
|
||||
run ./autogen.sh
|
||||
echo "##[endgroup]"
|
||||
|
||||
if [ -n "$PATCH_LEVEL" ] ; then
|
||||
sed -i -E 's/(Release:\s+)1/\1'$PATCH_LEVEL'/g' META
|
||||
fi
|
||||
|
||||
echo "##[group]Configure"
|
||||
run ./configure --enable-debuginfo $extra
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Build"
|
||||
run make pkg-kmod pkg-utils
|
||||
echo "##[endgroup]"
|
||||
|
||||
if [ -n "$DKMS" ] ; then
|
||||
echo "##[group]DKMS"
|
||||
make rpm-dkms
|
||||
echo "##[endgroup]"
|
||||
fi
|
||||
|
||||
if [ -n "$REPO" ] ; then
|
||||
echo "Skipping install since we're only building RPMs and nothing else"
|
||||
else
|
||||
echo "##[group]Install"
|
||||
run sudo dnf -y --nobest install $(ls *.rpm | grep -Ev 'dkms|src.rpm')
|
||||
echo "##[endgroup]"
|
||||
fi
|
||||
|
||||
# Optionally build the zfs-release.*.rpm
|
||||
if [ -n "$RELEASE" ] ; then
|
||||
echo "##[group]Release"
|
||||
pushd ~
|
||||
sudo dnf -y install rpm-build || true
|
||||
# Check out a sparse copy of zfsonlinux.github.com.git so we don't get
|
||||
# all the binaries. We just need a few kilobytes of files to build RPMs.
|
||||
git clone --depth 1 --no-checkout \
|
||||
https://github.com/zfsonlinux/zfsonlinux.github.com.git
|
||||
|
||||
cd zfsonlinux.github.com
|
||||
git sparse-checkout set zfs-release
|
||||
git checkout
|
||||
cd zfs-release
|
||||
|
||||
mkdir -p ~/rpmbuild/{BUILDROOT,SPECS,RPMS,SRPMS,SOURCES,BUILD}
|
||||
cp RPM-GPG-KEY-openzfs* *.repo ~/rpmbuild/SOURCES
|
||||
cp zfs-release.spec ~/rpmbuild/SPECS/
|
||||
rpmbuild -ba ~/rpmbuild/SPECS/zfs-release.spec
|
||||
|
||||
# ZFS release RPMs are built. Copy them to the ~/zfs directory just to
|
||||
# keep all the RPMs in the same place.
|
||||
cp ~/rpmbuild/RPMS/noarch/*.rpm ~/zfs
|
||||
cp ~/rpmbuild/SRPMS/*.rpm ~/zfs
|
||||
|
||||
popd
|
||||
rm -fr ~/rpmbuild
|
||||
echo "##[endgroup]"
|
||||
fi
|
||||
|
||||
if [ -n "$REPO" ] ; then
|
||||
echo "##[group]Repo"
|
||||
copy_rpms_to_repo
|
||||
echo "##[endgroup]"
|
||||
fi
|
||||
}
|
||||
|
||||
function deb_build_and_install() {
|
||||
extra="${1:-}"
|
||||
|
||||
echo "##[group]Autogen.sh"
|
||||
run ./autogen.sh
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Configure"
|
||||
run ./configure \
|
||||
--prefix=/usr \
|
||||
--enable-pyzfs \
|
||||
--enable-debuginfo $extra
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Build"
|
||||
run make native-deb-kmod native-deb-utils
|
||||
echo "##[endgroup]"
|
||||
|
||||
echo "##[group]Install"
|
||||
# Do kmod install. Note that when you build the native debs, the
|
||||
# packages themselves are placed in parent directory '../' rather than
|
||||
# in the source directory like the rpms are.
|
||||
run sudo apt-get -y install $(find ../ | grep -E '\.deb$' \
|
||||
| grep -Ev 'dkms|dracut')
|
||||
echo "##[endgroup]"
|
||||
}
|
||||
|
||||
function build_tarball {
|
||||
if [ -n "$REPO" ] ; then
|
||||
./autogen.sh
|
||||
./configure --with-config=srpm
|
||||
make dist
|
||||
mkdir -p /tmp/repo/releases
|
||||
# The tarball name is based off of 'Version' field in the META file.
|
||||
mv *.tar.gz /tmp/repo/releases/
|
||||
fi
|
||||
}
|
||||
|
||||
# Debug: show kernel cmdline
|
||||
if [ -f /proc/cmdline ] ; then
|
||||
cat /proc/cmdline || true
|
||||
fi
|
||||
|
||||
# Set our hostname to our OS name and version number. Specifically, we set the
|
||||
# major and minor number so that when we query the Build Host field in the RPMs
|
||||
# we build, we can see what specific version of Fedora/Almalinux we were using
|
||||
# to build them. This is helpful for matching up KMOD versions.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# rhel8.10
|
||||
# almalinux9.5
|
||||
# fedora42
|
||||
source /etc/os-release
|
||||
if which hostnamectl &> /dev/null ; then
|
||||
# Fedora 42+ use hostnamectl
|
||||
sudo hostnamectl set-hostname "$ID$VERSION_ID"
|
||||
sudo hostnamectl set-hostname --pretty "$ID$VERSION_ID"
|
||||
else
|
||||
sudo hostname "$ID$VERSION_ID"
|
||||
fi
|
||||
|
||||
# save some sysinfo
|
||||
uname -a > /var/tmp/uname.txt
|
||||
|
||||
cd $HOME/zfs
|
||||
export PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
|
||||
|
||||
extra=""
|
||||
if [ -n "$ENABLE_DEBUG" ] ; then
|
||||
extra="--enable-debug"
|
||||
fi
|
||||
|
||||
# build
|
||||
case "$OS" in
|
||||
freebsd*)
|
||||
freebsd "$extra"
|
||||
;;
|
||||
alma*|centos*)
|
||||
rpm_build_and_install "--with-spec=redhat $extra"
|
||||
;;
|
||||
fedora*)
|
||||
rpm_build_and_install "$extra"
|
||||
|
||||
# Historically, we've always built the release tarballs on Fedora, since
|
||||
# there was one instance long ago where we built them on CentOS 7, and they
|
||||
# didn't work correctly for everyone.
|
||||
if [ -n "$TARBALL" ] ; then
|
||||
build_tarball
|
||||
fi
|
||||
;;
|
||||
debian*|ubuntu*)
|
||||
deb_build_and_install "$extra"
|
||||
;;
|
||||
*)
|
||||
linux "$extra"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
# building the zfs module was ok
|
||||
echo 0 > /var/tmp/build-exitcode.txt
|
||||
|
||||
# reset cloud-init configuration and poweroff
|
||||
if [ -n "$POWEROFF" ] ; then
|
||||
sudo cloud-init clean --logs
|
||||
sync && sleep 2 && sudo poweroff &
|
||||
fi
|
||||
exit 0
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 4) configure and build openzfs modules
|
||||
######################################################################
|
||||
echo "Build modules in QEMU machine"
|
||||
|
||||
# Bring our VM back up and copy over ZFS source
|
||||
.github/workflows/scripts/qemu-prepare-for-build.sh
|
||||
|
||||
ssh zfs@vm0 '$HOME/zfs/.github/workflows/scripts/qemu-4-build-vm.sh' $@
|
||||
@@ -1,137 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 5) start test machines and load openzfs module
|
||||
######################################################################
|
||||
|
||||
set -eu
|
||||
|
||||
# read our defined variables
|
||||
source /var/tmp/env.txt
|
||||
|
||||
# wait for poweroff to succeed
|
||||
PID=$(pidof /usr/bin/qemu-system-x86_64)
|
||||
tail --pid=$PID -f /dev/null
|
||||
sudo virsh undefine --nvram openzfs
|
||||
|
||||
# cpu pinning
|
||||
CPUSET=("0,1" "2,3")
|
||||
|
||||
# additional options for virt-install
|
||||
OPTS[0]=""
|
||||
OPTS[1]=""
|
||||
|
||||
case "$OS" in
|
||||
freebsd*)
|
||||
# FreeBSD needs only 6GiB
|
||||
RAM=6
|
||||
;;
|
||||
debian13)
|
||||
RAM=8
|
||||
# Boot Debian 13 with uefi=on and secureboot=off (ZFS Kernel Module not signed)
|
||||
OPTS[0]="--boot"
|
||||
OPTS[1]="firmware=efi,firmware.feature0.name=secure-boot,firmware.feature0.enabled=no"
|
||||
;;
|
||||
*)
|
||||
# Linux needs more memory, but can be optimized to share it via KSM
|
||||
RAM=8
|
||||
;;
|
||||
esac
|
||||
|
||||
# create snapshot we can clone later
|
||||
sudo zfs snapshot zpool/openzfs@now
|
||||
|
||||
# setup the testing vm's
|
||||
PUBKEY=$(cat ~/.ssh/id_ed25519.pub)
|
||||
|
||||
# start testing VMs
|
||||
for ((i=1; i<=VMs; i++)); do
|
||||
echo "Creating disk for vm$i..."
|
||||
DISK="/dev/zvol/zpool/vm$i"
|
||||
FORMAT="raw"
|
||||
sudo zfs clone zpool/openzfs@now zpool/vm$i-system
|
||||
sudo zfs create -ps -b 64k -V 64g zpool/vm$i-tests
|
||||
|
||||
cat <<EOF > /tmp/user-data
|
||||
#cloud-config
|
||||
|
||||
fqdn: vm$i
|
||||
|
||||
users:
|
||||
- name: root
|
||||
shell: $BASH
|
||||
- name: zfs
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
shell: $BASH
|
||||
ssh_authorized_keys:
|
||||
- $PUBKEY
|
||||
|
||||
growpart:
|
||||
mode: auto
|
||||
devices: ['/']
|
||||
ignore_growroot_disabled: false
|
||||
EOF
|
||||
|
||||
sudo virsh net-update default add ip-dhcp-host \
|
||||
"<host mac='52:54:00:83:79:0$i' ip='192.168.122.1$i'/>" --live --config
|
||||
|
||||
sudo virt-install \
|
||||
--os-variant $OSv \
|
||||
--name "vm$i" \
|
||||
--cpu host-passthrough \
|
||||
--virt-type=kvm --hvm \
|
||||
--vcpus=$CPU,sockets=1 \
|
||||
--cpuset=${CPUSET[$((i-1))]} \
|
||||
--memory $((1024*RAM)) \
|
||||
--memballoon model=virtio \
|
||||
--graphics none \
|
||||
--cloud-init user-data=/tmp/user-data \
|
||||
--network bridge=virbr0,model=$NIC,mac="52:54:00:83:79:0$i" \
|
||||
--disk $DISK-system,bus=virtio,cache=none,format=$FORMAT,driver.discard=unmap \
|
||||
--disk $DISK-tests,bus=virtio,cache=none,format=$FORMAT,driver.discard=unmap \
|
||||
--import --noautoconsole ${OPTS[0]} ${OPTS[1]}
|
||||
done
|
||||
|
||||
# generate some memory stats
|
||||
cat <<EOF > cronjob.sh
|
||||
exec 1>>/var/tmp/stats.txt
|
||||
exec 2>&1
|
||||
echo "********************************************************************************"
|
||||
uptime
|
||||
free -m
|
||||
zfs list
|
||||
EOF
|
||||
|
||||
sudo chmod +x cronjob.sh
|
||||
sudo mv -f cronjob.sh /root/cronjob.sh
|
||||
echo '*/5 * * * * /root/cronjob.sh' > crontab.txt
|
||||
sudo crontab crontab.txt
|
||||
rm crontab.txt
|
||||
|
||||
# Save the VM's serial output (ttyS0) to /var/tmp/console.txt
|
||||
# - ttyS0 on the VM corresponds to a local /dev/pty/N entry
|
||||
# - use 'virsh ttyconsole' to lookup the /dev/pty/N entry
|
||||
for ((i=1; i<=VMs; i++)); do
|
||||
mkdir -p $RESPATH/vm$i
|
||||
read "pty" <<< $(sudo virsh ttyconsole vm$i)
|
||||
|
||||
# Create the file so we can tail it, even if there's no output.
|
||||
touch $RESPATH/vm$i/console.txt
|
||||
|
||||
sudo nohup bash -c "cat $pty > $RESPATH/vm$i/console.txt" &
|
||||
|
||||
# Write all VM boot lines to the console to aid in debugging failed boots.
|
||||
# The boot lines from all the VMs will be munged together, so prepend each
|
||||
# line with the vm hostname (like 'vm1:').
|
||||
(while IFS=$'\n' read -r line; do echo "vm$i: $line" ; done < <(sudo tail -f $RESPATH/vm$i/console.txt)) &
|
||||
|
||||
done
|
||||
echo "Console logging for ${VMs}x $OS started."
|
||||
|
||||
|
||||
# check if the machines are okay
|
||||
echo "Waiting for vm's to come up... (${VMs}x CPU=$CPU RAM=$RAM)"
|
||||
for ((i=1; i<=VMs; i++)); do
|
||||
.github/workflows/scripts/qemu-wait-for-vm.sh vm$i
|
||||
done
|
||||
echo "All $VMs VMs are up now."
|
||||
@@ -1,119 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 6) load openzfs module and run the tests
|
||||
#
|
||||
# called on runner: qemu-6-tests.sh
|
||||
# called on qemu-vm: qemu-6-tests.sh $OS $2/$3
|
||||
######################################################################
|
||||
|
||||
set -eu
|
||||
|
||||
function prefix() {
|
||||
ID="$1"
|
||||
LINE="$2"
|
||||
CURRENT=$(date +%s)
|
||||
TSSTART=$(cat /tmp/tsstart)
|
||||
DIFF=$((CURRENT-TSSTART))
|
||||
H=$((DIFF/3600))
|
||||
DIFF=$((DIFF-(H*3600)))
|
||||
M=$((DIFF/60))
|
||||
S=$((DIFF-(M*60)))
|
||||
|
||||
CTR=$(cat /tmp/ctr)
|
||||
echo $LINE| grep -q '^\[.*] Test[: ]' && CTR=$((CTR+1)) && echo $CTR > /tmp/ctr
|
||||
|
||||
BASE="$HOME/work/zfs/zfs"
|
||||
COLOR="$BASE/scripts/zfs-tests-color.sh"
|
||||
CLINE=$(echo $LINE| grep '^\[.*] Test[: ]' \
|
||||
| sed -e 's|^\[.*] Test|Test|g' \
|
||||
| sed -e 's|/usr/local|/usr|g' \
|
||||
| sed -e 's| /usr/share/zfs/zfs-tests/tests/| |g' | $COLOR)
|
||||
if [ -z "$CLINE" ]; then
|
||||
printf "vm${ID}: %s\n" "$LINE"
|
||||
else
|
||||
# [vm2: 00:15:54 256] Test: functional/checksum/setup (run as root) [00:00] [PASS]
|
||||
printf "[vm${ID}: %02d:%02d:%02d %4d] %s\n" \
|
||||
"$H" "$M" "$S" "$CTR" "$CLINE"
|
||||
fi
|
||||
}
|
||||
|
||||
# called directly on the runner
|
||||
if [ -z ${1:-} ]; then
|
||||
cd "/var/tmp"
|
||||
source env.txt
|
||||
SSH=$(which ssh)
|
||||
TESTS='$HOME/zfs/.github/workflows/scripts/qemu-6-tests.sh'
|
||||
echo 0 > /tmp/ctr
|
||||
date "+%s" > /tmp/tsstart
|
||||
|
||||
for ((i=1; i<=VMs; i++)); do
|
||||
IP="192.168.122.1$i"
|
||||
daemonize -c /var/tmp -p vm${i}.pid -o vm${i}log.txt -- \
|
||||
$SSH zfs@$IP $TESTS $OS $i $VMs $CI_TYPE
|
||||
# handly line by line and add info prefix
|
||||
stdbuf -oL tail -fq vm${i}log.txt \
|
||||
| while read -r line; do prefix "$i" "$line"; done &
|
||||
echo $! > vm${i}log.pid
|
||||
# don't mix up the initial --- Configuration --- part
|
||||
sleep 0.13
|
||||
done
|
||||
|
||||
# wait for all vm's to finish
|
||||
for ((i=1; i<=VMs; i++)); do
|
||||
tail --pid=$(cat vm${i}.pid) -f /dev/null
|
||||
pid=$(cat vm${i}log.pid)
|
||||
rm -f vm${i}log.pid
|
||||
kill $pid
|
||||
done
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# this part runs inside qemu vm
|
||||
export PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/usr/local/bin"
|
||||
case "$1" in
|
||||
freebsd*)
|
||||
TDIR="/usr/local/share/zfs"
|
||||
sudo kldstat -n zfs 2>/dev/null && sudo kldunload zfs
|
||||
sudo -E ./zfs/scripts/zfs.sh
|
||||
sudo mv -f /var/tmp/*.txt /tmp
|
||||
sudo newfs -U -t -L tmp /dev/vtbd1 >/dev/null
|
||||
sudo mount -o noatime /dev/vtbd1 /var/tmp
|
||||
sudo chmod 1777 /var/tmp
|
||||
sudo mv -f /tmp/*.txt /var/tmp
|
||||
;;
|
||||
*)
|
||||
# use xfs @ /var/tmp for all distros
|
||||
TDIR="/usr/share/zfs"
|
||||
sudo -E modprobe zfs
|
||||
sudo mv -f /var/tmp/*.txt /tmp
|
||||
sudo mkfs.xfs -fq /dev/vdb
|
||||
sudo mount -o noatime /dev/vdb /var/tmp
|
||||
sudo chmod 1777 /var/tmp
|
||||
sudo mv -f /tmp/*.txt /var/tmp
|
||||
;;
|
||||
esac
|
||||
|
||||
# enable io_uring on el9/el10
|
||||
case "$1" in
|
||||
almalinux9|almalinux10|centos-stream*)
|
||||
sudo sysctl kernel.io_uring_disabled=0 > /dev/null
|
||||
;;
|
||||
esac
|
||||
|
||||
# run functional testings and save exitcode
|
||||
cd /var/tmp
|
||||
TAGS=$2/$3
|
||||
if [ "$4" == "quick" ]; then
|
||||
export RUNFILES="sanity.run"
|
||||
fi
|
||||
sudo dmesg -c > dmesg-prerun.txt
|
||||
mount > mount.txt
|
||||
df -h > df-prerun.txt
|
||||
$TDIR/zfs-tests.sh -vKO -s 3GB -T $TAGS
|
||||
RV=$?
|
||||
df -h > df-postrun.txt
|
||||
echo $RV > tests-exitcode.txt
|
||||
sync
|
||||
exit 0
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 7) prepare output of the results
|
||||
# - this script pre-creates all needed logfiles for later summary
|
||||
######################################################################
|
||||
|
||||
set -eu
|
||||
|
||||
# read our defined variables
|
||||
cd /var/tmp
|
||||
source env.txt
|
||||
|
||||
mkdir -p $RESPATH
|
||||
|
||||
# check if building the module has failed
|
||||
if [ -z ${VMs:-} ]; then
|
||||
cd $RESPATH
|
||||
echo ":exclamation: ZFS module didn't build successfully :exclamation:" \
|
||||
| tee summary.txt | tee /tmp/summary.txt
|
||||
cp /var/tmp/*.txt .
|
||||
tar cf /tmp/qemu-$OS.tar -C $RESPATH -h . || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# build was okay
|
||||
BASE="$HOME/work/zfs/zfs"
|
||||
MERGE="$BASE/.github/workflows/scripts/merge_summary.awk"
|
||||
|
||||
# catch result files of testings (vm's should be there)
|
||||
for ((i=1; i<=VMs; i++)); do
|
||||
rsync -arL zfs@vm$i:$RESPATH/current $RESPATH/vm$i || true
|
||||
scp zfs@vm$i:"/var/tmp/*.txt" $RESPATH/vm$i || true
|
||||
scp zfs@vm$i:"/var/tmp/*.rpm" $RESPATH/vm$i || true
|
||||
done
|
||||
cp -f /var/tmp/*.txt $RESPATH || true
|
||||
cd $RESPATH
|
||||
|
||||
# prepare result files for summary
|
||||
for ((i=1; i<=VMs; i++)); do
|
||||
file="vm$i/build-stderr.txt"
|
||||
test -s $file && mv -f $file build-stderr.txt
|
||||
|
||||
file="vm$i/build-exitcode.txt"
|
||||
test -s $file && mv -f $file build-exitcode.txt
|
||||
|
||||
file="vm$i/uname.txt"
|
||||
test -s $file && mv -f $file uname.txt
|
||||
|
||||
file="vm$i/tests-exitcode.txt"
|
||||
if [ ! -s $file ]; then
|
||||
# XXX - add some tests for kernel panic's here
|
||||
# tail -n 80 vm$i/console.txt | grep XYZ
|
||||
echo 1 > $file
|
||||
fi
|
||||
rv=$(cat vm$i/tests-exitcode.txt)
|
||||
test $rv != 0 && touch /tmp/have_failed_tests
|
||||
|
||||
file="vm$i/current/log"
|
||||
if [ -s $file ]; then
|
||||
cat $file >> log
|
||||
awk '/\[FAIL\]|\[KILLED\]/{ show=1; print; next; }; \
|
||||
/\[SKIP\]|\[PASS\]/{ show=0; } show' \
|
||||
$file > /tmp/vm${i}dbg.txt
|
||||
fi
|
||||
|
||||
file="vm${i}log.txt"
|
||||
fileC="/tmp/vm${i}log.txt"
|
||||
if [ -s $file ]; then
|
||||
cat $file >> summary
|
||||
cat $file | $BASE/scripts/zfs-tests-color.sh > $fileC
|
||||
fi
|
||||
done
|
||||
|
||||
# create summary of tests
|
||||
if [ -s summary ]; then
|
||||
$MERGE summary | grep -v '^/' > summary.txt
|
||||
$MERGE summary | $BASE/scripts/zfs-tests-color.sh > /tmp/summary.txt
|
||||
rm -f summary
|
||||
else
|
||||
touch summary.txt /tmp/summary.txt
|
||||
fi
|
||||
|
||||
# create file for debugging
|
||||
if [ -s log ]; then
|
||||
awk '/\[FAIL\]|\[KILLED\]/{ show=1; print; next; }; \
|
||||
/\[SKIP\]|\[PASS\]/{ show=0; } show' \
|
||||
log > summary-failure-logs.txt
|
||||
rm -f log
|
||||
else
|
||||
touch summary-failure-logs.txt
|
||||
fi
|
||||
|
||||
# create debug overview for failed tests
|
||||
cat summary.txt \
|
||||
| awk '/\(expected PASS\)/{ if ($1!="SKIP") print $2; next; } show' \
|
||||
| while read t; do
|
||||
cat summary-failure-logs.txt \
|
||||
| awk '$0~/Test[: ]/{ show=0; } $0~v{ show=1; } show' v="$t" \
|
||||
> /tmp/fail.txt
|
||||
SIZE=$(stat --printf="%s" /tmp/fail.txt)
|
||||
SIZE=$((SIZE/1024))
|
||||
# Test Summary:
|
||||
echo "##[group]$t ($SIZE KiB)" >> /tmp/failed.txt
|
||||
cat /tmp/fail.txt | $BASE/scripts/zfs-tests-color.sh >> /tmp/failed.txt
|
||||
echo "##[endgroup]" >> /tmp/failed.txt
|
||||
# Job Summary:
|
||||
echo -e "\n<details>\n<summary>$t ($SIZE KiB)</summary><pre>" >> failed.txt
|
||||
cat /tmp/fail.txt >> failed.txt
|
||||
echo "</pre></details>" >> failed.txt
|
||||
done
|
||||
|
||||
if [ -e /tmp/have_failed_tests ]; then
|
||||
echo ":warning: Some tests failed!" >> failed.txt
|
||||
else
|
||||
echo ":thumbsup: All tests passed." >> failed.txt
|
||||
fi
|
||||
|
||||
if [ ! -s uname.txt ]; then
|
||||
echo ":interrobang: Panic - where is my uname.txt?" > uname.txt
|
||||
fi
|
||||
|
||||
# artifact ready now
|
||||
tar cf /tmp/qemu-$OS.tar -C $RESPATH -h . || true
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 8) show colored output of results
|
||||
######################################################################
|
||||
|
||||
set -eu
|
||||
|
||||
# read our defined variables
|
||||
source /var/tmp/env.txt
|
||||
cd $RESPATH
|
||||
|
||||
# helper function for showing some content with headline
|
||||
function showfile() {
|
||||
content=$(dd if=$1 bs=1024 count=400k 2>/dev/null)
|
||||
if [ -z "$2" ]; then
|
||||
group1=""
|
||||
group2=""
|
||||
else
|
||||
SIZE=$(stat --printf="%s" "$file")
|
||||
SIZE=$((SIZE/1024))
|
||||
group1="##[group]$2 ($SIZE KiB)"
|
||||
group2="##[endgroup]"
|
||||
fi
|
||||
cat <<EOF > tmp$$
|
||||
$group1
|
||||
$content
|
||||
$group2
|
||||
EOF
|
||||
cat tmp$$
|
||||
rm -f tmp$$
|
||||
}
|
||||
|
||||
# overview
|
||||
cat /tmp/summary.txt
|
||||
echo ""
|
||||
|
||||
if [ -f /tmp/have_failed_tests -a -s /tmp/failed.txt ]; then
|
||||
echo "Debuginfo of failed tests:"
|
||||
cat /tmp/failed.txt
|
||||
echo ""
|
||||
cat /tmp/summary.txt | grep -v '^/'
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo -e "\nFull logs for download:\n $1\n"
|
||||
|
||||
for ((i=1; i<=VMs; i++)); do
|
||||
rv=$(cat vm$i/tests-exitcode.txt)
|
||||
|
||||
if [ $rv = 0 ]; then
|
||||
vm="[92mvm$i[0m"
|
||||
else
|
||||
vm="[1;91mvm$i[0m"
|
||||
fi
|
||||
|
||||
file="vm$i/dmesg-prerun.txt"
|
||||
test -s "$file" && showfile "$file" "$vm: dmesg kernel"
|
||||
|
||||
file="/tmp/vm${i}log.txt"
|
||||
test -s "$file" && showfile "$file" "$vm: test results"
|
||||
|
||||
file="vm$i/console.txt"
|
||||
test -s "$file" && showfile "$file" "$vm: serial console"
|
||||
|
||||
file="/tmp/vm${i}dbg.txt"
|
||||
test -s "$file" && showfile "$file" "$vm: failure logfile"
|
||||
done
|
||||
|
||||
test -f /tmp/have_failed_tests && exit 1
|
||||
exit 0
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################
|
||||
# 9) generate github summary page of all the testings
|
||||
######################################################################
|
||||
|
||||
set -eu
|
||||
|
||||
function output() {
|
||||
echo -e $* >> "out-$logfile.md"
|
||||
}
|
||||
|
||||
function outfile() {
|
||||
cat "$1" >> "out-$logfile.md"
|
||||
}
|
||||
|
||||
function outfile_plain() {
|
||||
output "<pre>"
|
||||
cat "$1" >> "out-$logfile.md"
|
||||
output "</pre>"
|
||||
}
|
||||
|
||||
function send2github() {
|
||||
test -f "$1" || exit 0
|
||||
dd if="$1" bs=1023k count=1 >> $GITHUB_STEP_SUMMARY
|
||||
}
|
||||
|
||||
# https://docs.github.com/en/enterprise-server@3.6/actions/using-workflows/workflow-commands-for-github-actions#step-isolation-and-limits
|
||||
# Job summaries are isolated between steps and each step is restricted to a maximum size of 1MiB.
|
||||
# [ ] can not show all error findings here
|
||||
# [x] split files into smaller ones and create additional steps
|
||||
|
||||
# first call, generate all summaries
|
||||
if [ ! -f out-1.md ]; then
|
||||
logfile="1"
|
||||
for tarfile in Logs-functional-*/qemu-*.tar; do
|
||||
rm -rf vm* *.txt
|
||||
if [ ! -s "$tarfile" ]; then
|
||||
output "\n## Functional Tests: unknown\n"
|
||||
output ":exclamation: Tarfile $tarfile is empty :exclamation:"
|
||||
continue
|
||||
fi
|
||||
tar xf "$tarfile"
|
||||
test -s env.txt || continue
|
||||
source env.txt
|
||||
# when uname.txt is there, the other files are also ok
|
||||
test -s uname.txt || continue
|
||||
output "\n## Functional Tests: $OSNAME\n"
|
||||
outfile_plain uname.txt
|
||||
outfile_plain summary.txt
|
||||
outfile failed.txt
|
||||
logfile=$((logfile+1))
|
||||
done
|
||||
send2github out-1.md
|
||||
else
|
||||
send2github out-$1.md
|
||||
fi
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Helper script to run after installing dependencies. This brings the VM back
|
||||
# up and copies over the zfs source directory.
|
||||
echo "Build modules in QEMU machine"
|
||||
sudo virsh start openzfs
|
||||
.github/workflows/scripts/qemu-wait-for-vm.sh vm0
|
||||
rsync -ar $HOME/work/zfs/zfs zfs@vm0:./
|
||||
@@ -1,90 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Do a test install of ZFS from an external repository.
|
||||
#
|
||||
# USAGE:
|
||||
#
|
||||
# ./qemu-test-repo-vm [URL]
|
||||
#
|
||||
# URL: URL to use instead of http://download.zfsonlinux.org
|
||||
# If blank, use the default repo from zfs-release RPM.
|
||||
|
||||
set -e
|
||||
|
||||
source /etc/os-release
|
||||
OS="$ID"
|
||||
VERSION="$VERSION_ID"
|
||||
|
||||
ALTHOST=""
|
||||
if [ -n "$1" ] ; then
|
||||
ALTHOST="$1"
|
||||
fi
|
||||
|
||||
# Write summary to /tmp/repo so our artifacts scripts pick it up
|
||||
mkdir /tmp/repo
|
||||
SUMMARY=/tmp/repo/$OS-$VERSION-summary.txt
|
||||
|
||||
# $1: Repo 'zfs' 'zfs-kmod' 'zfs-testing' 'zfs-testing-kmod'
|
||||
# $2: (optional) Alternate host than 'http://download.zfsonlinux.org' to
|
||||
# install from. Blank means use default from zfs-release RPM.
|
||||
function test_install {
|
||||
repo=$1
|
||||
host=""
|
||||
if [ -n "$2" ] ; then
|
||||
host=$2
|
||||
fi
|
||||
|
||||
args="--disablerepo=zfs --enablerepo=$repo"
|
||||
|
||||
# If we supplied an alternate repo URL, and have not already edited
|
||||
# zfs.repo, then update the repo file.
|
||||
if [ -n "$host" ] && ! grep -q $host /etc/yum.repos.d/zfs.repo ; then
|
||||
sudo sed -i "s;baseurl=http://download.zfsonlinux.org;baseurl=$host;g" /etc/yum.repos.d/zfs.repo
|
||||
fi
|
||||
|
||||
sudo dnf -y install $args zfs zfs-test
|
||||
|
||||
# Load modules and create a simple pool as a sanity test.
|
||||
sudo /usr/share/zfs/zfs.sh -r
|
||||
truncate -s 100M /tmp/file
|
||||
sudo zpool create tank /tmp/file
|
||||
sudo zpool status
|
||||
|
||||
# Print out repo name, rpm installed (kmod or dkms), and repo URL
|
||||
baseurl=$(grep -A 5 "\[$repo\]" /etc/yum.repos.d/zfs.repo | awk -F'=' '/baseurl=/{print $2; exit}')
|
||||
package=$(sudo rpm -qa | grep zfs | grep -E 'kmod|dkms')
|
||||
|
||||
echo "$repo $package $baseurl" >> $SUMMARY
|
||||
|
||||
sudo zpool destroy tank
|
||||
sudo rm /tmp/file
|
||||
sudo dnf -y remove zfs
|
||||
}
|
||||
|
||||
echo "##[group]Installing from repo"
|
||||
# The openzfs docs are the authoritative instructions for the install. Use
|
||||
# the specific version of zfs-release RPM it recommends.
|
||||
case $OS in
|
||||
almalinux*)
|
||||
url='https://raw.githubusercontent.com/openzfs/openzfs-docs/refs/heads/master/docs/Getting%20Started/RHEL-based%20distro/index.rst'
|
||||
name=$(curl -Ls $url | grep 'dnf install' | grep -Eo 'zfs-release-[0-9]+-[0-9]+')
|
||||
sudo dnf -y install https://zfsonlinux.org/epel/$name$(rpm --eval "%{dist}").noarch.rpm 2>&1
|
||||
sudo rpm -qi zfs-release
|
||||
test_install zfs $ALTHOST
|
||||
test_install zfs-kmod $ALTHOST
|
||||
test_install zfs-testing $ALTHOST
|
||||
test_install zfs-testing-kmod $ALTHOST
|
||||
;;
|
||||
fedora*)
|
||||
url='https://raw.githubusercontent.com/openzfs/openzfs-docs/refs/heads/master/docs/Getting%20Started/Fedora/index.rst'
|
||||
name=$(curl -Ls $url | grep 'dnf install' | grep -Eo 'zfs-release-[0-9]+-[0-9]+')
|
||||
sudo dnf -y install -y https://zfsonlinux.org/fedora/$name$(rpm --eval "%{dist}").noarch.rpm
|
||||
test_install zfs $ALTHOST
|
||||
;;
|
||||
esac
|
||||
echo "##[endgroup]"
|
||||
|
||||
# Write out a simple version of the summary here. Later on we will collate all
|
||||
# the summaries and put them into a nice table in the workflow Summary page.
|
||||
echo "Summary: "
|
||||
cat $SUMMARY
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Wait for a VM to boot up and become active. This is used in a number of our
|
||||
# scripts.
|
||||
#
|
||||
# $1: VM hostname or IP address
|
||||
|
||||
while pidof /usr/bin/qemu-system-x86_64 >/dev/null; do
|
||||
ssh 2>/dev/null zfs@$1 "uname -a" && break
|
||||
done
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Recursively go though a directory structure and replace duplicate files with
|
||||
# symlinks. This cuts down our RPM repo size by ~25%.
|
||||
#
|
||||
# replace-dupes-with-symlinks.sh [DIR]
|
||||
#
|
||||
# DIR: Directory to traverse. Defaults to current directory if not specified.
|
||||
#
|
||||
|
||||
src="$1"
|
||||
if [ -z "$src" ] ; then
|
||||
src="."
|
||||
fi
|
||||
|
||||
declare -A db
|
||||
|
||||
pushd "$src"
|
||||
while read line ; do
|
||||
bn="$(basename $line)"
|
||||
if [ -z "${db[$bn]}" ] ; then
|
||||
# First time this file has been seen
|
||||
db[$bn]="$line"
|
||||
else
|
||||
if diff -b "$line" "${db[$bn]}" &>/dev/null ; then
|
||||
# Files are the same, make a symlink
|
||||
rm "$line"
|
||||
ln -sr "${db[$bn]}" "$line"
|
||||
fi
|
||||
fi
|
||||
done <<< "$(find . -type f)"
|
||||
popd
|
||||
@@ -1,151 +0,0 @@
|
||||
# This workflow is used to build and test RPM packages. It is a
|
||||
# 'workflow_dispatch' workflow, which means it gets run manually.
|
||||
#
|
||||
# The workflow has a dropdown menu with two options:
|
||||
#
|
||||
# Build RPMs - Build release RPMs and tarballs and put them into an artifact
|
||||
# ZIP file. The directory structure used in the ZIP file mirrors
|
||||
# the ZFS yum repo.
|
||||
#
|
||||
# Test repo - Test install the ZFS RPMs from the ZFS repo. On EL distos, this
|
||||
# will do a DKMS and KMOD test install from both the regular and
|
||||
# testing repos. On Fedora, it will do a DKMS install from the
|
||||
# regular repo. All test install results will be displayed in the
|
||||
# Summary page. Note that the workflow provides an optional text
|
||||
# text box where you can specify the full URL to an alternate repo.
|
||||
# If left blank, it will install from the default repo from the
|
||||
# zfs-release RPM (http://download.zfsonlinux.org).
|
||||
#
|
||||
# Most users will never need to use this workflow. It will be used primary by
|
||||
# ZFS admins for building and testing releases.
|
||||
#
|
||||
name: zfs-qemu-packages
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
test_type:
|
||||
type: choice
|
||||
required: false
|
||||
default: "Build RPMs"
|
||||
description: "Build RPMs or test the repo?"
|
||||
options:
|
||||
- "Build RPMs"
|
||||
- "Test repo"
|
||||
patch_level:
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
description: "(optional) patch level number"
|
||||
repo_url:
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
description: "(optional) repo URL (blank: use http://download.zfsonlinux.org)"
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
zfs-qemu-packages-jobs:
|
||||
name: qemu-VMs
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: ['almalinux8', 'almalinux9', 'almalinux10', 'fedora41', 'fedora42', 'fedora43']
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Setup QEMU
|
||||
timeout-minutes: 10
|
||||
run: .github/workflows/scripts/qemu-1-setup.sh
|
||||
|
||||
- name: Start build machine
|
||||
timeout-minutes: 10
|
||||
run: .github/workflows/scripts/qemu-2-start.sh ${{ matrix.os }}
|
||||
|
||||
- name: Install dependencies
|
||||
timeout-minutes: 20
|
||||
run: |
|
||||
.github/workflows/scripts/qemu-3-deps.sh ${{ matrix.os }}
|
||||
|
||||
- name: Build modules or Test repo
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
set -e
|
||||
if [ "${{ github.event.inputs.test_type }}" == "Test repo" ] ; then
|
||||
# Bring VM back up and copy over zfs source
|
||||
.github/workflows/scripts/qemu-prepare-for-build.sh
|
||||
|
||||
mkdir -p /tmp/repo
|
||||
ssh zfs@vm0 '$HOME/zfs/.github/workflows/scripts/qemu-test-repo-vm.sh' ${{ github.event.inputs.repo_url }}
|
||||
else
|
||||
EXTRA=""
|
||||
if [ -n "${{ github.event.inputs.patch_level }}" ] ; then
|
||||
EXTRA="--patch-level ${{ github.event.inputs.patch_level }}"
|
||||
fi
|
||||
|
||||
.github/workflows/scripts/qemu-4-build.sh $EXTRA \
|
||||
--repo --release --dkms --tarball ${{ matrix.os }}
|
||||
fi
|
||||
|
||||
- name: Prepare artifacts
|
||||
if: always()
|
||||
timeout-minutes: 10
|
||||
run: |
|
||||
rsync -a zfs@vm0:/tmp/repo /tmp || true
|
||||
.github/workflows/scripts/replace-dupes-with-symlinks.sh /tmp/repo
|
||||
tar -cf ${{ matrix.os }}-repo.tar -C /tmp repo
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
id: artifact-upload
|
||||
if: always()
|
||||
with:
|
||||
name: ${{ matrix.os }}-repo
|
||||
path: ${{ matrix.os }}-repo.tar
|
||||
compression-level: 0
|
||||
retention-days: 2
|
||||
if-no-files-found: ignore
|
||||
|
||||
combine_repos:
|
||||
if: always()
|
||||
needs: [zfs-qemu-packages-jobs]
|
||||
name: "Results"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
id: artifact-download
|
||||
if: always()
|
||||
- name: Test Summary
|
||||
if: always()
|
||||
run: |
|
||||
for i in $(find . -type f -iname "*.tar") ; do
|
||||
tar -xf $i -C /tmp
|
||||
done
|
||||
tar -cf all-repo.tar -C /tmp repo
|
||||
|
||||
# If we're installing from a repo, print out the summary of the versions
|
||||
# that got installed using Markdown.
|
||||
if [ "${{ github.event.inputs.test_type }}" == "Test repo" ] ; then
|
||||
cd /tmp/repo
|
||||
for i in $(ls *.txt) ; do
|
||||
nicename="$(echo $i | sed 's/.txt//g; s/-/ /g')"
|
||||
echo "### $nicename" >> $GITHUB_STEP_SUMMARY
|
||||
echo "|repo|RPM|URL|" >> $GITHUB_STEP_SUMMARY
|
||||
echo "|:---|:---|:---|" >> $GITHUB_STEP_SUMMARY
|
||||
awk '{print "|"$1"|"$2"|"$3"|"}' $i >> $GITHUB_STEP_SUMMARY
|
||||
done
|
||||
fi
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
id: artifact-upload2
|
||||
if: always()
|
||||
with:
|
||||
name: all-repo
|
||||
path: all-repo.tar
|
||||
compression-level: 0
|
||||
retention-days: 5
|
||||
if-no-files-found: ignore
|
||||
@@ -1,188 +0,0 @@
|
||||
name: zfs-qemu
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
fedora_kernel_ver:
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
description: "(optional) Experimental kernel version to install on Fedora (like '6.14' or '6.13.3-0.rc3')"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test-config:
|
||||
name: Setup
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
test_os: ${{ steps.os.outputs.os }}
|
||||
ci_type: ${{ steps.os.outputs.ci_type }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Generate OS config and CI type
|
||||
id: os
|
||||
run: |
|
||||
ci_type="default"
|
||||
|
||||
# determine CI type when running on PR
|
||||
if ${{ github.event_name == 'pull_request' }}; then
|
||||
head=${{ github.event.pull_request.head.sha }}
|
||||
base=${{ github.event.pull_request.base.sha }}
|
||||
ci_type=$(python3 .github/workflows/scripts/generate-ci-type.py $head $base)
|
||||
fi
|
||||
|
||||
case "$ci_type" in
|
||||
quick)
|
||||
os_selection='["almalinux8", "almalinux9", "almalinux10", "debian12", "fedora42", "freebsd15-0s", "ubuntu24"]'
|
||||
;;
|
||||
linux)
|
||||
os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian11", "debian12", "debian13", "fedora41", "fedora42", "fedora43", "ubuntu22", "ubuntu24"]'
|
||||
;;
|
||||
freebsd)
|
||||
os_selection='["freebsd13-5r", "freebsd14-2r", "freebsd14-3r", "freebsd13-5s", "freebsd14-3s", "freebsd15-0s", "freebsd16-0c"]'
|
||||
;;
|
||||
*)
|
||||
# default list
|
||||
os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian12", "debian13", "fedora42", "fedora43", "freebsd14-3r", "freebsd15-0s", "freebsd16-0c", "ubuntu22", "ubuntu24"]'
|
||||
;;
|
||||
esac
|
||||
|
||||
if ${{ github.event.inputs.fedora_kernel_ver != '' }}; then
|
||||
# They specified a custom kernel version for Fedora.
|
||||
# Use only Fedora runners.
|
||||
os_json=$(echo ${os_selection} | jq -c '[.[] | select(startswith("fedora"))]')
|
||||
else
|
||||
# Normal case
|
||||
os_json=$(echo ${os_selection} | jq -c)
|
||||
fi
|
||||
|
||||
echo "os=$os_json" | tee -a $GITHUB_OUTPUT
|
||||
echo "ci_type=$ci_type" | tee -a $GITHUB_OUTPUT
|
||||
|
||||
qemu-vm:
|
||||
name: qemu-x86
|
||||
needs: [ test-config ]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# rhl: almalinux8, almalinux9, centos-streamX, fedora4x
|
||||
# debian: debian12, debian13, ubuntu22, ubuntu24
|
||||
# misc: archlinux, tumbleweed
|
||||
# FreeBSD variants of november 2025:
|
||||
# FreeBSD Release: freebsd13-5r, freebsd14-2r, freebsd14-3r
|
||||
# FreeBSD Stable: freebsd13-5s, freebsd14-3s, freebsd15-0s
|
||||
# FreeBSD Current: freebsd16-0c
|
||||
os: ${{ fromJson(needs.test-config.outputs.test_os) }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Setup QEMU
|
||||
timeout-minutes: 20
|
||||
run: |
|
||||
# Add a timestamp to each line to debug timeouts
|
||||
while IFS=$'\n' read -r line; do
|
||||
echo "$(date +'%H:%M:%S') $line"
|
||||
done < <(.github/workflows/scripts/qemu-1-setup.sh)
|
||||
|
||||
- name: Start build machine
|
||||
timeout-minutes: 10
|
||||
run: .github/workflows/scripts/qemu-2-start.sh ${{ matrix.os }}
|
||||
|
||||
- name: Install dependencies
|
||||
timeout-minutes: 20
|
||||
run: .github/workflows/scripts/qemu-3-deps.sh ${{ matrix.os }} ${{ github.event.inputs.fedora_kernel_ver }}
|
||||
|
||||
- name: Build modules
|
||||
timeout-minutes: 30
|
||||
run: .github/workflows/scripts/qemu-4-build.sh --poweroff --enable-debug ${{ matrix.os }}
|
||||
|
||||
- name: Setup testing machines
|
||||
timeout-minutes: 5
|
||||
run: .github/workflows/scripts/qemu-5-setup.sh
|
||||
|
||||
- name: Run tests
|
||||
timeout-minutes: 270
|
||||
run: .github/workflows/scripts/qemu-6-tests.sh
|
||||
env:
|
||||
CI_TYPE: ${{ needs.test-config.outputs.ci_type }}
|
||||
|
||||
- name: Prepare artifacts
|
||||
if: always()
|
||||
timeout-minutes: 10
|
||||
run: .github/workflows/scripts/qemu-7-prepare.sh
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
id: artifact-upload
|
||||
if: always()
|
||||
with:
|
||||
name: Logs-functional-${{ matrix.os }}
|
||||
path: /tmp/qemu-${{ matrix.os }}.tar
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Test Summary
|
||||
if: always()
|
||||
run: .github/workflows/scripts/qemu-8-summary.sh '${{ steps.artifact-upload.outputs.artifact-url }}'
|
||||
|
||||
cleanup:
|
||||
if: always()
|
||||
name: Cleanup
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ qemu-vm ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- uses: actions/download-artifact@v4
|
||||
- name: Generating summary
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 2
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 3
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 4
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 5
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 6
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 7
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 8
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 9
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 10
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 11
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 12
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 13
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 14
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 15
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 16
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 17
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 18
|
||||
- name: Generating summary...
|
||||
run: .github/workflows/scripts/qemu-9-summary-page.sh 19
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Summary Files
|
||||
path: out-*
|
||||
@@ -0,0 +1,70 @@
|
||||
name: zfs-tests-functional
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
tests-functional-ubuntu:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [18.04, 20.04]
|
||||
runs-on: ubuntu-${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes -qq build-essential autoconf libtool gdb lcov \
|
||||
git alien fakeroot wget curl bc fio acl \
|
||||
sysstat mdadm lsscsi parted gdebi attr dbench watchdog ksh \
|
||||
nfs-kernel-server samba rng-tools xz-utils \
|
||||
zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
|
||||
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
||||
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
||||
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
|
||||
python3 python3-dev python3-setuptools python3-cffi
|
||||
- name: Autogen.sh
|
||||
run: |
|
||||
sh autogen.sh
|
||||
- name: Configure
|
||||
run: |
|
||||
./configure --enable-debug --enable-debuginfo
|
||||
- name: Make
|
||||
run: |
|
||||
make --no-print-directory -s pkg-utils pkg-kmod
|
||||
- name: Install
|
||||
run: |
|
||||
sudo dpkg -i *.deb
|
||||
# Update order of directories to search for modules, otherwise
|
||||
# Ubuntu will load kernel-shipped ones.
|
||||
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
|
||||
sudo depmod
|
||||
sudo modprobe zfs
|
||||
# Workaround to provide additional free space for testing.
|
||||
# https://github.com/actions/virtual-environments/issues/2840
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf "/usr/local/share/boost"
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
- name: Tests
|
||||
run: |
|
||||
/usr/share/zfs/zfs-tests.sh -v -s 3G
|
||||
- name: Prepare artifacts
|
||||
if: failure()
|
||||
run: |
|
||||
RESULTS_PATH=$(readlink -f /var/tmp/test_results/current)
|
||||
sudo dmesg > $RESULTS_PATH/dmesg
|
||||
sudo cp /var/log/syslog $RESULTS_PATH/
|
||||
sudo chmod +r $RESULTS_PATH/*
|
||||
# Replace ':' in dir names, actions/upload-artifact doesn't support it
|
||||
for f in $(find $RESULTS_PATH -name '*:*'); do mv "$f" "${f//:/__}"; done
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: Test logs Ubuntu-${{ matrix.os }}
|
||||
path: /var/tmp/test_results/20*/
|
||||
if-no-files-found: ignore
|
||||
@@ -0,0 +1,66 @@
|
||||
name: zfs-tests-sanity
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes -qq build-essential autoconf libtool gdb lcov \
|
||||
git alien fakeroot wget curl bc fio acl \
|
||||
sysstat mdadm lsscsi parted gdebi attr dbench watchdog ksh \
|
||||
nfs-kernel-server samba rng-tools xz-utils \
|
||||
zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
|
||||
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
||||
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
||||
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
|
||||
python3 python3-dev python3-setuptools python3-cffi
|
||||
- name: Autogen.sh
|
||||
run: |
|
||||
sh autogen.sh
|
||||
- name: Configure
|
||||
run: |
|
||||
./configure --enable-debug --enable-debuginfo
|
||||
- name: Make
|
||||
run: |
|
||||
make --no-print-directory -s pkg-utils pkg-kmod
|
||||
- name: Install
|
||||
run: |
|
||||
sudo dpkg -i *.deb
|
||||
# Update order of directories to search for modules, otherwise
|
||||
# Ubuntu will load kernel-shipped ones.
|
||||
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
|
||||
sudo depmod
|
||||
sudo modprobe zfs
|
||||
# Workaround to provide additional free space for testing.
|
||||
# https://github.com/actions/virtual-environments/issues/2840
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf "/usr/local/share/boost"
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
- name: Tests
|
||||
run: |
|
||||
/usr/share/zfs/zfs-tests.sh -v -s 3G -r sanity
|
||||
- name: Prepare artifacts
|
||||
if: failure()
|
||||
run: |
|
||||
RESULTS_PATH=$(readlink -f /var/tmp/test_results/current)
|
||||
sudo dmesg > $RESULTS_PATH/dmesg
|
||||
sudo cp /var/log/syslog $RESULTS_PATH/
|
||||
sudo chmod +r $RESULTS_PATH/*
|
||||
# Replace ':' in dir names, actions/upload-artifact doesn't support it
|
||||
for f in $(find $RESULTS_PATH -name '*:*'); do mv "$f" "${f//:/__}"; done
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: Test logs
|
||||
path: /var/tmp/test_results/20*/
|
||||
if-no-files-found: ignore
|
||||
+29
-39
@@ -4,74 +4,64 @@ on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
zloop:
|
||||
runs-on: ubuntu-24.04
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
WORK_DIR: /mnt/zloop
|
||||
CORE_DIR: /mnt/zloop/cores
|
||||
TEST_DIR: /var/tmp/zloop
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get purge -y snapd google-chrome-stable firefox
|
||||
ONLY_DEPS=1 .github/workflows/scripts/qemu-3-deps-vm.sh ubuntu24
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes -qq build-essential autoconf libtool gdb \
|
||||
git alien fakeroot \
|
||||
zlib1g-dev uuid-dev libblkid-dev libselinux-dev \
|
||||
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
||||
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
||||
libpam0g-dev \
|
||||
python-dev python-setuptools python-cffi \
|
||||
python3 python3-dev python3-setuptools python3-cffi
|
||||
- name: Autogen.sh
|
||||
run: |
|
||||
sed -i '/DEBUG_CFLAGS="-Werror"/s/^/#/' config/zfs-build.m4
|
||||
./autogen.sh
|
||||
sh autogen.sh
|
||||
- name: Configure
|
||||
run: |
|
||||
./configure --prefix=/usr --enable-debug --enable-debuginfo \
|
||||
--enable-asan --enable-ubsan \
|
||||
--enable-debug-kmem --enable-debug-kmem-tracking
|
||||
./configure --enable-debug --enable-debuginfo
|
||||
- name: Make
|
||||
run: |
|
||||
make -j$(nproc)
|
||||
make --no-print-directory -s pkg-utils pkg-kmod
|
||||
- name: Install
|
||||
run: |
|
||||
sudo make install
|
||||
sudo dpkg -i *.deb
|
||||
# Update order of directories to search for modules, otherwise
|
||||
# Ubuntu will load kernel-shipped ones.
|
||||
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
|
||||
sudo depmod
|
||||
sudo modprobe zfs
|
||||
- name: Tests
|
||||
run: |
|
||||
sudo truncate -s 256G /mnt/vdev
|
||||
sudo zpool create cipool -m $WORK_DIR -O compression=on -o autotrim=on /mnt/vdev
|
||||
sudo /usr/share/zfs/zloop.sh -t 600 -I 6 -l -m 1 -c $CORE_DIR -f $WORK_DIR -- -T 120 -P 60
|
||||
sudo mkdir -p $TEST_DIR
|
||||
# run for 20 minutes to have a total runner time of 30 minutes
|
||||
sudo /usr/share/zfs/zloop.sh -t 1200 -l -m1
|
||||
- name: Prepare artifacts
|
||||
if: failure()
|
||||
run: |
|
||||
sudo chmod +r -R $WORK_DIR/
|
||||
- name: Ztest log
|
||||
if: failure()
|
||||
run: |
|
||||
grep -B10 -A1000 'ASSERT' $CORE_DIR/*/ztest.out || tail -n 1000 $CORE_DIR/*/ztest.out
|
||||
- name: Gdb log
|
||||
if: failure()
|
||||
run: |
|
||||
sed -n '/Backtraces (full)/q;p' $CORE_DIR/*/ztest.gdb
|
||||
- name: Zdb log
|
||||
if: failure()
|
||||
run: |
|
||||
cat $CORE_DIR/*/ztest.zdb
|
||||
- uses: actions/upload-artifact@v4
|
||||
sudo chmod +r -R $TEST_DIR/
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: Logs
|
||||
path: |
|
||||
/mnt/zloop/*/
|
||||
!/mnt/zloop/cores/*/vdev/
|
||||
/var/tmp/zloop/*/
|
||||
!/var/tmp/zloop/*/vdev/
|
||||
if-no-files-found: ignore
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: Pool files
|
||||
path: |
|
||||
/mnt/zloop/cores/*/vdev/
|
||||
/var/tmp/zloop/*/vdev/
|
||||
if-no-files-found: ignore
|
||||
|
||||
+36
-56
@@ -1,7 +1,6 @@
|
||||
#
|
||||
# This is the top-level .gitignore file:
|
||||
# ignore everything except a list of allowed files.
|
||||
#
|
||||
# N.B.
|
||||
# This is the toplevel .gitignore file.
|
||||
# This is not the place for entries that are specific to
|
||||
# a subdirectory. Instead add those files to the
|
||||
# .gitignore file in that subdirectory.
|
||||
@@ -11,57 +10,6 @@
|
||||
# command after changing this file, to see if there are
|
||||
# any tracked files which get ignored after the change.
|
||||
|
||||
*
|
||||
|
||||
!.github
|
||||
!cmd
|
||||
!config
|
||||
!contrib
|
||||
!etc
|
||||
!include
|
||||
!lib
|
||||
!man
|
||||
!module
|
||||
!rpm
|
||||
!scripts
|
||||
!tests
|
||||
!udev
|
||||
|
||||
!.github/**
|
||||
!cmd/**
|
||||
!config/**
|
||||
!contrib/**
|
||||
!etc/**
|
||||
!include/**
|
||||
!lib/**
|
||||
!man/**
|
||||
!module/**
|
||||
!rpm/**
|
||||
!scripts/**
|
||||
!tests/**
|
||||
!udev/**
|
||||
|
||||
!.editorconfig
|
||||
!.cirrus.yml
|
||||
!.gitignore
|
||||
!.gitmodules
|
||||
!.mailmap
|
||||
!AUTHORS
|
||||
!autogen.sh
|
||||
!CODE_OF_CONDUCT.md
|
||||
!configure.ac
|
||||
!copy-builtin
|
||||
!COPYRIGHT
|
||||
!LICENSE
|
||||
!Makefile.am
|
||||
!META
|
||||
!NEWS
|
||||
!NOTICE
|
||||
!README.md
|
||||
!RELEASES.md
|
||||
!TEST
|
||||
!zfs.release.in
|
||||
|
||||
#
|
||||
# Normal rules
|
||||
#
|
||||
@@ -83,8 +31,40 @@
|
||||
modules.order
|
||||
Makefile
|
||||
Makefile.in
|
||||
changelog
|
||||
|
||||
#
|
||||
# Top level generated files specific to this top level dir
|
||||
#
|
||||
/bin
|
||||
/build
|
||||
/configure
|
||||
/config.log
|
||||
/config.status
|
||||
/libtool
|
||||
/zfs_config.h
|
||||
/zfs_config.h.in
|
||||
/zfs.release
|
||||
/stamp-h1
|
||||
/aclocal.m4
|
||||
/autom4te.cache
|
||||
|
||||
#
|
||||
# Top level generic files
|
||||
#
|
||||
!.gitignore
|
||||
tags
|
||||
TAGS
|
||||
current
|
||||
cscope.*
|
||||
*.rpm
|
||||
*.deb
|
||||
*.tar.gz
|
||||
*.patch
|
||||
*.orig
|
||||
*.tmp
|
||||
*.log
|
||||
*.tmp
|
||||
venv
|
||||
|
||||
*.so
|
||||
*.so.debug
|
||||
*.so.full
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[submodule "scripts/zfs-images"]
|
||||
path = scripts/zfs-images
|
||||
url = https://github.com/openzfs/zfs-images
|
||||
url = https://github.com/zfsonlinux/zfs-images
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
# This file maps the name+email seen in a commit back to a canonical
|
||||
# name+email. Git will replace the commit name/email with the canonical version
|
||||
# wherever it sees it.
|
||||
#
|
||||
# If there is a commit in the history with a "wrong" name or email, list it
|
||||
# here. If you regularly commit with an alternate name or email address and
|
||||
# would like to ensure that you are always listed consistently in the repo, add
|
||||
# mapping here.
|
||||
#
|
||||
# On the other hand, if you use multiple names or email addresses legitimately
|
||||
# (eg you use a company email address for your paid OpenZFS work, and a
|
||||
# personal address for your evening side projects), then don't map one to the
|
||||
# other here.
|
||||
#
|
||||
# The most common formats are:
|
||||
#
|
||||
# Canonical Name <canonical-email>
|
||||
# Canonical Name <canonical-email> <commit-email>
|
||||
# Canonical Name <canonical-email> Commit Name <commit-email>
|
||||
#
|
||||
# See https://git-scm.com/docs/gitmailmap for more info.
|
||||
|
||||
# These maps are making names consistent where they have varied but the email
|
||||
# address has never changed. In most cases, the full name is in the
|
||||
# Signed-off-by of a commit with a matching author.
|
||||
Ahelenia Ziemiańska <nabijaczleweli@gmail.com>
|
||||
Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
|
||||
Alex John <alex@stty.io>
|
||||
Andreas Dilger <adilger@dilger.ca>
|
||||
Andrew Walker <awalker@ixsystems.com>
|
||||
Benedikt Neuffer <github@itfriend.de>
|
||||
Chengfei Zhu <chengfeix.zhu@intel.com>
|
||||
ChenHao Lu <18302010006@fudan.edu.cn>
|
||||
Chris Lindee <chris.lindee+github@gmail.com>
|
||||
Colm Buckley <colm@tuatha.org>
|
||||
Crag Wang <crag0715@gmail.com>
|
||||
Damian Szuberski <szuberskidamian@gmail.com>
|
||||
Daniel Kolesa <daniel@octaforge.org>
|
||||
Debabrata Banerjee <dbavatar@gmail.com>
|
||||
Finix Yan <yanchongwen@hotmail.com>
|
||||
Gaurav Kumar <gauravk.18@gmail.com>
|
||||
Gionatan Danti <g.danti@assyoma.it>
|
||||
Glenn Washburn <development@efficientek.com>
|
||||
Gordan Bobic <gordan.bobic@gmail.com>
|
||||
Gregory Bartholomew <gregory.lee.bartholomew@gmail.com>
|
||||
hedong zhang <h_d_zhang@163.com>
|
||||
Ilkka Sovanto <github@ilkka.kapsi.fi>
|
||||
InsanePrawn <Insane.Prawny@gmail.com>
|
||||
Jason Cohen <jwittlincohen@gmail.com>
|
||||
Jason Harmening <jason.harmening@gmail.com>
|
||||
Jeremy Faulkner <gldisater@gmail.com>
|
||||
Jinshan Xiong <jinshan.xiong@gmail.com>
|
||||
John Poduska <jpoduska@datto.com>
|
||||
Justin Scholz <git@justinscholz.de>
|
||||
Ka Ho Ng <khng300@gmail.com>
|
||||
Kash Pande <github@tripleback.net>
|
||||
Kay Pedersen <christianpe96@gmail.com>
|
||||
KernelOfTruth <kerneloftruth@gmail.com>
|
||||
Liu Hua <liu.hua130@zte.com.cn>
|
||||
Liu Qing <winglq@gmail.com>
|
||||
loli10K <ezomori.nozomu@gmail.com>
|
||||
Mart Frauenlob <allkind@fastest.cc>
|
||||
Matthias Blankertz <matthias@blankertz.org>
|
||||
Michael Gmelin <grembo@FreeBSD.org>
|
||||
Olivier Mazouffre <olivier.mazouffre@ims-bordeaux.fr>
|
||||
Piotr Kubaj <pkubaj@anongoth.pl>
|
||||
Quentin Zdanis <zdanisq@gmail.com>
|
||||
Roberto Ricci <ricci@disroot.org>
|
||||
Rob Norris <robn@despairlabs.com>
|
||||
Rob Norris <rob.norris@klarasystems.com>
|
||||
Sam Lunt <samuel.j.lunt@gmail.com>
|
||||
Sanjeev Bagewadi <sanjeev.bagewadi@gmail.com>
|
||||
Stoiko Ivanov <github@nomore.at>
|
||||
Tamas TEVESZ <ice@extreme.hu>
|
||||
WHR <msl0000023508@gmail.com>
|
||||
Yanping Gao <yanping.gao@xtaotech.com>
|
||||
Youzhong Yang <youzhong@gmail.com>
|
||||
|
||||
# Signed-off-by: overriding Author:
|
||||
Ryan <errornointernet@envs.net> <error.nointernet@gmail.com>
|
||||
Qiuhao Chen <chenqiuhao1997@gmail.com> <haohao0924@126.com>
|
||||
Yuxin Wang <yuxinwang9999@gmail.com> <Bi11gates9999@gmail.com>
|
||||
Zhenlei Huang <zlei@FreeBSD.org> <zlei.huang@gmail.com>
|
||||
|
||||
# Commits from strange places, long ago
|
||||
Brian Behlendorf <behlendorf1@llnl.gov> <behlendo@7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c>
|
||||
Brian Behlendorf <behlendorf1@llnl.gov> <behlendo@fedora-17-amd64.(none)>
|
||||
Brian Behlendorf <behlendorf1@llnl.gov> <behlendo@myhost.(none)>
|
||||
Brian Behlendorf <behlendorf1@llnl.gov> <ubuntu@ip-172-31-16-145.us-west-1.compute.internal>
|
||||
Brian Behlendorf <behlendorf1@llnl.gov> <ubuntu@ip-172-31-20-6.us-west-1.compute.internal>
|
||||
Herb Wartens <wartens2@llnl.gov> <wartens2@7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c>
|
||||
Ned Bass <bass6@llnl.gov> <bass6@zeno1.(none)>
|
||||
Tulsi Jain <tulsi.jain@delphix.com> <tulsi.jain@Tulsi-Jains-MacBook-Pro.local>
|
||||
|
||||
# Mappings from Github no-reply addresses
|
||||
ajs124 <git@ajs124.de> <ajs124@users.noreply.github.com>
|
||||
Alek Pinchuk <apinchuk@axcient.com> <alek-p@users.noreply.github.com>
|
||||
Alexander Lobakin <alobakin@pm.me> <solbjorn@users.noreply.github.com>
|
||||
Alexey Smirnoff <fling@member.fsf.org> <fling-@users.noreply.github.com>
|
||||
Allen Holl <allen.m.holl@gmail.com> <65494904+allen-4@users.noreply.github.com>
|
||||
Alphan Yılmaz <alphanyilmaz@gmail.com> <a1ea321@users.noreply.github.com>
|
||||
Ameer Hamza <ahamza@ixsystems.com> <106930537+ixhamza@users.noreply.github.com>
|
||||
Andrew J. Hesford <ajh@sideband.org> <48421688+ahesford@users.noreply.github.com>>
|
||||
Andrew Sun <me@andrewsun.com> <as-com@users.noreply.github.com>
|
||||
Aron Xu <happyaron.xu@gmail.com> <happyaron@users.noreply.github.com>
|
||||
Arun KV <arun.kv@datacore.com> <65647132+arun-kv@users.noreply.github.com>
|
||||
Ben Wolsieffer <benwolsieffer@gmail.com> <lopsided98@users.noreply.github.com>
|
||||
bernie1995 <bernie.pikes@gmail.com> <42413912+bernie1995@users.noreply.github.com>
|
||||
Bojan Novković <bnovkov@FreeBSD.org> <72801811+bnovkov@users.noreply.github.com>
|
||||
Boris Protopopov <boris.protopopov@actifio.com> <bprotopopov@users.noreply.github.com>
|
||||
Brad Forschinger <github@bnjf.id.au> <bnjf@users.noreply.github.com>
|
||||
Brandon Thetford <brandon@dodecatec.com> <dodexahedron@users.noreply.github.com>
|
||||
buzzingwires <buzzingwires@outlook.com> <131118055+buzzingwires@users.noreply.github.com>
|
||||
Cedric Maunoury <cedric.maunoury@gmail.com> <38213715+cedricmaunoury@users.noreply.github.com>
|
||||
Charles Suh <charles.suh@gmail.com> <charlessuh@users.noreply.github.com>
|
||||
Chris Peredun <chris.peredun@ixsystems.com> <126915832+chrisperedun@users.noreply.github.com>
|
||||
Dacian Reece-Stremtan <dacianstremtan@gmail.com> <35844628+dacianstremtan@users.noreply.github.com>
|
||||
Damian Szuberski <szuberskidamian@gmail.com> <30863496+szubersk@users.noreply.github.com>
|
||||
Daniel Hiepler <d-git@coderdu.de> <32984777+heeplr@users.noreply.github.com>
|
||||
Daniel Kobras <d.kobras@science-computing.de> <sckobras@users.noreply.github.com>
|
||||
Daniel Reichelt <hacking@nachtgeist.net> <nachtgeist@users.noreply.github.com>
|
||||
David Quigley <david.quigley@intel.com> <dpquigl@users.noreply.github.com>
|
||||
Dennis R. Friedrichsen <dennis.r.friedrichsen@gmail.com> <31087738+dennisfriedrichsen@users.noreply.github.com>
|
||||
Dex Wood <slash2314@gmail.com> <slash2314@users.noreply.github.com>
|
||||
DHE <git@dehacked.net> <DeHackEd@users.noreply.github.com>
|
||||
Dmitri John Ledkov <dimitri.ledkov@canonical.com> <19779+xnox@users.noreply.github.com>
|
||||
Dries Michiels <driesm.michiels@gmail.com> <32487486+driesmp@users.noreply.github.com>
|
||||
Edmund Nadolski <edmund.nadolski@ixsystems.com> <137826107+ednadolski-ix@users.noreply.github.com>
|
||||
Érico Nogueira <erico.erc@gmail.com> <34201958+ericonr@users.noreply.github.com>
|
||||
Fedor Uporov <fuporov.vstack@gmail.com> <60701163+fuporovvStack@users.noreply.github.com>
|
||||
Felix Dörre <felix@dogcraft.de> <felixdoerre@users.noreply.github.com>
|
||||
Felix Neumärker <xdch47@posteo.de> <34678034+xdch47@users.noreply.github.com>
|
||||
Finix Yan <yancw@info2soft.com> <Finix1979@users.noreply.github.com>
|
||||
Gaurav Kumar <gauravk.18@gmail.com> <gaurkuma@users.noreply.github.com>
|
||||
George Gaydarov <git@gg7.io> <gg7@users.noreply.github.com>
|
||||
Georgy Yakovlev <gyakovlev@gentoo.org> <168902+gyakovlev@users.noreply.github.com>
|
||||
Gerardwx <gerardw@alum.mit.edu> <Gerardwx@users.noreply.github.com>
|
||||
Gian-Carlo DeFazio <defazio1@llnl.gov> <defaziogiancarlo@users.noreply.github.com>
|
||||
Giuseppe Di Natale <dinatale2@llnl.gov> <dinatale2@users.noreply.github.com>
|
||||
Hajo Möller <dasjoe@gmail.com> <dasjoe@users.noreply.github.com>
|
||||
Harry Mallon <hjmallon@gmail.com> <1816667+hjmallon@users.noreply.github.com>
|
||||
Hiếu Lê <leorize+oss@disroot.org> <alaviss@users.noreply.github.com>
|
||||
Jake Howard <git@theorangeone.net> <RealOrangeOne@users.noreply.github.com>
|
||||
James Cowgill <james.cowgill@mips.com> <jcowgill@users.noreply.github.com>
|
||||
Jaron Kent-Dobias <jaron@kent-dobias.com> <kentdobias@users.noreply.github.com>
|
||||
Jason King <jason.king@joyent.com> <jasonbking@users.noreply.github.com>
|
||||
Jeff Dike <jdike@akamai.com> <52420226+jdike@users.noreply.github.com>
|
||||
Jitendra Patidar <jitendra.patidar@nutanix.com> <53164267+jsai20@users.noreply.github.com>
|
||||
João Carlos Mendes Luís <jonny@jonny.eng.br> <dioni21@users.noreply.github.com>
|
||||
John Eismeier <john.eismeier@gmail.com> <32205350+jeis2497052@users.noreply.github.com>
|
||||
John L. Hammond <john.hammond@intel.com> <35266395+jhammond-intel@users.noreply.github.com>
|
||||
John-Mark Gurney <jmg@funkthat.com> <jmgurney@users.noreply.github.com>
|
||||
John Ramsden <johnramsden@riseup.net> <johnramsden@users.noreply.github.com>
|
||||
Jonathon Fernyhough <jonathon@m2x.dev> <559369+jonathonf@users.noreply.github.com>
|
||||
Jose Luis Duran <jlduran@gmail.com> <jlduran@users.noreply.github.com>
|
||||
Justin Hibbits <chmeeedalf@gmail.com> <chmeeedalf@users.noreply.github.com>
|
||||
Kevin Greene <kevin.greene@delphix.com> <104801862+kxgreene@users.noreply.github.com>
|
||||
Kevin Jin <lostking2008@hotmail.com> <33590050+jxdking@users.noreply.github.com>
|
||||
Kevin P. Fleming <kevin@km6g.us> <kpfleming@users.noreply.github.com>
|
||||
Krzysztof Piecuch <piecuch@kpiecuch.pl> <3964215+pikrzysztof@users.noreply.github.com>
|
||||
Kyle Evans <kevans@FreeBSD.org> <kevans91@users.noreply.github.com>
|
||||
Laurențiu Nicola <lnicola@dend.ro> <lnicola@users.noreply.github.com>
|
||||
loli10K <ezomori.nozomu@gmail.com> <loli10K@users.noreply.github.com>
|
||||
Lorenz Hüdepohl <dev@stellardeath.org> <lhuedepohl@users.noreply.github.com>
|
||||
Luís Henriques <henrix@camandro.org> <73643340+lumigch@users.noreply.github.com>
|
||||
Marcin Skarbek <git@skarbek.name> <mskarbek@users.noreply.github.com>
|
||||
Matt Fiddaman <github@m.fiddaman.uk> <81489167+matt-fidd@users.noreply.github.com>
|
||||
Maxim Filimonov <che@bein.link> <part1zano@users.noreply.github.com>
|
||||
Max Zettlmeißl <max@zettlmeissl.de> <6818198+maxz@users.noreply.github.com>
|
||||
Michael Niewöhner <foss@mniewoehner.de> <c0d3z3r0@users.noreply.github.com>
|
||||
Michael Zhivich <mzhivich@akamai.com> <33133421+mzhivich@users.noreply.github.com>
|
||||
MigeljanImeri <ImeriMigel@gmail.com> <78048439+MigeljanImeri@users.noreply.github.com>
|
||||
Mo Zhou <cdluminate@gmail.com> <5723047+cdluminate@users.noreply.github.com>
|
||||
Nick Mattis <nickm970@gmail.com> <nmattis@users.noreply.github.com>
|
||||
omni <omni+vagant@hack.org> <79493359+omnivagant@users.noreply.github.com>
|
||||
Pablo Correa Gómez <ablocorrea@hotmail.com> <32678034+pablofsf@users.noreply.github.com>
|
||||
Paul Zuchowski <pzuchowski@datto.com> <31706010+PaulZ-98@users.noreply.github.com>
|
||||
Peter Ashford <ashford@accs.com> <pashford@users.noreply.github.com>
|
||||
Peter Dave Hello <hsu@peterdavehello.org> <PeterDaveHello@users.noreply.github.com>
|
||||
Peter Wirdemo <peter.wirdemo@gmail.com> <4224155+pewo@users.noreply.github.com>
|
||||
Petros Koutoupis <petros@petroskoutoupis.com> <pkoutoupis@users.noreply.github.com>
|
||||
Ping Huang <huangping@smartx.com> <101400146+hpingfs@users.noreply.github.com>
|
||||
Piotr P. Stefaniak <pstef@freebsd.org> <pstef@users.noreply.github.com>
|
||||
Richard Allen <belperite@gmail.com> <33836503+belperite@users.noreply.github.com>
|
||||
Rich Ercolani <rincebrain@gmail.com> <214141+rincebrain@users.noreply.github.com>
|
||||
Rick Macklem <rmacklem@uoguelph.ca> <64620010+rmacklem@users.noreply.github.com>
|
||||
Rob Wing <rob.wing@klarasystems.com> <98866084+rob-wing@users.noreply.github.com>
|
||||
Roman Strashkin <roman.strashkin@nexenta.com> <Ramzec@users.noreply.github.com>
|
||||
Ryan Hirasaki <ryanhirasaki@gmail.com> <4690732+RyanHir@users.noreply.github.com>
|
||||
Samuel Wycliffe J <samwyc@hpe.com> <115969550+samwyc@users.noreply.github.com>
|
||||
Samuel Wycliffe <samuelwycliffe@gmail.com> <50765275+npc203@users.noreply.github.com>
|
||||
Savyasachee Jha <hi@savyasacheejha.com> <savyajha@users.noreply.github.com>
|
||||
Scott Colby <scott@scolby.com> <scolby33@users.noreply.github.com>
|
||||
Sean Eric Fagan <kithrup@mac.com> <kithrup@users.noreply.github.com>
|
||||
Spencer Kinny <spencerkinny1995@gmail.com> <30333052+Spencer-Kinny@users.noreply.github.com>
|
||||
Srikanth N S <srikanth.nagasubbaraoseetharaman@hpe.com> <75025422+nssrikanth@users.noreply.github.com>
|
||||
Stefan Lendl <s.lendl@proxmox.com> <1321542+stfl@users.noreply.github.com>
|
||||
Thomas Bertschinger <bertschinger@lanl.gov> <101425190+bertschinger@users.noreply.github.com>
|
||||
Thomas Geppert <geppi@digitx.de> <geppi@users.noreply.github.com>
|
||||
Tim Crawford <tcrawford@datto.com> <crawfxrd@users.noreply.github.com>
|
||||
Todd Seidelmann <18294602+seidelma@users.noreply.github.com>
|
||||
Tom Matthews <tom@axiom-partners.com> <tomtastic@users.noreply.github.com>
|
||||
Tony Perkins <tperkins@datto.com> <62951051+tony-zfs@users.noreply.github.com>
|
||||
Torsten Wörtwein <twoertwein@gmail.com> <twoertwein@users.noreply.github.com>
|
||||
Tulsi Jain <tulsi.jain@delphix.com> <TulsiJain@users.noreply.github.com>
|
||||
Václav Skála <skala@vshosting.cz> <33496485+vaclavskala@users.noreply.github.com>
|
||||
Vaibhav Bhanawat <vaibhav.bhanawat@delphix.com> <88050553+vaibhav-delphix@users.noreply.github.com>
|
||||
Violet Purcell <vimproved@inventati.org> <66446404+vimproved@users.noreply.github.com>
|
||||
Vipin Kumar Verma <vipin.verma@hpe.com> <75025470+vermavipinkumar@users.noreply.github.com>
|
||||
Wolfgang Bumiller <w.bumiller@proxmox.com> <Blub@users.noreply.github.com>
|
||||
xtouqh <xtouqh@hotmail.com> <72357159+xtouqh@users.noreply.github.com>
|
||||
Yuri Pankov <yuripv@FreeBSD.org> <113725409+yuripv@users.noreply.github.com>
|
||||
Yuri Pankov <yuripv@FreeBSD.org> <82001006+yuripv@users.noreply.github.com>
|
||||
@@ -10,663 +10,299 @@ PAST MAINTAINERS:
|
||||
CONTRIBUTORS:
|
||||
|
||||
Aaron Fineman <abyxcos@gmail.com>
|
||||
Adam D. Moss <c@yotes.com>
|
||||
Adam Leventhal <ahl@delphix.com>
|
||||
Adam Stevko <adam.stevko@gmail.com>
|
||||
adisbladis <adis@blad.is>
|
||||
Adrian Chadd <adrian@freebsd.org>
|
||||
Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
|
||||
Ahmed G <ahmedg@delphix.com>
|
||||
Aidan Harris <me@aidanharr.is>
|
||||
AJ Jordan <alex@strugee.net>
|
||||
ajs124 <git@ajs124.de>
|
||||
Akash Ayare <aayare@delphix.com>
|
||||
Akash B <akash-b@hpe.com>
|
||||
Alan Somers <asomers@gmail.com>
|
||||
Alar Aun <spamtoaun@gmail.com>
|
||||
Albert Lee <trisk@nexenta.com>
|
||||
Alec Salazar <alec.j.salazar@gmail.com>
|
||||
Alejandro Colomar <Colomar.6.4.3@GMail.com>
|
||||
Alejandro R. Sedeño <asedeno@mit.edu>
|
||||
Alek Pinchuk <alek@nexenta.com>
|
||||
Aleksa Sarai <cyphar@cyphar.com>
|
||||
Alexander Eremin <a.eremin@nexenta.com>
|
||||
Alexander Lobakin <alobakin@pm.me>
|
||||
Alexander Motin <mav@freebsd.org>
|
||||
Alexander Pyhalov <apyhalov@gmail.com>
|
||||
Alexander Richardson <Alexander.Richardson@cl.cam.ac.uk>
|
||||
Alexander Stetsenko <ams@nexenta.com>
|
||||
Alex Braunegg <alex.braunegg@gmail.com>
|
||||
Alexey Shvetsov <alexxy@gentoo.org>
|
||||
Alexey Smirnoff <fling@member.fsf.org>
|
||||
Alex John <alex@stty.io>
|
||||
Alex McWhirter <alexmcwhirter@triadic.us>
|
||||
Alex Reece <alex@delphix.com>
|
||||
Alex Wilson <alex.wilson@joyent.com>
|
||||
Alex Zhuravlev <alexey.zhuravlev@intel.com>
|
||||
Alexander Eremin <a.eremin@nexenta.com>
|
||||
Alexander Motin <mav@freebsd.org>
|
||||
Alexander Pyhalov <apyhalov@gmail.com>
|
||||
Alexander Stetsenko <ams@nexenta.com>
|
||||
Alexey Shvetsov <alexxy@gentoo.org>
|
||||
Alexey Smirnoff <fling@member.fsf.org>
|
||||
Allan Jude <allanjude@freebsd.org>
|
||||
Allen Holl <allen.m.holl@gmail.com>
|
||||
Alphan Yılmaz <alphanyilmaz@gmail.com>
|
||||
alteriks <alteriks@gmail.com>
|
||||
Alyssa Ross <hi@alyssa.is>
|
||||
Ameer Hamza <ahamza@ixsystems.com>
|
||||
Anatoly Borodin <anatoly.borodin@gmail.com>
|
||||
AndCycle <andcycle@andcycle.idv.tw>
|
||||
Andrea Gelmini <andrea.gelmini@gelma.net>
|
||||
Andrea Righi <andrea.righi@canonical.com>
|
||||
Andreas Buschmann <andreas.buschmann@tech.net.de>
|
||||
Andreas Dilger <adilger@intel.com>
|
||||
Andreas Vögele <andreas@andreasvoegele.com>
|
||||
Andrew Barnes <barnes333@gmail.com>
|
||||
Andrew Hamilton <ahamilto@tjhsst.edu>
|
||||
Andrew Innes <andrew.c12@gmail.com>
|
||||
Andrew J. Hesford <ajh@sideband.org>
|
||||
Andrew Reid <ColdCanuck@nailedtotheperch.com>
|
||||
Andrew Stormont <andrew.stormont@nexenta.com>
|
||||
Andrew Sun <me@andrewsun.com>
|
||||
Andrew Tselischev <andrewtselischev@gmail.com>
|
||||
Andrew Turner <andrew@fubar.geek.nz>
|
||||
Andrew Walker <awalker@ixsystems.com>
|
||||
Andrey Prokopenko <job@terem.fr>
|
||||
Andrey Vesnovaty <andrey.vesnovaty@gmail.com>
|
||||
Andriy Gapon <avg@freebsd.org>
|
||||
Andy Bakun <github@thwartedefforts.org>
|
||||
Andy Fiddaman <omnios@citrus-it.co.uk>
|
||||
Aniruddha Shankar <k@191a.net>
|
||||
Anton Gubarkov <anton.gubarkov@gmail.com>
|
||||
Antonio Russo <antonio.e.russo@gmail.com>
|
||||
Arkadiusz Bubała <arkadiusz.bubala@open-e.com>
|
||||
Armin Wehrfritz <dkxls23@gmail.com>
|
||||
Arne Jansen <arne@die-jansens.de>
|
||||
Aron Xu <happyaron.xu@gmail.com>
|
||||
Arshad Hussain <arshad.hussain@aeoncomputing.com>
|
||||
Arun KV <arun.kv@datacore.com>
|
||||
Arvind Sankar <nivedita@alum.mit.edu>
|
||||
Attila Fülöp <attila@fueloep.org>
|
||||
Avatat <kontakt@avatat.pl>
|
||||
Bart Coddens <bart.coddens@gmail.com>
|
||||
Basil Crow <basil.crow@delphix.com>
|
||||
Bassu <bassu@phi9.com>
|
||||
Huang Liu <liu.huang@zte.com.cn>
|
||||
Ben Allen <bsallen@alcf.anl.gov>
|
||||
Ben Cordero <bencord0@condi.me>
|
||||
Benda Xu <orv@debian.org>
|
||||
Benedikt Neuffer <github@itfriend.de>
|
||||
Benjamin Albrecht <git@albrecht.io>
|
||||
Benjamin Gentil <benjgentil.pro@gmail.com>
|
||||
Benjamin Sherman <benjamin@holyarmy.org>
|
||||
Ben McGough <bmcgough@fredhutch.org>
|
||||
Ben Rubson <ben.rubson@gmail.com>
|
||||
Ben Wolsieffer <benwolsieffer@gmail.com>
|
||||
bernie1995 <bernie.pikes@gmail.com>
|
||||
Benjamin Albrecht <git@albrecht.io>
|
||||
Bill McGonigle <bill-github.com-public1@bfccomputing.com>
|
||||
Bill Pijewski <wdp@joyent.com>
|
||||
Bojan Novković <bnovkov@FreeBSD.org>
|
||||
Boris Protopopov <boris.protopopov@nexenta.com>
|
||||
Brad Forschinger <github@bnjf.id.au>
|
||||
Brad Lewis <brad.lewis@delphix.com>
|
||||
Brandon Thetford <brandon@dodecatec.com>
|
||||
Brian Atkinson <bwa@g.clemson.edu>
|
||||
Brian Behlendorf <behlendorf1@llnl.gov>
|
||||
Brian J. Murrell <brian@sun.com>
|
||||
Brooks Davis <brooks@one-eyed-alien.net>
|
||||
BtbN <btbn@btbn.de>
|
||||
bunder2015 <omfgbunder@gmail.com>
|
||||
buzzingwires <buzzingwires@outlook.com>
|
||||
bzzz77 <bzzz.tomas@gmail.com>
|
||||
cable2999 <cable2999@users.noreply.github.com>
|
||||
Caleb James DeLisle <calebdelisle@lavabit.com>
|
||||
Cameron Harr <harr1@llnl.gov>
|
||||
Cao Xuewen <cao.xuewen@zte.com.cn>
|
||||
Carlo Landmeter <clandmeter@gmail.com>
|
||||
Carlos Alberto Lopez Perez <clopez@igalia.com>
|
||||
Cedric Maunoury <cedric.maunoury@gmail.com>
|
||||
Chaoyu Zhang <zhang.chaoyu@zte.com.cn>
|
||||
Charles Suh <charles.suh@gmail.com>
|
||||
Chen Can <chen.can2@zte.com.cn>
|
||||
Chengfei Zhu <chengfeix.zhu@intel.com>
|
||||
Chen Haiquan <oc@yunify.com>
|
||||
ChenHao Lu <18302010006@fudan.edu.cn>
|
||||
Chip Parker <aparker@enthought.com>
|
||||
Chris Burroughs <chris.burroughs@gmail.com>
|
||||
Chris Davidson <christopher.davidson@gmail.com>
|
||||
Chris Dunlap <cdunlap@llnl.gov>
|
||||
Chris Dunlop <chris@onthe.net.au>
|
||||
Chris Lindee <chris.lindee+github@gmail.com>
|
||||
Chris McDonough <chrism@plope.com>
|
||||
Chris Peredun <chris.peredun@ixsystems.com>
|
||||
Chris Siden <chris.siden@delphix.com>
|
||||
Chris Siebenmann <cks.github@cs.toronto.edu>
|
||||
Chris Wedgwood <cw@f00f.org>
|
||||
Chris Williamson <chris.williamson@delphix.com>
|
||||
Chris Zubrzycki <github@mid-earth.net>
|
||||
Christ Schlacta <aarcane@aarcane.info>
|
||||
Christer Ekholm <che@chrekh.se>
|
||||
Christian Kohlschütter <christian@kohlschutter.com>
|
||||
Christian Neukirchen <chneukirchen@gmail.com>
|
||||
Christian Schwarz <me@cschwarz.com>
|
||||
Christopher Voltz <cjunk@voltz.ws>
|
||||
Christ Schlacta <aarcane@aarcane.info>
|
||||
Chris Wedgwood <cw@f00f.org>
|
||||
Chris Williamson <chris.williamson@delphix.com>
|
||||
Chris Zubrzycki <github@mid-earth.net>
|
||||
Chuck Tuffli <ctuffli@gmail.com>
|
||||
Chunwei Chen <david.chen@nutanix.com>
|
||||
Clemens Fruhwirth <clemens@endorphin.org>
|
||||
Clemens Lang <cl@clang.name>
|
||||
Clint Armstrong <clint@clintarmstrong.net>
|
||||
Coleman Kane <ckane@colemankane.org>
|
||||
Colin Ian King <colin.king@canonical.com>
|
||||
Colin Percival <cperciva@tarsnap.com>
|
||||
Colm Buckley <colm@tuatha.org>
|
||||
Crag Wang <crag0715@gmail.com>
|
||||
Craig Loomis <cloomis@astro.princeton.edu>
|
||||
Craig Sanders <github@taz.net.au>
|
||||
Cyril Plisko <cyril.plisko@infinidat.com>
|
||||
Cy Schubert <cy@FreeBSD.org>
|
||||
Cédric Berger <cedric@precidata.com>
|
||||
Dacian Reece-Stremtan <dacianstremtan@gmail.com>
|
||||
Dag-Erling Smørgrav <des@FreeBSD.org>
|
||||
Damiano Albani <damiano.albani@gmail.com>
|
||||
Damian Szuberski <szuberskidamian@gmail.com>
|
||||
DHE <git@dehacked.net>
|
||||
Damian Wojsław <damian@wojslaw.pl>
|
||||
Daniel Berlin <dberlin@dberlin.org>
|
||||
Daniel Hiepler <d-git@coderdu.de>
|
||||
Daniel Hoffman <dj.hoffman@delphix.com>
|
||||
Daniel Kobras <d.kobras@science-computing.de>
|
||||
Daniel Kolesa <daniel@octaforge.org>
|
||||
Daniel Perry <dtperry@amazon.com>
|
||||
Daniel Reichelt <hacking@nachtgeist.net>
|
||||
Daniel Stevenson <bot@dstev.net>
|
||||
Daniel Verite <daniel@verite.pro>
|
||||
Daniil Lunev <d.lunev.mail@gmail.com>
|
||||
Dan Kimmel <dan.kimmel@delphix.com>
|
||||
Dan McDonald <danmcd@nexenta.com>
|
||||
Dan Swartzendruber <dswartz@druber.com>
|
||||
Dan Vatca <dan.vatca@gmail.com>
|
||||
Daniel Hoffman <dj.hoffman@delphix.com>
|
||||
Daniel Verite <daniel@verite.pro>
|
||||
Daniil Lunev <d.lunev.mail@gmail.com>
|
||||
Darik Horn <dajhorn@vanadac.com>
|
||||
Dave Eddy <dave@daveeddy.com>
|
||||
David Hedberg <david@qzx.se>
|
||||
David Lamparter <equinox@diac24.net>
|
||||
David Qian <david.qian@intel.com>
|
||||
David Quigley <david.quigley@intel.com>
|
||||
Debabrata Banerjee <dbanerje@akamai.com>
|
||||
D. Ebdrup <debdrup@freebsd.org>
|
||||
Dennis R. Friedrichsen <dennis.r.friedrichsen@gmail.com>
|
||||
Denys Rtveliashvili <denys@rtveliashvili.name>
|
||||
Derek Dai <daiderek@gmail.com>
|
||||
Derek Schrock <dereks@lifeofadishwasher.com>
|
||||
Dex Wood <slash2314@gmail.com>
|
||||
DHE <git@dehacked.net>
|
||||
Didier Roche <didrocks@ubuntu.com>
|
||||
Dimitri John Ledkov <xnox@ubuntu.com>
|
||||
Dimitry Andric <dimitry@andric.com>
|
||||
Dirkjan Bussink <d.bussink@gmail.com>
|
||||
Dmitry Khasanov <pik4ez@gmail.com>
|
||||
Dominic Pearson <dsp@technoanimal.net>
|
||||
Dominik Hassler <hadfl@omniosce.org>
|
||||
Dominik Honnef <dominikh@fork-bomb.org>
|
||||
Don Brady <don.brady@delphix.com>
|
||||
Doug Rabson <dfr@rabson.org>
|
||||
Dr. András Korn <korn-github.com@elan.rulez.org>
|
||||
Dries Michiels <driesm.michiels@gmail.com>
|
||||
Edmund Nadolski <edmund.nadolski@ixsystems.com>
|
||||
Eitan Adler <lists@eitanadler.com>
|
||||
Eli Rosenthal <eli.rosenthal@delphix.com>
|
||||
Eli Schwartz <eschwartz93@gmail.com>
|
||||
Eric Desrochers <eric.desrochers@canonical.com>
|
||||
Eric Dillmann <eric@jave.fr>
|
||||
Eric Schrock <Eric.Schrock@delphix.com>
|
||||
Ethan Coe-Renner <coerenner1@llnl.gov>
|
||||
Etienne Dechamps <etienne@edechamps.fr>
|
||||
Evan Allrich <eallrich@gmail.com>
|
||||
Evan Harris <eharris@puremagic.com>
|
||||
Evan Susarret <evansus@gmail.com>
|
||||
Fabian Grünbichler <f.gruenbichler@proxmox.com>
|
||||
Fabio Buso <dev.siroibaf@gmail.com>
|
||||
Fabio Scaccabarozzi <fsvm88@gmail.com>
|
||||
Fajar A. Nugraha <github@fajar.net>
|
||||
Fan Yong <fan.yong@intel.com>
|
||||
fbynite <fbynite@users.noreply.github.com>
|
||||
Fedor Uporov <fuporov.vstack@gmail.com>
|
||||
Felix Dörre <felix@dogcraft.de>
|
||||
Felix Neumärker <xdch47@posteo.de>
|
||||
Feng Sun <loyou85@gmail.com>
|
||||
Finix Yan <yancw@info2soft.com>
|
||||
Francesco Mazzoli <f@mazzo.li>
|
||||
Frederik Wessels <wessels147@gmail.com>
|
||||
Frédéric Vanniere <f.vanniere@planet-work.com>
|
||||
Gabriel A. Devenyi <gdevenyi@gmail.com>
|
||||
Garrett D'Amore <garrett@nexenta.com>
|
||||
Garrett Fields <ghfields@gmail.com>
|
||||
Garrison Jensen <garrison.jensen@gmail.com>
|
||||
Gary Mills <gary_mills@fastmail.fm>
|
||||
Gaurav Kumar <gauravk.18@gmail.com>
|
||||
GeLiXin <ge.lixin@zte.com.cn>
|
||||
George Amanakis <g_amanakis@yahoo.com>
|
||||
George Diamantopoulos <georgediam@gmail.com>
|
||||
George Gaydarov <git@gg7.io>
|
||||
George Melikov <mail@gmelikov.ru>
|
||||
George Wilson <gwilson@delphix.com>
|
||||
Georgy Yakovlev <ya@sysdump.net>
|
||||
Gerardwx <gerardw@alum.mit.edu>
|
||||
Gian-Carlo DeFazio <defazio1@llnl.gov>
|
||||
Gionatan Danti <g.danti@assyoma.it>
|
||||
Giuseppe Di Natale <guss80@gmail.com>
|
||||
Glenn Washburn <development@efficientek.com>
|
||||
glibg10b <glibg10b@users.noreply.github.com>
|
||||
gofaster <felix.gofaster@gmail.com>
|
||||
Gordan Bobic <gordan@redsleeve.org>
|
||||
Gordon Bergling <gbergling@googlemail.com>
|
||||
Gordon Ross <gwr@nexenta.com>
|
||||
Gordon Tetlow <gordon@freebsd.org>
|
||||
Graham Christensen <graham@grahamc.com>
|
||||
Graham Perrin <grahamperrin@gmail.com>
|
||||
Gregor Kopka <gregor@kopka.net>
|
||||
Gregory Bartholomew <gregory.lee.bartholomew@gmail.com>
|
||||
grembo <freebsd@grem.de>
|
||||
Grischa Zengel <github.zfsonlinux@zengel.info>
|
||||
grodik <pat@litke.dev>
|
||||
Gunnar Beutner <gunnar@beutner.name>
|
||||
Gvozden Neskovic <neskovic@gmail.com>
|
||||
Hajo Möller <dasjoe@gmail.com>
|
||||
Han Gao <rabenda.cn@gmail.com>
|
||||
Hans Rosenfeld <hans.rosenfeld@nexenta.com>
|
||||
Harald van Dijk <harald@gigawatt.nl>
|
||||
Harry Mallon <hjmallon@gmail.com>
|
||||
Harry Sintonen <github-piru@kyber.fi>
|
||||
HC <mmttdebbcc@yahoo.com>
|
||||
hedong zhang <h_d_zhang@163.com>
|
||||
Heitor Alves de Siqueira <halves@canonical.com>
|
||||
Henrik Riomar <henrik.riomar@gmail.com>
|
||||
Herb Wartens <wartens2@llnl.gov>
|
||||
Hiếu Lê <leorize+oss@disroot.org>
|
||||
Huang Liu <liu.huang@zte.com.cn>
|
||||
Håkan Johansson <f96hajo@chalmers.se>
|
||||
Igor K <igor@dilos.org>
|
||||
Igor Kozhukhov <ikozhukhov@gmail.com>
|
||||
Igor Lvovsky <ilvovsky@gmail.com>
|
||||
ilbsmart <wgqimut@gmail.com>
|
||||
Ilkka Sovanto <github@ilkka.kapsi.fi>
|
||||
illiliti <illiliti@protonmail.com>
|
||||
ilovezfs <ilovezfs@icloud.com>
|
||||
InsanePrawn <Insane.Prawny@gmail.com>
|
||||
Isaac Huang <he.huang@intel.com>
|
||||
JK Dingwall <james@dingwall.me.uk>
|
||||
Jacek Fefliński <feflik@gmail.com>
|
||||
Jacob Adams <tookmund@gmail.com>
|
||||
Jake Howard <git@theorangeone.net>
|
||||
James Cowgill <james.cowgill@mips.com>
|
||||
James H <james@kagisoft.co.uk>
|
||||
James Lee <jlee@thestaticvoid.com>
|
||||
James Pan <jiaming.pan@yahoo.com>
|
||||
James Wah <james@laird-wah.net>
|
||||
Jan Engelhardt <jengelh@inai.de>
|
||||
Jan Kryl <jan.kryl@nexenta.com>
|
||||
Jan Sanislo <oystr@cs.washington.edu>
|
||||
Jaron Kent-Dobias <jaron@kent-dobias.com>
|
||||
Jason Cohen <jwittlincohen@gmail.com>
|
||||
Jason Harmening <jason.harmening@gmail.com>
|
||||
Jason King <jason.brian.king@gmail.com>
|
||||
Jason Lee <jasonlee@lanl.gov>
|
||||
Jason Zaman <jasonzaman@gmail.com>
|
||||
Javen Wu <wu.javen@gmail.com>
|
||||
Jean-Baptiste Lallement <jean-baptiste@ubuntu.com>
|
||||
Jeff Dike <jdike@akamai.com>
|
||||
Jeremy Faulkner <gldisater@gmail.com>
|
||||
Jeremy Gill <jgill@parallax-innovations.com>
|
||||
Jeremy Jones <jeremy@delphix.com>
|
||||
Jeremy Visser <jeremy.visser@gmail.com>
|
||||
Jerry Jelinek <jerry.jelinek@joyent.com>
|
||||
Jessica Clarke <jrtc27@jrtc27.com>
|
||||
Jinshan Xiong <jinshan.xiong@intel.com>
|
||||
Jitendra Patidar <jitendra.patidar@nutanix.com>
|
||||
JK Dingwall <james@dingwall.me.uk>
|
||||
Joe Stein <joe.stein@delphix.com>
|
||||
John-Mark Gurney <jmg@funkthat.com>
|
||||
John Albietz <inthecloud247@gmail.com>
|
||||
John Eismeier <john.eismeier@gmail.com>
|
||||
John Gallagher <john.gallagher@delphix.com>
|
||||
John Layman <jlayman@sagecloud.com>
|
||||
John L. Hammond <john.hammond@intel.com>
|
||||
John M. Layman <jml@frijid.net>
|
||||
Johnny Stenback <github@jstenback.com>
|
||||
John Layman <jlayman@sagecloud.com>
|
||||
John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
|
||||
John Poduska <jpoduska@datto.com>
|
||||
John Ramsden <johnramsden@riseup.net>
|
||||
John Wren Kennedy <john.kennedy@delphix.com>
|
||||
jokersus <lolivampireslave@gmail.com>
|
||||
Jonathon Fernyhough <jonathon@m2x.dev>
|
||||
Johnny Stenback <github@jstenback.com>
|
||||
Jorgen Lundman <lundman@lundman.net>
|
||||
Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
|
||||
Jose Luis Duran <jlduran@gmail.com>
|
||||
Josh Soref <jsoref@users.noreply.github.com>
|
||||
Joshua M. Clulow <josh@sysmgr.org>
|
||||
José Luis Salvador Rufo <salvador.joseluis@gmail.com>
|
||||
João Carlos Mendes Luís <jonny@jonny.eng.br>
|
||||
Julian Brunner <julian.brunner@gmail.com>
|
||||
Julian Heuking <JulianH@beckhoff.com>
|
||||
jumbi77 <jumbi77@users.noreply.github.com>
|
||||
Justin Bedő <cu@cua0.org>
|
||||
Justin Gottula <justin@jgottula.com>
|
||||
Justin Hibbits <chmeeedalf@gmail.com>
|
||||
Justin Keogh <github.com@v6y.net>
|
||||
Justin Lecher <jlec@gentoo.org>
|
||||
Justin Scholz <git@justinscholz.de>
|
||||
Justin T. Gibbs <gibbs@FreeBSD.org>
|
||||
jyxent <jordanp@gmail.com>
|
||||
Jörg Thalheim <joerg@higgsboson.tk>
|
||||
ka7 <ka7@la-evento.com>
|
||||
Ka Ho Ng <khng@FreeBSD.org>
|
||||
KORN Andras <korn@elan.rulez.org>
|
||||
Kamil Domański <kamil@domanski.co>
|
||||
Karsten Kretschmer <kkretschmer@gmail.com>
|
||||
Kash Pande <kash@tripleback.net>
|
||||
Kay Pedersen <christianpe96@gmail.com>
|
||||
Keith M Wesolowski <wesolows@foobazco.org>
|
||||
Kent Ross <k@mad.cash>
|
||||
KernelOfTruth <kerneloftruth@gmail.com>
|
||||
Kevin Bowling <kevin.bowling@kev009.com>
|
||||
Kevin Greene <kevin.greene@delphix.com>
|
||||
Kevin Jin <lostking2008@hotmail.com>
|
||||
Kevin P. Fleming <kevin@km6g.us>
|
||||
Kevin Tanguy <kevin.tanguy@ovh.net>
|
||||
KireinaHoro <i@jsteward.moe>
|
||||
Kjeld Schouten-Lebbing <kjeld@schouten-lebbing.nl>
|
||||
Kleber Tarcísio <klebertarcisio@yahoo.com.br>
|
||||
Kody A Kantor <kody.kantor@gmail.com>
|
||||
Kohsuke Kawaguchi <kk@kohsuke.org>
|
||||
Konstantin Khorenko <khorenko@virtuozzo.com>
|
||||
KORN Andras <korn@elan.rulez.org>
|
||||
Kristof Provost <github@sigsegv.be>
|
||||
Krzysztof Piecuch <piecuch@kpiecuch.pl>
|
||||
Kyle Blatter <kyleblatter@llnl.gov>
|
||||
Kyle Evans <kevans@FreeBSD.org>
|
||||
Kyle Fuller <inbox@kylefuller.co.uk>
|
||||
Laevos <Laevos@users.noreply.github.com>
|
||||
Lalufu <Lalufu@users.noreply.github.com>
|
||||
Lars Johannsen <laj@it.dk>
|
||||
Laura Hild <lsh@jlab.org>
|
||||
Laurențiu Nicola <lnicola@dend.ro>
|
||||
Lauri Tirkkonen <lauri@hacktheplanet.fi>
|
||||
liaoyuxiangqin <guo.yong33@zte.com.cn>
|
||||
Li Dongyang <dongyang.li@anu.edu.au>
|
||||
Liu Hua <liu.hua130@zte.com.cn>
|
||||
Liu Qing <winglq@gmail.com>
|
||||
Li Wei <W.Li@Sun.COM>
|
||||
Loli <ezomori.nozomu@gmail.com>
|
||||
lorddoskias <lorddoskias@gmail.com>
|
||||
Lorenz Brun <lorenz@dolansoft.org>
|
||||
Lorenz Hüdepohl <dev@stellardeath.org>
|
||||
louwrentius <louwrentius@gmail.com>
|
||||
Lars Johannsen <laj@it.dk>
|
||||
Li Dongyang <dongyang.li@anu.edu.au>
|
||||
Li Wei <W.Li@Sun.COM>
|
||||
Lukas Wunner <lukas@wunner.de>
|
||||
luozhengzheng <luo.zhengzheng@zte.com.cn>
|
||||
Luís Henriques <henrix@camandro.org>
|
||||
Madhav Suresh <madhav.suresh@delphix.com>
|
||||
manfromafar <jonsonb10@gmail.com>
|
||||
Manoj Joseph <manoj.joseph@delphix.com>
|
||||
Manuel Amador (Rudd-O) <rudd-o@rudd-o.com>
|
||||
Marcel Huber <marcelhuberfoo@gmail.com>
|
||||
Marcel Menzel <mail@mcl.gg>
|
||||
Marcel Schilling <marcel.schilling@uni-luebeck.de>
|
||||
Marcel Telka <marcel.telka@nexenta.com>
|
||||
Marcel Wysocki <maci.stgn@gmail.com>
|
||||
Marcin Skarbek <git@skarbek.name>
|
||||
Mariusz Zaborski <mariusz.zaborski@klarasystems.com>
|
||||
Mark Johnston <markj@FreeBSD.org>
|
||||
Mark Maybee <mark.maybee@delphix.com>
|
||||
Mark Roper <markroper@gmail.com>
|
||||
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
|
||||
marku89 <mar42@kola.li>
|
||||
Mark Wright <markwright@internode.on.net>
|
||||
Mart Frauenlob <allkind@fastest.cc>
|
||||
Martin Matuska <mm@FreeBSD.org>
|
||||
Martin Rüegg <martin.rueegg@metaworx.ch>
|
||||
Martin Wagner <martin.wagner.dev@gmail.com>
|
||||
Massimo Maggi <me@massimo-maggi.eu>
|
||||
Mateusz Guzik <mjguzik@gmail.com>
|
||||
Mateusz Piotrowski <0mp@FreeBSD.org>
|
||||
Mathieu Velten <matmaul@gmail.com>
|
||||
Matt Fiddaman <github@m.fiddaman.uk>
|
||||
Matthew Ahrens <matt@delphix.com>
|
||||
Matthew Thode <mthode@mthode.org>
|
||||
Matthias Blankertz <matthias@blankertz.org>
|
||||
Matt Johnston <matt@fugro-fsi.com.au>
|
||||
Matt Kemp <matt@mattikus.com>
|
||||
Matt Macy <mmacy@freebsd.org>
|
||||
Matthew Ahrens <matt@delphix.com>
|
||||
Matthew Thode <mthode@mthode.org>
|
||||
Matus Kral <matuskral@me.com>
|
||||
Mauricio Faria de Oliveira <mfo@canonical.com>
|
||||
Max Grossman <max.grossman@delphix.com>
|
||||
Maxim Filimonov <che@bein.link>
|
||||
Maximilian Mehnert <maximilian.mehnert@gmx.de>
|
||||
Max Zettlmeißl <max@zettlmeissl.de>
|
||||
Md Islam <mdnahian@outlook.com>
|
||||
megari <megari@iki.fi>
|
||||
Michael D Labriola <michael.d.labriola@gmail.com>
|
||||
Michael Franzl <michael@franzl.name>
|
||||
Michael Gebetsroither <michael@mgeb.org>
|
||||
Michael Kjorling <michael@kjorling.se>
|
||||
Michael Martin <mgmartin.mgm@gmail.com>
|
||||
Michael Niewöhner <foss@mniewoehner.de>
|
||||
Michael Zhivich <mzhivich@akamai.com>
|
||||
Michal Vasilek <michal@vasilek.cz>
|
||||
MigeljanImeri <ImeriMigel@gmail.com>
|
||||
Mike Gerdts <mike.gerdts@joyent.com>
|
||||
Mike Harsch <mike@harschsystems.com>
|
||||
Mike Leddy <mike.leddy@gmail.com>
|
||||
Mike Swanson <mikeonthecomputer@gmail.com>
|
||||
Milan Jurik <milan.jurik@xylab.cz>
|
||||
Minsoo Choo <minsoochoo0122@proton.me>
|
||||
Mohamed Tawfik <m_tawfik@aucegypt.edu>
|
||||
Morgan Jones <mjones@rice.edu>
|
||||
Moritz Maxeiner <moritz@ucworks.org>
|
||||
Mo Zhou <cdluminate@gmail.com>
|
||||
naivekun <naivekun@outlook.com>
|
||||
nathancheek <myself@nathancheek.com>
|
||||
Nathaniel Clark <Nathaniel.Clark@misrule.us>
|
||||
Nathaniel Wesley Filardo <nwf@cs.jhu.edu>
|
||||
Nathan Lewis <linux.robotdude@gmail.com>
|
||||
Nav Ravindranath <nav@delphix.com>
|
||||
Neal Gompa (ニール・ゴンパ) <ngompa13@gmail.com>
|
||||
Ned Bass <bass6@llnl.gov>
|
||||
Neependra Khare <neependra@kqinfotech.com>
|
||||
Neil Stockbridge <neil@dist.ro>
|
||||
Nick Black <dank@qemfd.net>
|
||||
Nick Garvey <garvey.nick@gmail.com>
|
||||
Nick Mattis <nickm970@gmail.com>
|
||||
Nick Terrell <terrelln@fb.com>
|
||||
Niklas Haas <github-c6e1c8@haasn.xyz>
|
||||
Nikolay Borisov <n.borisov.lkml@gmail.com>
|
||||
nordaux <nordaux@gmail.com>
|
||||
ofthesun9 <olivier@ofthesun.net>
|
||||
Olaf Faaland <faaland1@llnl.gov>
|
||||
Oleg Drokin <green@linuxhacker.ru>
|
||||
Oleg Stepura <oleg@stepura.com>
|
||||
Olivier Certner <olce.freebsd@certner.fr>
|
||||
Olivier Mazouffre <olivier.mazouffre@ims-bordeaux.fr>
|
||||
omni <omni+vagant@hack.org>
|
||||
Orivej Desh <orivej@gmx.fr>
|
||||
Pablo Correa Gómez <ablocorrea@hotmail.com>
|
||||
Palash Gandhi <pbg4930@rit.edu>
|
||||
Patrick Mooney <pmooney@pfmooney.com>
|
||||
Patrik Greco <sikevux@sikevux.se>
|
||||
Paul B. Henson <henson@acm.org>
|
||||
Paul Dagnelie <pcd@delphix.com>
|
||||
Paul Zuchowski <pzuchowski@datto.com>
|
||||
Pavel Boldin <boldin.pavel@gmail.com>
|
||||
Pavel Snajdr <snajpa@snajpa.net>
|
||||
Pavel Zakharov <pavel.zakharov@delphix.com>
|
||||
Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
Pedro Giffuni <pfg@freebsd.org>
|
||||
Peng <peng.hse@xtaotech.com>
|
||||
Peter Ashford <ashford@accs.com>
|
||||
Peter Dave Hello <hsu@peterdavehello.org>
|
||||
Peter Doherty <peterd@acranox.org>
|
||||
Peter Levine <plevine457@gmail.com>
|
||||
Peter Wirdemo <peter.wirdemo@gmail.com>
|
||||
Petros Koutoupis <petros@petroskoutoupis.com>
|
||||
Philip Pokorny <ppokorny@penguincomputing.com>
|
||||
Philipp Riederer <pt@philipptoelke.de>
|
||||
Phil Kauffman <philip@kauffman.me>
|
||||
Ping Huang <huangping@smartx.com>
|
||||
Piotr Kubaj <pkubaj@anongoth.pl>
|
||||
Piotr P. Stefaniak <pstef@freebsd.org>
|
||||
Prakash Surya <prakash.surya@delphix.com>
|
||||
Prasad Joshi <prasadjoshi124@gmail.com>
|
||||
privb0x23 <privb0x23@users.noreply.github.com>
|
||||
P.SCH <p88@yahoo.com>
|
||||
Qiuhao Chen <chenqiuhao1997@gmail.com>
|
||||
Quartz <yyhran@163.com>
|
||||
Quentin Zdanis <zdanisq@gmail.com>
|
||||
Rafael Kitover <rkitover@gmail.com>
|
||||
RageLtMan <sempervictus@users.noreply.github.com>
|
||||
Ralf Ertzinger <ralf@skytale.net>
|
||||
Randall Mason <ClashTheBunny@gmail.com>
|
||||
Remy Blank <remy.blank@pobox.com>
|
||||
renelson <bnelson@nelsonbe.com>
|
||||
Reno Reckling <e-github@wthack.de>
|
||||
Ricardo M. Correia <ricardo.correia@oracle.com>
|
||||
Riccardo Schirone <rschirone91@gmail.com>
|
||||
Richard Allen <belperite@gmail.com>
|
||||
Rich Ercolani <rincebrain@gmail.com>
|
||||
Richard Elling <Richard.Elling@RichardElling.com>
|
||||
Richard Kojedzinszky <richard@kojedz.in>
|
||||
Richard Laager <rlaager@wiktel.com>
|
||||
Richard Lowe <richlowe@richlowe.net>
|
||||
Richard Sharpe <rsharpe@samba.org>
|
||||
Richard Yao <ryao@gentoo.org>
|
||||
Rich Ercolani <rincebrain@gmail.com>
|
||||
Rick Macklem <rmacklem@uoguelph.ca>
|
||||
rilysh <nightquick@proton.me>
|
||||
Robert Evans <evansr@google.com>
|
||||
Robert Novak <sailnfool@gmail.com>
|
||||
Roberto Ricci <ricci@disroot.org>
|
||||
Rob Norris <robn@despairlabs.com>
|
||||
Rob Wing <rew@FreeBSD.org>
|
||||
Rohan Puri <rohan.puri15@gmail.com>
|
||||
Romain Dolbeau <romain.dolbeau@atos.net>
|
||||
Roman Strashkin <roman.strashkin@nexenta.com>
|
||||
Ross Williams <ross@ross-williams.net>
|
||||
Ruben Kerkhof <ruben@rubenkerkhof.com>
|
||||
Ryan <errornointernet@envs.net>
|
||||
Ryan Hirasaki <ryanhirasaki@gmail.com>
|
||||
Ryan Lahfa <masterancpp@gmail.com>
|
||||
Ryan Libby <rlibby@FreeBSD.org>
|
||||
Ryan Moeller <freqlabs@FreeBSD.org>
|
||||
Sam Atkinson <samatk@amazon.com>
|
||||
Sam Hathaway <github.com@munkynet.org>
|
||||
Sam James <sam@gentoo.org>
|
||||
Sam Lunt <samuel.j.lunt@gmail.com>
|
||||
Samuel VERSCHELDE <stormi-github@ylix.fr>
|
||||
Samuel Wycliffe <samuelwycliffe@gmail.com>
|
||||
Samuel Wycliffe J <samwyc@hpe.com>
|
||||
Sanjeev Bagewadi <sanjeev.bagewadi@gmail.com>
|
||||
Sara Hartse <sara.hartse@delphix.com>
|
||||
Saso Kiselkov <saso.kiselkov@nexenta.com>
|
||||
Satadru Pramanik <satadru@gmail.com>
|
||||
Savyasachee Jha <genghizkhan91@hawkradius.com>
|
||||
Scott Colby <scott@scolby.com>
|
||||
Scot W. Stevenson <scot.stevenson@gmail.com>
|
||||
Sean Eric Fagan <sef@ixsystems.com>
|
||||
Sebastian Gottschall <s.gottschall@dd-wrt.com>
|
||||
Sebastien Roy <seb@delphix.com>
|
||||
Sen Haerens <sen@senhaerens.be>
|
||||
Serapheim Dimitropoulos <serapheim@delphix.com>
|
||||
Seth Forshee <seth.forshee@canonical.com>
|
||||
Seth Troisi <sethtroisi@google.com>
|
||||
Shaan Nobee <sniper111@gmail.com>
|
||||
Shampavman <sham.pavman@nexenta.com>
|
||||
Shaun Tancheff <shaun@aeonazure.com>
|
||||
Shawn Bayern <sbayern@law.fsu.edu>
|
||||
Shengqi Chen <harry-chen@outlook.com>
|
||||
Shen Yan <shenyanxxxy@qq.com>
|
||||
Simon Guest <simon.guest@tesujimath.org>
|
||||
Simon Klinkert <simon.klinkert@gmail.com>
|
||||
Sowrabha Gopal <sowrabha.gopal@delphix.com>
|
||||
Spencer Kinny <spencerkinny1995@gmail.com>
|
||||
Srikanth N S <srikanth.nagasubbaraoseetharaman@hpe.com>
|
||||
Stanislav Seletskiy <s.seletskiy@gmail.com>
|
||||
Stefan Lendl <s.lendl@proxmox.com>
|
||||
Steffen Müthing <steffen.muething@iwr.uni-heidelberg.de>
|
||||
Stephen Blinick <stephen.blinick@delphix.com>
|
||||
sterlingjensen <sterlingjensen@users.noreply.github.com>
|
||||
Steve Dougherty <sdougherty@barracuda.com>
|
||||
Steve Mokris <smokris@softpixel.com>
|
||||
Steven Burgess <sburgess@dattobackup.com>
|
||||
Steven Hartland <smh@freebsd.org>
|
||||
Steven Johnson <sjohnson@sakuraindustries.com>
|
||||
Steven Noonan <steven@uplinklabs.net>
|
||||
stf <s@ctrlc.hu>
|
||||
Stian Ellingsen <stian@plaimi.net>
|
||||
Stoiko Ivanov <github@nomore.at>
|
||||
Stéphane Lesimple <speed47_github@speed47.net>
|
||||
Suman Chakravartula <schakrava@gmail.com>
|
||||
Sydney Vanda <sydney.m.vanda@intel.com>
|
||||
Sören Tempel <soeren+git@soeren-tempel.net>
|
||||
Tamas TEVESZ <ice@extreme.hu>
|
||||
Teodor Spæren <teodor_spaeren@riseup.net>
|
||||
TerraTech <TerraTech@users.noreply.github.com>
|
||||
Thijs Cramer <thijs.cramer@gmail.com>
|
||||
Thomas Bertschinger <bertschinger@lanl.gov>
|
||||
Thomas Geppert <geppi@digitx.de>
|
||||
Thomas Lamprecht <guggentom@hotmail.de>
|
||||
Till Maas <opensource@till.name>
|
||||
Tim Chase <tim@chase2k.com>
|
||||
Tim Connors <tconnors@rather.puzzling.org>
|
||||
Tim Crawford <tcrawford@datto.com>
|
||||
Tim Haley <Tim.Haley@Sun.COM>
|
||||
timor <timor.dd@googlemail.com>
|
||||
Timothy Day <tday141@gmail.com>
|
||||
Tim Schumacher <timschumi@gmx.de>
|
||||
Tino Reichardt <milky-zfs@mcmilk.de>
|
||||
Tobin Harding <me@tobin.cc>
|
||||
Todd Seidelmann <seidelma@users.noreply.github.com>
|
||||
Tom Caputi <tcaputi@datto.com>
|
||||
Tom Matthews <tom@axiom-partners.com>
|
||||
Tomohiro Kusumi <kusumi.tomohiro@gmail.com>
|
||||
Tom Prince <tom.prince@ualberta.net>
|
||||
Tomohiro Kusumi <kusumi.tomohiro@gmail.com>
|
||||
Tony Hutter <hutter2@llnl.gov>
|
||||
Tony Nguyen <tony.nguyen@delphix.com>
|
||||
Tony Perkins <tperkins@datto.com>
|
||||
Toomas Soome <tsoome@me.com>
|
||||
Torsten Wörtwein <twoertwein@gmail.com>
|
||||
Toyam Cox <aviator45003@gmail.com>
|
||||
Trevor Bautista <trevrb@trevrb.net>
|
||||
Trey Dockendorf <treydock@gmail.com>
|
||||
Troels Nørgaard <tnn@tradeshift.com>
|
||||
Tulsi Jain <tulsi.jain@delphix.com>
|
||||
Turbo Fredriksson <turbo@bayour.com>
|
||||
Tyler J. Stachecki <stachecki.tyler@gmail.com>
|
||||
Umer Saleem <usaleem@ixsystems.com>
|
||||
Vaibhav Bhanawat <vaibhav.bhanawat@delphix.com>
|
||||
Valmiky Arquissandas <kayvlim@gmail.com>
|
||||
Val Packett <val@packett.cool>
|
||||
Vince van Oosten <techhazard@codeforyouand.me>
|
||||
Violet Purcell <vimproved@inventati.org>
|
||||
Vipin Kumar Verma <vipin.verma@hpe.com>
|
||||
Vitaut Bajaryn <vitaut.bayaryn@gmail.com>
|
||||
Volker Mauel <volkermauel@gmail.com>
|
||||
Václav Skála <skala@vshosting.cz>
|
||||
Walter Huf <hufman@gmail.com>
|
||||
Warner Losh <imp@bsdimp.com>
|
||||
Weigang Li <weigang.li@intel.com>
|
||||
WHR <msl0000023508@gmail.com>
|
||||
Will Andrews <will@freebsd.org>
|
||||
Will Rouesnel <w.rouesnel@gmail.com>
|
||||
Windel Bouwman <windel@windel.nl>
|
||||
Wojciech Małota-Wójcik <outofforest@users.noreply.github.com>
|
||||
Wolfgang Bumiller <w.bumiller@proxmox.com>
|
||||
Xin Li <delphij@FreeBSD.org>
|
||||
Xinliang Liu <xinliang.liu@linaro.org>
|
||||
xtouqh <xtouqh@hotmail.com>
|
||||
Yann Collet <cyan@fb.com>
|
||||
Yanping Gao <yanping.gao@xtaotech.com>
|
||||
Ying Zhu <casualfisher@gmail.com>
|
||||
Youzhong Yang <youzhong@gmail.com>
|
||||
yparitcher <y@paritcher.com>
|
||||
yuina822 <ayuichi@club.kyutech.ac.jp>
|
||||
YunQiang Su <syq@debian.org>
|
||||
Yuri Pankov <yuri.pankov@gmail.com>
|
||||
Yuxin Wang <yuxinwang9999@gmail.com>
|
||||
Yuxuan Shui <yshuiv7@gmail.com>
|
||||
Zachary Bedell <zac@thebedells.org>
|
||||
Zach Dykstra <dykstra.zachary@gmail.com>
|
||||
zgock <zgock@nuc.base.zgock-lab.net>
|
||||
Zhao Yongming <zym@apache.org>
|
||||
Zhenlei Huang <zlei@FreeBSD.org>
|
||||
Zhu Chuang <chuang@melty.land>
|
||||
Érico Nogueira <erico.erc@gmail.com>
|
||||
Đoàn Trần Công Danh <congdanhqx@gmail.com>
|
||||
韩朴宇 <w12101111@gmail.com>
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
The [OpenZFS Code of Conduct](https://openzfs.org/wiki/Code_of_Conduct)
|
||||
The [OpenZFS Code of Conduct](http://www.open-zfs.org/wiki/Code_of_Conduct)
|
||||
applies to spaces associated with the OpenZFS project, including GitHub.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
Meta: 1
|
||||
Name: zfs
|
||||
Branch: 1.0
|
||||
Version: 2.2.9
|
||||
Version: 2.0.6
|
||||
Release: 1
|
||||
Release-Tags: relext
|
||||
License: CDDL
|
||||
Author: OpenZFS
|
||||
Linux-Maximum: 6.17
|
||||
Linux-Minimum: 4.18
|
||||
Linux-Maximum: 5.14
|
||||
Linux-Minimum: 3.10
|
||||
|
||||
+154
-98
@@ -1,82 +1,66 @@
|
||||
CLEANFILES =
|
||||
dist_noinst_DATA =
|
||||
INSTALL_DATA_HOOKS =
|
||||
ALL_LOCAL =
|
||||
CLEAN_LOCAL =
|
||||
CHECKS = shellcheck checkbashisms
|
||||
|
||||
include $(top_srcdir)/config/Rules.am
|
||||
include $(top_srcdir)/config/CppCheck.am
|
||||
include $(top_srcdir)/config/Shellcheck.am
|
||||
include $(top_srcdir)/config/Substfiles.am
|
||||
include $(top_srcdir)/scripts/Makefile.am
|
||||
|
||||
ACLOCAL_AMFLAGS = -I config
|
||||
|
||||
SUBDIRS = include
|
||||
if BUILD_LINUX
|
||||
include $(srcdir)/%D%/rpm/Makefile.am
|
||||
SUBDIRS += rpm
|
||||
endif
|
||||
|
||||
if CONFIG_USER
|
||||
include $(srcdir)/%D%/cmd/Makefile.am
|
||||
include $(srcdir)/%D%/contrib/Makefile.am
|
||||
include $(srcdir)/%D%/etc/Makefile.am
|
||||
include $(srcdir)/%D%/lib/Makefile.am
|
||||
include $(srcdir)/%D%/man/Makefile.am
|
||||
include $(srcdir)/%D%/tests/Makefile.am
|
||||
SUBDIRS += etc man scripts lib tests cmd contrib
|
||||
if BUILD_LINUX
|
||||
include $(srcdir)/%D%/udev/Makefile.am
|
||||
SUBDIRS += udev
|
||||
endif
|
||||
endif
|
||||
CPPCHECKDIRS += module
|
||||
if CONFIG_KERNEL
|
||||
SUBDIRS += module
|
||||
|
||||
extradir = $(prefix)/src/zfs-$(VERSION)
|
||||
extra_HEADERS = zfs.release.in zfs_config.h.in
|
||||
|
||||
if BUILD_LINUX
|
||||
kerneldir = $(prefix)/src/zfs-$(VERSION)/$(LINUX_VERSION)
|
||||
nodist_kernel_HEADERS = zfs.release zfs_config.h module/$(LINUX_SYMBOLS)
|
||||
endif
|
||||
endif
|
||||
|
||||
dist_noinst_DATA += autogen.sh copy-builtin
|
||||
dist_noinst_DATA += AUTHORS CODE_OF_CONDUCT.md COPYRIGHT LICENSE META NEWS NOTICE
|
||||
dist_noinst_DATA += README.md RELEASES.md
|
||||
dist_noinst_DATA += module/lua/README.zfs module/os/linux/spl/README.md
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
EXTRA_DIST = autogen.sh copy-builtin
|
||||
EXTRA_DIST += config/config.awk config/rpm.am config/deb.am config/tgz.am
|
||||
EXTRA_DIST += META AUTHORS COPYRIGHT LICENSE NEWS NOTICE README.md
|
||||
EXTRA_DIST += CODE_OF_CONDUCT.md
|
||||
EXTRA_DIST += module/lua/README.zfs module/os/linux/spl/README.md
|
||||
|
||||
# Include all the extra licensing information for modules
|
||||
dist_noinst_DATA += module/icp/algs/skein/THIRDPARTYLICENSE
|
||||
dist_noinst_DATA += module/icp/algs/skein/THIRDPARTYLICENSE.descrip
|
||||
dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman
|
||||
dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman.descrip
|
||||
dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl
|
||||
dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl.descrip
|
||||
dist_noinst_DATA += module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.cryptogams
|
||||
dist_noinst_DATA += module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.cryptogams.descrip
|
||||
dist_noinst_DATA += module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.openssl
|
||||
dist_noinst_DATA += module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.openssl.descrip
|
||||
dist_noinst_DATA += module/os/linux/spl/THIRDPARTYLICENSE.gplv2
|
||||
dist_noinst_DATA += module/os/linux/spl/THIRDPARTYLICENSE.gplv2.descrip
|
||||
dist_noinst_DATA += module/zfs/THIRDPARTYLICENSE.cityhash
|
||||
dist_noinst_DATA += module/zfs/THIRDPARTYLICENSE.cityhash.descrip
|
||||
EXTRA_DIST += module/icp/algs/skein/THIRDPARTYLICENSE
|
||||
EXTRA_DIST += module/icp/algs/skein/THIRDPARTYLICENSE.descrip
|
||||
EXTRA_DIST += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman
|
||||
EXTRA_DIST += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman.descrip
|
||||
EXTRA_DIST += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl
|
||||
EXTRA_DIST += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl.descrip
|
||||
EXTRA_DIST += module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.cryptogams
|
||||
EXTRA_DIST += module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.cryptogams.descrip
|
||||
EXTRA_DIST += module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.openssl
|
||||
EXTRA_DIST += module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.openssl.descrip
|
||||
EXTRA_DIST += module/os/linux/spl/THIRDPARTYLICENSE.gplv2
|
||||
EXTRA_DIST += module/os/linux/spl/THIRDPARTYLICENSE.gplv2.descrip
|
||||
EXTRA_DIST += module/zfs/THIRDPARTYLICENSE.cityhash
|
||||
EXTRA_DIST += module/zfs/THIRDPARTYLICENSE.cityhash.descrip
|
||||
|
||||
@CODE_COVERAGE_RULES@
|
||||
|
||||
GITREV = include/zfs_gitrev.h
|
||||
CLEANFILES += $(GITREV)
|
||||
PHONY += gitrev
|
||||
|
||||
PHONY = gitrev
|
||||
gitrev:
|
||||
$(AM_V_GEN)$(top_srcdir)/scripts/make_gitrev.sh $(GITREV)
|
||||
|
||||
all: gitrev
|
||||
|
||||
PHONY += install-data-hook $(INSTALL_DATA_HOOKS)
|
||||
install-data-hook: $(INSTALL_DATA_HOOKS)
|
||||
|
||||
PHONY += maintainer-clean-local
|
||||
maintainer-clean-local:
|
||||
# Double-colon rules are allowed; there are multiple independent definitions.
|
||||
maintainer-clean-local::
|
||||
-$(RM) $(GITREV)
|
||||
|
||||
PHONY += distclean-local
|
||||
distclean-local:
|
||||
distclean-local::
|
||||
-$(RM) -R autom4te*.cache build
|
||||
-find . \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \
|
||||
-o -name .pc -o -name .hg -o -name .git \) -prune -o \
|
||||
@@ -86,105 +70,177 @@ distclean-local:
|
||||
-o -name 'core' -o -name 'Makefile' -o -name 'Module.symvers' \
|
||||
-o -name '*.order' -o -name '*.markers' -o -name '*.gcda' \
|
||||
-o -name '*.gcno' \) \
|
||||
-type f -delete
|
||||
-type f -print | xargs $(RM)
|
||||
|
||||
PHONY += $(CLEAN_LOCAL)
|
||||
clean-local: $(CLEAN_LOCAL)
|
||||
|
||||
PHONY += $(ALL_LOCAL)
|
||||
all-local: $(ALL_LOCAL)
|
||||
all-local:
|
||||
-[ -x ${top_builddir}/scripts/zfs-tests.sh ] && \
|
||||
${top_builddir}/scripts/zfs-tests.sh -c
|
||||
|
||||
dist-hook:
|
||||
$(top_srcdir)/scripts/make_gitrev.sh -D $(distdir) $(GITREV)
|
||||
$(SED) $(ac_inplace) 's/\(Release:[[:space:]]*\).*/\1$(RELEASE)/' $(distdir)/META
|
||||
$(AM_V_GEN)$(top_srcdir)/scripts/make_gitrev.sh -D $(distdir) $(GITREV)
|
||||
$(SED) ${ac_inplace} -e 's/Release:[[:print:]]*/Release: $(RELEASE)/' \
|
||||
$(distdir)/META
|
||||
|
||||
PHONY += codecheck $(CHECKS)
|
||||
codecheck: $(CHECKS)
|
||||
if BUILD_LINUX
|
||||
# For compatibility, create a matching spl-x.y.z directly which contains
|
||||
# symlinks to the updated header and object file locations. These
|
||||
# compatibility links will be removed in the next major release.
|
||||
if CONFIG_KERNEL
|
||||
install-data-hook:
|
||||
rm -rf $(DESTDIR)$(prefix)/src/spl-$(VERSION) && \
|
||||
mkdir $(DESTDIR)$(prefix)/src/spl-$(VERSION) && \
|
||||
cd $(DESTDIR)$(prefix)/src/spl-$(VERSION) && \
|
||||
ln -s ../zfs-$(VERSION)/include/spl include && \
|
||||
ln -s ../zfs-$(VERSION)/$(LINUX_VERSION) $(LINUX_VERSION) && \
|
||||
ln -s ../zfs-$(VERSION)/zfs_config.h.in spl_config.h.in && \
|
||||
ln -s ../zfs-$(VERSION)/zfs.release.in spl.release.in && \
|
||||
cd $(DESTDIR)$(prefix)/src/zfs-$(VERSION)/$(LINUX_VERSION) && \
|
||||
ln -fs zfs_config.h spl_config.h && \
|
||||
ln -fs zfs.release spl.release
|
||||
endif
|
||||
endif
|
||||
|
||||
SHELLCHECKSCRIPTS += autogen.sh
|
||||
PHONY += codecheck
|
||||
codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck
|
||||
|
||||
PHONY += checkstyle
|
||||
checkstyle: codecheck commitcheck
|
||||
|
||||
PHONY += commitcheck
|
||||
commitcheck:
|
||||
$(AM_V_at)if git rev-parse --git-dir > /dev/null 2>&1; then \
|
||||
@if git rev-parse --git-dir > /dev/null 2>&1; then \
|
||||
${top_srcdir}/scripts/commitcheck.sh; \
|
||||
fi
|
||||
|
||||
if HAVE_PARALLEL
|
||||
cstyle_line = -print0 | parallel -X0 ${top_srcdir}/scripts/cstyle.pl -cpP {}
|
||||
else
|
||||
cstyle_line = -exec ${top_srcdir}/scripts/cstyle.pl -cpP {} +
|
||||
endif
|
||||
CHECKS += cstyle
|
||||
PHONY += cstyle
|
||||
cstyle:
|
||||
$(AM_V_at)find $(top_srcdir) -name build -prune \
|
||||
@find ${top_srcdir} -name build -prune \
|
||||
-o -type f -name '*.[hc]' \
|
||||
! -name 'zfs_config.*' ! -name '*.mod.c' \
|
||||
! -name 'opt_global.h' ! -name '*_if*.h' \
|
||||
! -name 'zstd_compat_wrapper.h' \
|
||||
! -path './module/zstd/lib/*' \
|
||||
! -path './include/sys/lua/*' \
|
||||
! -path './module/lua/l*.[ch]' \
|
||||
! -path './module/zfs/lz4.c' \
|
||||
$(cstyle_line)
|
||||
-exec ${top_srcdir}/scripts/cstyle.pl -cpP {} \+
|
||||
|
||||
filter_executable = -exec test -x '{}' \; -print
|
||||
CHECKS += testscheck
|
||||
testscheck:
|
||||
$(AM_V_at)[ $$(find $(top_srcdir)/tests/zfs-tests -type f \
|
||||
\( -name '*.ksh' -not $(filter_executable) \) -o \
|
||||
\( -name '*.kshlib' $(filter_executable) \) -o \
|
||||
\( -name '*.shlib' $(filter_executable) \) -o \
|
||||
\( -name '*.cfg' $(filter_executable) \) | \
|
||||
tee /dev/stderr | wc -l) -eq 0 ]
|
||||
|
||||
CHECKS += vcscheck
|
||||
PHONY += shellcheck
|
||||
shellcheck:
|
||||
@if type shellcheck > /dev/null 2>&1; then \
|
||||
shellcheck --exclude=SC1090 --exclude=SC1117 --format=gcc \
|
||||
$$(find ${top_srcdir}/scripts/*.sh -type f) \
|
||||
$$(find ${top_srcdir}/cmd/zed/zed.d/*.sh -type f) \
|
||||
$$(find ${top_srcdir}/cmd/zpool/zpool.d/* \
|
||||
-type f ${filter_executable}); \
|
||||
else \
|
||||
echo "skipping shellcheck because shellcheck is not installed"; \
|
||||
fi
|
||||
|
||||
PHONY += checkabi storeabi
|
||||
checkabi: lib
|
||||
$(MAKE) -C lib checkabi
|
||||
|
||||
storeabi: lib
|
||||
$(MAKE) -C lib storeabi
|
||||
|
||||
PHONY += checkbashisms
|
||||
checkbashisms:
|
||||
@if type checkbashisms > /dev/null 2>&1; then \
|
||||
checkbashisms -n -p -x \
|
||||
$$(find ${top_srcdir} \
|
||||
-name '.git' -prune \
|
||||
-o -name 'build' -prune \
|
||||
-o -name 'tests' -prune \
|
||||
-o -name 'config' -prune \
|
||||
-o -name 'zed-functions.sh*' -prune \
|
||||
-o -name 'zfs-import*' -prune \
|
||||
-o -name 'zfs-mount*' -prune \
|
||||
-o -name 'zfs-zed*' -prune \
|
||||
-o -name 'smart' -prune \
|
||||
-o -name 'paxcheck.sh' -prune \
|
||||
-o -name 'make_gitrev.sh' -prune \
|
||||
-o -name '90zfs' -prune \
|
||||
-o -type f ! -name 'config*' \
|
||||
! -name 'libtool' \
|
||||
-exec sh -c 'awk "NR==1 && /#!.*bin\/sh.*/ {print FILENAME;}" "{}"' \;); \
|
||||
else \
|
||||
echo "skipping checkbashisms because checkbashisms is not installed"; \
|
||||
fi
|
||||
|
||||
PHONY += mancheck
|
||||
mancheck:
|
||||
@if type mandoc > /dev/null 2>&1; then \
|
||||
find ${top_srcdir}/man/man8 -type f -name 'zfs.8' \
|
||||
-o -name 'zpool.8' -o -name 'zdb.8' \
|
||||
-o -name 'zgenhostid.8' | \
|
||||
xargs mandoc -Tlint -Werror; \
|
||||
else \
|
||||
echo "skipping mancheck because mandoc is not installed"; \
|
||||
fi
|
||||
|
||||
if BUILD_LINUX
|
||||
stat_fmt = -c '%A %n'
|
||||
else
|
||||
stat_fmt = -f '%Sp %N'
|
||||
endif
|
||||
|
||||
PHONY += testscheck
|
||||
testscheck:
|
||||
@find ${top_srcdir}/tests/zfs-tests -type f \
|
||||
\( -name '*.ksh' -not ${filter_executable} \) -o \
|
||||
\( -name '*.kshlib' ${filter_executable} \) -o \
|
||||
\( -name '*.shlib' ${filter_executable} \) -o \
|
||||
\( -name '*.cfg' ${filter_executable} \) | \
|
||||
xargs -r stat ${stat_fmt} | \
|
||||
awk '{c++; print} END {if(c>0) exit 1}'
|
||||
|
||||
PHONY += vcscheck
|
||||
vcscheck:
|
||||
$(AM_V_at)if git rev-parse --git-dir > /dev/null 2>&1; then \
|
||||
@if git rev-parse --git-dir > /dev/null 2>&1; then \
|
||||
git ls-files . --exclude-standard --others | \
|
||||
awk '{c++; print} END {if(c>0) exit 1}' ; \
|
||||
fi
|
||||
|
||||
CHECKS += zstdcheck
|
||||
zstdcheck:
|
||||
@$(MAKE) -C module check-zstd-symbols
|
||||
|
||||
PHONY += lint
|
||||
lint: cppcheck paxcheck
|
||||
|
||||
CPPCHECKDIRS = cmd lib module
|
||||
PHONY += cppcheck
|
||||
cppcheck: $(CPPCHECKDIRS)
|
||||
@if test -n "$(CPPCHECK)"; then \
|
||||
set -e ; for dir in $(CPPCHECKDIRS) ; do \
|
||||
$(MAKE) -C $$dir cppcheck ; \
|
||||
done \
|
||||
else \
|
||||
echo "skipping cppcheck because cppcheck is not installed"; \
|
||||
fi
|
||||
|
||||
PHONY += paxcheck
|
||||
paxcheck:
|
||||
$(AM_V_at)if type scanelf > /dev/null 2>&1; then \
|
||||
$(top_srcdir)/scripts/paxcheck.sh $(top_builddir); \
|
||||
@if type scanelf > /dev/null 2>&1; then \
|
||||
${top_srcdir}/scripts/paxcheck.sh ${top_builddir}; \
|
||||
else \
|
||||
echo "skipping paxcheck because scanelf is not installed"; \
|
||||
fi
|
||||
|
||||
CHECKS += flake8
|
||||
PHONY += flake8
|
||||
flake8:
|
||||
$(AM_V_at)if type flake8 > /dev/null 2>&1; then \
|
||||
flake8 $(top_srcdir); \
|
||||
@if type flake8 > /dev/null 2>&1; then \
|
||||
flake8 ${top_srcdir}; \
|
||||
else \
|
||||
echo "skipping flake8 because flake8 is not installed"; \
|
||||
fi
|
||||
|
||||
PHONY += regen-tests
|
||||
regen-tests:
|
||||
@$(MAKE) -C tests/zfs-tests/tests regen
|
||||
|
||||
PHONY += ctags
|
||||
ctags:
|
||||
$(RM) tags
|
||||
find $(top_srcdir) -name '.?*' -prune \
|
||||
-o -type f -name '*.[hcS]' -exec ctags -a {} +
|
||||
-o -type f -name '*.[hcS]' -print | xargs ctags -a
|
||||
|
||||
PHONY += etags
|
||||
etags:
|
||||
$(RM) TAGS
|
||||
find $(top_srcdir) -name '.?*' -prune \
|
||||
-o -type f -name '*.[hcS]' -exec etags -a {} +
|
||||
-o -type f -name '*.[hcS]' -print | xargs etags -a
|
||||
|
||||
PHONY += cscopelist
|
||||
cscopelist:
|
||||
|
||||
@@ -12,7 +12,7 @@ This repository contains the code for running OpenZFS on Linux and FreeBSD.
|
||||
* [Documentation](https://openzfs.github.io/openzfs-docs/) - for using and developing this repo
|
||||
* [ZoL Site](https://zfsonlinux.org) - Linux release info & links
|
||||
* [Mailing lists](https://openzfs.github.io/openzfs-docs/Project%20and%20Community/Mailing%20Lists.html)
|
||||
* [OpenZFS site](https://openzfs.org/) - for conference videos and info on other platforms (illumos, OSX, Windows, etc)
|
||||
* [OpenZFS site](http://open-zfs.org/) - for conference videos and info on other platforms (illumos, OSX, Windows, etc)
|
||||
|
||||
# Installation
|
||||
|
||||
@@ -32,4 +32,4 @@ For more details see the NOTICE, LICENSE and COPYRIGHT files; `UCRL-CODE-235197`
|
||||
|
||||
# Supported Kernels
|
||||
* The `META` file contains the officially recognized supported Linux kernel versions.
|
||||
* Supported FreeBSD versions are any supported branches and releases starting from 13.0-RELEASE.
|
||||
* Supported FreeBSD versions are 12-STABLE and 13-CURRENT.
|
||||
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
OpenZFS uses the MAJOR.MINOR.PATCH versioning scheme described here:
|
||||
|
||||
* MAJOR - Incremented at the discretion of the OpenZFS developers to indicate
|
||||
a particularly noteworthy feature or change. An increase in MAJOR number
|
||||
does not indicate any incompatible on-disk format change. The ability
|
||||
to import a ZFS pool is controlled by the feature flags enabled on the
|
||||
pool and the feature flags supported by the installed OpenZFS version.
|
||||
Increasing the MAJOR version is expected to be an infrequent occurrence.
|
||||
|
||||
* MINOR - Incremented to indicate new functionality such as a new feature
|
||||
flag, pool/dataset property, zfs/zpool sub-command, new user/kernel
|
||||
interface, etc. MINOR releases may introduce incompatible changes to the
|
||||
user space library APIs (libzfs.so). Existing user/kernel interfaces are
|
||||
considered to be stable to maximize compatibility between OpenZFS releases.
|
||||
Additions to the user/kernel interface are backwards compatible.
|
||||
|
||||
* PATCH - Incremented when applying documentation updates, important bug
|
||||
fixes, minor performance improvements, and kernel compatibility patches.
|
||||
The user space library APIs and user/kernel interface are considered to
|
||||
be stable. PATCH releases for a MAJOR.MINOR are published as needed.
|
||||
|
||||
Two release branches are maintained for OpenZFS, they are:
|
||||
|
||||
* OpenZFS LTS - A designated MAJOR.MINOR release with periodic PATCH
|
||||
releases that incorporate important changes backported from newer OpenZFS
|
||||
releases. This branch is intended for use in environments using an
|
||||
LTS, enterprise, or similarly managed kernel (RHEL, Ubuntu LTS, Debian).
|
||||
Minor changes to support these distribution kernels will be applied as
|
||||
needed. New kernel versions released after the OpenZFS LTS release are
|
||||
not supported. LTS releases will receive patches for at least 2 years.
|
||||
The current LTS release is OpenZFS 2.1.
|
||||
|
||||
* OpenZFS current - Tracks the newest MAJOR.MINOR release. This branch
|
||||
includes support for the latest OpenZFS features and recently releases
|
||||
kernels. When a new MINOR release is tagged the previous MINOR release
|
||||
will no longer be maintained (unless it is an LTS release). New MINOR
|
||||
releases are planned to occur roughly annually.
|
||||
+2
-60
@@ -1,62 +1,4 @@
|
||||
#!/bin/sh
|
||||
[ "${0%/*}" = "$0" ] || cd "${0%/*}" || exit
|
||||
|
||||
# %reldir%/%canon_reldir% (%D%/%C%) only appeared in automake 1.14, but RHEL/CentOS 7 has 1.13.4
|
||||
# This is an (overly) simplistic preprocessor that papers around this for the duration of the generation step,
|
||||
# and can be removed once support for CentOS 7 is dropped
|
||||
automake --version | awk '{print $NF; exit}' | (
|
||||
IFS=. read -r AM_MAJ AM_MIN _
|
||||
[ "$AM_MAJ" -gt 1 ] || [ "$AM_MIN" -ge 14 ]
|
||||
) || {
|
||||
process_root() {
|
||||
root="$1"; shift
|
||||
|
||||
grep -q '%[CD]%' "$root/Makefile.am" || return
|
||||
find "$root" -name Makefile.am "$@" | while read -r dir; do
|
||||
dir="${dir%/Makefile.am}"
|
||||
grep -q '%[CD]%' "$dir/Makefile.am" || continue
|
||||
|
||||
reldir="${dir#"$root"}"
|
||||
reldir="${reldir#/}"
|
||||
|
||||
canon_reldir="$(printf '%s' "$reldir" | tr -C 'a-zA-Z0-9@_' '_')"
|
||||
|
||||
reldir_slash="$reldir/"
|
||||
canon_reldir_slash="${canon_reldir}_"
|
||||
[ -z "$reldir" ] && reldir_slash=
|
||||
[ -z "$reldir" ] && canon_reldir_slash=
|
||||
|
||||
echo "$dir/Makefile.am" >&3
|
||||
sed -i~ -e "s:%D%/:$reldir_slash:g" -e "s:%D%:$reldir:g" \
|
||||
-e "s:%C%_:$canon_reldir_slash:g" -e "s:%C%:$canon_reldir:g" "$dir/Makefile.am"
|
||||
done 3>>"$substituted_files"
|
||||
}
|
||||
|
||||
rollback() {
|
||||
while read -r f; do
|
||||
mv "$f~" "$f"
|
||||
done < "$substituted_files"
|
||||
rm -f "$substituted_files"
|
||||
}
|
||||
|
||||
|
||||
echo "Automake <1.14; papering over missing %reldir%/%canon_reldir% support" >&2
|
||||
|
||||
substituted_files="$(mktemp)"
|
||||
trap rollback EXIT
|
||||
|
||||
roots="$(sed '/Makefile$/!d;/module/d;s:^\s*:./:;s:/Makefile::;/^\.$/d' configure.ac)"
|
||||
|
||||
IFS="
|
||||
"
|
||||
for root in $roots; do
|
||||
root="${root#./}"
|
||||
process_root "$root"
|
||||
done
|
||||
|
||||
set -f
|
||||
# shellcheck disable=SC2086,SC2046
|
||||
process_root . $(printf '!\n-path\n%s/*\n' $roots)
|
||||
}
|
||||
|
||||
autoreconf -fiv && rm -rf autom4te.cache
|
||||
autoreconf -fiv || exit 1
|
||||
rm -Rf autom4te.cache
|
||||
|
||||
+14
-110
@@ -1,116 +1,20 @@
|
||||
bin_SCRIPTS =
|
||||
bin_PROGRAMS =
|
||||
sbin_SCRIPTS =
|
||||
sbin_PROGRAMS =
|
||||
dist_bin_SCRIPTS =
|
||||
zfsexec_PROGRAMS =
|
||||
mounthelper_PROGRAMS =
|
||||
|
||||
|
||||
sbin_SCRIPTS += fsck.zfs
|
||||
SHELLCHECKSCRIPTS += fsck.zfs
|
||||
CLEANFILES += fsck.zfs
|
||||
dist_noinst_DATA += %D%/fsck.zfs.in
|
||||
$(call SUBST,fsck.zfs,%D%/)
|
||||
|
||||
|
||||
sbin_PROGRAMS += zfs_ids_to_path
|
||||
CPPCHECKTARGETS += zfs_ids_to_path
|
||||
|
||||
zfs_ids_to_path_SOURCES = \
|
||||
%D%/zfs_ids_to_path.c
|
||||
|
||||
zfs_ids_to_path_LDADD = \
|
||||
libzfs.la
|
||||
|
||||
|
||||
zhack_CPPFLAGS = $(AM_CPPFLAGS) $(FORCEDEBUG_CPPFLAGS)
|
||||
|
||||
sbin_PROGRAMS += zhack
|
||||
CPPCHECKTARGETS += zhack
|
||||
|
||||
zhack_SOURCES = \
|
||||
%D%/zhack.c
|
||||
|
||||
zhack_LDADD = \
|
||||
libzpool.la \
|
||||
libzfs_core.la \
|
||||
libnvpair.la
|
||||
|
||||
|
||||
ztest_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS)
|
||||
# Get rid of compiler warning for unchecked truncating snprintfs on gcc 7.1.1
|
||||
ztest_CFLAGS += $(NO_FORMAT_TRUNCATION)
|
||||
ztest_CPPFLAGS = $(AM_CPPFLAGS) $(FORCEDEBUG_CPPFLAGS)
|
||||
|
||||
sbin_PROGRAMS += ztest
|
||||
CPPCHECKTARGETS += ztest
|
||||
|
||||
ztest_SOURCES = \
|
||||
%D%/ztest.c
|
||||
|
||||
ztest_LDADD = \
|
||||
libzpool.la \
|
||||
libzfs_core.la \
|
||||
libnvpair.la
|
||||
|
||||
ztest_LDADD += -lm
|
||||
ztest_LDFLAGS = -pthread
|
||||
|
||||
|
||||
include $(srcdir)/%D%/raidz_test/Makefile.am
|
||||
include $(srcdir)/%D%/zdb/Makefile.am
|
||||
include $(srcdir)/%D%/zfs/Makefile.am
|
||||
include $(srcdir)/%D%/zinject/Makefile.am
|
||||
include $(srcdir)/%D%/zpool/Makefile.am
|
||||
include $(srcdir)/%D%/zpool_influxdb/Makefile.am
|
||||
include $(srcdir)/%D%/zstream/Makefile.am
|
||||
|
||||
|
||||
if BUILD_LINUX
|
||||
mounthelper_PROGRAMS += mount.zfs
|
||||
CPPCHECKTARGETS += mount.zfs
|
||||
|
||||
mount_zfs_SOURCES = \
|
||||
%D%/mount_zfs.c
|
||||
|
||||
mount_zfs_LDADD = \
|
||||
libzfs.la \
|
||||
libzfs_core.la \
|
||||
libnvpair.la
|
||||
|
||||
mount_zfs_LDADD += $(LTLIBINTL)
|
||||
|
||||
CPPCHECKTARGETS += raidz_test
|
||||
|
||||
|
||||
sbin_PROGRAMS += zgenhostid
|
||||
CPPCHECKTARGETS += zgenhostid
|
||||
|
||||
zgenhostid_SOURCES = \
|
||||
%D%/zgenhostid.c
|
||||
|
||||
|
||||
dist_bin_SCRIPTS += %D%/zvol_wait
|
||||
SHELLCHECKSCRIPTS += %D%/zvol_wait
|
||||
|
||||
|
||||
include $(srcdir)/%D%/zed/Makefile.am
|
||||
endif
|
||||
SUBDIRS = zfs zpool zdb zhack zinject zstream zstreamdump ztest
|
||||
SUBDIRS += fsck_zfs vdev_id raidz_test zfs_ids_to_path
|
||||
|
||||
CPPCHECKDIRS = zfs zpool zdb zhack zinject zstream ztest
|
||||
CPPCHECKDIRS += raidz_test zfs_ids_to_path
|
||||
|
||||
if USING_PYTHON
|
||||
bin_SCRIPTS += arc_summary arcstat dbufstat zilstat
|
||||
CLEANFILES += arc_summary arcstat dbufstat zilstat
|
||||
dist_noinst_DATA += %D%/arc_summary %D%/arcstat.in %D%/dbufstat.in %D%/zilstat.in
|
||||
|
||||
$(call SUBST,arcstat,%D%/)
|
||||
$(call SUBST,dbufstat,%D%/)
|
||||
$(call SUBST,zilstat,%D%/)
|
||||
arc_summary: %D%/arc_summary
|
||||
$(AM_V_at)cp $< $@
|
||||
SUBDIRS += arcstat arc_summary dbufstat
|
||||
endif
|
||||
|
||||
if BUILD_LINUX
|
||||
SUBDIRS += mount_zfs zed zgenhostid zvol_id zvol_wait
|
||||
CPPCHECKDIRS += mount_zfs zed zgenhostid zvol_id
|
||||
endif
|
||||
|
||||
PHONY += cmd
|
||||
cmd: $(bin_SCRIPTS) $(bin_PROGRAMS) $(sbin_SCRIPTS) $(sbin_PROGRAMS) $(dist_bin_SCRIPTS) $(zfsexec_PROGRAMS) $(mounthelper_PROGRAMS)
|
||||
PHONY = cppcheck
|
||||
cppcheck: $(CPPCHECKDIRS)
|
||||
set -e ; for dir in $(CPPCHECKDIRS) ; do \
|
||||
$(MAKE) -C $$dir cppcheck ; \
|
||||
done
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
arc_summary
|
||||
@@ -0,0 +1,13 @@
|
||||
bin_SCRIPTS = arc_summary
|
||||
|
||||
CLEANFILES = arc_summary
|
||||
EXTRA_DIST = arc_summary2 arc_summary3
|
||||
|
||||
if USING_PYTHON_2
|
||||
SCRIPT = arc_summary2
|
||||
else
|
||||
SCRIPT = arc_summary3
|
||||
endif
|
||||
|
||||
arc_summary: $(SCRIPT)
|
||||
cp $< $@
|
||||
Executable
+1099
File diff suppressed because it is too large
Load Diff
@@ -42,13 +42,6 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import errno
|
||||
|
||||
# We can't use env -S portably, and we need python3 -u to handle pipes in
|
||||
# the shell abruptly closing the way we want to, so...
|
||||
import io
|
||||
if isinstance(sys.__stderr__.buffer, io.BufferedWriter):
|
||||
os.execv(sys.executable, [sys.executable, "-u"] + sys.argv)
|
||||
|
||||
DESCRIPTION = 'Print ARC and other statistics for OpenZFS'
|
||||
INDENT = ' '*8
|
||||
@@ -64,6 +57,8 @@ SECTION_HELP = 'print info from one section ('+' '.join(SECTIONS)+')'
|
||||
SECTION_PATHS = {'arc': 'arcstats',
|
||||
'dmu': 'dmu_tx',
|
||||
'l2arc': 'arcstats', # L2ARC stuff lives in arcstats
|
||||
'vdev': 'vdev_cache_stats',
|
||||
'xuio': 'xuio_stats',
|
||||
'zfetch': 'zfetchstats',
|
||||
'zil': 'zil'}
|
||||
|
||||
@@ -89,6 +84,8 @@ if sys.platform.startswith('freebsd'):
|
||||
# Requires py36-sysctl on FreeBSD
|
||||
import sysctl
|
||||
|
||||
VDEV_CACHE_SIZE = 'vdev.cache_size'
|
||||
|
||||
def is_value(ctl):
|
||||
return ctl.type != sysctl.CTLTYPE_NODE
|
||||
|
||||
@@ -132,6 +129,8 @@ elif sys.platform.startswith('linux'):
|
||||
SPL_PATH = '/sys/module/spl/parameters'
|
||||
TUNABLES_PATH = '/sys/module/zfs/parameters'
|
||||
|
||||
VDEV_CACHE_SIZE = 'zfs_vdev_cache_size'
|
||||
|
||||
def load_kstats(section):
|
||||
path = os.path.join(KSTAT_PATH, section)
|
||||
with open(path) as f:
|
||||
@@ -163,11 +162,21 @@ elif sys.platform.startswith('linux'):
|
||||
# The original arc_summary called /sbin/modinfo/{spl,zfs} to get
|
||||
# the version information. We switch to /sys/module/{spl,zfs}/version
|
||||
# to make sure we get what is really loaded in the kernel
|
||||
try:
|
||||
with open("/sys/module/{}/version".format(request)) as f:
|
||||
return f.read().strip()
|
||||
except:
|
||||
return "(unknown)"
|
||||
command = ["cat", "/sys/module/{0}/version".format(request)]
|
||||
req = request.upper()
|
||||
|
||||
# The recommended way to do this is with subprocess.run(). However,
|
||||
# some installed versions of Python are < 3.5, so we offer them
|
||||
# the option of doing it the old way (for now)
|
||||
if 'run' in dir(subprocess):
|
||||
info = subprocess.run(command, stdout=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
version = info.stdout.strip()
|
||||
else:
|
||||
info = subprocess.check_output(command, universal_newlines=True)
|
||||
version = info.strip()
|
||||
|
||||
return version
|
||||
|
||||
def get_descriptions(request):
|
||||
"""Get the descriptions of the Solaris Porting Layer (SPL) or the
|
||||
@@ -186,13 +195,21 @@ elif sys.platform.startswith('linux'):
|
||||
# there, so we fall back on modinfo
|
||||
command = ["/sbin/modinfo", request, "-0"]
|
||||
|
||||
# The recommended way to do this is with subprocess.run(). However,
|
||||
# some installed versions of Python are < 3.5, so we offer them
|
||||
# the option of doing it the old way (for now)
|
||||
info = ''
|
||||
|
||||
try:
|
||||
|
||||
info = subprocess.run(command, stdout=subprocess.PIPE,
|
||||
check=True, universal_newlines=True)
|
||||
raw_output = info.stdout.split('\0')
|
||||
if 'run' in dir(subprocess):
|
||||
info = subprocess.run(command, stdout=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
raw_output = info.stdout.split('\0')
|
||||
else:
|
||||
info = subprocess.check_output(command,
|
||||
universal_newlines=True)
|
||||
raw_output = info.split('\0')
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
print("Error: Descriptions not available",
|
||||
@@ -215,29 +232,6 @@ elif sys.platform.startswith('linux'):
|
||||
|
||||
return descs
|
||||
|
||||
def handle_unraisableException(exc_type, exc_value=None, exc_traceback=None,
|
||||
err_msg=None, object=None):
|
||||
handle_Exception(exc_type, object, exc_traceback)
|
||||
|
||||
def handle_Exception(ex_cls, ex, tb):
|
||||
if ex_cls is KeyboardInterrupt:
|
||||
sys.exit()
|
||||
|
||||
if ex_cls is BrokenPipeError:
|
||||
# It turns out that while sys.exit() triggers an exception
|
||||
# not handled message on Python 3.8+, os._exit() does not.
|
||||
os._exit(0)
|
||||
|
||||
if ex_cls is OSError:
|
||||
if ex.errno == errno.ENOTCONN:
|
||||
sys.exit()
|
||||
|
||||
raise ex
|
||||
|
||||
if hasattr(sys,'unraisablehook'): # Python 3.8+
|
||||
sys.unraisablehook = handle_unraisableException
|
||||
sys.excepthook = handle_Exception
|
||||
|
||||
|
||||
def cleanup_line(single_line):
|
||||
"""Format a raw line of data from /proc and isolate the name value
|
||||
@@ -265,14 +259,16 @@ def draw_graph(kstats_dict):
|
||||
arc_perc = f_perc(arc_stats['size'], arc_stats['c_max'])
|
||||
mfu_size = f_bytes(arc_stats['mfu_size'])
|
||||
mru_size = f_bytes(arc_stats['mru_size'])
|
||||
meta_limit = f_bytes(arc_stats['arc_meta_limit'])
|
||||
meta_size = f_bytes(arc_stats['arc_meta_used'])
|
||||
dnode_limit = f_bytes(arc_stats['arc_dnode_limit'])
|
||||
dnode_size = f_bytes(arc_stats['dnode_size'])
|
||||
|
||||
info_form = ('ARC: {0} ({1}) MFU: {2} MRU: {3} META: {4} '
|
||||
'DNODE {5} ({6})')
|
||||
info_form = ('ARC: {0} ({1}) MFU: {2} MRU: {3} META: {4} ({5}) '
|
||||
'DNODE {6} ({7})')
|
||||
info_line = info_form.format(arc_size, arc_perc, mfu_size, mru_size,
|
||||
meta_size, dnode_size, dnode_limit)
|
||||
meta_size, meta_limit, dnode_size,
|
||||
dnode_limit)
|
||||
info_spc = ' '*int((GRAPH_WIDTH-len(info_line))/2)
|
||||
info_line = GRAPH_INDENT+info_spc+info_line
|
||||
|
||||
@@ -551,28 +547,12 @@ def section_arc(kstats_dict):
|
||||
arc_target_size = arc_stats['c']
|
||||
arc_max = arc_stats['c_max']
|
||||
arc_min = arc_stats['c_min']
|
||||
meta = arc_stats['meta']
|
||||
pd = arc_stats['pd']
|
||||
pm = arc_stats['pm']
|
||||
anon_data = arc_stats['anon_data']
|
||||
anon_metadata = arc_stats['anon_metadata']
|
||||
mfu_data = arc_stats['mfu_data']
|
||||
mfu_metadata = arc_stats['mfu_metadata']
|
||||
mru_data = arc_stats['mru_data']
|
||||
mru_metadata = arc_stats['mru_metadata']
|
||||
mfug_data = arc_stats['mfu_ghost_data']
|
||||
mfug_metadata = arc_stats['mfu_ghost_metadata']
|
||||
mrug_data = arc_stats['mru_ghost_data']
|
||||
mrug_metadata = arc_stats['mru_ghost_metadata']
|
||||
unc_data = arc_stats['uncached_data']
|
||||
unc_metadata = arc_stats['uncached_metadata']
|
||||
bonus_size = arc_stats['bonus_size']
|
||||
mfu_size = arc_stats['mfu_size']
|
||||
mru_size = arc_stats['mru_size']
|
||||
meta_limit = arc_stats['arc_meta_limit']
|
||||
meta_size = arc_stats['arc_meta_used']
|
||||
dnode_limit = arc_stats['arc_dnode_limit']
|
||||
dnode_size = arc_stats['dnode_size']
|
||||
dbuf_size = arc_stats['dbuf_size']
|
||||
hdr_size = arc_stats['hdr_size']
|
||||
l2_hdr_size = arc_stats['l2_hdr_size']
|
||||
abd_chunk_waste_size = arc_stats['abd_chunk_waste_size']
|
||||
target_size_ratio = '{0}:1'.format(int(arc_max) // int(arc_min))
|
||||
|
||||
prt_2('ARC size (current):',
|
||||
@@ -583,56 +563,19 @@ def section_arc(kstats_dict):
|
||||
f_perc(arc_min, arc_max), f_bytes(arc_min))
|
||||
prt_i2('Max size (high water):',
|
||||
target_size_ratio, f_bytes(arc_max))
|
||||
caches_size = int(anon_data)+int(anon_metadata)+\
|
||||
int(mfu_data)+int(mfu_metadata)+int(mru_data)+int(mru_metadata)+\
|
||||
int(unc_data)+int(unc_metadata)
|
||||
prt_i2('Anonymous data size:',
|
||||
f_perc(anon_data, caches_size), f_bytes(anon_data))
|
||||
prt_i2('Anonymous metadata size:',
|
||||
f_perc(anon_metadata, caches_size), f_bytes(anon_metadata))
|
||||
s = 4294967296
|
||||
v = (s-int(pd))*(s-int(meta))/s
|
||||
prt_i2('MFU data target:', f_perc(v, s),
|
||||
f_bytes(v / 65536 * caches_size / 65536))
|
||||
prt_i2('MFU data size:',
|
||||
f_perc(mfu_data, caches_size), f_bytes(mfu_data))
|
||||
prt_i1('MFU ghost data size:', f_bytes(mfug_data))
|
||||
v = (s-int(pm))*int(meta)/s
|
||||
prt_i2('MFU metadata target:', f_perc(v, s),
|
||||
f_bytes(v / 65536 * caches_size / 65536))
|
||||
prt_i2('MFU metadata size:',
|
||||
f_perc(mfu_metadata, caches_size), f_bytes(mfu_metadata))
|
||||
prt_i1('MFU ghost metadata size:', f_bytes(mfug_metadata))
|
||||
v = int(pd)*(s-int(meta))/s
|
||||
prt_i2('MRU data target:', f_perc(v, s),
|
||||
f_bytes(v / 65536 * caches_size / 65536))
|
||||
prt_i2('MRU data size:',
|
||||
f_perc(mru_data, caches_size), f_bytes(mru_data))
|
||||
prt_i1('MRU ghost data size:', f_bytes(mrug_data))
|
||||
v = int(pm)*int(meta)/s
|
||||
prt_i2('MRU metadata target:', f_perc(v, s),
|
||||
f_bytes(v / 65536 * caches_size / 65536))
|
||||
prt_i2('MRU metadata size:',
|
||||
f_perc(mru_metadata, caches_size), f_bytes(mru_metadata))
|
||||
prt_i1('MRU ghost metadata size:', f_bytes(mrug_metadata))
|
||||
prt_i2('Uncached data size:',
|
||||
f_perc(unc_data, caches_size), f_bytes(unc_data))
|
||||
prt_i2('Uncached metadata size:',
|
||||
f_perc(unc_metadata, caches_size), f_bytes(unc_metadata))
|
||||
prt_i2('Bonus size:',
|
||||
f_perc(bonus_size, arc_size), f_bytes(bonus_size))
|
||||
prt_i2('Dnode cache target:',
|
||||
f_perc(dnode_limit, arc_max), f_bytes(dnode_limit))
|
||||
prt_i2('Dnode cache size:',
|
||||
caches_size = int(mfu_size)+int(mru_size)
|
||||
prt_i2('Most Frequently Used (MFU) cache size:',
|
||||
f_perc(mfu_size, caches_size), f_bytes(mfu_size))
|
||||
prt_i2('Most Recently Used (MRU) cache size:',
|
||||
f_perc(mru_size, caches_size), f_bytes(mru_size))
|
||||
prt_i2('Metadata cache size (hard limit):',
|
||||
f_perc(meta_limit, arc_max), f_bytes(meta_limit))
|
||||
prt_i2('Metadata cache size (current):',
|
||||
f_perc(meta_size, meta_limit), f_bytes(meta_size))
|
||||
prt_i2('Dnode cache size (hard limit):',
|
||||
f_perc(dnode_limit, meta_limit), f_bytes(dnode_limit))
|
||||
prt_i2('Dnode cache size (current):',
|
||||
f_perc(dnode_size, dnode_limit), f_bytes(dnode_size))
|
||||
prt_i2('Dbuf size:',
|
||||
f_perc(dbuf_size, arc_size), f_bytes(dbuf_size))
|
||||
prt_i2('Header size:',
|
||||
f_perc(hdr_size, arc_size), f_bytes(hdr_size))
|
||||
prt_i2('L2 header size:',
|
||||
f_perc(l2_hdr_size, arc_size), f_bytes(l2_hdr_size))
|
||||
prt_i2('ABD chunk waste size:',
|
||||
f_perc(abd_chunk_waste_size, arc_size), f_bytes(abd_chunk_waste_size))
|
||||
print()
|
||||
|
||||
print('ARC hash breakdown:')
|
||||
@@ -650,20 +593,6 @@ def section_arc(kstats_dict):
|
||||
prt_i1('Deleted:', f_hits(arc_stats['deleted']))
|
||||
prt_i1('Mutex misses:', f_hits(arc_stats['mutex_miss']))
|
||||
prt_i1('Eviction skips:', f_hits(arc_stats['evict_skip']))
|
||||
prt_i1('Eviction skips due to L2 writes:',
|
||||
f_hits(arc_stats['evict_l2_skip']))
|
||||
prt_i1('L2 cached evictions:', f_bytes(arc_stats['evict_l2_cached']))
|
||||
prt_i1('L2 eligible evictions:', f_bytes(arc_stats['evict_l2_eligible']))
|
||||
prt_i2('L2 eligible MFU evictions:',
|
||||
f_perc(arc_stats['evict_l2_eligible_mfu'],
|
||||
arc_stats['evict_l2_eligible']),
|
||||
f_bytes(arc_stats['evict_l2_eligible_mfu']))
|
||||
prt_i2('L2 eligible MRU evictions:',
|
||||
f_perc(arc_stats['evict_l2_eligible_mru'],
|
||||
arc_stats['evict_l2_eligible']),
|
||||
f_bytes(arc_stats['evict_l2_eligible_mru']))
|
||||
prt_i1('L2 ineligible evictions:',
|
||||
f_bytes(arc_stats['evict_l2_ineligible']))
|
||||
print()
|
||||
|
||||
|
||||
@@ -672,119 +601,78 @@ def section_archits(kstats_dict):
|
||||
"""
|
||||
|
||||
arc_stats = isolate_section('arcstats', kstats_dict)
|
||||
all_accesses = int(arc_stats['hits'])+int(arc_stats['iohits'])+\
|
||||
int(arc_stats['misses'])
|
||||
all_accesses = int(arc_stats['hits'])+int(arc_stats['misses'])
|
||||
actual_hits = int(arc_stats['mfu_hits'])+int(arc_stats['mru_hits'])
|
||||
|
||||
prt_1('ARC total accesses (hits + misses):', f_hits(all_accesses))
|
||||
ta_todo = (('Cache hit ratio:', arc_stats['hits']),
|
||||
('Cache miss ratio:', arc_stats['misses']),
|
||||
('Actual hit ratio (MFU + MRU hits):', actual_hits))
|
||||
|
||||
prt_1('ARC total accesses:', f_hits(all_accesses))
|
||||
ta_todo = (('Total hits:', arc_stats['hits']),
|
||||
('Total I/O hits:', arc_stats['iohits']),
|
||||
('Total misses:', arc_stats['misses']))
|
||||
for title, value in ta_todo:
|
||||
prt_i2(title, f_perc(value, all_accesses), f_hits(value))
|
||||
print()
|
||||
|
||||
dd_total = int(arc_stats['demand_data_hits']) +\
|
||||
int(arc_stats['demand_data_iohits']) +\
|
||||
int(arc_stats['demand_data_misses'])
|
||||
prt_2('ARC demand data accesses:', f_perc(dd_total, all_accesses),
|
||||
f_hits(dd_total))
|
||||
dd_todo = (('Demand data hits:', arc_stats['demand_data_hits']),
|
||||
('Demand data I/O hits:', arc_stats['demand_data_iohits']),
|
||||
('Demand data misses:', arc_stats['demand_data_misses']))
|
||||
for title, value in dd_todo:
|
||||
prt_i2(title, f_perc(value, dd_total), f_hits(value))
|
||||
print()
|
||||
prt_i2('Data demand efficiency:',
|
||||
f_perc(arc_stats['demand_data_hits'], dd_total),
|
||||
f_hits(dd_total))
|
||||
|
||||
dm_total = int(arc_stats['demand_metadata_hits']) +\
|
||||
int(arc_stats['demand_metadata_iohits']) +\
|
||||
int(arc_stats['demand_metadata_misses'])
|
||||
prt_2('ARC demand metadata accesses:', f_perc(dm_total, all_accesses),
|
||||
f_hits(dm_total))
|
||||
dm_todo = (('Demand metadata hits:', arc_stats['demand_metadata_hits']),
|
||||
('Demand metadata I/O hits:',
|
||||
arc_stats['demand_metadata_iohits']),
|
||||
('Demand metadata misses:', arc_stats['demand_metadata_misses']))
|
||||
for title, value in dm_todo:
|
||||
prt_i2(title, f_perc(value, dm_total), f_hits(value))
|
||||
print()
|
||||
|
||||
pd_total = int(arc_stats['prefetch_data_hits']) +\
|
||||
int(arc_stats['prefetch_data_iohits']) +\
|
||||
dp_total = int(arc_stats['prefetch_data_hits']) +\
|
||||
int(arc_stats['prefetch_data_misses'])
|
||||
prt_2('ARC prefetch data accesses:', f_perc(pd_total, all_accesses),
|
||||
f_hits(pd_total))
|
||||
pd_todo = (('Prefetch data hits:', arc_stats['prefetch_data_hits']),
|
||||
('Prefetch data I/O hits:', arc_stats['prefetch_data_iohits']),
|
||||
('Prefetch data misses:', arc_stats['prefetch_data_misses']))
|
||||
for title, value in pd_todo:
|
||||
prt_i2(title, f_perc(value, pd_total), f_hits(value))
|
||||
print()
|
||||
prt_i2('Data prefetch efficiency:',
|
||||
f_perc(arc_stats['prefetch_data_hits'], dp_total),
|
||||
f_hits(dp_total))
|
||||
|
||||
pm_total = int(arc_stats['prefetch_metadata_hits']) +\
|
||||
int(arc_stats['prefetch_metadata_iohits']) +\
|
||||
int(arc_stats['prefetch_metadata_misses'])
|
||||
prt_2('ARC prefetch metadata accesses:', f_perc(pm_total, all_accesses),
|
||||
f_hits(pm_total))
|
||||
pm_todo = (('Prefetch metadata hits:',
|
||||
arc_stats['prefetch_metadata_hits']),
|
||||
('Prefetch metadata I/O hits:',
|
||||
arc_stats['prefetch_metadata_iohits']),
|
||||
('Prefetch metadata misses:',
|
||||
arc_stats['prefetch_metadata_misses']))
|
||||
for title, value in pm_todo:
|
||||
prt_i2(title, f_perc(value, pm_total), f_hits(value))
|
||||
print()
|
||||
known_hits = int(arc_stats['mfu_hits']) +\
|
||||
int(arc_stats['mru_hits']) +\
|
||||
int(arc_stats['mfu_ghost_hits']) +\
|
||||
int(arc_stats['mru_ghost_hits'])
|
||||
|
||||
all_prefetches = int(arc_stats['predictive_prefetch'])+\
|
||||
int(arc_stats['prescient_prefetch'])
|
||||
prt_2('ARC predictive prefetches:',
|
||||
f_perc(arc_stats['predictive_prefetch'], all_prefetches),
|
||||
f_hits(arc_stats['predictive_prefetch']))
|
||||
prt_i2('Demand hits after predictive:',
|
||||
f_perc(arc_stats['demand_hit_predictive_prefetch'],
|
||||
arc_stats['predictive_prefetch']),
|
||||
f_hits(arc_stats['demand_hit_predictive_prefetch']))
|
||||
prt_i2('Demand I/O hits after predictive:',
|
||||
f_perc(arc_stats['demand_iohit_predictive_prefetch'],
|
||||
arc_stats['predictive_prefetch']),
|
||||
f_hits(arc_stats['demand_iohit_predictive_prefetch']))
|
||||
never = int(arc_stats['predictive_prefetch']) -\
|
||||
int(arc_stats['demand_hit_predictive_prefetch']) -\
|
||||
int(arc_stats['demand_iohit_predictive_prefetch'])
|
||||
prt_i2('Never demanded after predictive:',
|
||||
f_perc(never, arc_stats['predictive_prefetch']),
|
||||
f_hits(never))
|
||||
print()
|
||||
anon_hits = int(arc_stats['hits'])-known_hits
|
||||
|
||||
prt_2('ARC prescient prefetches:',
|
||||
f_perc(arc_stats['prescient_prefetch'], all_prefetches),
|
||||
f_hits(arc_stats['prescient_prefetch']))
|
||||
prt_i2('Demand hits after prescient:',
|
||||
f_perc(arc_stats['demand_hit_prescient_prefetch'],
|
||||
arc_stats['prescient_prefetch']),
|
||||
f_hits(arc_stats['demand_hit_prescient_prefetch']))
|
||||
prt_i2('Demand I/O hits after prescient:',
|
||||
f_perc(arc_stats['demand_iohit_prescient_prefetch'],
|
||||
arc_stats['prescient_prefetch']),
|
||||
f_hits(arc_stats['demand_iohit_prescient_prefetch']))
|
||||
never = int(arc_stats['prescient_prefetch'])-\
|
||||
int(arc_stats['demand_hit_prescient_prefetch'])-\
|
||||
int(arc_stats['demand_iohit_prescient_prefetch'])
|
||||
prt_i2('Never demanded after prescient:',
|
||||
f_perc(never, arc_stats['prescient_prefetch']),
|
||||
f_hits(never))
|
||||
print()
|
||||
|
||||
print('ARC states hits of all accesses:')
|
||||
print('Cache hits by cache type:')
|
||||
cl_todo = (('Most frequently used (MFU):', arc_stats['mfu_hits']),
|
||||
('Most recently used (MRU):', arc_stats['mru_hits']),
|
||||
('Most frequently used (MFU) ghost:',
|
||||
arc_stats['mfu_ghost_hits']),
|
||||
('Most recently used (MRU) ghost:',
|
||||
arc_stats['mru_ghost_hits']),
|
||||
('Uncached:', arc_stats['uncached_hits']))
|
||||
arc_stats['mru_ghost_hits']))
|
||||
|
||||
for title, value in cl_todo:
|
||||
prt_i2(title, f_perc(value, all_accesses), f_hits(value))
|
||||
prt_i2(title, f_perc(value, arc_stats['hits']), f_hits(value))
|
||||
|
||||
# For some reason, anon_hits can turn negative, which is weird. Until we
|
||||
# have figured out why this happens, we just hide the problem, following
|
||||
# the behavior of the original arc_summary.
|
||||
if anon_hits >= 0:
|
||||
prt_i2('Anonymously used:',
|
||||
f_perc(anon_hits, arc_stats['hits']), f_hits(anon_hits))
|
||||
|
||||
print()
|
||||
print('Cache hits by data type:')
|
||||
dt_todo = (('Demand data:', arc_stats['demand_data_hits']),
|
||||
('Demand prefetch data:', arc_stats['prefetch_data_hits']),
|
||||
('Demand metadata:', arc_stats['demand_metadata_hits']),
|
||||
('Demand prefetch metadata:',
|
||||
arc_stats['prefetch_metadata_hits']))
|
||||
|
||||
for title, value in dt_todo:
|
||||
prt_i2(title, f_perc(value, arc_stats['hits']), f_hits(value))
|
||||
|
||||
print()
|
||||
print('Cache misses by data type:')
|
||||
dm_todo = (('Demand data:', arc_stats['demand_data_misses']),
|
||||
('Demand prefetch data:',
|
||||
arc_stats['prefetch_data_misses']),
|
||||
('Demand metadata:', arc_stats['demand_metadata_misses']),
|
||||
('Demand prefetch metadata:',
|
||||
arc_stats['prefetch_metadata_misses']))
|
||||
|
||||
for title, value in dm_todo:
|
||||
prt_i2(title, f_perc(value, arc_stats['misses']), f_hits(value))
|
||||
|
||||
print()
|
||||
|
||||
|
||||
@@ -793,28 +681,13 @@ def section_dmu(kstats_dict):
|
||||
|
||||
zfetch_stats = isolate_section('zfetchstats', kstats_dict)
|
||||
|
||||
zfetch_access_total = int(zfetch_stats['hits']) +\
|
||||
int(zfetch_stats['future']) + int(zfetch_stats['stride']) +\
|
||||
int(zfetch_stats['past']) + int(zfetch_stats['misses'])
|
||||
zfetch_access_total = int(zfetch_stats['hits'])+int(zfetch_stats['misses'])
|
||||
|
||||
prt_1('DMU predictive prefetcher calls:', f_hits(zfetch_access_total))
|
||||
prt_i2('Stream hits:',
|
||||
f_perc(zfetch_stats['hits'], zfetch_access_total),
|
||||
prt_1('DMU prefetch efficiency:', f_hits(zfetch_access_total))
|
||||
prt_i2('Hit ratio:', f_perc(zfetch_stats['hits'], zfetch_access_total),
|
||||
f_hits(zfetch_stats['hits']))
|
||||
future = int(zfetch_stats['future']) + int(zfetch_stats['stride'])
|
||||
prt_i2('Hits ahead of stream:', f_perc(future, zfetch_access_total),
|
||||
f_hits(future))
|
||||
prt_i2('Hits behind stream:',
|
||||
f_perc(zfetch_stats['past'], zfetch_access_total),
|
||||
f_hits(zfetch_stats['past']))
|
||||
prt_i2('Stream misses:',
|
||||
f_perc(zfetch_stats['misses'], zfetch_access_total),
|
||||
prt_i2('Miss ratio:', f_perc(zfetch_stats['misses'], zfetch_access_total),
|
||||
f_hits(zfetch_stats['misses']))
|
||||
prt_i2('Streams limit reached:',
|
||||
f_perc(zfetch_stats['max_streams'], zfetch_stats['misses']),
|
||||
f_hits(zfetch_stats['max_streams']))
|
||||
prt_i1('Stream strides:', f_hits(zfetch_stats['stride']))
|
||||
prt_i1('Prefetches issued', f_hits(zfetch_stats['io_issued']))
|
||||
print()
|
||||
|
||||
|
||||
@@ -846,8 +719,7 @@ def section_l2arc(kstats_dict):
|
||||
('Free on write:', 'l2_free_on_write'),
|
||||
('R/W clashes:', 'l2_rw_clash'),
|
||||
('Bad checksums:', 'l2_cksum_bad'),
|
||||
('Read errors:', 'l2_io_error'),
|
||||
('Write errors:', 'l2_writes_error'))
|
||||
('I/O errors:', 'l2_io_error'))
|
||||
|
||||
for title, value in l2_todo:
|
||||
prt_i1(title, f_hits(arc_stats[value]))
|
||||
@@ -859,21 +731,6 @@ def section_l2arc(kstats_dict):
|
||||
prt_i2('Header size:',
|
||||
f_perc(arc_stats['l2_hdr_size'], arc_stats['l2_size']),
|
||||
f_bytes(arc_stats['l2_hdr_size']))
|
||||
prt_i2('MFU allocated size:',
|
||||
f_perc(arc_stats['l2_mfu_asize'], arc_stats['l2_asize']),
|
||||
f_bytes(arc_stats['l2_mfu_asize']))
|
||||
prt_i2('MRU allocated size:',
|
||||
f_perc(arc_stats['l2_mru_asize'], arc_stats['l2_asize']),
|
||||
f_bytes(arc_stats['l2_mru_asize']))
|
||||
prt_i2('Prefetch allocated size:',
|
||||
f_perc(arc_stats['l2_prefetch_asize'], arc_stats['l2_asize']),
|
||||
f_bytes(arc_stats['l2_prefetch_asize']))
|
||||
prt_i2('Data (buffer content) allocated size:',
|
||||
f_perc(arc_stats['l2_bufc_data_asize'], arc_stats['l2_asize']),
|
||||
f_bytes(arc_stats['l2_bufc_data_asize']))
|
||||
prt_i2('Metadata (buffer content) allocated size:',
|
||||
f_perc(arc_stats['l2_bufc_metadata_asize'], arc_stats['l2_asize']),
|
||||
f_bytes(arc_stats['l2_bufc_metadata_asize']))
|
||||
|
||||
print()
|
||||
prt_1('L2ARC breakdown:', f_hits(l2_access_total))
|
||||
@@ -883,20 +740,28 @@ def section_l2arc(kstats_dict):
|
||||
prt_i2('Miss ratio:',
|
||||
f_perc(arc_stats['l2_misses'], l2_access_total),
|
||||
f_hits(arc_stats['l2_misses']))
|
||||
prt_i1('Feeds:', f_hits(arc_stats['l2_feeds']))
|
||||
|
||||
print()
|
||||
print('L2ARC I/O:')
|
||||
prt_i2('Reads:',
|
||||
f_bytes(arc_stats['l2_read_bytes']),
|
||||
f_hits(arc_stats['l2_hits']))
|
||||
prt_i2('Writes:',
|
||||
f_bytes(arc_stats['l2_write_bytes']),
|
||||
f_hits(arc_stats['l2_writes_sent']))
|
||||
print('L2ARC writes:')
|
||||
|
||||
if arc_stats['l2_writes_done'] != arc_stats['l2_writes_sent']:
|
||||
prt_i2('Writes sent:', 'FAULTED', f_hits(arc_stats['l2_writes_sent']))
|
||||
prt_i2('Done ratio:',
|
||||
f_perc(arc_stats['l2_writes_done'],
|
||||
arc_stats['l2_writes_sent']),
|
||||
f_hits(arc_stats['l2_writes_done']))
|
||||
prt_i2('Error ratio:',
|
||||
f_perc(arc_stats['l2_writes_error'],
|
||||
arc_stats['l2_writes_sent']),
|
||||
f_hits(arc_stats['l2_writes_error']))
|
||||
else:
|
||||
prt_i2('Writes sent:', '100 %', f_hits(arc_stats['l2_writes_sent']))
|
||||
|
||||
print()
|
||||
print('L2ARC evicts:')
|
||||
prt_i1('L1 cached:', f_hits(arc_stats['l2_evict_l1cached']))
|
||||
prt_i1('While reading:', f_hits(arc_stats['l2_evict_reading']))
|
||||
prt_i1('Lock retries:', f_hits(arc_stats['l2_evict_lock_retry']))
|
||||
prt_i1('Upon reading:', f_hits(arc_stats['l2_evict_reading']))
|
||||
print()
|
||||
|
||||
|
||||
@@ -956,6 +821,35 @@ def section_tunables(*_):
|
||||
print()
|
||||
|
||||
|
||||
def section_vdev(kstats_dict):
|
||||
"""Collect information on VDEV caches"""
|
||||
|
||||
# Currently [Nov 2017] the VDEV cache is disabled, because it is actually
|
||||
# harmful. When this is the case, we just skip the whole entry. See
|
||||
# https://github.com/openzfs/zfs/blob/master/module/zfs/vdev_cache.c
|
||||
# for details
|
||||
tunables = get_vdev_params()
|
||||
|
||||
if tunables[VDEV_CACHE_SIZE] == '0':
|
||||
print('VDEV cache disabled, skipping section\n')
|
||||
return
|
||||
|
||||
vdev_stats = isolate_section('vdev_cache_stats', kstats_dict)
|
||||
|
||||
vdev_cache_total = int(vdev_stats['hits']) +\
|
||||
int(vdev_stats['misses']) +\
|
||||
int(vdev_stats['delegations'])
|
||||
|
||||
prt_1('VDEV cache summary:', f_hits(vdev_cache_total))
|
||||
prt_i2('Hit ratio:', f_perc(vdev_stats['hits'], vdev_cache_total),
|
||||
f_hits(vdev_stats['hits']))
|
||||
prt_i2('Miss ratio:', f_perc(vdev_stats['misses'], vdev_cache_total),
|
||||
f_hits(vdev_stats['misses']))
|
||||
prt_i2('Delegations:', f_perc(vdev_stats['delegations'], vdev_cache_total),
|
||||
f_hits(vdev_stats['delegations']))
|
||||
print()
|
||||
|
||||
|
||||
def section_zil(kstats_dict):
|
||||
"""Collect information on the ZFS Intent Log. Some of the information
|
||||
taken from https://github.com/openzfs/zfs/blob/master/include/sys/zil.h
|
||||
@@ -983,6 +877,7 @@ section_calls = {'arc': section_arc,
|
||||
'l2arc': section_l2arc,
|
||||
'spl': section_spl,
|
||||
'tunables': section_tunables,
|
||||
'vdev': section_vdev,
|
||||
'zil': section_zil}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
arcstat
|
||||
@@ -0,0 +1,5 @@
|
||||
include $(top_srcdir)/config/Substfiles.am
|
||||
|
||||
bin_SCRIPTS = arcstat
|
||||
|
||||
SUBSTFILES += $(bin_SCRIPTS)
|
||||
@@ -29,7 +29,7 @@
|
||||
# with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or https://opensource.org/licenses/CDDL-1.0.
|
||||
# or http://www.opensolaris.org/os/licensing.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
@@ -47,7 +47,7 @@
|
||||
# @hdr is the array of fields that needs to be printed, so we
|
||||
# just iterate over this array and print the values using our pretty printer.
|
||||
#
|
||||
# This script must remain compatible with Python 3.6+.
|
||||
# This script must remain compatible with Python 2.6+ and Python 3.4+.
|
||||
#
|
||||
|
||||
import sys
|
||||
@@ -62,125 +62,61 @@ from signal import signal, SIGINT, SIGWINCH, SIG_DFL
|
||||
cols = {
|
||||
# HDR: [Size, Scale, Description]
|
||||
"time": [8, -1, "Time"],
|
||||
"hits": [4, 1000, "ARC hits per second"],
|
||||
"iohs": [4, 1000, "ARC I/O hits per second"],
|
||||
"hits": [4, 1000, "ARC reads per second"],
|
||||
"miss": [4, 1000, "ARC misses per second"],
|
||||
"read": [4, 1000, "Total ARC accesses per second"],
|
||||
"hit%": [4, 100, "ARC hit percentage"],
|
||||
"ioh%": [4, 100, "ARC I/O hit percentage"],
|
||||
"miss%": [5, 100, "ARC miss percentage"],
|
||||
"dhit": [4, 1000, "Demand hits per second"],
|
||||
"dioh": [4, 1000, "Demand I/O hits per second"],
|
||||
"dmis": [4, 1000, "Demand misses per second"],
|
||||
"dh%": [3, 100, "Demand hit percentage"],
|
||||
"di%": [3, 100, "Demand I/O hit percentage"],
|
||||
"dm%": [3, 100, "Demand miss percentage"],
|
||||
"ddhit": [5, 1000, "Demand data hits per second"],
|
||||
"ddioh": [5, 1000, "Demand data I/O hits per second"],
|
||||
"ddmis": [5, 1000, "Demand data misses per second"],
|
||||
"ddh%": [4, 100, "Demand data hit percentage"],
|
||||
"ddi%": [4, 100, "Demand data I/O hit percentage"],
|
||||
"ddm%": [4, 100, "Demand data miss percentage"],
|
||||
"dmhit": [5, 1000, "Demand metadata hits per second"],
|
||||
"dmioh": [5, 1000, "Demand metadata I/O hits per second"],
|
||||
"dmmis": [5, 1000, "Demand metadata misses per second"],
|
||||
"dmh%": [4, 100, "Demand metadata hit percentage"],
|
||||
"dmi%": [4, 100, "Demand metadata I/O hit percentage"],
|
||||
"dmm%": [4, 100, "Demand metadata miss percentage"],
|
||||
"phit": [4, 1000, "Prefetch hits per second"],
|
||||
"pioh": [4, 1000, "Prefetch I/O hits per second"],
|
||||
"pmis": [4, 1000, "Prefetch misses per second"],
|
||||
"ph%": [3, 100, "Prefetch hits percentage"],
|
||||
"pi%": [3, 100, "Prefetch I/O hits percentage"],
|
||||
"pm%": [3, 100, "Prefetch miss percentage"],
|
||||
"pdhit": [5, 1000, "Prefetch data hits per second"],
|
||||
"pdioh": [5, 1000, "Prefetch data I/O hits per second"],
|
||||
"pdmis": [5, 1000, "Prefetch data misses per second"],
|
||||
"pdh%": [4, 100, "Prefetch data hits percentage"],
|
||||
"pdi%": [4, 100, "Prefetch data I/O hits percentage"],
|
||||
"pdm%": [4, 100, "Prefetch data miss percentage"],
|
||||
"pmhit": [5, 1000, "Prefetch metadata hits per second"],
|
||||
"pmioh": [5, 1000, "Prefetch metadata I/O hits per second"],
|
||||
"pmmis": [5, 1000, "Prefetch metadata misses per second"],
|
||||
"pmh%": [4, 100, "Prefetch metadata hits percentage"],
|
||||
"pmi%": [4, 100, "Prefetch metadata I/O hits percentage"],
|
||||
"pmm%": [4, 100, "Prefetch metadata miss percentage"],
|
||||
"mhit": [4, 1000, "Metadata hits per second"],
|
||||
"mioh": [4, 1000, "Metadata I/O hits per second"],
|
||||
"mmis": [4, 1000, "Metadata misses per second"],
|
||||
"mread": [5, 1000, "Metadata accesses per second"],
|
||||
"mh%": [3, 100, "Metadata hit percentage"],
|
||||
"mi%": [3, 100, "Metadata I/O hit percentage"],
|
||||
"mm%": [3, 100, "Metadata miss percentage"],
|
||||
"arcsz": [5, 1024, "ARC size"],
|
||||
"size": [5, 1024, "ARC size"],
|
||||
"c": [5, 1024, "ARC target size"],
|
||||
"size": [4, 1024, "ARC size"],
|
||||
"c": [4, 1024, "ARC target size"],
|
||||
"mfu": [4, 1000, "MFU list hits per second"],
|
||||
"mru": [4, 1000, "MRU list hits per second"],
|
||||
"mfug": [4, 1000, "MFU ghost list hits per second"],
|
||||
"mrug": [4, 1000, "MRU ghost list hits per second"],
|
||||
"unc": [4, 1000, "Uncached list hits per second"],
|
||||
"eskip": [5, 1000, "evict_skip per second"],
|
||||
"el2skip": [7, 1000, "evict skip, due to l2 writes, per second"],
|
||||
"el2cach": [7, 1024, "Size of L2 cached evictions per second"],
|
||||
"el2el": [5, 1024, "Size of L2 eligible evictions per second"],
|
||||
"el2mfu": [6, 1024, "Size of L2 eligible MFU evictions per second"],
|
||||
"el2mru": [6, 1024, "Size of L2 eligible MRU evictions per second"],
|
||||
"el2inel": [7, 1024, "Size of L2 ineligible evictions per second"],
|
||||
"mtxmis": [6, 1000, "mutex_miss per second"],
|
||||
"dread": [5, 1000, "Demand accesses per second"],
|
||||
"ddread": [6, 1000, "Demand data accesses per second"],
|
||||
"dmread": [6, 1000, "Demand metadata accesses per second"],
|
||||
"pread": [5, 1000, "Prefetch accesses per second"],
|
||||
"pdread": [6, 1000, "Prefetch data accesses per second"],
|
||||
"pmread": [6, 1000, "Prefetch metadata accesses per second"],
|
||||
"l2hits": [6, 1000, "L2ARC hits per second"],
|
||||
"l2miss": [6, 1000, "L2ARC misses per second"],
|
||||
"l2read": [6, 1000, "Total L2ARC accesses per second"],
|
||||
"l2hit%": [6, 100, "L2ARC access hit percentage"],
|
||||
"l2miss%": [7, 100, "L2ARC access miss percentage"],
|
||||
"l2pref": [6, 1024, "L2ARC prefetch allocated size"],
|
||||
"l2mfu": [5, 1024, "L2ARC MFU allocated size"],
|
||||
"l2mru": [5, 1024, "L2ARC MRU allocated size"],
|
||||
"l2data": [6, 1024, "L2ARC data allocated size"],
|
||||
"l2meta": [6, 1024, "L2ARC metadata allocated size"],
|
||||
"l2pref%": [7, 100, "L2ARC prefetch percentage"],
|
||||
"l2mfu%": [6, 100, "L2ARC MFU percentage"],
|
||||
"l2mru%": [6, 100, "L2ARC MRU percentage"],
|
||||
"l2data%": [7, 100, "L2ARC data percentage"],
|
||||
"l2meta%": [7, 100, "L2ARC metadata percentage"],
|
||||
"l2asize": [7, 1024, "Actual (compressed) size of the L2ARC"],
|
||||
"l2size": [6, 1024, "Size of the L2ARC"],
|
||||
"l2bytes": [7, 1024, "Bytes read per second from the L2ARC"],
|
||||
"grow": [4, 1000, "ARC grow disabled"],
|
||||
"need": [5, 1024, "ARC reclaim need"],
|
||||
"free": [5, 1024, "ARC free memory"],
|
||||
"need": [4, 1024, "ARC reclaim need"],
|
||||
"free": [4, 1024, "ARC free memory"],
|
||||
"avail": [5, 1024, "ARC available memory"],
|
||||
"waste": [5, 1024, "Wasted memory due to round up to pagesize"],
|
||||
"ztotal": [6, 1000, "zfetch total prefetcher calls per second"],
|
||||
"zhits": [5, 1000, "zfetch stream hits per second"],
|
||||
"zahead": [6, 1000, "zfetch hits ahead of streams per second"],
|
||||
"zpast": [5, 1000, "zfetch hits behind streams per second"],
|
||||
"zmisses": [7, 1000, "zfetch stream misses per second"],
|
||||
"zmax": [4, 1000, "zfetch limit reached per second"],
|
||||
"zfuture": [7, 1000, "zfetch stream future per second"],
|
||||
"zstride": [7, 1000, "zfetch stream strides per second"],
|
||||
"zissued": [7, 1000, "zfetch prefetches issued per second"],
|
||||
"zactive": [7, 1000, "zfetch prefetches active per second"],
|
||||
}
|
||||
|
||||
v = {}
|
||||
hdr = ["time", "read", "ddread", "ddh%", "dmread", "dmh%", "pread", "ph%",
|
||||
"size", "c", "avail"]
|
||||
xhdr = ["time", "mfu", "mru", "mfug", "mrug", "unc", "eskip", "mtxmis",
|
||||
"dread", "pread", "read"]
|
||||
zhdr = ["time", "ztotal", "zhits", "zahead", "zpast", "zmisses", "zmax",
|
||||
"zfuture", "zstride", "zissued", "zactive"]
|
||||
hdr = ["time", "read", "miss", "miss%", "dmis", "dm%", "pmis", "pm%", "mmis",
|
||||
"mm%", "size", "c", "avail"]
|
||||
xhdr = ["time", "mfu", "mru", "mfug", "mrug", "eskip", "mtxmis", "dread",
|
||||
"pread", "read"]
|
||||
sint = 1 # Default interval is 1 second
|
||||
count = 1 # Default count is 1
|
||||
hdr_intr = 20 # Print header every 20 lines of output
|
||||
opfile = None
|
||||
sep = " " # Default separator is 2 spaces
|
||||
version = "0.4"
|
||||
l2exist = False
|
||||
cmd = ("Usage: arcstat [-havxp] [-f fields] [-o file] [-s string] [interval "
|
||||
"[count]]\n")
|
||||
@@ -200,8 +136,6 @@ if sys.platform.startswith('freebsd'):
|
||||
|
||||
k = [ctl for ctl in sysctl.filter('kstat.zfs.misc.arcstats')
|
||||
if ctl.type != sysctl.CTLTYPE_NODE]
|
||||
k += [ctl for ctl in sysctl.filter('kstat.zfs.misc.zfetchstats')
|
||||
if ctl.type != sysctl.CTLTYPE_NODE]
|
||||
|
||||
if not k:
|
||||
sys.exit(1)
|
||||
@@ -213,28 +147,19 @@ if sys.platform.startswith('freebsd'):
|
||||
continue
|
||||
|
||||
name, value = s.name, s.value
|
||||
|
||||
if "arcstats" in name:
|
||||
# Trims 'kstat.zfs.misc.arcstats' from the name
|
||||
kstat[name[24:]] = int(value)
|
||||
else:
|
||||
kstat["zfetch_" + name[27:]] = int(value)
|
||||
# Trims 'kstat.zfs.misc.arcstats' from the name
|
||||
kstat[name[24:]] = int(value)
|
||||
|
||||
elif sys.platform.startswith('linux'):
|
||||
def kstat_update():
|
||||
global kstat
|
||||
|
||||
k1 = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')]
|
||||
k = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')]
|
||||
|
||||
k2 = ["zfetch_" + line.strip() for line in
|
||||
open('/proc/spl/kstat/zfs/zfetchstats')]
|
||||
|
||||
if k1 is None or k2 is None:
|
||||
if not k:
|
||||
sys.exit(1)
|
||||
|
||||
del k1[0:2]
|
||||
del k2[0:2]
|
||||
k = k1 + k2
|
||||
del k[0:2]
|
||||
kstat = {}
|
||||
|
||||
for s in k:
|
||||
@@ -262,7 +187,6 @@ def usage():
|
||||
sys.stderr.write("\t -v : List all possible field headers and definitions"
|
||||
"\n")
|
||||
sys.stderr.write("\t -x : Print extended stats\n")
|
||||
sys.stderr.write("\t -z : Print zfetch stats\n")
|
||||
sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n")
|
||||
sys.stderr.write("\t -o : Redirect output to the specified file\n")
|
||||
sys.stderr.write("\t -s : Override default field separator with custom "
|
||||
@@ -331,7 +255,7 @@ def print_values():
|
||||
if pretty_print:
|
||||
fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col])
|
||||
else:
|
||||
fmt = lambda col: str(v[col])
|
||||
fmt = lambda col: v[col]
|
||||
|
||||
sys.stdout.write(sep.join(fmt(col) for col in hdr))
|
||||
sys.stdout.write("\n")
|
||||
@@ -381,7 +305,6 @@ def init():
|
||||
global count
|
||||
global hdr
|
||||
global xhdr
|
||||
global zhdr
|
||||
global opfile
|
||||
global sep
|
||||
global out
|
||||
@@ -393,17 +316,15 @@ def init():
|
||||
xflag = False
|
||||
hflag = False
|
||||
vflag = False
|
||||
zflag = False
|
||||
i = 1
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
"axzo:hvs:f:p",
|
||||
"axo:hvs:f:p",
|
||||
[
|
||||
"all",
|
||||
"extended",
|
||||
"zfetch",
|
||||
"outfile",
|
||||
"help",
|
||||
"verbose",
|
||||
@@ -437,15 +358,13 @@ def init():
|
||||
i += 1
|
||||
if opt in ('-p', '--parsable'):
|
||||
pretty_print = False
|
||||
if opt in ('-z', '--zfetch'):
|
||||
zflag = True
|
||||
i += 1
|
||||
|
||||
argv = sys.argv[i:]
|
||||
sint = int(argv[0]) if argv else sint
|
||||
count = int(argv[1]) if len(argv) > 1 else (0 if len(argv) > 0 else 1)
|
||||
|
||||
if hflag or (xflag and zflag) or ((zflag or xflag) and desired_cols):
|
||||
if hflag or (xflag and desired_cols):
|
||||
usage()
|
||||
|
||||
if vflag:
|
||||
@@ -454,9 +373,6 @@ def init():
|
||||
if xflag:
|
||||
hdr = xhdr
|
||||
|
||||
if zflag:
|
||||
hdr = zhdr
|
||||
|
||||
update_hdr_intr()
|
||||
|
||||
# check if L2ARC exists
|
||||
@@ -509,131 +425,56 @@ def calculate():
|
||||
|
||||
v = dict()
|
||||
v["time"] = time.strftime("%H:%M:%S", time.localtime())
|
||||
v["hits"] = d["hits"] // sint
|
||||
v["iohs"] = d["iohits"] // sint
|
||||
v["miss"] = d["misses"] // sint
|
||||
v["read"] = v["hits"] + v["iohs"] + v["miss"]
|
||||
v["hit%"] = 100 * v["hits"] // v["read"] if v["read"] > 0 else 0
|
||||
v["ioh%"] = 100 * v["iohs"] // v["read"] if v["read"] > 0 else 0
|
||||
v["miss%"] = 100 - v["hit%"] - v["ioh%"] if v["read"] > 0 else 0
|
||||
v["hits"] = d["hits"] / sint
|
||||
v["miss"] = d["misses"] / sint
|
||||
v["read"] = v["hits"] + v["miss"]
|
||||
v["hit%"] = 100 * v["hits"] / v["read"] if v["read"] > 0 else 0
|
||||
v["miss%"] = 100 - v["hit%"] if v["read"] > 0 else 0
|
||||
|
||||
v["dhit"] = (d["demand_data_hits"] + d["demand_metadata_hits"]) // sint
|
||||
v["dioh"] = (d["demand_data_iohits"] + d["demand_metadata_iohits"]) // sint
|
||||
v["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) // sint
|
||||
v["dhit"] = (d["demand_data_hits"] + d["demand_metadata_hits"]) / sint
|
||||
v["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) / sint
|
||||
|
||||
v["dread"] = v["dhit"] + v["dioh"] + v["dmis"]
|
||||
v["dh%"] = 100 * v["dhit"] // v["dread"] if v["dread"] > 0 else 0
|
||||
v["di%"] = 100 * v["dioh"] // v["dread"] if v["dread"] > 0 else 0
|
||||
v["dm%"] = 100 - v["dh%"] - v["di%"] if v["dread"] > 0 else 0
|
||||
v["dread"] = v["dhit"] + v["dmis"]
|
||||
v["dh%"] = 100 * v["dhit"] / v["dread"] if v["dread"] > 0 else 0
|
||||
v["dm%"] = 100 - v["dh%"] if v["dread"] > 0 else 0
|
||||
|
||||
v["ddhit"] = d["demand_data_hits"] // sint
|
||||
v["ddioh"] = d["demand_data_iohits"] // sint
|
||||
v["ddmis"] = d["demand_data_misses"] // sint
|
||||
|
||||
v["ddread"] = v["ddhit"] + v["ddioh"] + v["ddmis"]
|
||||
v["ddh%"] = 100 * v["ddhit"] // v["ddread"] if v["ddread"] > 0 else 0
|
||||
v["ddi%"] = 100 * v["ddioh"] // v["ddread"] if v["ddread"] > 0 else 0
|
||||
v["ddm%"] = 100 - v["ddh%"] - v["ddi%"] if v["ddread"] > 0 else 0
|
||||
|
||||
v["dmhit"] = d["demand_metadata_hits"] // sint
|
||||
v["dmioh"] = d["demand_metadata_iohits"] // sint
|
||||
v["dmmis"] = d["demand_metadata_misses"] // sint
|
||||
|
||||
v["dmread"] = v["dmhit"] + v["dmioh"] + v["dmmis"]
|
||||
v["dmh%"] = 100 * v["dmhit"] // v["dmread"] if v["dmread"] > 0 else 0
|
||||
v["dmi%"] = 100 * v["dmioh"] // v["dmread"] if v["dmread"] > 0 else 0
|
||||
v["dmm%"] = 100 - v["dmh%"] - v["dmi%"] if v["dmread"] > 0 else 0
|
||||
|
||||
v["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) // sint
|
||||
v["pioh"] = (d["prefetch_data_iohits"] +
|
||||
d["prefetch_metadata_iohits"]) // sint
|
||||
v["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) / sint
|
||||
v["pmis"] = (d["prefetch_data_misses"] +
|
||||
d["prefetch_metadata_misses"]) // sint
|
||||
d["prefetch_metadata_misses"]) / sint
|
||||
|
||||
v["pread"] = v["phit"] + v["pioh"] + v["pmis"]
|
||||
v["ph%"] = 100 * v["phit"] // v["pread"] if v["pread"] > 0 else 0
|
||||
v["pi%"] = 100 * v["pioh"] // v["pread"] if v["pread"] > 0 else 0
|
||||
v["pm%"] = 100 - v["ph%"] - v["pi%"] if v["pread"] > 0 else 0
|
||||
|
||||
v["pdhit"] = d["prefetch_data_hits"] // sint
|
||||
v["pdioh"] = d["prefetch_data_iohits"] // sint
|
||||
v["pdmis"] = d["prefetch_data_misses"] // sint
|
||||
|
||||
v["pdread"] = v["pdhit"] + v["pdioh"] + v["pdmis"]
|
||||
v["pdh%"] = 100 * v["pdhit"] // v["pdread"] if v["pdread"] > 0 else 0
|
||||
v["pdi%"] = 100 * v["pdioh"] // v["pdread"] if v["pdread"] > 0 else 0
|
||||
v["pdm%"] = 100 - v["pdh%"] - v["pdi%"] if v["pdread"] > 0 else 0
|
||||
|
||||
v["pmhit"] = d["prefetch_metadata_hits"] // sint
|
||||
v["pmioh"] = d["prefetch_metadata_iohits"] // sint
|
||||
v["pmmis"] = d["prefetch_metadata_misses"] // sint
|
||||
|
||||
v["pmread"] = v["pmhit"] + v["pmioh"] + v["pmmis"]
|
||||
v["pmh%"] = 100 * v["pmhit"] // v["pmread"] if v["pmread"] > 0 else 0
|
||||
v["pmi%"] = 100 * v["pmioh"] // v["pmread"] if v["pmread"] > 0 else 0
|
||||
v["pmm%"] = 100 - v["pmh%"] - v["pmi%"] if v["pmread"] > 0 else 0
|
||||
v["pread"] = v["phit"] + v["pmis"]
|
||||
v["ph%"] = 100 * v["phit"] / v["pread"] if v["pread"] > 0 else 0
|
||||
v["pm%"] = 100 - v["ph%"] if v["pread"] > 0 else 0
|
||||
|
||||
v["mhit"] = (d["prefetch_metadata_hits"] +
|
||||
d["demand_metadata_hits"]) // sint
|
||||
v["mioh"] = (d["prefetch_metadata_iohits"] +
|
||||
d["demand_metadata_iohits"]) // sint
|
||||
d["demand_metadata_hits"]) / sint
|
||||
v["mmis"] = (d["prefetch_metadata_misses"] +
|
||||
d["demand_metadata_misses"]) // sint
|
||||
d["demand_metadata_misses"]) / sint
|
||||
|
||||
v["mread"] = v["mhit"] + v["mioh"] + v["mmis"]
|
||||
v["mh%"] = 100 * v["mhit"] // v["mread"] if v["mread"] > 0 else 0
|
||||
v["mi%"] = 100 * v["mioh"] // v["mread"] if v["mread"] > 0 else 0
|
||||
v["mm%"] = 100 - v["mh%"] - v["mi%"] if v["mread"] > 0 else 0
|
||||
v["mread"] = v["mhit"] + v["mmis"]
|
||||
v["mh%"] = 100 * v["mhit"] / v["mread"] if v["mread"] > 0 else 0
|
||||
v["mm%"] = 100 - v["mh%"] if v["mread"] > 0 else 0
|
||||
|
||||
v["arcsz"] = cur["size"]
|
||||
v["size"] = cur["size"]
|
||||
v["c"] = cur["c"]
|
||||
v["mfu"] = d["mfu_hits"] // sint
|
||||
v["mru"] = d["mru_hits"] // sint
|
||||
v["mrug"] = d["mru_ghost_hits"] // sint
|
||||
v["mfug"] = d["mfu_ghost_hits"] // sint
|
||||
v["unc"] = d["uncached_hits"] // sint
|
||||
v["eskip"] = d["evict_skip"] // sint
|
||||
v["el2skip"] = d["evict_l2_skip"] // sint
|
||||
v["el2cach"] = d["evict_l2_cached"] // sint
|
||||
v["el2el"] = d["evict_l2_eligible"] // sint
|
||||
v["el2mfu"] = d["evict_l2_eligible_mfu"] // sint
|
||||
v["el2mru"] = d["evict_l2_eligible_mru"] // sint
|
||||
v["el2inel"] = d["evict_l2_ineligible"] // sint
|
||||
v["mtxmis"] = d["mutex_miss"] // sint
|
||||
v["ztotal"] = (d["zfetch_hits"] + d["zfetch_future"] + d["zfetch_stride"] +
|
||||
d["zfetch_past"] + d["zfetch_misses"]) // sint
|
||||
v["zhits"] = d["zfetch_hits"] // sint
|
||||
v["zahead"] = (d["zfetch_future"] + d["zfetch_stride"]) // sint
|
||||
v["zpast"] = d["zfetch_past"] // sint
|
||||
v["zmisses"] = d["zfetch_misses"] // sint
|
||||
v["zmax"] = d["zfetch_max_streams"] // sint
|
||||
v["zfuture"] = d["zfetch_future"] // sint
|
||||
v["zstride"] = d["zfetch_stride"] // sint
|
||||
v["zissued"] = d["zfetch_io_issued"] // sint
|
||||
v["zactive"] = d["zfetch_io_active"] // sint
|
||||
v["mfu"] = d["mfu_hits"] / sint
|
||||
v["mru"] = d["mru_hits"] / sint
|
||||
v["mrug"] = d["mru_ghost_hits"] / sint
|
||||
v["mfug"] = d["mfu_ghost_hits"] / sint
|
||||
v["eskip"] = d["evict_skip"] / sint
|
||||
v["mtxmis"] = d["mutex_miss"] / sint
|
||||
|
||||
if l2exist:
|
||||
v["l2hits"] = d["l2_hits"] // sint
|
||||
v["l2miss"] = d["l2_misses"] // sint
|
||||
v["l2hits"] = d["l2_hits"] / sint
|
||||
v["l2miss"] = d["l2_misses"] / sint
|
||||
v["l2read"] = v["l2hits"] + v["l2miss"]
|
||||
v["l2hit%"] = 100 * v["l2hits"] // v["l2read"] if v["l2read"] > 0 else 0
|
||||
v["l2hit%"] = 100 * v["l2hits"] / v["l2read"] if v["l2read"] > 0 else 0
|
||||
|
||||
v["l2miss%"] = 100 - v["l2hit%"] if v["l2read"] > 0 else 0
|
||||
v["l2asize"] = cur["l2_asize"]
|
||||
v["l2size"] = cur["l2_size"]
|
||||
v["l2bytes"] = d["l2_read_bytes"] // sint
|
||||
|
||||
v["l2pref"] = cur["l2_prefetch_asize"]
|
||||
v["l2mfu"] = cur["l2_mfu_asize"]
|
||||
v["l2mru"] = cur["l2_mru_asize"]
|
||||
v["l2data"] = cur["l2_bufc_data_asize"]
|
||||
v["l2meta"] = cur["l2_bufc_metadata_asize"]
|
||||
v["l2pref%"] = 100 * v["l2pref"] // v["l2asize"]
|
||||
v["l2mfu%"] = 100 * v["l2mfu"] // v["l2asize"]
|
||||
v["l2mru%"] = 100 * v["l2mru"] // v["l2asize"]
|
||||
v["l2data%"] = 100 * v["l2data"] // v["l2asize"]
|
||||
v["l2meta%"] = 100 * v["l2meta"] // v["l2asize"]
|
||||
v["l2bytes"] = d["l2_read_bytes"] / sint
|
||||
|
||||
v["grow"] = 0 if cur["arc_no_grow"] else 1
|
||||
v["need"] = cur["arc_need_free"]
|
||||
@@ -0,0 +1 @@
|
||||
dbufstat
|
||||
@@ -0,0 +1,5 @@
|
||||
include $(top_srcdir)/config/Substfiles.am
|
||||
|
||||
bin_SCRIPTS = dbufstat
|
||||
|
||||
SUBSTFILES += $(bin_SCRIPTS)
|
||||
@@ -12,7 +12,7 @@
|
||||
# with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or https://opensource.org/licenses/CDDL-1.0.
|
||||
# or http://www.opensolaris.org/os/licensing.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
@@ -27,7 +27,7 @@
|
||||
# Copyright (C) 2013 Lawrence Livermore National Security, LLC.
|
||||
# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
|
||||
#
|
||||
# This script must remain compatible with and Python 3.6+.
|
||||
# This script must remain compatible with Python 2.6+ and Python 3.4+.
|
||||
#
|
||||
|
||||
import sys
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# fsck.zfs: A fsck helper to accommodate distributions that expect
|
||||
# to be able to execute a fsck on all filesystem types.
|
||||
#
|
||||
# This script simply bubbles up some already-known-about errors,
|
||||
# see fsck.zfs(8)
|
||||
#
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 [options] dataset…" >&2
|
||||
exit 16
|
||||
fi
|
||||
|
||||
ret=0
|
||||
for dataset; do
|
||||
case "$dataset" in
|
||||
-*)
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
pool="${dataset%%/*}"
|
||||
|
||||
case "$(@sbindir@/zpool list -Ho health "$pool")" in
|
||||
DEGRADED)
|
||||
ret=$(( ret | 4 ))
|
||||
;;
|
||||
FAULTED)
|
||||
awk '!/^([[:space:]]*#.*)?$/ && $1 == "'"$dataset"'" && $3 == "zfs" {exit 1}' /etc/fstab || \
|
||||
ret=$(( ret | 8 ))
|
||||
;;
|
||||
"")
|
||||
# Pool not found, error printed by zpool(8)
|
||||
ret=$(( ret | 8 ))
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
exit "$ret"
|
||||
@@ -0,0 +1 @@
|
||||
dist_sbin_SCRIPTS = fsck.zfs
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# fsck.zfs: A fsck helper to accommodate distributions that expect
|
||||
# to be able to execute a fsck on all filesystem types. Currently
|
||||
# this script does nothing but it could be extended to act as a
|
||||
# compatibility wrapper for 'zpool scrub'.
|
||||
#
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1 @@
|
||||
mount.zfs
|
||||
@@ -0,0 +1,22 @@
|
||||
include $(top_srcdir)/config/Rules.am
|
||||
|
||||
#
|
||||
# Ignore the prefix for the mount helper. It must be installed in /sbin/
|
||||
# because this path is hardcoded in the mount(8) for security reasons.
|
||||
# However, if needed, the configure option --with-mounthelperdir= can be used
|
||||
# to override the default install location.
|
||||
#
|
||||
sbindir=$(mounthelperdir)
|
||||
sbin_PROGRAMS = mount.zfs
|
||||
|
||||
mount_zfs_SOURCES = \
|
||||
mount_zfs.c
|
||||
|
||||
mount_zfs_LDADD = \
|
||||
$(abs_top_builddir)/lib/libzfs/libzfs.la \
|
||||
$(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \
|
||||
$(abs_top_builddir)/lib/libnvpair/libnvpair.la
|
||||
|
||||
mount_zfs_LDADD += $(LTLIBINTL)
|
||||
|
||||
include $(top_srcdir)/config/CppCheck.am
|
||||
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -74,7 +74,7 @@ parse_dataset(const char *target, char **dataset)
|
||||
|
||||
nvlist_t *cfg = NULL;
|
||||
if (zpool_read_label(fd, &cfg, NULL) == 0) {
|
||||
const char *nm = NULL;
|
||||
char *nm = NULL;
|
||||
if (!nvlist_lookup_string(cfg, ZPOOL_CONFIG_POOL_NAME, &nm))
|
||||
strlcpy(*dataset, nm, PATH_MAX);
|
||||
nvlist_free(cfg);
|
||||
@@ -108,21 +108,20 @@ mtab_is_writeable(void)
|
||||
}
|
||||
|
||||
static int
|
||||
mtab_update(const char *dataset, const char *mntpoint, const char *type,
|
||||
const char *mntopts)
|
||||
mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts)
|
||||
{
|
||||
struct mntent mnt;
|
||||
FILE *fp;
|
||||
int error;
|
||||
|
||||
mnt.mnt_fsname = (char *)dataset;
|
||||
mnt.mnt_dir = (char *)mntpoint;
|
||||
mnt.mnt_type = (char *)type;
|
||||
mnt.mnt_opts = (char *)(mntopts ?: "");
|
||||
mnt.mnt_fsname = dataset;
|
||||
mnt.mnt_dir = mntpoint;
|
||||
mnt.mnt_type = type;
|
||||
mnt.mnt_opts = mntopts ? mntopts : "";
|
||||
mnt.mnt_freq = 0;
|
||||
mnt.mnt_passno = 0;
|
||||
|
||||
fp = setmntent("/etc/mtab", "a+e");
|
||||
fp = setmntent("/etc/mtab", "a+");
|
||||
if (!fp) {
|
||||
(void) fprintf(stderr, gettext(
|
||||
"filesystem '%s' was mounted, but /etc/mtab "
|
||||
@@ -186,11 +185,10 @@ main(int argc, char **argv)
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
if (optopt)
|
||||
(void) fprintf(stderr,
|
||||
gettext("Invalid option '%c'\n"), optopt);
|
||||
(void) fprintf(stderr, gettext("Invalid option '%c'\n"),
|
||||
optopt);
|
||||
(void) fprintf(stderr, gettext("Usage: mount.zfs "
|
||||
"[-sfnvh] [-o options] <dataset> <mountpoint>\n"));
|
||||
"[-sfnv] [-o options] <dataset> <mountpoint>\n"));
|
||||
return (MOUNT_USAGE);
|
||||
}
|
||||
}
|
||||
@@ -247,6 +245,13 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
(void) fprintf(stdout, gettext("mount.zfs:\n"
|
||||
" dataset: \"%s\"\n mountpoint: \"%s\"\n"
|
||||
" mountflags: 0x%lx\n zfsflags: 0x%lx\n"
|
||||
" mountopts: \"%s\"\n mtabopts: \"%s\"\n"),
|
||||
dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
|
||||
|
||||
if (mntflags & MS_REMOUNT) {
|
||||
nomtab = 1;
|
||||
remount = 1;
|
||||
@@ -269,10 +274,7 @@ main(int argc, char **argv)
|
||||
return (MOUNT_USAGE);
|
||||
}
|
||||
|
||||
if (!zfsutil || sloppy ||
|
||||
libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
|
||||
zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt);
|
||||
}
|
||||
zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt);
|
||||
|
||||
/* treat all snapshots as legacy mount points */
|
||||
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
|
||||
@@ -290,11 +292,12 @@ main(int argc, char **argv)
|
||||
if (zfs_version == 0) {
|
||||
fprintf(stderr, gettext("unable to fetch "
|
||||
"ZFS version for filesystem '%s'\n"), dataset);
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
return (MOUNT_SYSERR);
|
||||
}
|
||||
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
|
||||
/*
|
||||
* Legacy mount points may only be mounted using 'mount', never using
|
||||
* 'zfs mount'. However, since 'zfs mount' actually invokes 'mount'
|
||||
@@ -312,8 +315,6 @@ main(int argc, char **argv)
|
||||
"Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n"
|
||||
"See zfs(8) for more information.\n"),
|
||||
dataset, mntpoint, dataset, mntpoint);
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
return (MOUNT_USAGE);
|
||||
}
|
||||
|
||||
@@ -324,38 +325,14 @@ main(int argc, char **argv)
|
||||
"Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n"
|
||||
"See zfs(8) for more information.\n"),
|
||||
dataset, "legacy", dataset);
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
return (MOUNT_USAGE);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
(void) fprintf(stdout, gettext("mount.zfs:\n"
|
||||
" dataset: \"%s\"\n mountpoint: \"%s\"\n"
|
||||
" mountflags: 0x%lx\n zfsflags: 0x%lx\n"
|
||||
" mountopts: \"%s\"\n mtabopts: \"%s\"\n"),
|
||||
dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
|
||||
|
||||
if (!fake) {
|
||||
if (zfsutil && !sloppy &&
|
||||
!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
|
||||
error = zfs_mount_at(zhp, mntopts, mntflags, mntpoint);
|
||||
if (error) {
|
||||
(void) fprintf(stderr, "zfs_mount_at() failed: "
|
||||
"%s", libzfs_error_description(g_zfs));
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
return (MOUNT_SYSERR);
|
||||
}
|
||||
} else {
|
||||
error = mount(dataset, mntpoint, MNTTYPE_ZFS,
|
||||
mntflags, mntopts);
|
||||
}
|
||||
error = mount(dataset, mntpoint, MNTTYPE_ZFS,
|
||||
mntflags, mntopts);
|
||||
}
|
||||
|
||||
zfs_close(zhp);
|
||||
libzfs_fini(g_zfs);
|
||||
|
||||
if (error) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
@@ -390,8 +367,8 @@ main(int argc, char **argv)
|
||||
"mount the filesystem again.\n"), dataset);
|
||||
return (MOUNT_SYSERR);
|
||||
}
|
||||
/* fallthru */
|
||||
#endif
|
||||
zfs_fallthrough;
|
||||
default:
|
||||
(void) fprintf(stderr, gettext("filesystem "
|
||||
"'%s' can not be mounted: %s\n"), dataset,
|
||||
@@ -0,0 +1 @@
|
||||
/raidz_test
|
||||
@@ -1,16 +1,22 @@
|
||||
raidz_test_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS)
|
||||
raidz_test_CPPFLAGS = $(AM_CPPFLAGS) $(FORCEDEBUG_CPPFLAGS)
|
||||
include $(top_srcdir)/config/Rules.am
|
||||
|
||||
bin_PROGRAMS += raidz_test
|
||||
CPPCHECKTARGETS += raidz_test
|
||||
# Includes kernel code, generate warnings for large stack frames
|
||||
AM_CFLAGS += $(FRAME_LARGER_THAN)
|
||||
|
||||
# Unconditionally enable ASSERTs
|
||||
AM_CPPFLAGS += -DDEBUG -UNDEBUG -DZFS_DEBUG
|
||||
|
||||
bin_PROGRAMS = raidz_test
|
||||
|
||||
raidz_test_SOURCES = \
|
||||
%D%/raidz_bench.c \
|
||||
%D%/raidz_test.c \
|
||||
%D%/raidz_test.h
|
||||
raidz_test.h \
|
||||
raidz_test.c \
|
||||
raidz_bench.c
|
||||
|
||||
raidz_test_LDADD = \
|
||||
libzpool.la \
|
||||
libzfs_core.la
|
||||
$(abs_top_builddir)/lib/libzpool/libzpool.la \
|
||||
$(abs_top_builddir)/lib/libzfs_core/libzfs_core.la
|
||||
|
||||
raidz_test_LDADD += -lm
|
||||
|
||||
include $(top_srcdir)/config/CppCheck.am
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <sys/vdev_raidz_impl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "raidz_test.h"
|
||||
|
||||
#define GEN_BENCH_MEMORY (((uint64_t)1ULL)<<32)
|
||||
@@ -63,7 +65,7 @@ bench_fini_raidz_maps(void)
|
||||
{
|
||||
/* tear down golden zio */
|
||||
raidz_free(zio_bench.io_abd, max_data_size);
|
||||
memset(&zio_bench, 0, sizeof (zio_t));
|
||||
bzero(&zio_bench, sizeof (zio_t));
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -81,17 +83,8 @@ run_gen_bench_impl(const char *impl)
|
||||
/* create suitable raidz_map */
|
||||
ncols = rto_opts.rto_dcols + fn + 1;
|
||||
zio_bench.io_size = 1ULL << ds;
|
||||
|
||||
if (rto_opts.rto_expand) {
|
||||
rm_bench = vdev_raidz_map_alloc_expanded(
|
||||
zio_bench.io_abd,
|
||||
zio_bench.io_size, zio_bench.io_offset,
|
||||
rto_opts.rto_ashift, ncols+1, ncols,
|
||||
fn+1, rto_opts.rto_expand_offset);
|
||||
} else {
|
||||
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
||||
BENCH_ASHIFT, ncols, fn+1);
|
||||
}
|
||||
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
||||
BENCH_ASHIFT, ncols, fn+1);
|
||||
|
||||
/* estimate iteration count */
|
||||
iter_cnt = GEN_BENCH_MEMORY;
|
||||
@@ -170,16 +163,8 @@ run_rec_bench_impl(const char *impl)
|
||||
(1ULL << BENCH_ASHIFT))
|
||||
continue;
|
||||
|
||||
if (rto_opts.rto_expand) {
|
||||
rm_bench = vdev_raidz_map_alloc_expanded(
|
||||
zio_bench.io_abd,
|
||||
zio_bench.io_size, zio_bench.io_offset,
|
||||
BENCH_ASHIFT, ncols+1, ncols,
|
||||
PARITY_PQR, rto_opts.rto_expand_offset);
|
||||
} else {
|
||||
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
||||
BENCH_ASHIFT, ncols, PARITY_PQR);
|
||||
}
|
||||
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
||||
BENCH_ASHIFT, ncols, PARITY_PQR);
|
||||
|
||||
/* estimate iteration count */
|
||||
iter_cnt = (REC_BENCH_MEMORY);
|
||||
|
||||
+69
-311
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -37,11 +37,11 @@
|
||||
static int *rand_data;
|
||||
raidz_test_opts_t rto_opts;
|
||||
|
||||
static char pid_s[16];
|
||||
static char gdb[256];
|
||||
static const char gdb_tmpl[] = "gdb -ex \"set pagination 0\" -p %d";
|
||||
|
||||
static void sig_handler(int signo)
|
||||
{
|
||||
int old_errno = errno;
|
||||
struct sigaction action;
|
||||
/*
|
||||
* Restore default action and re-raise signal so SIGSEGV and
|
||||
@@ -52,32 +52,22 @@ static void sig_handler(int signo)
|
||||
action.sa_flags = 0;
|
||||
(void) sigaction(signo, &action, NULL);
|
||||
|
||||
if (rto_opts.rto_gdb) {
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
execlp("gdb", "gdb", "-ex", "set pagination 0",
|
||||
"-p", pid_s, NULL);
|
||||
_exit(-1);
|
||||
} else if (pid > 0)
|
||||
while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
|
||||
;
|
||||
}
|
||||
if (rto_opts.rto_gdb)
|
||||
if (system(gdb)) { }
|
||||
|
||||
raise(signo);
|
||||
errno = old_errno;
|
||||
}
|
||||
|
||||
static void print_opts(raidz_test_opts_t *opts, boolean_t force)
|
||||
{
|
||||
const char *verbose;
|
||||
char *verbose;
|
||||
switch (opts->rto_v) {
|
||||
case D_ALL:
|
||||
case 0:
|
||||
verbose = "no";
|
||||
break;
|
||||
case D_INFO:
|
||||
case 1:
|
||||
verbose = "info";
|
||||
break;
|
||||
case D_DEBUG:
|
||||
default:
|
||||
verbose = "debug";
|
||||
break;
|
||||
@@ -87,20 +77,16 @@ static void print_opts(raidz_test_opts_t *opts, boolean_t force)
|
||||
(void) fprintf(stdout, DBLSEP "Running with options:\n"
|
||||
" (-a) zio ashift : %zu\n"
|
||||
" (-o) zio offset : 1 << %zu\n"
|
||||
" (-e) expanded map : %s\n"
|
||||
" (-r) reflow offset : %llx\n"
|
||||
" (-d) number of raidz data columns : %zu\n"
|
||||
" (-s) size of DATA : 1 << %zu\n"
|
||||
" (-S) sweep parameters : %s \n"
|
||||
" (-v) verbose : %s \n\n",
|
||||
opts->rto_ashift, /* -a */
|
||||
ilog2(opts->rto_offset), /* -o */
|
||||
opts->rto_expand ? "yes" : "no", /* -e */
|
||||
(u_longlong_t)opts->rto_expand_offset, /* -r */
|
||||
opts->rto_dcols, /* -d */
|
||||
ilog2(opts->rto_dsize), /* -s */
|
||||
opts->rto_sweep ? "yes" : "no", /* -S */
|
||||
verbose); /* -v */
|
||||
opts->rto_ashift, /* -a */
|
||||
ilog2(opts->rto_offset), /* -o */
|
||||
opts->rto_dcols, /* -d */
|
||||
ilog2(opts->rto_dsize), /* -s */
|
||||
opts->rto_sweep ? "yes" : "no", /* -S */
|
||||
verbose); /* -v */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,9 +104,7 @@ static void usage(boolean_t requested)
|
||||
"\t[-S parameter sweep (default: %s)]\n"
|
||||
"\t[-t timeout for parameter sweep test]\n"
|
||||
"\t[-B benchmark all raidz implementations]\n"
|
||||
"\t[-e use expanded raidz map (default: %s)]\n"
|
||||
"\t[-r expanded raidz map reflow offset (default: %llx)]\n"
|
||||
"\t[-v increase verbosity (default: %d)]\n"
|
||||
"\t[-v increase verbosity (default: %zu)]\n"
|
||||
"\t[-h (print help)]\n"
|
||||
"\t[-T test the test, see if failure would be detected]\n"
|
||||
"\t[-D debug (attach gdb on SIGSEGV)]\n"
|
||||
@@ -130,9 +114,7 @@ static void usage(boolean_t requested)
|
||||
o->rto_dcols, /* -d */
|
||||
ilog2(o->rto_dsize), /* -s */
|
||||
rto_opts.rto_sweep ? "yes" : "no", /* -S */
|
||||
rto_opts.rto_expand ? "yes" : "no", /* -e */
|
||||
(u_longlong_t)o->rto_expand_offset, /* -r */
|
||||
o->rto_v); /* -v */
|
||||
o->rto_v); /* -d */
|
||||
|
||||
exit(requested ? 0 : 1);
|
||||
}
|
||||
@@ -141,22 +123,19 @@ static void process_options(int argc, char **argv)
|
||||
{
|
||||
size_t value;
|
||||
int opt;
|
||||
|
||||
raidz_test_opts_t *o = &rto_opts;
|
||||
|
||||
memcpy(o, &rto_opts_defaults, sizeof (*o));
|
||||
bcopy(&rto_opts_defaults, o, sizeof (*o));
|
||||
|
||||
while ((opt = getopt(argc, argv, "TDBSvha:o:d:s:t:")) != -1) {
|
||||
value = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "TDBSvha:er:o:d:s:t:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
value = strtoull(optarg, NULL, 0);
|
||||
o->rto_ashift = MIN(13, MAX(9, value));
|
||||
break;
|
||||
case 'e':
|
||||
o->rto_expand = 1;
|
||||
break;
|
||||
case 'r':
|
||||
o->rto_expand_offset = strtoull(optarg, NULL, 0);
|
||||
break;
|
||||
case 'o':
|
||||
value = strtoull(optarg, NULL, 0);
|
||||
o->rto_offset = ((1ULL << MIN(12, value)) >> 9) << 9;
|
||||
@@ -200,34 +179,25 @@ static void process_options(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
#define DATA_COL(rr, i) ((rr)->rr_col[rr->rr_firstdatacol + (i)].rc_abd)
|
||||
#define DATA_COL_SIZE(rr, i) ((rr)->rr_col[rr->rr_firstdatacol + (i)].rc_size)
|
||||
#define DATA_COL(rm, i) ((rm)->rm_col[raidz_parity(rm) + (i)].rc_abd)
|
||||
#define DATA_COL_SIZE(rm, i) ((rm)->rm_col[raidz_parity(rm) + (i)].rc_size)
|
||||
|
||||
#define CODE_COL(rr, i) ((rr)->rr_col[(i)].rc_abd)
|
||||
#define CODE_COL_SIZE(rr, i) ((rr)->rr_col[(i)].rc_size)
|
||||
#define CODE_COL(rm, i) ((rm)->rm_col[(i)].rc_abd)
|
||||
#define CODE_COL_SIZE(rm, i) ((rm)->rm_col[(i)].rc_size)
|
||||
|
||||
static int
|
||||
cmp_code(raidz_test_opts_t *opts, const raidz_map_t *rm, const int parity)
|
||||
{
|
||||
int r, i, ret = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
VERIFY(parity >= 1 && parity <= 3);
|
||||
|
||||
for (r = 0; r < rm->rm_nrows; r++) {
|
||||
raidz_row_t * const rr = rm->rm_row[r];
|
||||
raidz_row_t * const rrg = opts->rm_golden->rm_row[r];
|
||||
for (i = 0; i < parity; i++) {
|
||||
if (CODE_COL_SIZE(rrg, i) == 0) {
|
||||
VERIFY0(CODE_COL_SIZE(rr, i));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (abd_cmp(CODE_COL(rr, i),
|
||||
CODE_COL(rrg, i)) != 0) {
|
||||
ret++;
|
||||
LOG_OPT(D_DEBUG, opts,
|
||||
"\nParity block [%d] different!\n", i);
|
||||
}
|
||||
for (i = 0; i < parity; i++) {
|
||||
if (abd_cmp(CODE_COL(rm, i), CODE_COL(opts->rm_golden, i))
|
||||
!= 0) {
|
||||
ret++;
|
||||
LOG_OPT(D_DEBUG, opts,
|
||||
"\nParity block [%d] different!\n", i);
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
@@ -236,26 +206,16 @@ cmp_code(raidz_test_opts_t *opts, const raidz_map_t *rm, const int parity)
|
||||
static int
|
||||
cmp_data(raidz_test_opts_t *opts, raidz_map_t *rm)
|
||||
{
|
||||
int r, i, dcols, ret = 0;
|
||||
int i, ret = 0;
|
||||
int dcols = opts->rm_golden->rm_cols - raidz_parity(opts->rm_golden);
|
||||
|
||||
for (r = 0; r < rm->rm_nrows; r++) {
|
||||
raidz_row_t *rr = rm->rm_row[r];
|
||||
raidz_row_t *rrg = opts->rm_golden->rm_row[r];
|
||||
dcols = opts->rm_golden->rm_row[0]->rr_cols -
|
||||
raidz_parity(opts->rm_golden);
|
||||
for (i = 0; i < dcols; i++) {
|
||||
if (DATA_COL_SIZE(rrg, i) == 0) {
|
||||
VERIFY0(DATA_COL_SIZE(rr, i));
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < dcols; i++) {
|
||||
if (abd_cmp(DATA_COL(opts->rm_golden, i), DATA_COL(rm, i))
|
||||
!= 0) {
|
||||
ret++;
|
||||
|
||||
if (abd_cmp(DATA_COL(rrg, i),
|
||||
DATA_COL(rr, i)) != 0) {
|
||||
ret++;
|
||||
|
||||
LOG_OPT(D_DEBUG, opts,
|
||||
"\nData block [%d] different!\n", i);
|
||||
}
|
||||
LOG_OPT(D_DEBUG, opts,
|
||||
"\nData block [%d] different!\n", i);
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
@@ -264,21 +224,24 @@ cmp_data(raidz_test_opts_t *opts, raidz_map_t *rm)
|
||||
static int
|
||||
init_rand(void *data, size_t size, void *private)
|
||||
{
|
||||
(void) private;
|
||||
memcpy(data, rand_data, size);
|
||||
int i;
|
||||
int *dst = (int *)data;
|
||||
|
||||
for (i = 0; i < size / sizeof (int); i++)
|
||||
dst[i] = rand_data[i];
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)
|
||||
{
|
||||
for (int r = 0; r < rm->rm_nrows; r++) {
|
||||
raidz_row_t *rr = rm->rm_row[r];
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
raidz_col_t *col = &rr->rr_col[tgts[i]];
|
||||
abd_iterate_func(col->rc_abd, 0, col->rc_size,
|
||||
init_rand, NULL);
|
||||
}
|
||||
int i;
|
||||
raidz_col_t *col;
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
col = &rm->rm_col[tgts[i]];
|
||||
abd_iterate_func(col->rc_abd, 0, col->rc_size, init_rand, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,22 +288,10 @@ init_raidz_golden_map(raidz_test_opts_t *opts, const int parity)
|
||||
|
||||
VERIFY0(vdev_raidz_impl_set("original"));
|
||||
|
||||
if (opts->rto_expand) {
|
||||
opts->rm_golden =
|
||||
vdev_raidz_map_alloc_expanded(opts->zio_golden->io_abd,
|
||||
opts->zio_golden->io_size, opts->zio_golden->io_offset,
|
||||
opts->rto_ashift, total_ncols+1, total_ncols,
|
||||
parity, opts->rto_expand_offset);
|
||||
rm_test = vdev_raidz_map_alloc_expanded(zio_test->io_abd,
|
||||
zio_test->io_size, zio_test->io_offset,
|
||||
opts->rto_ashift, total_ncols+1, total_ncols,
|
||||
parity, opts->rto_expand_offset);
|
||||
} else {
|
||||
opts->rm_golden = vdev_raidz_map_alloc(opts->zio_golden,
|
||||
opts->rto_ashift, total_ncols, parity);
|
||||
rm_test = vdev_raidz_map_alloc(zio_test,
|
||||
opts->rto_ashift, total_ncols, parity);
|
||||
}
|
||||
opts->rm_golden = vdev_raidz_map_alloc(opts->zio_golden,
|
||||
opts->rto_ashift, total_ncols, parity);
|
||||
rm_test = vdev_raidz_map_alloc(zio_test,
|
||||
opts->rto_ashift, total_ncols, parity);
|
||||
|
||||
VERIFY(opts->zio_golden);
|
||||
VERIFY(opts->rm_golden);
|
||||
@@ -361,187 +312,6 @@ init_raidz_golden_map(raidz_test_opts_t *opts, const int parity)
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* If reflow is not in progress, reflow_offset should be UINT64_MAX.
|
||||
* For each row, if the row is entirely before reflow_offset, it will
|
||||
* come from the new location. Otherwise this row will come from the
|
||||
* old location. Therefore, rows that straddle the reflow_offset will
|
||||
* come from the old location.
|
||||
*
|
||||
* NOTE: Until raidz expansion is implemented this function is only
|
||||
* needed by raidz_test.c to the multi-row raid_map_t functionality.
|
||||
*/
|
||||
raidz_map_t *
|
||||
vdev_raidz_map_alloc_expanded(abd_t *abd, uint64_t size, uint64_t offset,
|
||||
uint64_t ashift, uint64_t physical_cols, uint64_t logical_cols,
|
||||
uint64_t nparity, uint64_t reflow_offset)
|
||||
{
|
||||
/* The zio's size in units of the vdev's minimum sector size. */
|
||||
uint64_t s = size >> ashift;
|
||||
uint64_t q, r, bc, devidx, asize = 0, tot;
|
||||
|
||||
/*
|
||||
* "Quotient": The number of data sectors for this stripe on all but
|
||||
* the "big column" child vdevs that also contain "remainder" data.
|
||||
* AKA "full rows"
|
||||
*/
|
||||
q = s / (logical_cols - nparity);
|
||||
|
||||
/*
|
||||
* "Remainder": The number of partial stripe data sectors in this I/O.
|
||||
* This will add a sector to some, but not all, child vdevs.
|
||||
*/
|
||||
r = s - q * (logical_cols - nparity);
|
||||
|
||||
/* The number of "big columns" - those which contain remainder data. */
|
||||
bc = (r == 0 ? 0 : r + nparity);
|
||||
|
||||
/*
|
||||
* The total number of data and parity sectors associated with
|
||||
* this I/O.
|
||||
*/
|
||||
tot = s + nparity * (q + (r == 0 ? 0 : 1));
|
||||
|
||||
/* How many rows contain data (not skip) */
|
||||
uint64_t rows = howmany(tot, logical_cols);
|
||||
int cols = MIN(tot, logical_cols);
|
||||
|
||||
raidz_map_t *rm = kmem_zalloc(offsetof(raidz_map_t, rm_row[rows]),
|
||||
KM_SLEEP);
|
||||
rm->rm_nrows = rows;
|
||||
|
||||
for (uint64_t row = 0; row < rows; row++) {
|
||||
raidz_row_t *rr = kmem_alloc(offsetof(raidz_row_t,
|
||||
rr_col[cols]), KM_SLEEP);
|
||||
rm->rm_row[row] = rr;
|
||||
|
||||
/* The starting RAIDZ (parent) vdev sector of the row. */
|
||||
uint64_t b = (offset >> ashift) + row * logical_cols;
|
||||
|
||||
/*
|
||||
* If we are in the middle of a reflow, and any part of this
|
||||
* row has not been copied, then use the old location of
|
||||
* this row.
|
||||
*/
|
||||
int row_phys_cols = physical_cols;
|
||||
if (b + (logical_cols - nparity) > reflow_offset >> ashift)
|
||||
row_phys_cols--;
|
||||
|
||||
/* starting child of this row */
|
||||
uint64_t child_id = b % row_phys_cols;
|
||||
/* The starting byte offset on each child vdev. */
|
||||
uint64_t child_offset = (b / row_phys_cols) << ashift;
|
||||
|
||||
/*
|
||||
* We set cols to the entire width of the block, even
|
||||
* if this row is shorter. This is needed because parity
|
||||
* generation (for Q and R) needs to know the entire width,
|
||||
* because it treats the short row as though it was
|
||||
* full-width (and the "phantom" sectors were zero-filled).
|
||||
*
|
||||
* Another approach to this would be to set cols shorter
|
||||
* (to just the number of columns that we might do i/o to)
|
||||
* and have another mechanism to tell the parity generation
|
||||
* about the "entire width". Reconstruction (at least
|
||||
* vdev_raidz_reconstruct_general()) would also need to
|
||||
* know about the "entire width".
|
||||
*/
|
||||
rr->rr_cols = cols;
|
||||
rr->rr_bigcols = bc;
|
||||
rr->rr_missingdata = 0;
|
||||
rr->rr_missingparity = 0;
|
||||
rr->rr_firstdatacol = nparity;
|
||||
rr->rr_abd_empty = NULL;
|
||||
rr->rr_nempty = 0;
|
||||
|
||||
for (int c = 0; c < rr->rr_cols; c++, child_id++) {
|
||||
if (child_id >= row_phys_cols) {
|
||||
child_id -= row_phys_cols;
|
||||
child_offset += 1ULL << ashift;
|
||||
}
|
||||
rr->rr_col[c].rc_devidx = child_id;
|
||||
rr->rr_col[c].rc_offset = child_offset;
|
||||
rr->rr_col[c].rc_orig_data = NULL;
|
||||
rr->rr_col[c].rc_error = 0;
|
||||
rr->rr_col[c].rc_tried = 0;
|
||||
rr->rr_col[c].rc_skipped = 0;
|
||||
rr->rr_col[c].rc_need_orig_restore = B_FALSE;
|
||||
|
||||
uint64_t dc = c - rr->rr_firstdatacol;
|
||||
if (c < rr->rr_firstdatacol) {
|
||||
rr->rr_col[c].rc_size = 1ULL << ashift;
|
||||
rr->rr_col[c].rc_abd =
|
||||
abd_alloc_linear(rr->rr_col[c].rc_size,
|
||||
B_TRUE);
|
||||
} else if (row == rows - 1 && bc != 0 && c >= bc) {
|
||||
/*
|
||||
* Past the end, this for parity generation.
|
||||
*/
|
||||
rr->rr_col[c].rc_size = 0;
|
||||
rr->rr_col[c].rc_abd = NULL;
|
||||
} else {
|
||||
/*
|
||||
* "data column" (col excluding parity)
|
||||
* Add an ASCII art diagram here
|
||||
*/
|
||||
uint64_t off;
|
||||
|
||||
if (c < bc || r == 0) {
|
||||
off = dc * rows + row;
|
||||
} else {
|
||||
off = r * rows +
|
||||
(dc - r) * (rows - 1) + row;
|
||||
}
|
||||
rr->rr_col[c].rc_size = 1ULL << ashift;
|
||||
rr->rr_col[c].rc_abd = abd_get_offset_struct(
|
||||
&rr->rr_col[c].rc_abdstruct,
|
||||
abd, off << ashift, 1 << ashift);
|
||||
}
|
||||
|
||||
asize += rr->rr_col[c].rc_size;
|
||||
}
|
||||
/*
|
||||
* If all data stored spans all columns, there's a danger that
|
||||
* parity will always be on the same device and, since parity
|
||||
* isn't read during normal operation, that that device's I/O
|
||||
* bandwidth won't be used effectively. We therefore switch
|
||||
* the parity every 1MB.
|
||||
*
|
||||
* ...at least that was, ostensibly, the theory. As a practical
|
||||
* matter unless we juggle the parity between all devices
|
||||
* evenly, we won't see any benefit. Further, occasional writes
|
||||
* that aren't a multiple of the LCM of the number of children
|
||||
* and the minimum stripe width are sufficient to avoid pessimal
|
||||
* behavior. Unfortunately, this decision created an implicit
|
||||
* on-disk format requirement that we need to support for all
|
||||
* eternity, but only for single-parity RAID-Z.
|
||||
*
|
||||
* If we intend to skip a sector in the zeroth column for
|
||||
* padding we must make sure to note this swap. We will never
|
||||
* intend to skip the first column since at least one data and
|
||||
* one parity column must appear in each row.
|
||||
*/
|
||||
if (rr->rr_firstdatacol == 1 && rr->rr_cols > 1 &&
|
||||
(offset & (1ULL << 20))) {
|
||||
ASSERT(rr->rr_cols >= 2);
|
||||
ASSERT(rr->rr_col[0].rc_size == rr->rr_col[1].rc_size);
|
||||
devidx = rr->rr_col[0].rc_devidx;
|
||||
uint64_t o = rr->rr_col[0].rc_offset;
|
||||
rr->rr_col[0].rc_devidx = rr->rr_col[1].rc_devidx;
|
||||
rr->rr_col[0].rc_offset = rr->rr_col[1].rc_offset;
|
||||
rr->rr_col[1].rc_devidx = devidx;
|
||||
rr->rr_col[1].rc_offset = o;
|
||||
}
|
||||
|
||||
}
|
||||
ASSERT3U(asize, ==, tot << ashift);
|
||||
|
||||
/* init RAIDZ parity ops */
|
||||
rm->rm_ops = vdev_raidz_math_get_ops();
|
||||
|
||||
return (rm);
|
||||
}
|
||||
|
||||
static raidz_map_t *
|
||||
init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)
|
||||
{
|
||||
@@ -560,15 +330,8 @@ init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)
|
||||
(*zio)->io_abd = raidz_alloc(alloc_dsize);
|
||||
init_zio_abd(*zio);
|
||||
|
||||
if (opts->rto_expand) {
|
||||
rm = vdev_raidz_map_alloc_expanded((*zio)->io_abd,
|
||||
(*zio)->io_size, (*zio)->io_offset,
|
||||
opts->rto_ashift, total_ncols+1, total_ncols,
|
||||
parity, opts->rto_expand_offset);
|
||||
} else {
|
||||
rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,
|
||||
total_ncols, parity);
|
||||
}
|
||||
rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,
|
||||
total_ncols, parity);
|
||||
VERIFY(rm);
|
||||
|
||||
/* Make sure code columns are destroyed */
|
||||
@@ -657,7 +420,7 @@ run_rec_check_impl(raidz_test_opts_t *opts, raidz_map_t *rm, const int fn)
|
||||
if (fn < RAIDZ_REC_PQ) {
|
||||
/* can reconstruct 1 failed data disk */
|
||||
for (x0 = 0; x0 < opts->rto_dcols; x0++) {
|
||||
if (x0 >= rm->rm_row[0]->rr_cols - raidz_parity(rm))
|
||||
if (x0 >= rm->rm_cols - raidz_parity(rm))
|
||||
continue;
|
||||
|
||||
/* Check if should stop */
|
||||
@@ -682,11 +445,10 @@ run_rec_check_impl(raidz_test_opts_t *opts, raidz_map_t *rm, const int fn)
|
||||
} else if (fn < RAIDZ_REC_PQR) {
|
||||
/* can reconstruct 2 failed data disk */
|
||||
for (x0 = 0; x0 < opts->rto_dcols; x0++) {
|
||||
if (x0 >= rm->rm_row[0]->rr_cols - raidz_parity(rm))
|
||||
if (x0 >= rm->rm_cols - raidz_parity(rm))
|
||||
continue;
|
||||
for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {
|
||||
if (x1 >= rm->rm_row[0]->rr_cols -
|
||||
raidz_parity(rm))
|
||||
if (x1 >= rm->rm_cols - raidz_parity(rm))
|
||||
continue;
|
||||
|
||||
/* Check if should stop */
|
||||
@@ -713,15 +475,14 @@ run_rec_check_impl(raidz_test_opts_t *opts, raidz_map_t *rm, const int fn)
|
||||
} else {
|
||||
/* can reconstruct 3 failed data disk */
|
||||
for (x0 = 0; x0 < opts->rto_dcols; x0++) {
|
||||
if (x0 >= rm->rm_row[0]->rr_cols - raidz_parity(rm))
|
||||
if (x0 >= rm->rm_cols - raidz_parity(rm))
|
||||
continue;
|
||||
for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {
|
||||
if (x1 >= rm->rm_row[0]->rr_cols -
|
||||
raidz_parity(rm))
|
||||
if (x1 >= rm->rm_cols - raidz_parity(rm))
|
||||
continue;
|
||||
for (x2 = x1 + 1; x2 < opts->rto_dcols; x2++) {
|
||||
if (x2 >= rm->rm_row[0]->rr_cols -
|
||||
raidz_parity(rm))
|
||||
if (x2 >=
|
||||
rm->rm_cols - raidz_parity(rm))
|
||||
continue;
|
||||
|
||||
/* Check if should stop */
|
||||
@@ -837,7 +598,7 @@ static kcondvar_t sem_cv;
|
||||
static int max_free_slots;
|
||||
static int free_slots;
|
||||
|
||||
static __attribute__((noreturn)) void
|
||||
static void
|
||||
sweep_thread(void *arg)
|
||||
{
|
||||
int err = 0;
|
||||
@@ -937,10 +698,8 @@ run_sweep(void)
|
||||
opts = umem_zalloc(sizeof (raidz_test_opts_t), UMEM_NOFAIL);
|
||||
opts->rto_ashift = ashift_v[a];
|
||||
opts->rto_dcols = dcols_v[d];
|
||||
opts->rto_offset = (1ULL << ashift_v[a]) * rand();
|
||||
opts->rto_offset = (1 << ashift_v[a]) * rand();
|
||||
opts->rto_dsize = size_v[s];
|
||||
opts->rto_expand = rto_opts.rto_expand;
|
||||
opts->rto_expand_offset = rto_opts.rto_expand_offset;
|
||||
opts->rto_v = 0; /* be quiet */
|
||||
|
||||
VERIFY3P(thread_create(NULL, 0, sweep_thread, (void *) opts,
|
||||
@@ -973,7 +732,6 @@ exit:
|
||||
return (sweep_state == SWEEP_ERROR ? SWEEP_ERROR : 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
@@ -981,8 +739,8 @@ main(int argc, char **argv)
|
||||
struct sigaction action;
|
||||
int err = 0;
|
||||
|
||||
/* init gdb pid string early */
|
||||
(void) sprintf(pid_s, "%d", getpid());
|
||||
/* init gdb string early */
|
||||
(void) sprintf(gdb, gdb_tmpl, getpid());
|
||||
|
||||
action.sa_handler = sig_handler;
|
||||
sigemptyset(&action.sa_mask);
|
||||
|
||||
+14
-23
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include <sys/spa.h>
|
||||
|
||||
static const char *const raidz_impl_names[] = {
|
||||
static const char *raidz_impl_names[] = {
|
||||
"original",
|
||||
"scalar",
|
||||
"sse2",
|
||||
@@ -42,23 +42,15 @@ static const char *const raidz_impl_names[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
enum raidz_verbosity {
|
||||
D_ALL,
|
||||
D_INFO,
|
||||
D_DEBUG,
|
||||
};
|
||||
|
||||
typedef struct raidz_test_opts {
|
||||
size_t rto_ashift;
|
||||
uint64_t rto_offset;
|
||||
size_t rto_offset;
|
||||
size_t rto_dcols;
|
||||
size_t rto_dsize;
|
||||
enum raidz_verbosity rto_v;
|
||||
size_t rto_v;
|
||||
size_t rto_sweep;
|
||||
size_t rto_sweep_timeout;
|
||||
size_t rto_benchmark;
|
||||
size_t rto_expand;
|
||||
uint64_t rto_expand_offset;
|
||||
size_t rto_sanity;
|
||||
size_t rto_gdb;
|
||||
|
||||
@@ -74,11 +66,9 @@ static const raidz_test_opts_t rto_opts_defaults = {
|
||||
.rto_offset = 1ULL << 0,
|
||||
.rto_dcols = 8,
|
||||
.rto_dsize = 1<<19,
|
||||
.rto_v = D_ALL,
|
||||
.rto_v = 0,
|
||||
.rto_sweep = 0,
|
||||
.rto_benchmark = 0,
|
||||
.rto_expand = 0,
|
||||
.rto_expand_offset = -1ULL,
|
||||
.rto_sanity = 0,
|
||||
.rto_gdb = 0,
|
||||
.rto_should_stop = B_FALSE
|
||||
@@ -92,19 +82,23 @@ static inline size_t ilog2(size_t a)
|
||||
}
|
||||
|
||||
|
||||
#define LOG(lvl, ...) \
|
||||
#define D_ALL 0
|
||||
#define D_INFO 1
|
||||
#define D_DEBUG 2
|
||||
|
||||
#define LOG(lvl, a...) \
|
||||
{ \
|
||||
if (rto_opts.rto_v >= lvl) \
|
||||
(void) fprintf(stdout, __VA_ARGS__); \
|
||||
(void) fprintf(stdout, a); \
|
||||
} \
|
||||
|
||||
#define LOG_OPT(lvl, opt, ...) \
|
||||
#define LOG_OPT(lvl, opt, a...) \
|
||||
{ \
|
||||
if (opt->rto_v >= lvl) \
|
||||
(void) fprintf(stdout, __VA_ARGS__); \
|
||||
(void) fprintf(stdout, a); \
|
||||
} \
|
||||
|
||||
#define ERR(...) (void) fprintf(stderr, __VA_ARGS__)
|
||||
#define ERR(a...) (void) fprintf(stderr, a)
|
||||
|
||||
|
||||
#define DBLSEP "================\n"
|
||||
@@ -119,7 +113,4 @@ void init_zio_abd(zio_t *zio);
|
||||
|
||||
void run_raidz_benchmark(void);
|
||||
|
||||
struct raidz_map *vdev_raidz_map_alloc_expanded(abd_t *, uint64_t, uint64_t,
|
||||
uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||
|
||||
#endif /* RAIDZ_TEST_H */
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
dist_udev_SCRIPTS = vdev_id
|
||||
+119
-305
@@ -79,34 +79,6 @@
|
||||
# channel 86:00.0 1 A
|
||||
# channel 86:00.0 0 B
|
||||
|
||||
# #
|
||||
# # Example vdev_id.conf - multipath / multijbod-daisychaining
|
||||
# #
|
||||
#
|
||||
# multipath yes
|
||||
# multijbod yes
|
||||
#
|
||||
# # PCI_ID HBA PORT CHANNEL NAME
|
||||
# channel 85:00.0 1 A
|
||||
# channel 85:00.0 0 B
|
||||
# channel 86:00.0 1 A
|
||||
# channel 86:00.0 0 B
|
||||
|
||||
# #
|
||||
# # Example vdev_id.conf - multipath / mixed
|
||||
# #
|
||||
#
|
||||
# multipath yes
|
||||
# slot mix
|
||||
#
|
||||
# # PCI_ID HBA PORT CHANNEL NAME
|
||||
# channel 85:00.0 3 A
|
||||
# channel 85:00.0 2 B
|
||||
# channel 86:00.0 3 A
|
||||
# channel 86:00.0 2 B
|
||||
# channel af:00.0 0 C
|
||||
# channel af:00.0 1 C
|
||||
|
||||
# #
|
||||
# # Example vdev_id.conf - alias
|
||||
# #
|
||||
@@ -120,10 +92,9 @@ PATH=/bin:/sbin:/usr/bin:/usr/sbin
|
||||
CONFIG=/etc/zfs/vdev_id.conf
|
||||
PHYS_PER_PORT=
|
||||
DEV=
|
||||
MULTIPATH=
|
||||
TOPOLOGY=
|
||||
BAY=
|
||||
ENCL_ID=""
|
||||
UNIQ_ENCL_ID=""
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
@@ -136,25 +107,22 @@ Usage: vdev_id [-h]
|
||||
-e Create enclose device symlinks only (/dev/by-enclosure)
|
||||
-g Storage network topology [default="$TOPOLOGY"]
|
||||
-m Run in multipath mode
|
||||
-j Run in multijbod mode
|
||||
-p number of phy's per switch port [default=$PHYS_PER_PORT]
|
||||
-h show this summary
|
||||
EOF
|
||||
exit 1
|
||||
# exit with error to avoid processing usage message by a udev rule
|
||||
exit 0
|
||||
}
|
||||
|
||||
map_slot() {
|
||||
LINUX_SLOT=$1
|
||||
CHANNEL=$2
|
||||
|
||||
MAPPED_SLOT=$(awk -v linux_slot="$LINUX_SLOT" -v channel="$CHANNEL" \
|
||||
'$1 == "slot" && $2 == linux_slot && \
|
||||
($4 ~ "^"channel"$" || $4 ~ /^$/) { print $3; exit}' $CONFIG)
|
||||
MAPPED_SLOT=`awk "\\$1 == \"slot\" && \\$2 == ${LINUX_SLOT} && \
|
||||
\\$4 ~ /^${CHANNEL}$|^$/ { print \\$3; exit }" $CONFIG`
|
||||
if [ -z "$MAPPED_SLOT" ] ; then
|
||||
MAPPED_SLOT=$LINUX_SLOT
|
||||
fi
|
||||
printf "%d" "${MAPPED_SLOT}"
|
||||
printf "%d" ${MAPPED_SLOT}
|
||||
}
|
||||
|
||||
map_channel() {
|
||||
@@ -164,120 +132,40 @@ map_channel() {
|
||||
|
||||
case $TOPOLOGY in
|
||||
"sas_switch")
|
||||
MAPPED_CHAN=$(awk -v port="$PORT" \
|
||||
'$1 == "channel" && $2 == port \
|
||||
{ print $3; exit }' $CONFIG)
|
||||
MAPPED_CHAN=`awk "\\$1 == \"channel\" && \\$2 == ${PORT} \
|
||||
{ print \\$3; exit }" $CONFIG`
|
||||
;;
|
||||
"sas_direct"|"scsi")
|
||||
MAPPED_CHAN=$(awk -v pciID="$PCI_ID" -v port="$PORT" \
|
||||
'$1 == "channel" && $2 == pciID && $3 == port \
|
||||
{print $4}' $CONFIG)
|
||||
MAPPED_CHAN=`awk "\\$1 == \"channel\" && \
|
||||
\\$2 == \"${PCI_ID}\" && \\$3 == ${PORT} \
|
||||
{ print \\$4; exit }" $CONFIG`
|
||||
;;
|
||||
esac
|
||||
printf "%s" "${MAPPED_CHAN}"
|
||||
}
|
||||
|
||||
get_encl_id() {
|
||||
set -- $(echo $1)
|
||||
count=$#
|
||||
|
||||
i=1
|
||||
while [ $i -le $count ] ; do
|
||||
d=$(eval echo '$'{$i})
|
||||
id=$(cat "/sys/class/enclosure/${d}/id")
|
||||
ENCL_ID="${ENCL_ID} $id"
|
||||
i=$((i + 1))
|
||||
done
|
||||
}
|
||||
|
||||
get_uniq_encl_id() {
|
||||
for uuid in ${ENCL_ID}; do
|
||||
found=0
|
||||
|
||||
for count in ${UNIQ_ENCL_ID}; do
|
||||
if [ $count = $uuid ]; then
|
||||
found=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $found -eq 0 ]; then
|
||||
UNIQ_ENCL_ID="${UNIQ_ENCL_ID} $uuid"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# map_jbod explainer: The bsg driver knows the difference between a SAS
|
||||
# expander and fanout expander. Use hostX instance along with top-level
|
||||
# (whole enclosure) expander instances in /sys/class/enclosure and
|
||||
# matching a field in an array of expanders, using the index of the
|
||||
# matched array field as the enclosure instance, thereby making jbod IDs
|
||||
# dynamic. Avoids reliance on high overhead userspace commands like
|
||||
# multipath and lsscsi and instead uses existing sysfs data. $HOSTCHAN
|
||||
# variable derived from devpath gymnastics in sas_handler() function.
|
||||
map_jbod() {
|
||||
DEVEXP=$(ls -l "/sys/block/$DEV/device/" | grep enclos | awk -F/ '{print $(NF-1) }')
|
||||
DEV=$1
|
||||
|
||||
# Use "set --" to create index values (Arrays)
|
||||
set -- $(ls -l /sys/class/enclosure | grep -v "^total" | awk '{print $9}')
|
||||
# Get count of total elements
|
||||
JBOD_COUNT=$#
|
||||
JBOD_ITEM=$*
|
||||
|
||||
# Build JBODs (enclosure) id from sys/class/enclosure/<dev>/id
|
||||
get_encl_id "$JBOD_ITEM"
|
||||
# Different expander instances for each paths.
|
||||
# Filter out and keep only unique id.
|
||||
get_uniq_encl_id
|
||||
|
||||
# Identify final 'mapped jbod'
|
||||
j=0
|
||||
for count in ${UNIQ_ENCL_ID}; do
|
||||
i=1
|
||||
j=$((j + 1))
|
||||
while [ $i -le $JBOD_COUNT ] ; do
|
||||
d=$(eval echo '$'{$i})
|
||||
id=$(cat "/sys/class/enclosure/${d}/id")
|
||||
if [ "$d" = "$DEVEXP" ] && [ $id = $count ] ; then
|
||||
MAPPED_JBOD=$j
|
||||
break
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
done
|
||||
|
||||
printf "%d" "${MAPPED_JBOD}"
|
||||
printf "%s" ${MAPPED_CHAN}
|
||||
}
|
||||
|
||||
sas_handler() {
|
||||
if [ -z "$PHYS_PER_PORT" ] ; then
|
||||
PHYS_PER_PORT=$(awk '$1 == "phys_per_port" \
|
||||
{print $2; exit}' $CONFIG)
|
||||
PHYS_PER_PORT=`awk "\\$1 == \"phys_per_port\" \
|
||||
{print \\$2; exit}" $CONFIG`
|
||||
fi
|
||||
PHYS_PER_PORT=${PHYS_PER_PORT:-4}
|
||||
|
||||
if ! echo "$PHYS_PER_PORT" | grep -q -E '^[0-9]+$' ; then
|
||||
if ! echo $PHYS_PER_PORT | grep -q -E '^[0-9]+$' ; then
|
||||
echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$MULTIPATH_MODE" ] ; then
|
||||
MULTIPATH_MODE=$(awk '$1 == "multipath" \
|
||||
{print $2; exit}' $CONFIG)
|
||||
fi
|
||||
|
||||
if [ -z "$MULTIJBOD_MODE" ] ; then
|
||||
MULTIJBOD_MODE=$(awk '$1 == "multijbod" \
|
||||
{print $2; exit}' $CONFIG)
|
||||
MULTIPATH_MODE=`awk "\\$1 == \"multipath\" \
|
||||
{print \\$2; exit}" $CONFIG`
|
||||
fi
|
||||
|
||||
# Use first running component device if we're handling a dm-mpath device
|
||||
if [ "$MULTIPATH_MODE" = "yes" ] ; then
|
||||
# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
|
||||
if [ -z "$DM_NAME" ] ; then
|
||||
DM_NAME=$(ls -l --full-time /dev/mapper |
|
||||
grep "$DEV"$ | awk '{print $9}')
|
||||
DM_NAME=`ls -l --full-time /dev/mapper |
|
||||
awk "/\/$DEV$/{print \\$9}"`
|
||||
fi
|
||||
|
||||
# For raw disks udev exports DEVTYPE=partition when
|
||||
@@ -287,50 +175,28 @@ sas_handler() {
|
||||
# we have to append the -part suffix directly in the
|
||||
# helper.
|
||||
if [ "$DEVTYPE" != "partition" ] ; then
|
||||
# Match p[number], remove the 'p' and prepend "-part"
|
||||
PART=$(echo "$DM_NAME" |
|
||||
awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
|
||||
PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
|
||||
fi
|
||||
|
||||
# Strip off partition information.
|
||||
DM_NAME=$(echo "$DM_NAME" | sed 's/p[0-9][0-9]*$//')
|
||||
DM_NAME=`echo $DM_NAME | sed 's/p[0-9][0-9]*$//'`
|
||||
if [ -z "$DM_NAME" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Utilize DM device name to gather subordinate block devices
|
||||
# using sysfs to avoid userspace utilities
|
||||
|
||||
# If our DEVNAME is something like /dev/dm-177, then we may be
|
||||
# able to get our DMDEV from it.
|
||||
DMDEV=$(echo $DEVNAME | sed 's;/dev/;;g')
|
||||
if [ ! -e /sys/block/$DMDEV/slaves/* ] ; then
|
||||
# It's not there, try looking in /dev/mapper
|
||||
DMDEV=$(ls -l --full-time /dev/mapper | grep $DM_NAME |
|
||||
awk '{gsub("../", " "); print $NF}')
|
||||
fi
|
||||
|
||||
# Use sysfs pointers in /sys/block/dm-X/slaves because using
|
||||
# userspace tools creates lots of overhead and should be avoided
|
||||
# whenever possible. Use awk to isolate lowest instance of
|
||||
# sd device member in dm device group regardless of string
|
||||
# length.
|
||||
DEV=$(ls "/sys/block/$DMDEV/slaves" | awk '
|
||||
{ len=sprintf ("%20s",length($0)); gsub(/ /,0,str); a[NR]=len "_" $0; }
|
||||
END {
|
||||
asort(a)
|
||||
print substr(a[1],22)
|
||||
}')
|
||||
|
||||
# Get the raw scsi device name from multipath -ll. Strip off
|
||||
# leading pipe symbols to make field numbering consistent.
|
||||
DEV=`multipath -ll $DM_NAME |
|
||||
awk '/running/{gsub("^[|]"," "); print $3 ; exit}'`
|
||||
if [ -z "$DEV" ] ; then
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
if echo "$DEV" | grep -q ^/devices/ ; then
|
||||
if echo $DEV | grep -q ^/devices/ ; then
|
||||
sys_path=$DEV
|
||||
else
|
||||
sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
|
||||
sys_path=`udevadm info -q path -p /sys/block/$DEV 2>/dev/null`
|
||||
fi
|
||||
|
||||
# Use positional parameters as an ad-hoc array
|
||||
@@ -340,104 +206,84 @@ sas_handler() {
|
||||
|
||||
# Get path up to /sys/.../hostX
|
||||
i=1
|
||||
|
||||
while [ $i -le "$num_dirs" ] ; do
|
||||
d=$(eval echo '$'{$i})
|
||||
while [ $i -le $num_dirs ] ; do
|
||||
d=$(eval echo \${$i})
|
||||
scsi_host_dir="$scsi_host_dir/$d"
|
||||
echo "$d" | grep -q -E '^host[0-9]+$' && break
|
||||
i=$((i + 1))
|
||||
echo $d | grep -q -E '^host[0-9]+$' && break
|
||||
i=$(($i + 1))
|
||||
done
|
||||
|
||||
# Lets grab the SAS host channel number and save it for JBOD sorting later
|
||||
HOSTCHAN=$(echo "$d" | awk -F/ '{ gsub("host","",$NF); print $NF}')
|
||||
|
||||
if [ $i = "$num_dirs" ] ; then
|
||||
if [ $i = $num_dirs ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
|
||||
PCI_ID=$(eval echo \${$(($i -1))} | awk -F: '{print $2":"$3}')
|
||||
|
||||
# In sas_switch mode, the directory four levels beneath
|
||||
# /sys/.../hostX contains symlinks to phy devices that reveal
|
||||
# the switch port number. In sas_direct mode, the phy links one
|
||||
# directory down reveal the HBA port.
|
||||
port_dir=$scsi_host_dir
|
||||
|
||||
case $TOPOLOGY in
|
||||
"sas_switch") j=$((i + 4)) ;;
|
||||
"sas_direct") j=$((i + 1)) ;;
|
||||
"sas_switch") j=$(($i + 4)) ;;
|
||||
"sas_direct") j=$(($i + 1)) ;;
|
||||
esac
|
||||
|
||||
i=$((i + 1))
|
||||
|
||||
i=$(($i + 1))
|
||||
while [ $i -le $j ] ; do
|
||||
port_dir="$port_dir/$(eval echo '$'{$i})"
|
||||
i=$((i + 1))
|
||||
port_dir="$port_dir/$(eval echo \${$i})"
|
||||
i=$(($i + 1))
|
||||
done
|
||||
|
||||
PHY=$(ls -vd "$port_dir"/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}')
|
||||
PHY=`ls -d $port_dir/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}'`
|
||||
if [ -z "$PHY" ] ; then
|
||||
PHY=0
|
||||
fi
|
||||
PORT=$((PHY / PHYS_PER_PORT))
|
||||
PORT=$(( $PHY / $PHYS_PER_PORT ))
|
||||
|
||||
# Look in /sys/.../sas_device/end_device-X for the bay_identifier
|
||||
# attribute.
|
||||
end_device_dir=$port_dir
|
||||
|
||||
while [ $i -lt "$num_dirs" ] ; do
|
||||
d=$(eval echo '$'{$i})
|
||||
while [ $i -lt $num_dirs ] ; do
|
||||
d=$(eval echo \${$i})
|
||||
end_device_dir="$end_device_dir/$d"
|
||||
if echo "$d" | grep -q '^end_device' ; then
|
||||
if echo $d | grep -q '^end_device' ; then
|
||||
end_device_dir="$end_device_dir/sas_device/$d"
|
||||
break
|
||||
fi
|
||||
i=$((i + 1))
|
||||
i=$(($i + 1))
|
||||
done
|
||||
|
||||
# Add 'mix' slot type for environments where dm-multipath devices
|
||||
# include end-devices connected via SAS expanders or direct connection
|
||||
# to SAS HBA. A mixed connectivity environment such as pool devices
|
||||
# contained in a SAS JBOD and spare drives or log devices directly
|
||||
# connected in a server backplane without expanders in the I/O path.
|
||||
SLOT=
|
||||
|
||||
case $BAY in
|
||||
"bay")
|
||||
SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
|
||||
;;
|
||||
"mix")
|
||||
if [ $(cat "$end_device_dir/bay_identifier" 2>/dev/null) ] ; then
|
||||
SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
|
||||
else
|
||||
SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
|
||||
fi
|
||||
SLOT=`cat $end_device_dir/bay_identifier 2>/dev/null`
|
||||
;;
|
||||
"phy")
|
||||
SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
|
||||
SLOT=`cat $end_device_dir/phy_identifier 2>/dev/null`
|
||||
;;
|
||||
"port")
|
||||
d=$(eval echo '$'{$i})
|
||||
SLOT=$(echo "$d" | sed -e 's/^.*://')
|
||||
d=$(eval echo \${$i})
|
||||
SLOT=`echo $d | sed -e 's/^.*://'`
|
||||
;;
|
||||
"id")
|
||||
i=$((i + 1))
|
||||
d=$(eval echo '$'{$i})
|
||||
SLOT=$(echo "$d" | sed -e 's/^.*://')
|
||||
i=$(($i + 1))
|
||||
d=$(eval echo \${$i})
|
||||
SLOT=`echo $d | sed -e 's/^.*://'`
|
||||
;;
|
||||
"lun")
|
||||
i=$((i + 2))
|
||||
d=$(eval echo '$'{$i})
|
||||
SLOT=$(echo "$d" | sed -e 's/^.*://')
|
||||
i=$(($i + 2))
|
||||
d=$(eval echo \${$i})
|
||||
SLOT=`echo $d | sed -e 's/^.*://'`
|
||||
;;
|
||||
"ses")
|
||||
# look for this SAS path in all SCSI Enclosure Services
|
||||
# (SES) enclosures
|
||||
sas_address=$(cat "$end_device_dir/sas_address" 2>/dev/null)
|
||||
enclosures=$(lsscsi -g | \
|
||||
sed -n -e '/enclosu/s/^.* \([^ ][^ ]*\) *$/\1/p')
|
||||
sas_address=`cat $end_device_dir/sas_address 2>/dev/null`
|
||||
enclosures=`lsscsi -g | \
|
||||
sed -n -e '/enclosu/s/^.* \([^ ][^ ]*\) *$/\1/p'`
|
||||
for enclosure in $enclosures; do
|
||||
set -- $(sg_ses -p aes "$enclosure" | \
|
||||
set -- $(sg_ses -p aes $enclosure | \
|
||||
awk "/device slot number:/{slot=\$12} \
|
||||
/SAS address: $sas_address/\
|
||||
{print slot}")
|
||||
@@ -452,55 +298,42 @@ sas_handler() {
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$MULTIJBOD_MODE" = "yes" ] ; then
|
||||
CHAN=$(map_channel "$PCI_ID" "$PORT")
|
||||
SLOT=$(map_slot "$SLOT" "$CHAN")
|
||||
JBOD=$(map_jbod "$DEV")
|
||||
|
||||
if [ -z "$CHAN" ] ; then
|
||||
return
|
||||
fi
|
||||
echo "${CHAN}"-"${JBOD}"-"${SLOT}${PART}"
|
||||
else
|
||||
CHAN=$(map_channel "$PCI_ID" "$PORT")
|
||||
SLOT=$(map_slot "$SLOT" "$CHAN")
|
||||
|
||||
if [ -z "$CHAN" ] ; then
|
||||
return
|
||||
fi
|
||||
echo "${CHAN}${SLOT}${PART}"
|
||||
CHAN=`map_channel $PCI_ID $PORT`
|
||||
SLOT=`map_slot $SLOT $CHAN`
|
||||
if [ -z "$CHAN" ] ; then
|
||||
return
|
||||
fi
|
||||
echo ${CHAN}${SLOT}${PART}
|
||||
}
|
||||
|
||||
scsi_handler() {
|
||||
if [ -z "$FIRST_BAY_NUMBER" ] ; then
|
||||
FIRST_BAY_NUMBER=$(awk '$1 == "first_bay_number" \
|
||||
{print $2; exit}' $CONFIG)
|
||||
FIRST_BAY_NUMBER=`awk "\\$1 == \"first_bay_number\" \
|
||||
{print \\$2; exit}" $CONFIG`
|
||||
fi
|
||||
FIRST_BAY_NUMBER=${FIRST_BAY_NUMBER:-0}
|
||||
|
||||
if [ -z "$PHYS_PER_PORT" ] ; then
|
||||
PHYS_PER_PORT=$(awk '$1 == "phys_per_port" \
|
||||
{print $2; exit}' $CONFIG)
|
||||
PHYS_PER_PORT=`awk "\\$1 == \"phys_per_port\" \
|
||||
{print \\$2; exit}" $CONFIG`
|
||||
fi
|
||||
PHYS_PER_PORT=${PHYS_PER_PORT:-4}
|
||||
|
||||
if ! echo "$PHYS_PER_PORT" | grep -q -E '^[0-9]+$' ; then
|
||||
if ! echo $PHYS_PER_PORT | grep -q -E '^[0-9]+$' ; then
|
||||
echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$MULTIPATH_MODE" ] ; then
|
||||
MULTIPATH_MODE=$(awk '$1 == "multipath" \
|
||||
{print $2; exit}' $CONFIG)
|
||||
MULTIPATH_MODE=`awk "\\$1 == \"multipath\" \
|
||||
{print \\$2; exit}" $CONFIG`
|
||||
fi
|
||||
|
||||
# Use first running component device if we're handling a dm-mpath device
|
||||
if [ "$MULTIPATH_MODE" = "yes" ] ; then
|
||||
# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
|
||||
if [ -z "$DM_NAME" ] ; then
|
||||
DM_NAME=$(ls -l --full-time /dev/mapper |
|
||||
grep "$DEV"$ | awk '{print $9}')
|
||||
DM_NAME=`ls -l --full-time /dev/mapper |
|
||||
awk "/\/$DEV$/{print \\$9}"`
|
||||
fi
|
||||
|
||||
# For raw disks udev exports DEVTYPE=partition when
|
||||
@@ -510,30 +343,28 @@ scsi_handler() {
|
||||
# we have to append the -part suffix directly in the
|
||||
# helper.
|
||||
if [ "$DEVTYPE" != "partition" ] ; then
|
||||
# Match p[number], remove the 'p' and prepend "-part"
|
||||
PART=$(echo "$DM_NAME" |
|
||||
awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
|
||||
PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
|
||||
fi
|
||||
|
||||
# Strip off partition information.
|
||||
DM_NAME=$(echo "$DM_NAME" | sed 's/p[0-9][0-9]*$//')
|
||||
DM_NAME=`echo $DM_NAME | sed 's/p[0-9][0-9]*$//'`
|
||||
if [ -z "$DM_NAME" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Get the raw scsi device name from multipath -ll. Strip off
|
||||
# leading pipe symbols to make field numbering consistent.
|
||||
DEV=$(multipath -ll "$DM_NAME" |
|
||||
awk '/running/{gsub("^[|]"," "); print $3 ; exit}')
|
||||
DEV=`multipath -ll $DM_NAME |
|
||||
awk '/running/{gsub("^[|]"," "); print $3 ; exit}'`
|
||||
if [ -z "$DEV" ] ; then
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
if echo "$DEV" | grep -q ^/devices/ ; then
|
||||
if echo $DEV | grep -q ^/devices/ ; then
|
||||
sys_path=$DEV
|
||||
else
|
||||
sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
|
||||
sys_path=`udevadm info -q path -p /sys/block/$DEV 2>/dev/null`
|
||||
fi
|
||||
|
||||
# expect sys_path like this, for example:
|
||||
@@ -546,47 +377,44 @@ scsi_handler() {
|
||||
|
||||
# Get path up to /sys/.../hostX
|
||||
i=1
|
||||
|
||||
while [ $i -le "$num_dirs" ] ; do
|
||||
d=$(eval echo '$'{$i})
|
||||
while [ $i -le $num_dirs ] ; do
|
||||
d=$(eval echo \${$i})
|
||||
scsi_host_dir="$scsi_host_dir/$d"
|
||||
|
||||
echo "$d" | grep -q -E '^host[0-9]+$' && break
|
||||
i=$((i + 1))
|
||||
echo $d | grep -q -E '^host[0-9]+$' && break
|
||||
i=$(($i + 1))
|
||||
done
|
||||
|
||||
if [ $i = "$num_dirs" ] ; then
|
||||
if [ $i = $num_dirs ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
|
||||
PCI_ID=$(eval echo \${$(($i -1))} | awk -F: '{print $2":"$3}')
|
||||
|
||||
# In scsi mode, the directory two levels beneath
|
||||
# /sys/.../hostX reveals the port and slot.
|
||||
port_dir=$scsi_host_dir
|
||||
j=$((i + 2))
|
||||
j=$(($i + 2))
|
||||
|
||||
i=$((i + 1))
|
||||
i=$(($i + 1))
|
||||
while [ $i -le $j ] ; do
|
||||
port_dir="$port_dir/$(eval echo '$'{$i})"
|
||||
i=$((i + 1))
|
||||
port_dir="$port_dir/$(eval echo \${$i})"
|
||||
i=$(($i + 1))
|
||||
done
|
||||
|
||||
set -- $(echo "$port_dir" | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/')
|
||||
set -- $(echo $port_dir | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/')
|
||||
PORT=$1
|
||||
SLOT=$(($2 + FIRST_BAY_NUMBER))
|
||||
SLOT=$(($2 + $FIRST_BAY_NUMBER))
|
||||
|
||||
if [ -z "$SLOT" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
CHAN=$(map_channel "$PCI_ID" "$PORT")
|
||||
SLOT=$(map_slot "$SLOT" "$CHAN")
|
||||
|
||||
CHAN=`map_channel $PCI_ID $PORT`
|
||||
SLOT=`map_slot $SLOT $CHAN`
|
||||
if [ -z "$CHAN" ] ; then
|
||||
return
|
||||
fi
|
||||
echo "${CHAN}${SLOT}${PART}"
|
||||
echo ${CHAN}${SLOT}${PART}
|
||||
}
|
||||
|
||||
# Figure out the name for the enclosure symlink
|
||||
@@ -596,10 +424,8 @@ enclosure_handler () {
|
||||
# DEVPATH=/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/subsystem/devices/0:0:0:0/scsi_generic/sg0
|
||||
|
||||
# Get the enclosure ID ("0:0:0:0")
|
||||
ENC="${DEVPATH%/*}"
|
||||
ENC="${ENC%/*}"
|
||||
ENC="${ENC##*/}"
|
||||
if [ ! -d "/sys/class/enclosure/$ENC" ] ; then
|
||||
ENC=$(basename $(readlink -m "/sys/$DEVPATH/../.."))
|
||||
if [ ! -d /sys/class/enclosure/$ENC ] ; then
|
||||
# Not an enclosure, bail out
|
||||
return
|
||||
fi
|
||||
@@ -607,26 +433,25 @@ enclosure_handler () {
|
||||
# Get the long sysfs device path to our enclosure. Looks like:
|
||||
# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0/ ... /enclosure/0:0:0:0
|
||||
|
||||
ENC_DEVICE=$(readlink "/sys/class/enclosure/$ENC")
|
||||
ENC_DEVICE=$(readlink /sys/class/enclosure/$ENC)
|
||||
|
||||
# Grab the full path to the hosts port dir:
|
||||
# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0
|
||||
PORT_DIR=$(echo "$ENC_DEVICE" | grep -Eo '.+host[0-9]+/port-[0-9]+:[0-9]+')
|
||||
PORT_DIR=$(echo $ENC_DEVICE | grep -Eo '.+host[0-9]+/port-[0-9]+:[0-9]+')
|
||||
|
||||
# Get the port number
|
||||
PORT_ID=$(echo "$PORT_DIR" | grep -Eo "[0-9]+$")
|
||||
PORT_ID=$(echo $PORT_DIR | grep -Eo "[0-9]+$")
|
||||
|
||||
# The PCI directory is two directories up from the port directory
|
||||
# /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0
|
||||
PCI_ID_LONG="$(readlink -m "/sys/$PORT_DIR/../..")"
|
||||
PCI_ID_LONG="${PCI_ID_LONG##*/}"
|
||||
PCI_ID_LONG=$(basename $(readlink -m "/sys/$PORT_DIR/../.."))
|
||||
|
||||
# Strip down the PCI address from 0000:05:00.0 to 05:00.0
|
||||
PCI_ID="${PCI_ID_LONG#[0-9]*:}"
|
||||
PCI_ID=$(echo "$PCI_ID_LONG" | sed -r 's/^[0-9]+://g')
|
||||
|
||||
# Name our device according to vdev_id.conf (like "L0" or "U1").
|
||||
NAME=$(awk "/channel/{if (\$1 == \"channel\" && \$2 == \"$PCI_ID\" && \
|
||||
\$3 == \"$PORT_ID\") {print \$4\$3}}" $CONFIG)
|
||||
\$3 == \"$PORT_ID\") {print \$4int(count[\$4])}; count[\$4]++}" $CONFIG)
|
||||
|
||||
echo "${NAME}"
|
||||
}
|
||||
@@ -662,11 +487,9 @@ alias_handler () {
|
||||
# ambiguity seems unavoidable, so devices using this facility
|
||||
# must not use such names.
|
||||
DM_PART=
|
||||
if echo "$DM_NAME" | grep -q -E 'p[0-9][0-9]*$' ; then
|
||||
if echo $DM_NAME | grep -q -E 'p[0-9][0-9]*$' ; then
|
||||
if [ "$DEVTYPE" != "partition" ] ; then
|
||||
# Match p[number], remove the 'p' and prepend "-part"
|
||||
DM_PART=$(echo "$DM_NAME" |
|
||||
awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
|
||||
DM_PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -674,25 +497,21 @@ alias_handler () {
|
||||
for link in $DEVLINKS ; do
|
||||
# Remove partition information to match key of top-level device.
|
||||
if [ -n "$DM_PART" ] ; then
|
||||
link=$(echo "$link" | sed 's/p[0-9][0-9]*$//')
|
||||
link=`echo $link | sed 's/p[0-9][0-9]*$//'`
|
||||
fi
|
||||
# Check both the fully qualified and the base name of link.
|
||||
for l in $link ${link##*/} ; do
|
||||
if [ ! -z "$l" ]; then
|
||||
alias=$(awk -v var="$l" '($1 == "alias") && \
|
||||
($3 == var) \
|
||||
{ print $2; exit }' $CONFIG)
|
||||
if [ -n "$alias" ] ; then
|
||||
echo "${alias}${DM_PART}"
|
||||
return
|
||||
fi
|
||||
for l in $link `basename $link` ; do
|
||||
alias=`awk "\\$1 == \"alias\" && \\$3 == \"${l}\" \
|
||||
{ print \\$2; exit }" $CONFIG`
|
||||
if [ -n "$alias" ] ; then
|
||||
echo ${alias}${DM_PART}
|
||||
return
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# main
|
||||
while getopts 'c:d:eg:jmp:h' OPTION; do
|
||||
while getopts 'c:d:eg:mp:h' OPTION; do
|
||||
case ${OPTION} in
|
||||
c)
|
||||
CONFIG=${OPTARG}
|
||||
@@ -705,9 +524,7 @@ while getopts 'c:d:eg:jmp:h' OPTION; do
|
||||
# create the enclosure device symlinks only. We also need
|
||||
# "enclosure_symlinks yes" set in vdev_id.config to actually create the
|
||||
# symlink.
|
||||
ENCLOSURE_MODE=$(awk '{if ($1 == "enclosure_symlinks") \
|
||||
print $2}' "$CONFIG")
|
||||
|
||||
ENCLOSURE_MODE=$(awk '{if ($1 == "enclosure_symlinks") print $2}' $CONFIG)
|
||||
if [ "$ENCLOSURE_MODE" != "yes" ] ; then
|
||||
exit 0
|
||||
fi
|
||||
@@ -718,9 +535,6 @@ while getopts 'c:d:eg:jmp:h' OPTION; do
|
||||
p)
|
||||
PHYS_PER_PORT=${OPTARG}
|
||||
;;
|
||||
j)
|
||||
MULTIJBOD_MODE=yes
|
||||
;;
|
||||
m)
|
||||
MULTIPATH_MODE=yes
|
||||
;;
|
||||
@@ -730,9 +544,9 @@ while getopts 'c:d:eg:jmp:h' OPTION; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -r "$CONFIG" ] ; then
|
||||
if [ ! -r $CONFIG ] ; then
|
||||
echo "Error: Config file \"$CONFIG\" not found"
|
||||
exit 1
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then
|
||||
@@ -741,11 +555,11 @@ if [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then
|
||||
fi
|
||||
|
||||
if [ -z "$TOPOLOGY" ] ; then
|
||||
TOPOLOGY=$(awk '($1 == "topology") {print $2; exit}' "$CONFIG")
|
||||
TOPOLOGY=`awk "\\$1 == \"topology\" {print \\$2; exit}" $CONFIG`
|
||||
fi
|
||||
|
||||
if [ -z "$BAY" ] ; then
|
||||
BAY=$(awk '($1 == "slot") {print $2; exit}' "$CONFIG")
|
||||
BAY=`awk "\\$1 == \"slot\" {print \\$2; exit}" $CONFIG`
|
||||
fi
|
||||
|
||||
TOPOLOGY=${TOPOLOGY:-sas_direct}
|
||||
@@ -758,7 +572,7 @@ if [ "$ENCLOSURE_MODE" = "yes" ] && [ "$TOPOLOGY" = "sas_direct" ] ; then
|
||||
fi
|
||||
|
||||
# Just create the symlinks to the enclosure devices and then exit.
|
||||
ENCLOSURE_PREFIX=$(awk '/enclosure_symlinks_prefix/{print $2}' "$CONFIG")
|
||||
ENCLOSURE_PREFIX=$(awk '/enclosure_symlinks_prefix/{print $2}' $CONFIG)
|
||||
if [ -z "$ENCLOSURE_PREFIX" ] ; then
|
||||
ENCLOSURE_PREFIX="enc"
|
||||
fi
|
||||
@@ -768,16 +582,16 @@ if [ "$ENCLOSURE_MODE" = "yes" ] && [ "$TOPOLOGY" = "sas_direct" ] ; then
|
||||
fi
|
||||
|
||||
# First check if an alias was defined for this device.
|
||||
ID_VDEV=$(alias_handler)
|
||||
ID_VDEV=`alias_handler`
|
||||
|
||||
if [ -z "$ID_VDEV" ] ; then
|
||||
BAY=${BAY:-bay}
|
||||
case $TOPOLOGY in
|
||||
sas_direct|sas_switch)
|
||||
ID_VDEV=$(sas_handler)
|
||||
ID_VDEV=`sas_handler`
|
||||
;;
|
||||
scsi)
|
||||
ID_VDEV=$(scsi_handler)
|
||||
ID_VDEV=`scsi_handler`
|
||||
;;
|
||||
*)
|
||||
echo "Error: unknown topology $TOPOLOGY"
|
||||
@@ -0,0 +1 @@
|
||||
/zdb
|
||||
+12
-11
@@ -1,17 +1,18 @@
|
||||
zdb_CPPFLAGS = $(AM_CPPFLAGS) $(FORCEDEBUG_CPPFLAGS)
|
||||
zdb_CFLAGS = $(AM_CFLAGS) $(LIBCRYPTO_CFLAGS)
|
||||
include $(top_srcdir)/config/Rules.am
|
||||
|
||||
sbin_PROGRAMS += zdb
|
||||
CPPCHECKTARGETS += zdb
|
||||
# Unconditionally enable debugging for zdb
|
||||
AM_CPPFLAGS += -DDEBUG -UNDEBUG -DZFS_DEBUG
|
||||
|
||||
sbin_PROGRAMS = zdb
|
||||
|
||||
zdb_SOURCES = \
|
||||
%D%/zdb.c \
|
||||
%D%/zdb.h \
|
||||
%D%/zdb_il.c
|
||||
zdb.c \
|
||||
zdb_il.c \
|
||||
zdb.h
|
||||
|
||||
zdb_LDADD = \
|
||||
libzpool.la \
|
||||
libzfs_core.la \
|
||||
libnvpair.la
|
||||
$(abs_top_builddir)/lib/libzpool/libzpool.la \
|
||||
$(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \
|
||||
$(abs_top_builddir)/lib/libnvpair/libnvpair.la
|
||||
|
||||
zdb_LDADD += $(LIBCRYPTO_LIBS)
|
||||
include $(top_srcdir)/config/CppCheck.am
|
||||
|
||||
+414
-1392
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
|
||||
+17
-128
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -60,12 +60,11 @@ print_log_bp(const blkptr_t *bp, const char *prefix)
|
||||
(void) printf("%s%s\n", prefix, blkbuf);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_create(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog;
|
||||
const lr_create_t *lrc = arg;
|
||||
const _lr_create_t *lr = &lrc->lr_create;
|
||||
const lr_create_t *lr = arg;
|
||||
time_t crtime = lr->lr_crtime[0];
|
||||
char *name, *link;
|
||||
lr_attr_t *lrattr;
|
||||
@@ -97,20 +96,20 @@ zil_prt_rec_create(zilog_t *zilog, int txtype, const void *arg)
|
||||
(u_longlong_t)lr->lr_gen, (u_longlong_t)lr->lr_rdev);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_remove(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog, (void) txtype;
|
||||
const lr_remove_t *lr = arg;
|
||||
|
||||
(void) printf("%sdoid %llu, name %s\n", tab_prefix,
|
||||
(u_longlong_t)lr->lr_doid, (char *)(lr + 1));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_link(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog, (void) txtype;
|
||||
const lr_link_t *lr = arg;
|
||||
|
||||
(void) printf("%sdoid %llu, link_obj %llu, name %s\n", tab_prefix,
|
||||
@@ -118,32 +117,23 @@ zil_prt_rec_link(zilog_t *zilog, int txtype, const void *arg)
|
||||
(char *)(lr + 1));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_rename(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog, (void) txtype;
|
||||
const lr_rename_t *lrr = arg;
|
||||
const _lr_rename_t *lr = &lrr->lr_rename;
|
||||
const lr_rename_t *lr = arg;
|
||||
char *snm = (char *)(lr + 1);
|
||||
char *tnm = snm + strlen(snm) + 1;
|
||||
|
||||
(void) printf("%ssdoid %llu, tdoid %llu\n", tab_prefix,
|
||||
(u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid);
|
||||
(void) printf("%ssrc %s tgt %s\n", tab_prefix, snm, tnm);
|
||||
switch (txtype) {
|
||||
case TX_RENAME_EXCHANGE:
|
||||
(void) printf("%sflags RENAME_EXCHANGE\n", tab_prefix);
|
||||
break;
|
||||
case TX_RENAME_WHITEOUT:
|
||||
(void) printf("%sflags RENAME_WHITEOUT\n", tab_prefix);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zil_prt_rec_write_cb(void *data, size_t len, void *unused)
|
||||
{
|
||||
(void) unused;
|
||||
char *cdata = data;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
@@ -156,6 +146,7 @@ zil_prt_rec_write_cb(void *data, size_t len, void *unused)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
@@ -170,7 +161,7 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
|
||||
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset,
|
||||
(u_longlong_t)lr->lr_length);
|
||||
|
||||
if (txtype == TX_WRITE2 || verbose < 4)
|
||||
if (txtype == TX_WRITE2 || verbose < 5)
|
||||
return;
|
||||
|
||||
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
|
||||
@@ -180,8 +171,6 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
|
||||
"will claim" : "won't claim");
|
||||
print_log_bp(bp, tab_prefix);
|
||||
|
||||
if (verbose < 5)
|
||||
return;
|
||||
if (BP_IS_HOLE(bp)) {
|
||||
(void) printf("\t\t\tLSIZE 0x%llx\n",
|
||||
(u_longlong_t)BP_GET_LSIZE(bp));
|
||||
@@ -194,7 +183,6 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT3U(BP_GET_LSIZE(bp), !=, 0);
|
||||
SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os),
|
||||
lr->lr_foid, ZB_ZIL_LEVEL,
|
||||
lr->lr_offset / BP_GET_LSIZE(bp));
|
||||
@@ -206,9 +194,6 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
|
||||
if (error)
|
||||
goto out;
|
||||
} else {
|
||||
if (verbose < 5)
|
||||
return;
|
||||
|
||||
/* data is stored after the end of the lr_write record */
|
||||
data = abd_alloc(lr->lr_length, B_FALSE);
|
||||
abd_copy_from_buf(data, lr + 1, lr->lr_length);
|
||||
@@ -224,32 +209,10 @@ out:
|
||||
abd_free(data);
|
||||
}
|
||||
|
||||
static void
|
||||
zil_prt_rec_write_enc(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) txtype;
|
||||
const lr_write_t *lr = arg;
|
||||
const blkptr_t *bp = &lr->lr_blkptr;
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
|
||||
(void) printf("%s(encrypted)\n", tab_prefix);
|
||||
|
||||
if (verbose < 4)
|
||||
return;
|
||||
|
||||
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
|
||||
(void) printf("%shas blkptr, %s\n", tab_prefix,
|
||||
!BP_IS_HOLE(bp) &&
|
||||
bp->blk_birth >= spa_min_claim_txg(zilog->zl_spa) ?
|
||||
"will claim" : "won't claim");
|
||||
print_log_bp(bp, tab_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_truncate(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog, (void) txtype;
|
||||
const lr_truncate_t *lr = arg;
|
||||
|
||||
(void) printf("%sfoid %llu, offset 0x%llx, length 0x%llx\n", tab_prefix,
|
||||
@@ -257,10 +220,10 @@ zil_prt_rec_truncate(zilog_t *zilog, int txtype, const void *arg)
|
||||
(u_longlong_t)lr->lr_length);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_setattr(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog, (void) txtype;
|
||||
const lr_setattr_t *lr = arg;
|
||||
time_t atime = (time_t)lr->lr_atime[0];
|
||||
time_t mtime = (time_t)lr->lr_mtime[0];
|
||||
@@ -303,83 +266,19 @@ zil_prt_rec_setattr(zilog_t *zilog, int txtype, const void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
zil_prt_rec_setsaxattr(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog, (void) txtype;
|
||||
const lr_setsaxattr_t *lr = arg;
|
||||
|
||||
char *name = (char *)(lr + 1);
|
||||
(void) printf("%sfoid %llu\n", tab_prefix,
|
||||
(u_longlong_t)lr->lr_foid);
|
||||
|
||||
(void) printf("%sXAT_NAME %s\n", tab_prefix, name);
|
||||
if (lr->lr_size == 0) {
|
||||
(void) printf("%sXAT_VALUE NULL\n", tab_prefix);
|
||||
} else {
|
||||
(void) printf("%sXAT_VALUE ", tab_prefix);
|
||||
char *val = name + (strlen(name) + 1);
|
||||
for (int i = 0; i < lr->lr_size; i++) {
|
||||
(void) printf("%c", *val);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_acl(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog, (void) txtype;
|
||||
const lr_acl_t *lr = arg;
|
||||
|
||||
(void) printf("%sfoid %llu, aclcnt %llu\n", tab_prefix,
|
||||
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_aclcnt);
|
||||
}
|
||||
|
||||
static void
|
||||
zil_prt_rec_clone_range(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog, (void) txtype;
|
||||
const lr_clone_range_t *lr = arg;
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
|
||||
(void) printf("%sfoid %llu, offset %llx, length %llx, blksize %llx\n",
|
||||
tab_prefix, (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset,
|
||||
(u_longlong_t)lr->lr_length, (u_longlong_t)lr->lr_blksz);
|
||||
|
||||
if (verbose < 4)
|
||||
return;
|
||||
|
||||
for (unsigned int i = 0; i < lr->lr_nbps; i++) {
|
||||
(void) printf("%s[%u/%llu] ", tab_prefix, i + 1,
|
||||
(u_longlong_t)lr->lr_nbps);
|
||||
print_log_bp(&lr->lr_bps[i], "");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
zil_prt_rec_clone_range_enc(zilog_t *zilog, int txtype, const void *arg)
|
||||
{
|
||||
(void) zilog, (void) txtype;
|
||||
const lr_clone_range_t *lr = arg;
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
|
||||
(void) printf("%s(encrypted)\n", tab_prefix);
|
||||
|
||||
if (verbose < 4)
|
||||
return;
|
||||
|
||||
for (unsigned int i = 0; i < lr->lr_nbps; i++) {
|
||||
(void) printf("%s[%u/%llu] ", tab_prefix, i + 1,
|
||||
(u_longlong_t)lr->lr_nbps);
|
||||
print_log_bp(&lr->lr_bps[i], "");
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*zil_prt_rec_func_t)(zilog_t *, int, const void *);
|
||||
typedef struct zil_rec_info {
|
||||
zil_prt_rec_func_t zri_print;
|
||||
zil_prt_rec_func_t zri_print_enc;
|
||||
const char *zri_name;
|
||||
uint64_t zri_count;
|
||||
} zil_rec_info_t;
|
||||
@@ -394,9 +293,7 @@ static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
|
||||
{.zri_print = zil_prt_rec_remove, .zri_name = "TX_RMDIR "},
|
||||
{.zri_print = zil_prt_rec_link, .zri_name = "TX_LINK "},
|
||||
{.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME "},
|
||||
{.zri_print = zil_prt_rec_write,
|
||||
.zri_print_enc = zil_prt_rec_write_enc,
|
||||
.zri_name = "TX_WRITE "},
|
||||
{.zri_print = zil_prt_rec_write, .zri_name = "TX_WRITE "},
|
||||
{.zri_print = zil_prt_rec_truncate, .zri_name = "TX_TRUNCATE "},
|
||||
{.zri_print = zil_prt_rec_setattr, .zri_name = "TX_SETATTR "},
|
||||
{.zri_print = zil_prt_rec_acl, .zri_name = "TX_ACL_V0 "},
|
||||
@@ -408,19 +305,12 @@ static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
|
||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ATTR "},
|
||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ACL_ATTR "},
|
||||
{.zri_print = zil_prt_rec_write, .zri_name = "TX_WRITE2 "},
|
||||
{.zri_print = zil_prt_rec_setsaxattr,
|
||||
.zri_name = "TX_SETSAXATTR "},
|
||||
{.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME_EXCHANGE "},
|
||||
{.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME_WHITEOUT "},
|
||||
{.zri_print = zil_prt_rec_clone_range,
|
||||
.zri_print_enc = zil_prt_rec_clone_range_enc,
|
||||
.zri_name = "TX_CLONE_RANGE "},
|
||||
};
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
print_log_record(zilog_t *zilog, const lr_t *lr, void *arg, uint64_t claim_txg)
|
||||
{
|
||||
(void) arg, (void) claim_txg;
|
||||
int txtype;
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
|
||||
@@ -440,8 +330,6 @@ print_log_record(zilog_t *zilog, const lr_t *lr, void *arg, uint64_t claim_txg)
|
||||
if (txtype && verbose >= 3) {
|
||||
if (!zilog->zl_os->os_encrypted) {
|
||||
zil_rec_info[txtype].zri_print(zilog, txtype, lr);
|
||||
} else if (zil_rec_info[txtype].zri_print_enc) {
|
||||
zil_rec_info[txtype].zri_print_enc(zilog, txtype, lr);
|
||||
} else {
|
||||
(void) printf("%s(encrypted)\n", tab_prefix);
|
||||
}
|
||||
@@ -453,11 +341,11 @@ print_log_record(zilog_t *zilog, const lr_t *lr, void *arg, uint64_t claim_txg)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
print_log_block(zilog_t *zilog, const blkptr_t *bp, void *arg,
|
||||
uint64_t claim_txg)
|
||||
{
|
||||
(void) arg;
|
||||
char blkbuf[BP_SPRINTF_LEN + 10];
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
const char *claim;
|
||||
@@ -508,6 +396,7 @@ print_log_stats(int verbose)
|
||||
(void) printf("\n");
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
dump_intent_log(zilog_t *zilog)
|
||||
{
|
||||
|
||||
+43
-38
@@ -1,46 +1,51 @@
|
||||
include $(srcdir)/%D%/zed.d/Makefile.am
|
||||
include $(top_srcdir)/config/Rules.am
|
||||
|
||||
zed_CFLAGS = $(AM_CFLAGS)
|
||||
zed_CFLAGS += $(LIBUDEV_CFLAGS) $(LIBUUID_CFLAGS)
|
||||
AM_CFLAGS += $(LIBUDEV_CFLAGS) $(LIBUUID_CFLAGS)
|
||||
|
||||
sbin_PROGRAMS += zed
|
||||
CPPCHECKTARGETS += zed
|
||||
SUBDIRS = zed.d
|
||||
|
||||
zed_SOURCES = \
|
||||
%D%/zed.c \
|
||||
%D%/zed.h \
|
||||
%D%/zed_conf.c \
|
||||
%D%/zed_conf.h \
|
||||
%D%/zed_disk_event.c \
|
||||
%D%/zed_disk_event.h \
|
||||
%D%/zed_event.c \
|
||||
%D%/zed_event.h \
|
||||
%D%/zed_exec.c \
|
||||
%D%/zed_exec.h \
|
||||
%D%/zed_file.c \
|
||||
%D%/zed_file.h \
|
||||
%D%/zed_log.c \
|
||||
%D%/zed_log.h \
|
||||
%D%/zed_strings.c \
|
||||
%D%/zed_strings.h \
|
||||
\
|
||||
%D%/agents/fmd_api.c \
|
||||
%D%/agents/fmd_api.h \
|
||||
%D%/agents/fmd_serd.c \
|
||||
%D%/agents/fmd_serd.h \
|
||||
%D%/agents/zfs_agents.c \
|
||||
%D%/agents/zfs_agents.h \
|
||||
%D%/agents/zfs_diagnosis.c \
|
||||
%D%/agents/zfs_mod.c \
|
||||
%D%/agents/zfs_retire.c
|
||||
sbin_PROGRAMS = zed
|
||||
|
||||
ZED_SRC = \
|
||||
zed.c \
|
||||
zed.h \
|
||||
zed_conf.c \
|
||||
zed_conf.h \
|
||||
zed_disk_event.c \
|
||||
zed_disk_event.h \
|
||||
zed_event.c \
|
||||
zed_event.h \
|
||||
zed_exec.c \
|
||||
zed_exec.h \
|
||||
zed_file.c \
|
||||
zed_file.h \
|
||||
zed_log.c \
|
||||
zed_log.h \
|
||||
zed_strings.c \
|
||||
zed_strings.h
|
||||
|
||||
FMA_SRC = \
|
||||
agents/zfs_agents.c \
|
||||
agents/zfs_agents.h \
|
||||
agents/zfs_diagnosis.c \
|
||||
agents/zfs_mod.c \
|
||||
agents/zfs_retire.c \
|
||||
agents/fmd_api.c \
|
||||
agents/fmd_api.h \
|
||||
agents/fmd_serd.c \
|
||||
agents/fmd_serd.h
|
||||
|
||||
zed_SOURCES = $(ZED_SRC) $(FMA_SRC)
|
||||
|
||||
zed_LDADD = \
|
||||
libzfs.la \
|
||||
libzfs_core.la \
|
||||
libnvpair.la \
|
||||
libuutil.la
|
||||
$(abs_top_builddir)/lib/libzfs/libzfs.la \
|
||||
$(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \
|
||||
$(abs_top_builddir)/lib/libnvpair/libnvpair.la \
|
||||
$(abs_top_builddir)/lib/libuutil/libuutil.la
|
||||
|
||||
zed_LDADD += -lrt $(LIBATOMIC_LIBS) $(LIBUDEV_LIBS) $(LIBUUID_LIBS)
|
||||
zed_LDADD += -lrt $(LIBUDEV_LIBS) $(LIBUUID_LIBS)
|
||||
zed_LDFLAGS = -pthread
|
||||
|
||||
dist_noinst_DATA += %D%/agents/README.md
|
||||
EXTRA_DIST = agents/README.md
|
||||
|
||||
include $(top_srcdir)/config/CppCheck.am
|
||||
|
||||
+45
-61
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -22,7 +22,6 @@
|
||||
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2016, Intel Corporation.
|
||||
* Copyright (c) 2023, Klara Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -39,7 +38,7 @@
|
||||
#include <sys/fm/protocol.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "fmd_api.h"
|
||||
@@ -98,7 +97,6 @@ _umem_logging_init(void)
|
||||
int
|
||||
fmd_hdl_register(fmd_hdl_t *hdl, int version, const fmd_hdl_info_t *mip)
|
||||
{
|
||||
(void) version;
|
||||
fmd_module_t *mp = (fmd_module_t *)hdl;
|
||||
|
||||
mp->mod_info = mip;
|
||||
@@ -181,21 +179,18 @@ fmd_hdl_getspecific(fmd_hdl_t *hdl)
|
||||
void *
|
||||
fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags)
|
||||
{
|
||||
(void) hdl;
|
||||
return (umem_alloc(size, flags));
|
||||
}
|
||||
|
||||
void *
|
||||
fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags)
|
||||
{
|
||||
(void) hdl;
|
||||
return (umem_zalloc(size, flags));
|
||||
}
|
||||
|
||||
void
|
||||
fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size)
|
||||
{
|
||||
(void) hdl;
|
||||
umem_free(data, size);
|
||||
}
|
||||
|
||||
@@ -222,8 +217,6 @@ fmd_hdl_debug(fmd_hdl_t *hdl, const char *format, ...)
|
||||
int32_t
|
||||
fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name)
|
||||
{
|
||||
(void) hdl;
|
||||
|
||||
/*
|
||||
* These can be looked up in mp->modinfo->fmdi_props
|
||||
* For now we just hard code for phase 2. In the
|
||||
@@ -232,6 +225,26 @@ fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name)
|
||||
if (strcmp(name, "spare_on_remove") == 0)
|
||||
return (1);
|
||||
|
||||
if (strcmp(name, "io_N") == 0 || strcmp(name, "checksum_N") == 0)
|
||||
return (10); /* N = 10 events */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int64_t
|
||||
fmd_prop_get_int64(fmd_hdl_t *hdl, const char *name)
|
||||
{
|
||||
/*
|
||||
* These can be looked up in mp->modinfo->fmdi_props
|
||||
* For now we just hard code for phase 2. In the
|
||||
* future, there can be a ZED based override.
|
||||
*/
|
||||
if (strcmp(name, "remove_timeout") == 0)
|
||||
return (15ULL * 1000ULL * 1000ULL * 1000ULL); /* 15 sec */
|
||||
|
||||
if (strcmp(name, "io_T") == 0 || strcmp(name, "checksum_T") == 0)
|
||||
return (1000ULL * 1000ULL * 1000ULL * 600ULL); /* 10 min */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -321,24 +334,22 @@ fmd_case_uuresolved(fmd_hdl_t *hdl, const char *uuid)
|
||||
fmd_hdl_debug(hdl, "case resolved by uuid (%s)", uuid);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
int
|
||||
fmd_case_solved(fmd_hdl_t *hdl, fmd_case_t *cp)
|
||||
{
|
||||
(void) hdl;
|
||||
return (cp->ci_state >= FMD_CASE_SOLVED);
|
||||
return ((cp->ci_state >= FMD_CASE_SOLVED) ? FMD_B_TRUE : FMD_B_FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep)
|
||||
{
|
||||
(void) hdl, (void) cp, (void) ep;
|
||||
}
|
||||
|
||||
static void
|
||||
zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
|
||||
{
|
||||
nvlist_t *rsrc;
|
||||
const char *strval;
|
||||
char *strval;
|
||||
uint64_t guid;
|
||||
uint8_t byte;
|
||||
|
||||
@@ -351,7 +362,7 @@ zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
|
||||
if (code != NULL)
|
||||
zed_log_msg(LOG_INFO, "\t%s: %s", FM_SUSPECT_DIAG_CODE, code);
|
||||
if (nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &byte) == 0)
|
||||
zed_log_msg(LOG_INFO, "\t%s: %hhu", FM_FAULT_CERTAINTY, byte);
|
||||
zed_log_msg(LOG_INFO, "\t%s: %llu", FM_FAULT_CERTAINTY, byte);
|
||||
if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
|
||||
if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &strval) == 0)
|
||||
zed_log_msg(LOG_INFO, "\t%s: %s", FM_FMRI_SCHEME,
|
||||
@@ -368,8 +379,7 @@ zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
|
||||
static const char *
|
||||
fmd_fault_mkcode(nvlist_t *fault)
|
||||
{
|
||||
const char *class;
|
||||
const char *code = "-";
|
||||
char *class, *code = "-";
|
||||
|
||||
/*
|
||||
* Note: message codes come from: openzfs/usr/src/cmd/fm/dicts/ZFS.po
|
||||
@@ -418,8 +428,7 @@ fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *fault)
|
||||
err |= nvlist_add_string(nvl, FM_SUSPECT_DIAG_CODE, code);
|
||||
err |= nvlist_add_int64_array(nvl, FM_SUSPECT_DIAG_TIME, tod, 2);
|
||||
err |= nvlist_add_uint32(nvl, FM_SUSPECT_FAULT_SZ, 1);
|
||||
err |= nvlist_add_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
|
||||
(const nvlist_t **)&fault, 1);
|
||||
err |= nvlist_add_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &fault, 1);
|
||||
|
||||
if (err)
|
||||
zed_log_die("failed to populate nvlist");
|
||||
@@ -434,21 +443,19 @@ fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *fault)
|
||||
void
|
||||
fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data)
|
||||
{
|
||||
(void) hdl;
|
||||
cp->ci_data = data;
|
||||
}
|
||||
|
||||
void *
|
||||
fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp)
|
||||
{
|
||||
(void) hdl;
|
||||
return (cp->ci_data);
|
||||
}
|
||||
|
||||
void
|
||||
fmd_buf_create(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name, size_t size)
|
||||
{
|
||||
assert(strcmp(name, "data") == 0), (void) name;
|
||||
assert(strcmp(name, "data") == 0);
|
||||
assert(cp->ci_bufptr == NULL);
|
||||
assert(size < (1024 * 1024));
|
||||
|
||||
@@ -460,24 +467,22 @@ void
|
||||
fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp,
|
||||
const char *name, void *buf, size_t size)
|
||||
{
|
||||
(void) hdl;
|
||||
assert(strcmp(name, "data") == 0), (void) name;
|
||||
assert(strcmp(name, "data") == 0);
|
||||
assert(cp->ci_bufptr != NULL);
|
||||
assert(size <= cp->ci_bufsiz);
|
||||
|
||||
memcpy(buf, cp->ci_bufptr, size);
|
||||
bcopy(cp->ci_bufptr, buf, size);
|
||||
}
|
||||
|
||||
void
|
||||
fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp,
|
||||
const char *name, const void *buf, size_t size)
|
||||
{
|
||||
(void) hdl;
|
||||
assert(strcmp(name, "data") == 0), (void) name;
|
||||
assert(strcmp(name, "data") == 0);
|
||||
assert(cp->ci_bufptr != NULL);
|
||||
assert(cp->ci_bufsiz >= size);
|
||||
|
||||
memcpy(cp->ci_bufptr, buf, size);
|
||||
bcopy(buf, cp->ci_bufptr, size);
|
||||
}
|
||||
|
||||
/* SERD Engines */
|
||||
@@ -514,19 +519,6 @@ fmd_serd_exists(fmd_hdl_t *hdl, const char *name)
|
||||
return (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL);
|
||||
}
|
||||
|
||||
int
|
||||
fmd_serd_active(fmd_hdl_t *hdl, const char *name)
|
||||
{
|
||||
fmd_module_t *mp = (fmd_module_t *)hdl;
|
||||
fmd_serd_eng_t *sgp;
|
||||
|
||||
if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
|
||||
zed_log_msg(LOG_ERR, "serd engine '%s' does not exist", name);
|
||||
return (0);
|
||||
}
|
||||
return (fmd_serd_eng_fired(sgp) || !fmd_serd_eng_empty(sgp));
|
||||
}
|
||||
|
||||
void
|
||||
fmd_serd_reset(fmd_hdl_t *hdl, const char *name)
|
||||
{
|
||||
@@ -535,10 +527,12 @@ fmd_serd_reset(fmd_hdl_t *hdl, const char *name)
|
||||
|
||||
if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
|
||||
zed_log_msg(LOG_ERR, "serd engine '%s' does not exist", name);
|
||||
} else {
|
||||
fmd_serd_eng_reset(sgp);
|
||||
fmd_hdl_debug(hdl, "serd_reset %s", name);
|
||||
return;
|
||||
}
|
||||
|
||||
fmd_serd_eng_reset(sgp);
|
||||
|
||||
fmd_hdl_debug(hdl, "serd_reset %s", name);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -546,21 +540,16 @@ fmd_serd_record(fmd_hdl_t *hdl, const char *name, fmd_event_t *ep)
|
||||
{
|
||||
fmd_module_t *mp = (fmd_module_t *)hdl;
|
||||
fmd_serd_eng_t *sgp;
|
||||
int err;
|
||||
|
||||
if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
|
||||
zed_log_msg(LOG_ERR, "failed to add record to SERD engine '%s'",
|
||||
name);
|
||||
return (0);
|
||||
return (FMD_B_FALSE);
|
||||
}
|
||||
return (fmd_serd_eng_record(sgp, ep->ev_hrt));
|
||||
}
|
||||
err = fmd_serd_eng_record(sgp, ep->ev_hrt);
|
||||
|
||||
void
|
||||
fmd_serd_gc(fmd_hdl_t *hdl)
|
||||
{
|
||||
fmd_module_t *mp = (fmd_module_t *)hdl;
|
||||
|
||||
fmd_serd_hash_apply(&mp->mod_serds, fmd_serd_eng_gc, NULL);
|
||||
return (err);
|
||||
}
|
||||
|
||||
/* FMD Timers */
|
||||
@@ -574,10 +563,10 @@ _timer_notify(union sigval sv)
|
||||
const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
|
||||
struct itimerspec its;
|
||||
|
||||
fmd_hdl_debug(hdl, "%s timer fired (%p)", mp->mod_name, ftp->ft_tid);
|
||||
fmd_hdl_debug(hdl, "timer fired (%p)", ftp->ft_tid);
|
||||
|
||||
/* disarm the timer */
|
||||
memset(&its, 0, sizeof (struct itimerspec));
|
||||
bzero(&its, sizeof (struct itimerspec));
|
||||
timer_settime(ftp->ft_tid, 0, &its, NULL);
|
||||
|
||||
/* Note that the fmdo_timeout can remove this timer */
|
||||
@@ -593,7 +582,6 @@ _timer_notify(union sigval sv)
|
||||
fmd_timer_t *
|
||||
fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
|
||||
{
|
||||
(void) ep;
|
||||
struct sigevent sev;
|
||||
struct itimerspec its;
|
||||
fmd_timer_t *ftp;
|
||||
@@ -611,7 +599,6 @@ fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
|
||||
sev.sigev_notify_function = _timer_notify;
|
||||
sev.sigev_notify_attributes = NULL;
|
||||
sev.sigev_value.sival_ptr = ftp;
|
||||
sev.sigev_signo = 0;
|
||||
|
||||
timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid);
|
||||
timer_settime(ftp->ft_tid, 0, &its, NULL);
|
||||
@@ -638,7 +625,6 @@ nvlist_t *
|
||||
fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t certainty,
|
||||
nvlist_t *asru, nvlist_t *fru, nvlist_t *resource)
|
||||
{
|
||||
(void) hdl;
|
||||
nvlist_t *nvl;
|
||||
int err = 0;
|
||||
|
||||
@@ -702,8 +688,7 @@ fmd_strmatch(const char *s, const char *p)
|
||||
int
|
||||
fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern)
|
||||
{
|
||||
(void) hdl;
|
||||
const char *class;
|
||||
char *class;
|
||||
|
||||
return (nvl != NULL &&
|
||||
nvlist_lookup_string(nvl, FM_CLASS, &class) == 0 &&
|
||||
@@ -713,7 +698,6 @@ fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern)
|
||||
nvlist_t *
|
||||
fmd_nvl_alloc(fmd_hdl_t *hdl, int flags)
|
||||
{
|
||||
(void) hdl, (void) flags;
|
||||
nvlist_t *nvl = NULL;
|
||||
|
||||
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -72,6 +72,10 @@ typedef struct fmd_case {
|
||||
} fmd_case_t;
|
||||
|
||||
|
||||
#define FMD_B_FALSE 0 /* false value for booleans as int */
|
||||
#define FMD_B_TRUE 1 /* true value for booleans as int */
|
||||
|
||||
|
||||
#define FMD_CASE_UNSOLVED 0 /* case is not yet solved (waiting) */
|
||||
#define FMD_CASE_SOLVED 1 /* case is solved (suspects added) */
|
||||
#define FMD_CASE_CLOSE_WAIT 2 /* case is executing fmdo_close() */
|
||||
@@ -151,6 +155,7 @@ extern void fmd_hdl_vdebug(fmd_hdl_t *, const char *, va_list);
|
||||
extern void fmd_hdl_debug(fmd_hdl_t *, const char *, ...);
|
||||
|
||||
extern int32_t fmd_prop_get_int32(fmd_hdl_t *, const char *);
|
||||
extern int64_t fmd_prop_get_int64(fmd_hdl_t *, const char *);
|
||||
|
||||
#define FMD_STAT_NOALLOC 0x0 /* fmd should use caller's memory */
|
||||
#define FMD_STAT_ALLOC 0x1 /* fmd should allocate stats memory */
|
||||
@@ -171,7 +176,8 @@ extern int fmd_case_uuclosed(fmd_hdl_t *, const char *);
|
||||
extern int fmd_case_uuisresolved(fmd_hdl_t *, const char *);
|
||||
extern void fmd_case_uuresolved(fmd_hdl_t *, const char *);
|
||||
|
||||
extern boolean_t fmd_case_solved(fmd_hdl_t *, fmd_case_t *);
|
||||
extern int fmd_case_solved(fmd_hdl_t *, fmd_case_t *);
|
||||
extern int fmd_case_closed(fmd_hdl_t *, fmd_case_t *);
|
||||
|
||||
extern void fmd_case_add_ereport(fmd_hdl_t *, fmd_case_t *, fmd_event_t *);
|
||||
extern void fmd_case_add_serd(fmd_hdl_t *, fmd_case_t *, const char *);
|
||||
@@ -194,12 +200,10 @@ extern size_t fmd_buf_size(fmd_hdl_t *, fmd_case_t *, const char *);
|
||||
extern void fmd_serd_create(fmd_hdl_t *, const char *, uint_t, hrtime_t);
|
||||
extern void fmd_serd_destroy(fmd_hdl_t *, const char *);
|
||||
extern int fmd_serd_exists(fmd_hdl_t *, const char *);
|
||||
extern int fmd_serd_active(fmd_hdl_t *, const char *);
|
||||
extern void fmd_serd_reset(fmd_hdl_t *, const char *);
|
||||
extern int fmd_serd_record(fmd_hdl_t *, const char *, fmd_event_t *);
|
||||
extern int fmd_serd_fired(fmd_hdl_t *, const char *);
|
||||
extern int fmd_serd_empty(fmd_hdl_t *, const char *);
|
||||
extern void fmd_serd_gc(fmd_hdl_t *);
|
||||
|
||||
extern id_t fmd_timer_install(fmd_hdl_t *, void *, fmd_event_t *, hrtime_t);
|
||||
extern void fmd_timer_remove(fmd_hdl_t *, id_t);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/list.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
@@ -74,18 +74,9 @@ fmd_serd_eng_alloc(const char *name, uint64_t n, hrtime_t t)
|
||||
fmd_serd_eng_t *sgp;
|
||||
|
||||
sgp = malloc(sizeof (fmd_serd_eng_t));
|
||||
if (sgp == NULL) {
|
||||
perror("malloc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
memset(sgp, 0, sizeof (fmd_serd_eng_t));
|
||||
bzero(sgp, sizeof (fmd_serd_eng_t));
|
||||
|
||||
sgp->sg_name = strdup(name);
|
||||
if (sgp->sg_name == NULL) {
|
||||
perror("strdup");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sgp->sg_flags = FMD_SERD_DIRTY;
|
||||
sgp->sg_n = n;
|
||||
sgp->sg_t = t;
|
||||
@@ -132,12 +123,6 @@ fmd_serd_hash_create(fmd_serd_hash_t *shp)
|
||||
shp->sh_hashlen = FMD_STR_BUCKETS;
|
||||
shp->sh_hash = calloc(shp->sh_hashlen, sizeof (void *));
|
||||
shp->sh_count = 0;
|
||||
|
||||
if (shp->sh_hash == NULL) {
|
||||
perror("calloc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -154,7 +139,7 @@ fmd_serd_hash_destroy(fmd_serd_hash_t *shp)
|
||||
}
|
||||
|
||||
free(shp->sh_hash);
|
||||
memset(shp, 0, sizeof (fmd_serd_hash_t));
|
||||
bzero(shp, sizeof (fmd_serd_hash_t));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -249,17 +234,13 @@ fmd_serd_eng_record(fmd_serd_eng_t *sgp, hrtime_t hrt)
|
||||
if (sgp->sg_flags & FMD_SERD_FIRED) {
|
||||
serd_log_msg(" SERD Engine: record %s already fired!",
|
||||
sgp->sg_name);
|
||||
return (B_FALSE);
|
||||
return (FMD_B_FALSE);
|
||||
}
|
||||
|
||||
while (sgp->sg_count >= sgp->sg_n)
|
||||
fmd_serd_eng_discard(sgp, list_tail(&sgp->sg_list));
|
||||
|
||||
sep = malloc(sizeof (fmd_serd_elem_t));
|
||||
if (sep == NULL) {
|
||||
perror("malloc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sep->se_hrt = hrt;
|
||||
|
||||
list_insert_head(&sgp->sg_list, sep);
|
||||
@@ -278,11 +259,11 @@ fmd_serd_eng_record(fmd_serd_eng_t *sgp, hrtime_t hrt)
|
||||
fmd_event_delta(oep->se_hrt, sep->se_hrt) <= sgp->sg_t) {
|
||||
sgp->sg_flags |= FMD_SERD_FIRED | FMD_SERD_DIRTY;
|
||||
serd_log_msg(" SERD Engine: fired %s", sgp->sg_name);
|
||||
return (B_TRUE);
|
||||
return (FMD_B_TRUE);
|
||||
}
|
||||
|
||||
sgp->sg_flags |= FMD_SERD_DIRTY;
|
||||
return (B_FALSE);
|
||||
return (FMD_B_FALSE);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -310,9 +291,8 @@ fmd_serd_eng_reset(fmd_serd_eng_t *sgp)
|
||||
}
|
||||
|
||||
void
|
||||
fmd_serd_eng_gc(fmd_serd_eng_t *sgp, void *arg)
|
||||
fmd_serd_eng_gc(fmd_serd_eng_t *sgp)
|
||||
{
|
||||
(void) arg;
|
||||
fmd_serd_elem_t *sep, *nep;
|
||||
hrtime_t hrt;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -77,7 +77,7 @@ extern int fmd_serd_eng_fired(fmd_serd_eng_t *);
|
||||
extern int fmd_serd_eng_empty(fmd_serd_eng_t *);
|
||||
|
||||
extern void fmd_serd_eng_reset(fmd_serd_eng_t *);
|
||||
extern void fmd_serd_eng_gc(fmd_serd_eng_t *, void *);
|
||||
extern void fmd_serd_eng_gc(fmd_serd_eng_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+18
-49
@@ -13,7 +13,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Intel Corporation.
|
||||
* Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>
|
||||
* Copyright (c) 2021 Hewlett Packard Enterprise Development LP
|
||||
*/
|
||||
|
||||
#include <libnvpair.h>
|
||||
@@ -64,7 +63,7 @@ typedef enum device_type {
|
||||
typedef struct guid_search {
|
||||
uint64_t gs_pool_guid;
|
||||
uint64_t gs_vdev_guid;
|
||||
const char *gs_devid;
|
||||
char *gs_devid;
|
||||
device_type_t gs_vdev_type;
|
||||
uint64_t gs_vdev_expandtime; /* vdev expansion time */
|
||||
} guid_search_t;
|
||||
@@ -77,10 +76,9 @@ static boolean_t
|
||||
zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
|
||||
{
|
||||
guid_search_t *gsp = arg;
|
||||
const char *path = NULL;
|
||||
char *path = NULL;
|
||||
uint_t c, children;
|
||||
nvlist_t **child;
|
||||
uint64_t vdev_guid;
|
||||
|
||||
/*
|
||||
* First iterate over any children.
|
||||
@@ -101,7 +99,7 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
|
||||
&child, &children) == 0) {
|
||||
for (c = 0; c < children; c++) {
|
||||
if (zfs_agent_iter_vdev(zhp, child[c], gsp)) {
|
||||
gsp->gs_vdev_type = DEVICE_TYPE_SPARE;
|
||||
gsp->gs_vdev_type = DEVICE_TYPE_L2ARC;
|
||||
return (B_TRUE);
|
||||
}
|
||||
}
|
||||
@@ -110,7 +108,7 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
|
||||
&child, &children) == 0) {
|
||||
for (c = 0; c < children; c++) {
|
||||
if (zfs_agent_iter_vdev(zhp, child[c], gsp)) {
|
||||
gsp->gs_vdev_type = DEVICE_TYPE_L2ARC;
|
||||
gsp->gs_vdev_type = DEVICE_TYPE_SPARE;
|
||||
return (B_TRUE);
|
||||
}
|
||||
}
|
||||
@@ -127,21 +125,6 @@ zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
|
||||
&gsp->gs_vdev_expandtime);
|
||||
return (B_TRUE);
|
||||
}
|
||||
/*
|
||||
* Otherwise, on a vdev guid match, grab the devid and expansion
|
||||
* time. The devid might be missing on removal since its not part
|
||||
* of blkid cache and L2ARC VDEV does not contain pool guid in its
|
||||
* blkid, so this is a special case for L2ARC VDEV.
|
||||
*/
|
||||
else if (gsp->gs_vdev_guid != 0 && gsp->gs_devid == NULL &&
|
||||
nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, &vdev_guid) == 0 &&
|
||||
gsp->gs_vdev_guid == vdev_guid) {
|
||||
(void) nvlist_lookup_string(nvl, ZPOOL_CONFIG_DEVID,
|
||||
&gsp->gs_devid);
|
||||
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_EXPANSION_TIME,
|
||||
&gsp->gs_vdev_expandtime);
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
@@ -164,13 +147,13 @@ zfs_agent_iter_pool(zpool_handle_t *zhp, void *arg)
|
||||
/*
|
||||
* if a match was found then grab the pool guid
|
||||
*/
|
||||
if (gsp->gs_vdev_guid && gsp->gs_devid) {
|
||||
if (gsp->gs_vdev_guid) {
|
||||
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
|
||||
&gsp->gs_pool_guid);
|
||||
}
|
||||
|
||||
zpool_close(zhp);
|
||||
return (gsp->gs_devid != NULL && gsp->gs_vdev_guid != 0);
|
||||
return (gsp->gs_vdev_guid != 0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -211,13 +194,11 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
|
||||
uint64_t pool_guid = 0, vdev_guid = 0;
|
||||
guid_search_t search = { 0 };
|
||||
device_type_t devtype = DEVICE_TYPE_PRIMARY;
|
||||
const char *devid = NULL;
|
||||
|
||||
class = "resource.fs.zfs.removed";
|
||||
subclass = "";
|
||||
|
||||
(void) nvlist_add_string(payload, FM_CLASS, class);
|
||||
(void) nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid);
|
||||
(void) nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &pool_guid);
|
||||
(void) nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &vdev_guid);
|
||||
|
||||
@@ -227,25 +208,15 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
|
||||
(void) nvlist_add_int64_array(payload, FM_EREPORT_TIME, tod, 2);
|
||||
|
||||
/*
|
||||
* If devid is missing but vdev_guid is available, find devid
|
||||
* and pool_guid from vdev_guid.
|
||||
* For multipath, spare and l2arc devices ZFS_EV_VDEV_GUID or
|
||||
* ZFS_EV_POOL_GUID may be missing so find them.
|
||||
*/
|
||||
if (devid == NULL || pool_guid == 0 || vdev_guid == 0) {
|
||||
if (devid == NULL)
|
||||
search.gs_vdev_guid = vdev_guid;
|
||||
else
|
||||
search.gs_devid = devid;
|
||||
zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search);
|
||||
if (devid == NULL)
|
||||
devid = search.gs_devid;
|
||||
if (pool_guid == 0)
|
||||
pool_guid = search.gs_pool_guid;
|
||||
if (vdev_guid == 0)
|
||||
vdev_guid = search.gs_vdev_guid;
|
||||
devtype = search.gs_vdev_type;
|
||||
}
|
||||
(void) nvlist_lookup_string(nvl, DEV_IDENTIFIER,
|
||||
&search.gs_devid);
|
||||
(void) zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search);
|
||||
pool_guid = search.gs_pool_guid;
|
||||
vdev_guid = search.gs_vdev_guid;
|
||||
devtype = search.gs_vdev_type;
|
||||
|
||||
/*
|
||||
* We want to avoid reporting "remove" events coming from
|
||||
@@ -257,9 +228,7 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
|
||||
search.gs_vdev_expandtime + 10 > tv.tv_sec) {
|
||||
zed_log_msg(LOG_INFO, "agent post event: ignoring '%s' "
|
||||
"for recently expanded device '%s'", EC_DEV_REMOVE,
|
||||
devid);
|
||||
fnvlist_free(payload);
|
||||
free(event);
|
||||
search.gs_devid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -351,8 +320,6 @@ zfs_agent_dispatch(const char *class, const char *subclass, nvlist_t *nvl)
|
||||
static void *
|
||||
zfs_agent_consumer_thread(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
for (;;) {
|
||||
agent_event_t *event;
|
||||
|
||||
@@ -369,7 +336,9 @@ zfs_agent_consumer_thread(void *arg)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((event = list_remove_head(&agent_events)) != NULL) {
|
||||
if ((event = (list_head(&agent_events))) != NULL) {
|
||||
list_remove(&agent_events, event);
|
||||
|
||||
(void) pthread_mutex_unlock(&agent_lock);
|
||||
|
||||
/* dispatch to all event subscribers */
|
||||
@@ -416,7 +385,6 @@ zfs_agent_init(libzfs_handle_t *zfs_hdl)
|
||||
list_destroy(&agent_events);
|
||||
zed_log_die("Failed to initialize agents");
|
||||
}
|
||||
pthread_setname_np(g_agents_tid, "agents");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -432,7 +400,8 @@ zfs_agent_fini(void)
|
||||
(void) pthread_join(g_agents_tid, NULL);
|
||||
|
||||
/* drain any pending events */
|
||||
while ((event = list_remove_head(&agent_events)) != NULL) {
|
||||
while ((event = (list_head(&agent_events))) != NULL) {
|
||||
list_remove(&agent_events, event);
|
||||
nvlist_free(event->ae_nvl);
|
||||
free(event);
|
||||
}
|
||||
|
||||
+54
-192
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -23,11 +23,11 @@
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2016, Intel Corporation.
|
||||
* Copyright (c) 2023, Klara Inc.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <libuutil.h>
|
||||
#include <libzfs.h>
|
||||
#include <sys/types.h>
|
||||
@@ -35,29 +35,14 @@
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/fm/protocol.h>
|
||||
#include <sys/fm/fs/zfs.h>
|
||||
#include <sys/zio.h>
|
||||
|
||||
#include "zfs_agents.h"
|
||||
#include "fmd_api.h"
|
||||
|
||||
/*
|
||||
* Default values for the serd engine when processing checksum or io errors. The
|
||||
* semantics are N <events> in T <seconds>.
|
||||
*/
|
||||
#define DEFAULT_CHECKSUM_N 10 /* events */
|
||||
#define DEFAULT_CHECKSUM_T 600 /* seconds */
|
||||
#define DEFAULT_IO_N 10 /* events */
|
||||
#define DEFAULT_IO_T 600 /* seconds */
|
||||
#define DEFAULT_SLOW_IO_N 10 /* events */
|
||||
#define DEFAULT_SLOW_IO_T 30 /* seconds */
|
||||
|
||||
#define CASE_GC_TIMEOUT_SECS 43200 /* 12 hours */
|
||||
|
||||
/*
|
||||
* Our serd engines are named in the following format:
|
||||
* 'zfs_<pool_guid>_<vdev_guid>_{checksum,io,slow_io}'
|
||||
* This #define reserves enough space for two 64-bit hex values plus the
|
||||
* length of the longest string.
|
||||
* Our serd engines are named 'zfs_<pool_guid>_<vdev_guid>_{checksum,io}'. This
|
||||
* #define reserves enough space for two 64-bit hex values plus the length of
|
||||
* the longest string.
|
||||
*/
|
||||
#define MAX_SERDLEN (16 * 2 + sizeof ("zfs___checksum"))
|
||||
|
||||
@@ -74,7 +59,6 @@ typedef struct zfs_case_data {
|
||||
int zc_pool_state;
|
||||
char zc_serd_checksum[MAX_SERDLEN];
|
||||
char zc_serd_io[MAX_SERDLEN];
|
||||
char zc_serd_slow_io[MAX_SERDLEN];
|
||||
int zc_has_remove_timer;
|
||||
} zfs_case_data_t;
|
||||
|
||||
@@ -121,8 +105,7 @@ zfs_de_stats_t zfs_stats = {
|
||||
{ "resource_drops", FMD_TYPE_UINT64, "resource related ereports" }
|
||||
};
|
||||
|
||||
/* wait 15 seconds after a removal */
|
||||
static hrtime_t zfs_remove_timeout = SEC2NSEC(15);
|
||||
static hrtime_t zfs_remove_timeout;
|
||||
|
||||
uu_list_pool_t *zfs_case_pool;
|
||||
uu_list_t *zfs_cases;
|
||||
@@ -132,13 +115,11 @@ uu_list_t *zfs_cases;
|
||||
#define ZFS_MAKE_EREPORT(type) \
|
||||
FM_EREPORT_CLASS "." ZFS_ERROR_CLASS "." type
|
||||
|
||||
static void zfs_purge_cases(fmd_hdl_t *hdl);
|
||||
|
||||
/*
|
||||
* Write out the persistent representation of an active case.
|
||||
*/
|
||||
static void
|
||||
zfs_case_serialize(zfs_case_t *zcp)
|
||||
zfs_case_serialize(fmd_hdl_t *hdl, zfs_case_t *zcp)
|
||||
{
|
||||
zcp->zc_data.zc_version = CASE_DATA_VERSION_SERD;
|
||||
}
|
||||
@@ -180,42 +161,6 @@ zfs_case_unserialize(fmd_hdl_t *hdl, fmd_case_t *cp)
|
||||
return (zcp);
|
||||
}
|
||||
|
||||
/*
|
||||
* count other unique slow-io cases in a pool
|
||||
*/
|
||||
static uint_t
|
||||
zfs_other_slow_cases(fmd_hdl_t *hdl, const zfs_case_data_t *zfs_case)
|
||||
{
|
||||
zfs_case_t *zcp;
|
||||
uint_t cases = 0;
|
||||
static hrtime_t next_check = 0;
|
||||
|
||||
/*
|
||||
* Note that plumbing in some external GC would require adding locking,
|
||||
* since most of this module code is not thread safe and assumes there
|
||||
* is only one thread running against the module. So we perform GC here
|
||||
* inline periodically so that future delay induced faults will be
|
||||
* possible once the issue causing multiple vdev delays is resolved.
|
||||
*/
|
||||
if (gethrestime_sec() > next_check) {
|
||||
/* Periodically purge old SERD entries and stale cases */
|
||||
fmd_serd_gc(hdl);
|
||||
zfs_purge_cases(hdl);
|
||||
next_check = gethrestime_sec() + CASE_GC_TIMEOUT_SECS;
|
||||
}
|
||||
|
||||
for (zcp = uu_list_first(zfs_cases); zcp != NULL;
|
||||
zcp = uu_list_next(zfs_cases, zcp)) {
|
||||
if (zcp->zc_data.zc_pool_guid == zfs_case->zc_pool_guid &&
|
||||
zcp->zc_data.zc_vdev_guid != zfs_case->zc_vdev_guid &&
|
||||
zcp->zc_data.zc_serd_slow_io[0] != '\0' &&
|
||||
fmd_serd_active(hdl, zcp->zc_data.zc_serd_slow_io)) {
|
||||
cases++;
|
||||
}
|
||||
}
|
||||
return (cases);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over any active cases. If any cases are associated with a pool or
|
||||
* vdev which is no longer present on the system, close the associated case.
|
||||
@@ -264,10 +209,10 @@ zfs_mark_vdev(uint64_t pool_guid, nvlist_t *vd, er_timeval_t *loaded)
|
||||
}
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
zfs_mark_pool(zpool_handle_t *zhp, void *unused)
|
||||
{
|
||||
(void) unused;
|
||||
zfs_case_t *zcp;
|
||||
uint64_t pool_guid;
|
||||
uint64_t *tod;
|
||||
@@ -422,21 +367,14 @@ zfs_serd_name(char *buf, uint64_t pool_guid, uint64_t vdev_guid,
|
||||
(long long unsigned int)vdev_guid, type);
|
||||
}
|
||||
|
||||
static void
|
||||
zfs_case_retire(fmd_hdl_t *hdl, zfs_case_t *zcp)
|
||||
{
|
||||
fmd_hdl_debug(hdl, "retiring case");
|
||||
|
||||
fmd_case_close(hdl, zcp->zc_case);
|
||||
}
|
||||
|
||||
/*
|
||||
* Solve a given ZFS case. This first checks to make sure the diagnosis is
|
||||
* still valid, as well as cleaning up any pending timer associated with the
|
||||
* case.
|
||||
*/
|
||||
static void
|
||||
zfs_case_solve(fmd_hdl_t *hdl, zfs_case_t *zcp, const char *faultname)
|
||||
zfs_case_solve(fmd_hdl_t *hdl, zfs_case_t *zcp, const char *faultname,
|
||||
boolean_t checkunusable)
|
||||
{
|
||||
nvlist_t *detector, *fault;
|
||||
boolean_t serialize;
|
||||
@@ -474,7 +412,7 @@ zfs_case_solve(fmd_hdl_t *hdl, zfs_case_t *zcp, const char *faultname)
|
||||
serialize = B_TRUE;
|
||||
}
|
||||
if (serialize)
|
||||
zfs_case_serialize(zcp);
|
||||
zfs_case_serialize(hdl, zcp);
|
||||
|
||||
nvlist_free(detector);
|
||||
}
|
||||
@@ -486,10 +424,10 @@ timeval_earlier(er_timeval_t *a, er_timeval_t *b)
|
||||
(a->ertv_sec == b->ertv_sec && a->ertv_nsec < b->ertv_nsec));
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
zfs_ereport_when(fmd_hdl_t *hdl, nvlist_t *nvl, er_timeval_t *when)
|
||||
{
|
||||
(void) hdl;
|
||||
int64_t *tod;
|
||||
uint_t nelem;
|
||||
|
||||
@@ -505,20 +443,19 @@ zfs_ereport_when(fmd_hdl_t *hdl, nvlist_t *nvl, er_timeval_t *when)
|
||||
/*
|
||||
* Main fmd entry point.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
{
|
||||
zfs_case_t *zcp, *dcp;
|
||||
int32_t pool_state;
|
||||
uint64_t ena, pool_guid, vdev_guid;
|
||||
uint64_t checksum_n, checksum_t;
|
||||
uint64_t io_n, io_t;
|
||||
er_timeval_t pool_load;
|
||||
er_timeval_t er_when;
|
||||
nvlist_t *detector;
|
||||
boolean_t pool_found = B_FALSE;
|
||||
boolean_t isresource;
|
||||
const char *type;
|
||||
char *type;
|
||||
|
||||
/*
|
||||
* We subscribe to notifications for vdev or pool removal. In these
|
||||
@@ -686,7 +623,9 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
if (strcmp(class,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_DATA)) == 0 ||
|
||||
strcmp(class,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_CONFIG_CACHE_WRITE)) == 0) {
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_CONFIG_CACHE_WRITE)) == 0 ||
|
||||
strcmp(class,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_DELAY)) == 0) {
|
||||
zfs_stats.resource_drops.fmds_value.ui64++;
|
||||
return;
|
||||
}
|
||||
@@ -747,16 +686,13 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
if (zcp->zc_data.zc_has_remove_timer) {
|
||||
fmd_timer_remove(hdl, zcp->zc_remove_timer);
|
||||
zcp->zc_data.zc_has_remove_timer = 0;
|
||||
zfs_case_serialize(zcp);
|
||||
zfs_case_serialize(hdl, zcp);
|
||||
}
|
||||
if (zcp->zc_data.zc_serd_io[0] != '\0')
|
||||
fmd_serd_reset(hdl, zcp->zc_data.zc_serd_io);
|
||||
if (zcp->zc_data.zc_serd_checksum[0] != '\0')
|
||||
fmd_serd_reset(hdl,
|
||||
zcp->zc_data.zc_serd_checksum);
|
||||
if (zcp->zc_data.zc_serd_slow_io[0] != '\0')
|
||||
fmd_serd_reset(hdl,
|
||||
zcp->zc_data.zc_serd_slow_io);
|
||||
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_RSRC(FM_RESOURCE_STATECHANGE))) {
|
||||
uint64_t state = 0;
|
||||
@@ -785,11 +721,7 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
if (fmd_case_solved(hdl, zcp->zc_case))
|
||||
return;
|
||||
|
||||
if (vdev_guid)
|
||||
fmd_hdl_debug(hdl, "error event '%s', vdev %llu", class,
|
||||
vdev_guid);
|
||||
else
|
||||
fmd_hdl_debug(hdl, "error event '%s'", class);
|
||||
fmd_hdl_debug(hdl, "error event '%s'", class);
|
||||
|
||||
/*
|
||||
* Determine if we should solve the case and generate a fault. We solve
|
||||
@@ -819,18 +751,18 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
fmd_case_close(hdl, dcp->zc_case);
|
||||
}
|
||||
|
||||
zfs_case_solve(hdl, zcp, "fault.fs.zfs.pool");
|
||||
zfs_case_solve(hdl, zcp, "fault.fs.zfs.pool", B_TRUE);
|
||||
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_LOG_REPLAY))) {
|
||||
/*
|
||||
* Pool level fault for reading the intent logs.
|
||||
*/
|
||||
zfs_case_solve(hdl, zcp, "fault.fs.zfs.log_replay");
|
||||
zfs_case_solve(hdl, zcp, "fault.fs.zfs.log_replay", B_TRUE);
|
||||
} else if (fmd_nvl_class_match(hdl, nvl, "ereport.fs.zfs.vdev.*")) {
|
||||
/*
|
||||
* Device fault.
|
||||
*/
|
||||
zfs_case_solve(hdl, zcp, "fault.fs.zfs.device");
|
||||
zfs_case_solve(hdl, zcp, "fault.fs.zfs.device", B_TRUE);
|
||||
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO)) ||
|
||||
fmd_nvl_class_match(hdl, nvl,
|
||||
@@ -838,13 +770,9 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO_FAILURE)) ||
|
||||
fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_DELAY)) ||
|
||||
fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) {
|
||||
const char *failmode = NULL;
|
||||
char *failmode = NULL;
|
||||
boolean_t checkremove = B_FALSE;
|
||||
uint32_t pri = 0;
|
||||
int32_t flags = 0;
|
||||
|
||||
/*
|
||||
* If this is a checksum or I/O error, then toss it into the
|
||||
@@ -856,113 +784,30 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
if (fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO))) {
|
||||
if (zcp->zc_data.zc_serd_io[0] == '\0') {
|
||||
if (nvlist_lookup_uint64(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_IO_N,
|
||||
&io_n) != 0) {
|
||||
io_n = DEFAULT_IO_N;
|
||||
}
|
||||
if (nvlist_lookup_uint64(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_IO_T,
|
||||
&io_t) != 0) {
|
||||
io_t = DEFAULT_IO_T;
|
||||
}
|
||||
zfs_serd_name(zcp->zc_data.zc_serd_io,
|
||||
pool_guid, vdev_guid, "io");
|
||||
fmd_serd_create(hdl, zcp->zc_data.zc_serd_io,
|
||||
io_n,
|
||||
SEC2NSEC(io_t));
|
||||
zfs_case_serialize(zcp);
|
||||
fmd_prop_get_int32(hdl, "io_N"),
|
||||
fmd_prop_get_int64(hdl, "io_T"));
|
||||
zfs_case_serialize(hdl, zcp);
|
||||
}
|
||||
if (fmd_serd_record(hdl, zcp->zc_data.zc_serd_io, ep))
|
||||
checkremove = B_TRUE;
|
||||
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_DELAY))) {
|
||||
uint64_t slow_io_n, slow_io_t;
|
||||
|
||||
/*
|
||||
* Create a slow io SERD engine when the VDEV has the
|
||||
* 'vdev_slow_io_n' and 'vdev_slow_io_n' properties.
|
||||
*/
|
||||
if (zcp->zc_data.zc_serd_slow_io[0] == '\0' &&
|
||||
nvlist_lookup_uint64(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_SLOW_IO_N,
|
||||
&slow_io_n) == 0 &&
|
||||
nvlist_lookup_uint64(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_SLOW_IO_T,
|
||||
&slow_io_t) == 0) {
|
||||
zfs_serd_name(zcp->zc_data.zc_serd_slow_io,
|
||||
pool_guid, vdev_guid, "slow_io");
|
||||
fmd_serd_create(hdl,
|
||||
zcp->zc_data.zc_serd_slow_io,
|
||||
slow_io_n,
|
||||
SEC2NSEC(slow_io_t));
|
||||
zfs_case_serialize(zcp);
|
||||
}
|
||||
/* Pass event to SERD engine and see if this triggers */
|
||||
if (zcp->zc_data.zc_serd_slow_io[0] != '\0' &&
|
||||
fmd_serd_record(hdl, zcp->zc_data.zc_serd_slow_io,
|
||||
ep)) {
|
||||
/*
|
||||
* Ignore a slow io diagnosis when other
|
||||
* VDEVs in the pool show signs of being slow.
|
||||
*/
|
||||
if (zfs_other_slow_cases(hdl, &zcp->zc_data)) {
|
||||
zfs_case_retire(hdl, zcp);
|
||||
fmd_hdl_debug(hdl, "pool %llu has "
|
||||
"multiple slow io cases -- skip "
|
||||
"degrading vdev %llu",
|
||||
(u_longlong_t)
|
||||
zcp->zc_data.zc_pool_guid,
|
||||
(u_longlong_t)
|
||||
zcp->zc_data.zc_vdev_guid);
|
||||
} else {
|
||||
zfs_case_solve(hdl, zcp,
|
||||
"fault.fs.zfs.vdev.slow_io");
|
||||
}
|
||||
}
|
||||
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_CHECKSUM))) {
|
||||
/*
|
||||
* We ignore ereports for checksum errors generated by
|
||||
* scrub/resilver I/O to avoid potentially further
|
||||
* degrading the pool while it's being repaired.
|
||||
*/
|
||||
if (((nvlist_lookup_uint32(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_ZIO_PRIORITY, &pri) == 0) &&
|
||||
(pri == ZIO_PRIORITY_SCRUB ||
|
||||
pri == ZIO_PRIORITY_REBUILD)) ||
|
||||
((nvlist_lookup_int32(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS, &flags) == 0) &&
|
||||
(flags & (ZIO_FLAG_SCRUB | ZIO_FLAG_RESILVER)))) {
|
||||
fmd_hdl_debug(hdl, "ignoring '%s' for "
|
||||
"scrub/resilver I/O", class);
|
||||
return;
|
||||
}
|
||||
|
||||
if (zcp->zc_data.zc_serd_checksum[0] == '\0') {
|
||||
if (nvlist_lookup_uint64(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_CKSUM_N,
|
||||
&checksum_n) != 0) {
|
||||
checksum_n = DEFAULT_CHECKSUM_N;
|
||||
}
|
||||
if (nvlist_lookup_uint64(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_CKSUM_T,
|
||||
&checksum_t) != 0) {
|
||||
checksum_t = DEFAULT_CHECKSUM_T;
|
||||
}
|
||||
|
||||
zfs_serd_name(zcp->zc_data.zc_serd_checksum,
|
||||
pool_guid, vdev_guid, "checksum");
|
||||
fmd_serd_create(hdl,
|
||||
zcp->zc_data.zc_serd_checksum,
|
||||
checksum_n,
|
||||
SEC2NSEC(checksum_t));
|
||||
zfs_case_serialize(zcp);
|
||||
fmd_prop_get_int32(hdl, "checksum_N"),
|
||||
fmd_prop_get_int64(hdl, "checksum_T"));
|
||||
zfs_case_serialize(hdl, zcp);
|
||||
}
|
||||
if (fmd_serd_record(hdl,
|
||||
zcp->zc_data.zc_serd_checksum, ep)) {
|
||||
zfs_case_solve(hdl, zcp,
|
||||
"fault.fs.zfs.vdev.checksum");
|
||||
"fault.fs.zfs.vdev.checksum", B_FALSE);
|
||||
}
|
||||
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO_FAILURE)) &&
|
||||
@@ -972,11 +817,12 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
if (strncmp(failmode, FM_EREPORT_FAILMODE_CONTINUE,
|
||||
strlen(FM_EREPORT_FAILMODE_CONTINUE)) == 0) {
|
||||
zfs_case_solve(hdl, zcp,
|
||||
"fault.fs.zfs.io_failure_continue");
|
||||
"fault.fs.zfs.io_failure_continue",
|
||||
B_FALSE);
|
||||
} else if (strncmp(failmode, FM_EREPORT_FAILMODE_WAIT,
|
||||
strlen(FM_EREPORT_FAILMODE_WAIT)) == 0) {
|
||||
zfs_case_solve(hdl, zcp,
|
||||
"fault.fs.zfs.io_failure_wait");
|
||||
"fault.fs.zfs.io_failure_wait", B_FALSE);
|
||||
}
|
||||
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) {
|
||||
@@ -998,7 +844,7 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
zfs_remove_timeout);
|
||||
if (!zcp->zc_data.zc_has_remove_timer) {
|
||||
zcp->zc_data.zc_has_remove_timer = 1;
|
||||
zfs_case_serialize(zcp);
|
||||
zfs_case_serialize(hdl, zcp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1008,13 +854,14 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||
* The timeout is fired when we diagnosed an I/O error, and it was not due to
|
||||
* device removal (which would cause the timeout to be cancelled).
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zfs_fm_timeout(fmd_hdl_t *hdl, id_t id, void *data)
|
||||
{
|
||||
zfs_case_t *zcp = data;
|
||||
|
||||
if (id == zcp->zc_remove_timer)
|
||||
zfs_case_solve(hdl, zcp, "fault.fs.zfs.vdev.io");
|
||||
zfs_case_solve(hdl, zcp, "fault.fs.zfs.vdev.io", B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1030,8 +877,6 @@ zfs_fm_close(fmd_hdl_t *hdl, fmd_case_t *cs)
|
||||
fmd_serd_destroy(hdl, zcp->zc_data.zc_serd_checksum);
|
||||
if (zcp->zc_data.zc_serd_io[0] != '\0')
|
||||
fmd_serd_destroy(hdl, zcp->zc_data.zc_serd_io);
|
||||
if (zcp->zc_data.zc_serd_slow_io[0] != '\0')
|
||||
fmd_serd_destroy(hdl, zcp->zc_data.zc_serd_slow_io);
|
||||
if (zcp->zc_data.zc_has_remove_timer)
|
||||
fmd_timer_remove(hdl, zcp->zc_remove_timer);
|
||||
|
||||
@@ -1040,15 +885,30 @@ zfs_fm_close(fmd_hdl_t *hdl, fmd_case_t *cs)
|
||||
fmd_hdl_free(hdl, zcp, sizeof (zfs_case_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* We use the fmd gc entry point to look for old cases that no longer apply.
|
||||
* This allows us to keep our set of case data small in a long running system.
|
||||
*/
|
||||
static void
|
||||
zfs_fm_gc(fmd_hdl_t *hdl)
|
||||
{
|
||||
zfs_purge_cases(hdl);
|
||||
}
|
||||
|
||||
static const fmd_hdl_ops_t fmd_ops = {
|
||||
zfs_fm_recv, /* fmdo_recv */
|
||||
zfs_fm_timeout, /* fmdo_timeout */
|
||||
zfs_fm_close, /* fmdo_close */
|
||||
NULL, /* fmdo_stats */
|
||||
NULL, /* fmdo_gc */
|
||||
zfs_fm_gc, /* fmdo_gc */
|
||||
};
|
||||
|
||||
static const fmd_prop_t fmd_props[] = {
|
||||
{ "checksum_N", FMD_TYPE_UINT32, "10" },
|
||||
{ "checksum_T", FMD_TYPE_TIME, "10min" },
|
||||
{ "io_N", FMD_TYPE_UINT32, "10" },
|
||||
{ "io_T", FMD_TYPE_TIME, "10min" },
|
||||
{ "remove_timeout", FMD_TYPE_TIME, "15sec" },
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
|
||||
@@ -1089,6 +949,8 @@ _zfs_diagnosis_init(fmd_hdl_t *hdl)
|
||||
|
||||
(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (zfs_stats) /
|
||||
sizeof (fmd_stat_t), (fmd_stat_t *)&zfs_stats);
|
||||
|
||||
zfs_remove_timeout = fmd_prop_get_int64(hdl, "remove_timeout");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+91
-507
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -24,7 +24,6 @@
|
||||
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Intel Corporation.
|
||||
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
|
||||
* Copyright (c) 2023, Klara Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -134,11 +133,6 @@ zfs_unavail_pool(zpool_handle_t *zhp, void *data)
|
||||
if (zfs_toplevel_state(zhp) < VDEV_STATE_DEGRADED) {
|
||||
unavailpool_t *uap;
|
||||
uap = malloc(sizeof (unavailpool_t));
|
||||
if (uap == NULL) {
|
||||
perror("malloc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
uap->uap_zhp = zhp;
|
||||
list_insert_tail((list_t *)data, uap);
|
||||
} else {
|
||||
@@ -147,17 +141,6 @@ zfs_unavail_pool(zpool_handle_t *zhp, void *data)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write an array of strings to the zed log
|
||||
*/
|
||||
static void lines_to_zed_log_msg(char **lines, int lines_cnt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < lines_cnt; i++) {
|
||||
zed_log_msg(LOG_INFO, "%s", lines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Two stage replace on Linux
|
||||
* since we get disk notifications
|
||||
@@ -195,31 +178,22 @@ static void lines_to_zed_log_msg(char **lines, int lines_cnt)
|
||||
static void
|
||||
zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
{
|
||||
const char *path;
|
||||
char *path;
|
||||
vdev_state_t newstate;
|
||||
nvlist_t *nvroot, *newvd;
|
||||
pendingdev_t *device;
|
||||
uint64_t wholedisk = 0ULL;
|
||||
uint64_t offline = 0ULL, faulted = 0ULL;
|
||||
uint64_t offline = 0ULL;
|
||||
uint64_t guid = 0ULL;
|
||||
uint64_t is_spare = 0;
|
||||
const char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL;
|
||||
char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL;
|
||||
char rawpath[PATH_MAX], fullpath[PATH_MAX];
|
||||
char pathbuf[PATH_MAX];
|
||||
char devpath[PATH_MAX];
|
||||
int ret;
|
||||
int online_flag = ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE;
|
||||
boolean_t is_dm = B_FALSE;
|
||||
boolean_t is_sd = B_FALSE;
|
||||
boolean_t is_mpath_wholedisk = B_FALSE;
|
||||
uint_t c;
|
||||
vdev_stat_t *vs;
|
||||
char **lines = NULL;
|
||||
int lines_cnt = 0;
|
||||
|
||||
/*
|
||||
* Get the persistent path, typically under the '/dev/disk/by-id' or
|
||||
* '/dev/disk/by-vdev' directories. Note that this path can change
|
||||
* when a vdev is replaced with a new disk.
|
||||
*/
|
||||
if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0)
|
||||
return;
|
||||
|
||||
@@ -233,82 +207,19 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
}
|
||||
|
||||
(void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_PHYS_PATH, &physpath);
|
||||
|
||||
update_vdev_config_dev_sysfs_path(vdev, path,
|
||||
ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH);
|
||||
(void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
|
||||
&enc_sysfs_path);
|
||||
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline);
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_FAULTED, &faulted);
|
||||
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid);
|
||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_IS_SPARE, &is_spare);
|
||||
|
||||
/*
|
||||
* Special case:
|
||||
*
|
||||
* We've seen times where a disk won't have a ZPOOL_CONFIG_PHYS_PATH
|
||||
* entry in their config. For example, on this force-faulted disk:
|
||||
*
|
||||
* children[0]:
|
||||
* type: 'disk'
|
||||
* id: 0
|
||||
* guid: 14309659774640089719
|
||||
* path: '/dev/disk/by-vdev/L28'
|
||||
* whole_disk: 0
|
||||
* DTL: 654
|
||||
* create_txg: 4
|
||||
* com.delphix:vdev_zap_leaf: 1161
|
||||
* faulted: 1
|
||||
* aux_state: 'external'
|
||||
* children[1]:
|
||||
* type: 'disk'
|
||||
* id: 1
|
||||
* guid: 16002508084177980912
|
||||
* path: '/dev/disk/by-vdev/L29'
|
||||
* devid: 'dm-uuid-mpath-35000c500a61d68a3'
|
||||
* phys_path: 'L29'
|
||||
* vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32'
|
||||
* whole_disk: 0
|
||||
* DTL: 1028
|
||||
* create_txg: 4
|
||||
* com.delphix:vdev_zap_leaf: 131
|
||||
*
|
||||
* If the disk's path is a /dev/disk/by-vdev/ path, then we can infer
|
||||
* the ZPOOL_CONFIG_PHYS_PATH from the by-vdev disk name.
|
||||
*/
|
||||
if (physpath == NULL && path != NULL) {
|
||||
/* If path begins with "/dev/disk/by-vdev/" ... */
|
||||
if (strncmp(path, DEV_BYVDEV_PATH,
|
||||
strlen(DEV_BYVDEV_PATH)) == 0) {
|
||||
/* Set physpath to the char after "/dev/disk/by-vdev" */
|
||||
physpath = &path[strlen(DEV_BYVDEV_PATH)];
|
||||
}
|
||||
}
|
||||
if (offline)
|
||||
return; /* don't intervene if it was taken offline */
|
||||
|
||||
/*
|
||||
* We don't want to autoreplace offlined disks. However, we do want to
|
||||
* replace force-faulted disks (`zpool offline -f`). Force-faulted
|
||||
* disks have both offline=1 and faulted=1 in the nvlist.
|
||||
*/
|
||||
if (offline && !faulted) {
|
||||
zed_log_msg(LOG_INFO, "%s: %s is offline, skip autoreplace",
|
||||
__func__, path);
|
||||
return;
|
||||
}
|
||||
|
||||
is_mpath_wholedisk = is_mpath_whole_disk(path);
|
||||
is_dm = zfs_dev_is_dm(path);
|
||||
zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s', phys '%s'"
|
||||
" %s blank disk, %s mpath blank disk, %s labeled, enc sysfs '%s', "
|
||||
"(guid %llu)",
|
||||
zpool_get_name(zhp), path,
|
||||
physpath ? physpath : "NULL",
|
||||
wholedisk ? "is" : "not",
|
||||
is_mpath_wholedisk? "is" : "not",
|
||||
labeled ? "is" : "not",
|
||||
enc_sysfs_path,
|
||||
" wholedisk %d, %s dm (guid %llu)", zpool_get_name(zhp), path,
|
||||
physpath ? physpath : "NULL", wholedisk, is_dm ? "is" : "not",
|
||||
(long long unsigned int)guid);
|
||||
|
||||
/*
|
||||
@@ -335,18 +246,15 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
}
|
||||
}
|
||||
|
||||
if (is_spare)
|
||||
online_flag |= ZFS_ONLINE_SPARE;
|
||||
|
||||
/*
|
||||
* Attempt to online the device.
|
||||
*/
|
||||
if (zpool_vdev_online(zhp, fullpath, online_flag, &newstate) == 0 &&
|
||||
if (zpool_vdev_online(zhp, fullpath,
|
||||
ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, &newstate) == 0 &&
|
||||
(newstate == VDEV_STATE_HEALTHY ||
|
||||
newstate == VDEV_STATE_DEGRADED)) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zpool_vdev_online: vdev '%s' ('%s') is "
|
||||
"%s", fullpath, physpath, (newstate == VDEV_STATE_HEALTHY) ?
|
||||
zed_log_msg(LOG_INFO, " zpool_vdev_online: vdev %s is %s",
|
||||
fullpath, (newstate == VDEV_STATE_HEALTHY) ?
|
||||
"HEALTHY" : "DEGRADED");
|
||||
return;
|
||||
}
|
||||
@@ -363,12 +271,11 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
* vdev online to trigger a FMA fault by posting an ereport.
|
||||
*/
|
||||
if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) ||
|
||||
!(wholedisk || is_mpath_wholedisk) || (physpath == NULL)) {
|
||||
!(wholedisk || is_dm) || (physpath == NULL)) {
|
||||
(void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
|
||||
&newstate);
|
||||
zed_log_msg(LOG_INFO, "Pool's autoreplace is not enabled or "
|
||||
"not a blank disk for '%s' ('%s')", fullpath,
|
||||
physpath);
|
||||
"not a whole disk for '%s'", fullpath);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -380,50 +287,29 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
(void) snprintf(rawpath, sizeof (rawpath), "%s%s",
|
||||
is_sd ? DEV_BYVDEV_PATH : DEV_BYPATH_PATH, physpath);
|
||||
|
||||
if (realpath(rawpath, pathbuf) == NULL && !is_mpath_wholedisk) {
|
||||
if (realpath(rawpath, devpath) == NULL && !is_dm) {
|
||||
zed_log_msg(LOG_INFO, " realpath: %s failed (%s)",
|
||||
rawpath, strerror(errno));
|
||||
|
||||
int err = zpool_vdev_online(zhp, fullpath,
|
||||
ZFS_ONLINE_FORCEFAULT, &newstate);
|
||||
(void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
|
||||
&newstate);
|
||||
|
||||
zed_log_msg(LOG_INFO, " zpool_vdev_online: %s FORCEFAULT (%s) "
|
||||
"err %d, new state %d",
|
||||
fullpath, libzfs_error_description(g_zfshdl), err,
|
||||
err ? (int)newstate : 0);
|
||||
zed_log_msg(LOG_INFO, " zpool_vdev_online: %s FORCEFAULT (%s)",
|
||||
fullpath, libzfs_error_description(g_zfshdl));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only autoreplace bad disks */
|
||||
if ((vs->vs_state != VDEV_STATE_DEGRADED) &&
|
||||
(vs->vs_state != VDEV_STATE_FAULTED) &&
|
||||
(vs->vs_state != VDEV_STATE_REMOVED) &&
|
||||
(vs->vs_state != VDEV_STATE_CANT_OPEN)) {
|
||||
zed_log_msg(LOG_INFO, " not autoreplacing since disk isn't in "
|
||||
"a bad state (currently %llu)", vs->vs_state);
|
||||
return;
|
||||
}
|
||||
|
||||
nvlist_lookup_string(vdev, "new_devid", &new_devid);
|
||||
|
||||
if (is_mpath_wholedisk) {
|
||||
if (is_dm) {
|
||||
/* Don't label device mapper or multipath disks. */
|
||||
zed_log_msg(LOG_INFO,
|
||||
" it's a multipath wholedisk, don't label");
|
||||
if (zpool_prepare_disk(zhp, vdev, "autoreplace", &lines,
|
||||
&lines_cnt) != 0) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zpool_prepare_disk: could not "
|
||||
"prepare '%s' (%s)", fullpath,
|
||||
libzfs_error_description(g_zfshdl));
|
||||
if (lines_cnt > 0) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zfs_prepare_disk output:");
|
||||
lines_to_zed_log_msg(lines, lines_cnt);
|
||||
}
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
return;
|
||||
}
|
||||
} else if (!labeled) {
|
||||
/*
|
||||
* we're auto-replacing a raw disk, so label it first
|
||||
@@ -440,24 +326,16 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
* to trigger a ZFS fault for the device (and any hot spare
|
||||
* replacement).
|
||||
*/
|
||||
leafname = strrchr(pathbuf, '/') + 1;
|
||||
leafname = strrchr(devpath, '/') + 1;
|
||||
|
||||
/*
|
||||
* If this is a request to label a whole disk, then attempt to
|
||||
* write out the label.
|
||||
*/
|
||||
if (zpool_prepare_and_label_disk(g_zfshdl, zhp, leafname,
|
||||
vdev, "autoreplace", &lines, &lines_cnt) != 0) {
|
||||
zed_log_msg(LOG_WARNING,
|
||||
" zpool_prepare_and_label_disk: could not "
|
||||
if (zpool_label_disk(g_zfshdl, zhp, leafname) != 0) {
|
||||
zed_log_msg(LOG_INFO, " zpool_label_disk: could not "
|
||||
"label '%s' (%s)", leafname,
|
||||
libzfs_error_description(g_zfshdl));
|
||||
if (lines_cnt > 0) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zfs_prepare_disk output:");
|
||||
lines_to_zed_log_msg(lines, lines_cnt);
|
||||
}
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
|
||||
(void) zpool_vdev_online(zhp, fullpath,
|
||||
ZFS_ONLINE_FORCEFAULT, &newstate);
|
||||
@@ -471,16 +349,11 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
* completed.
|
||||
*/
|
||||
device = malloc(sizeof (pendingdev_t));
|
||||
if (device == NULL) {
|
||||
perror("malloc");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
(void) strlcpy(device->pd_physpath, physpath,
|
||||
sizeof (device->pd_physpath));
|
||||
list_insert_tail(&g_device_list, device);
|
||||
|
||||
zed_log_msg(LOG_NOTICE, " zpool_label_disk: async '%s' (%llu)",
|
||||
zed_log_msg(LOG_INFO, " zpool_label_disk: async '%s' (%llu)",
|
||||
leafname, (u_longlong_t)guid);
|
||||
|
||||
return; /* resumes at EC_DEV_ADD.ESC_DISK for partition */
|
||||
@@ -503,8 +376,8 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
}
|
||||
if (!found) {
|
||||
/* unexpected partition slice encountered */
|
||||
zed_log_msg(LOG_WARNING, "labeled disk %s was "
|
||||
"unexpected here", fullpath);
|
||||
zed_log_msg(LOG_INFO, "labeled disk %s unexpected here",
|
||||
fullpath);
|
||||
(void) zpool_vdev_online(zhp, fullpath,
|
||||
ZFS_ONLINE_FORCEFAULT, &newstate);
|
||||
return;
|
||||
@@ -513,21 +386,10 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
zed_log_msg(LOG_INFO, " zpool_label_disk: resume '%s' (%llu)",
|
||||
physpath, (u_longlong_t)guid);
|
||||
|
||||
/*
|
||||
* Paths that begin with '/dev/disk/by-id/' will change and so
|
||||
* they must be updated before calling zpool_vdev_attach().
|
||||
*/
|
||||
if (strncmp(path, DEV_BYID_PATH, strlen(DEV_BYID_PATH)) == 0) {
|
||||
(void) snprintf(pathbuf, sizeof (pathbuf), "%s%s",
|
||||
DEV_BYID_PATH, new_devid);
|
||||
zed_log_msg(LOG_INFO, " zpool_label_disk: path '%s' "
|
||||
"replaced by '%s'", path, pathbuf);
|
||||
path = pathbuf;
|
||||
}
|
||||
(void) snprintf(devpath, sizeof (devpath), "%s%s",
|
||||
DEV_BYID_PATH, new_devid);
|
||||
}
|
||||
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
|
||||
/*
|
||||
* Construct the root vdev to pass to zpool_vdev_attach(). While adding
|
||||
* the entire vdev structure is harmless, we construct a reduced set of
|
||||
@@ -552,8 +414,8 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH, enc_sysfs_path) != 0) ||
|
||||
nvlist_add_uint64(newvd, ZPOOL_CONFIG_WHOLE_DISK, wholedisk) != 0 ||
|
||||
nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) != 0 ||
|
||||
nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
|
||||
(const nvlist_t **)&newvd, 1) != 0) {
|
||||
nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, &newvd,
|
||||
1) != 0) {
|
||||
zed_log_msg(LOG_WARNING, "zfs_mod: unable to add nvlist pairs");
|
||||
nvlist_free(newvd);
|
||||
nvlist_free(nvroot);
|
||||
@@ -566,26 +428,16 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
* Wait for udev to verify the links exist, then auto-replace
|
||||
* the leaf disk at same physical location.
|
||||
*/
|
||||
if (zpool_label_disk_wait(path, DISK_LABEL_WAIT) != 0) {
|
||||
zed_log_msg(LOG_WARNING, "zfs_mod: pool '%s', after labeling "
|
||||
"replacement disk, the expected disk partition link '%s' "
|
||||
"is missing after waiting %u ms",
|
||||
zpool_get_name(zhp), path, DISK_LABEL_WAIT);
|
||||
if (zpool_label_disk_wait(path, 3000) != 0) {
|
||||
zed_log_msg(LOG_WARNING, "zfs_mod: expected replacement "
|
||||
"disk %s is missing", path);
|
||||
nvlist_free(nvroot);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prefer sequential resilvering when supported (mirrors and dRAID),
|
||||
* otherwise fallback to a traditional healing resilver.
|
||||
*/
|
||||
ret = zpool_vdev_attach(zhp, fullpath, path, nvroot, B_TRUE, B_TRUE);
|
||||
if (ret != 0) {
|
||||
ret = zpool_vdev_attach(zhp, fullpath, path, nvroot,
|
||||
B_TRUE, B_FALSE);
|
||||
}
|
||||
ret = zpool_vdev_attach(zhp, fullpath, path, nvroot, B_TRUE, B_FALSE);
|
||||
|
||||
zed_log_msg(LOG_WARNING, " zpool_vdev_replace: %s with %s (%s)",
|
||||
zed_log_msg(LOG_INFO, " zpool_vdev_replace: %s with %s (%s)",
|
||||
fullpath, path, (ret == 0) ? "no errors" :
|
||||
libzfs_error_description(g_zfshdl));
|
||||
|
||||
@@ -603,20 +455,16 @@ typedef struct dev_data {
|
||||
boolean_t dd_islabeled;
|
||||
uint64_t dd_pool_guid;
|
||||
uint64_t dd_vdev_guid;
|
||||
uint64_t dd_new_vdev_guid;
|
||||
const char *dd_new_devid;
|
||||
uint64_t dd_num_spares;
|
||||
} dev_data_t;
|
||||
|
||||
static void
|
||||
zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
|
||||
{
|
||||
dev_data_t *dp = data;
|
||||
const char *path = NULL;
|
||||
char *path = NULL;
|
||||
uint_t c, children;
|
||||
nvlist_t **child;
|
||||
uint64_t guid = 0;
|
||||
uint64_t isspare = 0;
|
||||
|
||||
/*
|
||||
* First iterate over any children.
|
||||
@@ -642,16 +490,19 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
|
||||
}
|
||||
|
||||
/* once a vdev was matched and processed there is nothing left to do */
|
||||
if (dp->dd_found && dp->dd_num_spares == 0)
|
||||
if (dp->dd_found)
|
||||
return;
|
||||
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, &guid);
|
||||
|
||||
/*
|
||||
* Match by GUID if available otherwise fallback to devid or physical
|
||||
*/
|
||||
if (dp->dd_vdev_guid != 0) {
|
||||
if (guid != dp->dd_vdev_guid)
|
||||
uint64_t guid;
|
||||
|
||||
if (nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID,
|
||||
&guid) != 0 || guid != dp->dd_vdev_guid) {
|
||||
return;
|
||||
}
|
||||
zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched on %llu", guid);
|
||||
dp->dd_found = B_TRUE;
|
||||
|
||||
@@ -661,39 +512,22 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
|
||||
* illumos, substring matching is not required to accommodate
|
||||
* the partition suffix. An exact match will be present in
|
||||
* the dp->dd_compare value.
|
||||
* If the attached disk already contains a vdev GUID, it means
|
||||
* the disk is not clean. In such a scenario, the physical path
|
||||
* would be a match that makes the disk faulted when trying to
|
||||
* online it. So, we would only want to proceed if either GUID
|
||||
* matches with the last attached disk or the disk is in clean
|
||||
* state.
|
||||
*/
|
||||
if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 ||
|
||||
strcmp(dp->dd_compare, path) != 0) {
|
||||
strcmp(dp->dd_compare, path) != 0)
|
||||
return;
|
||||
}
|
||||
if (dp->dd_new_vdev_guid != 0 && dp->dd_new_vdev_guid != guid) {
|
||||
zed_log_msg(LOG_INFO, " %s: no match (GUID:%llu"
|
||||
" != vdev GUID:%llu)", __func__,
|
||||
dp->dd_new_vdev_guid, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched %s on %s",
|
||||
dp->dd_prop, path);
|
||||
dp->dd_found = B_TRUE;
|
||||
|
||||
/* pass the new devid for use by auto-replacing code */
|
||||
/* pass the new devid for use by replacing code */
|
||||
if (dp->dd_new_devid != NULL) {
|
||||
(void) nvlist_add_string(nvl, "new_devid",
|
||||
dp->dd_new_devid);
|
||||
}
|
||||
}
|
||||
|
||||
if (dp->dd_found == B_TRUE && nvlist_lookup_uint64(nvl,
|
||||
ZPOOL_CONFIG_IS_SPARE, &isspare) == 0 && isspare)
|
||||
dp->dd_num_spares++;
|
||||
|
||||
(dp->dd_func)(zhp, nvl, dp->dd_islabeled);
|
||||
}
|
||||
|
||||
@@ -729,8 +563,6 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
|
||||
ZPOOL_CONFIG_VDEV_TREE, &nvl);
|
||||
zfs_iter_vdev(zhp, nvl, data);
|
||||
}
|
||||
} else {
|
||||
zed_log_msg(LOG_INFO, "%s: no config\n", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -754,9 +586,7 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
|
||||
}
|
||||
|
||||
zpool_close(zhp);
|
||||
|
||||
/* cease iteration after a match */
|
||||
return (dp->dd_found && dp->dd_num_spares == 0);
|
||||
return (dp->dd_found); /* cease iteration after a match */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -765,7 +595,7 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
|
||||
*/
|
||||
static boolean_t
|
||||
devphys_iter(const char *physical, const char *devid, zfs_process_func_t func,
|
||||
boolean_t is_slice, uint64_t new_vdev_guid)
|
||||
boolean_t is_slice)
|
||||
{
|
||||
dev_data_t data = { 0 };
|
||||
|
||||
@@ -775,73 +605,6 @@ devphys_iter(const char *physical, const char *devid, zfs_process_func_t func,
|
||||
data.dd_found = B_FALSE;
|
||||
data.dd_islabeled = is_slice;
|
||||
data.dd_new_devid = devid; /* used by auto replace code */
|
||||
data.dd_new_vdev_guid = new_vdev_guid;
|
||||
|
||||
(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
|
||||
|
||||
return (data.dd_found);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a device identifier, find any vdevs with a matching by-vdev
|
||||
* path. Normally we shouldn't need this as the comparison would be
|
||||
* made earlier in the devphys_iter(). For example, if we were replacing
|
||||
* /dev/disk/by-vdev/L28, normally devphys_iter() would match the
|
||||
* ZPOOL_CONFIG_PHYS_PATH of "L28" from the old disk config to "L28"
|
||||
* of the new disk config. However, we've seen cases where
|
||||
* ZPOOL_CONFIG_PHYS_PATH was not in the config for the old disk. Here's
|
||||
* an example of a real 2-disk mirror pool where one disk was force
|
||||
* faulted:
|
||||
*
|
||||
* com.delphix:vdev_zap_top: 129
|
||||
* children[0]:
|
||||
* type: 'disk'
|
||||
* id: 0
|
||||
* guid: 14309659774640089719
|
||||
* path: '/dev/disk/by-vdev/L28'
|
||||
* whole_disk: 0
|
||||
* DTL: 654
|
||||
* create_txg: 4
|
||||
* com.delphix:vdev_zap_leaf: 1161
|
||||
* faulted: 1
|
||||
* aux_state: 'external'
|
||||
* children[1]:
|
||||
* type: 'disk'
|
||||
* id: 1
|
||||
* guid: 16002508084177980912
|
||||
* path: '/dev/disk/by-vdev/L29'
|
||||
* devid: 'dm-uuid-mpath-35000c500a61d68a3'
|
||||
* phys_path: 'L29'
|
||||
* vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32'
|
||||
* whole_disk: 0
|
||||
* DTL: 1028
|
||||
* create_txg: 4
|
||||
* com.delphix:vdev_zap_leaf: 131
|
||||
*
|
||||
* So in the case above, the only thing we could compare is the path.
|
||||
*
|
||||
* We can do this because we assume by-vdev paths are authoritative as physical
|
||||
* paths. We could not assume this for normal paths like /dev/sda since the
|
||||
* physical location /dev/sda points to could change over time.
|
||||
*/
|
||||
static boolean_t
|
||||
by_vdev_path_iter(const char *by_vdev_path, const char *devid,
|
||||
zfs_process_func_t func, boolean_t is_slice)
|
||||
{
|
||||
dev_data_t data = { 0 };
|
||||
|
||||
data.dd_compare = by_vdev_path;
|
||||
data.dd_func = func;
|
||||
data.dd_prop = ZPOOL_CONFIG_PATH;
|
||||
data.dd_found = B_FALSE;
|
||||
data.dd_islabeled = is_slice;
|
||||
data.dd_new_devid = devid;
|
||||
|
||||
if (strncmp(by_vdev_path, DEV_BYVDEV_PATH,
|
||||
strlen(DEV_BYVDEV_PATH)) != 0) {
|
||||
/* by_vdev_path doesn't start with "/dev/disk/by-vdev/" */
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
|
||||
|
||||
@@ -869,27 +632,6 @@ devid_iter(const char *devid, zfs_process_func_t func, boolean_t is_slice)
|
||||
return (data.dd_found);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a device guid, find any vdevs with a matching guid.
|
||||
*/
|
||||
static boolean_t
|
||||
guid_iter(uint64_t pool_guid, uint64_t vdev_guid, const char *devid,
|
||||
zfs_process_func_t func, boolean_t is_slice)
|
||||
{
|
||||
dev_data_t data = { 0 };
|
||||
|
||||
data.dd_func = func;
|
||||
data.dd_found = B_FALSE;
|
||||
data.dd_pool_guid = pool_guid;
|
||||
data.dd_vdev_guid = vdev_guid;
|
||||
data.dd_islabeled = is_slice;
|
||||
data.dd_new_devid = devid;
|
||||
|
||||
(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
|
||||
|
||||
return (data.dd_found);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a EC_DEV_ADD.ESC_DISK event.
|
||||
*
|
||||
@@ -910,23 +652,18 @@ guid_iter(uint64_t pool_guid, uint64_t vdev_guid, const char *devid,
|
||||
* phys_path: 'pci-0000:04:00.0-sas-0x4433221106000000-lun-0'
|
||||
*/
|
||||
static int
|
||||
zfs_deliver_add(nvlist_t *nvl)
|
||||
zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi)
|
||||
{
|
||||
const char *devpath = NULL, *devid = NULL;
|
||||
uint64_t pool_guid = 0, vdev_guid = 0;
|
||||
char *devpath = NULL, *devid;
|
||||
boolean_t is_slice;
|
||||
|
||||
/*
|
||||
* Expecting a devid string and an optional physical location and guid
|
||||
* Expecting a devid string and an optional physical location
|
||||
*/
|
||||
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0) {
|
||||
zed_log_msg(LOG_INFO, "%s: no dev identifier\n", __func__);
|
||||
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
(void) nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devpath);
|
||||
(void) nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &pool_guid);
|
||||
(void) nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &vdev_guid);
|
||||
|
||||
is_slice = (nvlist_lookup_boolean(nvl, DEV_IS_PART) == 0);
|
||||
|
||||
@@ -937,28 +674,12 @@ zfs_deliver_add(nvlist_t *nvl)
|
||||
* Iterate over all vdevs looking for a match in the following order:
|
||||
* 1. ZPOOL_CONFIG_DEVID (identifies the unique disk)
|
||||
* 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location).
|
||||
* 3. ZPOOL_CONFIG_GUID (identifies unique vdev).
|
||||
* 4. ZPOOL_CONFIG_PATH for /dev/disk/by-vdev devices only (since
|
||||
* by-vdev paths represent physical paths).
|
||||
*
|
||||
* For disks, we only want to pay attention to vdevs marked as whole
|
||||
* disks or are a multipath device.
|
||||
*/
|
||||
if (devid_iter(devid, zfs_process_add, is_slice))
|
||||
return (0);
|
||||
if (devpath != NULL && devphys_iter(devpath, devid, zfs_process_add,
|
||||
is_slice, vdev_guid))
|
||||
return (0);
|
||||
if (vdev_guid != 0)
|
||||
(void) guid_iter(pool_guid, vdev_guid, devid, zfs_process_add,
|
||||
is_slice);
|
||||
|
||||
if (devpath != NULL) {
|
||||
/* Can we match a /dev/disk/by-vdev/ path? */
|
||||
char by_vdev_path[MAXPATHLEN];
|
||||
snprintf(by_vdev_path, sizeof (by_vdev_path),
|
||||
"/dev/disk/by-vdev/%s", devpath);
|
||||
if (by_vdev_path_iter(by_vdev_path, devid, zfs_process_add,
|
||||
is_slice))
|
||||
return (0);
|
||||
}
|
||||
if (!devid_iter(devid, zfs_process_add, is_slice) && devpath != NULL)
|
||||
(void) devphys_iter(devpath, devid, zfs_process_add, is_slice);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -990,98 +711,21 @@ zfs_deliver_check(nvlist_t *nvl)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a path to a vdev, lookup the vdev's physical size from its
|
||||
* config nvlist.
|
||||
*
|
||||
* Returns the vdev's physical size in bytes on success, 0 on error.
|
||||
*/
|
||||
static uint64_t
|
||||
vdev_size_from_config(zpool_handle_t *zhp, const char *vdev_path)
|
||||
{
|
||||
nvlist_t *nvl = NULL;
|
||||
boolean_t avail_spare, l2cache, log;
|
||||
vdev_stat_t *vs = NULL;
|
||||
uint_t c;
|
||||
|
||||
nvl = zpool_find_vdev(zhp, vdev_path, &avail_spare, &l2cache, &log);
|
||||
if (!nvl)
|
||||
return (0);
|
||||
|
||||
verify(nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
|
||||
(uint64_t **)&vs, &c) == 0);
|
||||
if (!vs) {
|
||||
zed_log_msg(LOG_INFO, "%s: no nvlist for '%s'", __func__,
|
||||
vdev_path);
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (vs->vs_pspace);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a path to a vdev, lookup if the vdev is a "whole disk" in the
|
||||
* config nvlist. "whole disk" means that ZFS was passed a whole disk
|
||||
* at pool creation time, which it partitioned up and has full control over.
|
||||
* Thus a partition with wholedisk=1 set tells us that zfs created the
|
||||
* partition at creation time. A partition without whole disk set would have
|
||||
* been created by externally (like with fdisk) and passed to ZFS.
|
||||
*
|
||||
* Returns the whole disk value (either 0 or 1).
|
||||
*/
|
||||
static uint64_t
|
||||
vdev_whole_disk_from_config(zpool_handle_t *zhp, const char *vdev_path)
|
||||
{
|
||||
nvlist_t *nvl = NULL;
|
||||
boolean_t avail_spare, l2cache, log;
|
||||
uint64_t wholedisk = 0;
|
||||
|
||||
nvl = zpool_find_vdev(zhp, vdev_path, &avail_spare, &l2cache, &log);
|
||||
if (!nvl)
|
||||
return (0);
|
||||
|
||||
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
|
||||
|
||||
return (wholedisk);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the device size grew more than 1% then return true.
|
||||
*/
|
||||
#define DEVICE_GREW(oldsize, newsize) \
|
||||
((newsize > oldsize) && \
|
||||
((newsize / (newsize - oldsize)) <= 100))
|
||||
|
||||
static int
|
||||
zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
|
||||
{
|
||||
char *devname = data;
|
||||
boolean_t avail_spare, l2cache;
|
||||
nvlist_t *udev_nvl = data;
|
||||
nvlist_t *tgt;
|
||||
int error;
|
||||
|
||||
const char *tmp_devname;
|
||||
char devname[MAXPATHLEN] = "";
|
||||
uint64_t guid;
|
||||
|
||||
if (nvlist_lookup_uint64(udev_nvl, ZFS_EV_VDEV_GUID, &guid) == 0) {
|
||||
sprintf(devname, "%llu", (u_longlong_t)guid);
|
||||
} else if (nvlist_lookup_string(udev_nvl, DEV_PHYS_PATH,
|
||||
&tmp_devname) == 0) {
|
||||
strlcpy(devname, tmp_devname, MAXPATHLEN);
|
||||
zfs_append_partition(devname, MAXPATHLEN);
|
||||
} else {
|
||||
zed_log_msg(LOG_INFO, "%s: no guid or physpath", __func__);
|
||||
}
|
||||
|
||||
zed_log_msg(LOG_INFO, "zfsdle_vdev_online: searching for '%s' in '%s'",
|
||||
devname, zpool_get_name(zhp));
|
||||
|
||||
if ((tgt = zpool_find_vdev_by_physpath(zhp, devname,
|
||||
&avail_spare, &l2cache, NULL)) != NULL) {
|
||||
const char *path;
|
||||
char fullpath[MAXPATHLEN];
|
||||
uint64_t wholedisk = 0;
|
||||
char *path, fullpath[MAXPATHLEN];
|
||||
uint64_t wholedisk;
|
||||
|
||||
error = nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &path);
|
||||
if (error) {
|
||||
@@ -1089,15 +733,16 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
|
||||
return (0);
|
||||
}
|
||||
|
||||
(void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
|
||||
error = nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
|
||||
&wholedisk);
|
||||
if (error)
|
||||
wholedisk = 0;
|
||||
|
||||
if (wholedisk) {
|
||||
char *tmp;
|
||||
path = strrchr(path, '/');
|
||||
if (path != NULL) {
|
||||
tmp = zfs_strip_partition(path + 1);
|
||||
if (tmp == NULL) {
|
||||
path = zfs_strip_partition(path + 1);
|
||||
if (path == NULL) {
|
||||
zpool_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
@@ -1106,8 +751,8 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
|
||||
return (0);
|
||||
}
|
||||
|
||||
(void) strlcpy(fullpath, tmp, sizeof (fullpath));
|
||||
free(tmp);
|
||||
(void) strlcpy(fullpath, path, sizeof (fullpath));
|
||||
free(path);
|
||||
|
||||
/*
|
||||
* We need to reopen the pool associated with this
|
||||
@@ -1125,75 +770,12 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
|
||||
vdev_state_t newstate;
|
||||
|
||||
if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL) {
|
||||
/*
|
||||
* If this disk size has not changed, then
|
||||
* there's no need to do an autoexpand. To
|
||||
* check we look at the disk's size in its
|
||||
* config, and compare it to the disk size
|
||||
* that udev is reporting.
|
||||
*/
|
||||
uint64_t udev_size = 0, conf_size = 0,
|
||||
wholedisk = 0, udev_parent_size = 0;
|
||||
|
||||
/*
|
||||
* Get the size of our disk that udev is
|
||||
* reporting.
|
||||
*/
|
||||
if (nvlist_lookup_uint64(udev_nvl, DEV_SIZE,
|
||||
&udev_size) != 0) {
|
||||
udev_size = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the size of our disk's parent device
|
||||
* from udev (where sda1's parent is sda).
|
||||
*/
|
||||
if (nvlist_lookup_uint64(udev_nvl,
|
||||
DEV_PARENT_SIZE, &udev_parent_size) != 0) {
|
||||
udev_parent_size = 0;
|
||||
}
|
||||
|
||||
conf_size = vdev_size_from_config(zhp,
|
||||
fullpath);
|
||||
|
||||
wholedisk = vdev_whole_disk_from_config(zhp,
|
||||
fullpath);
|
||||
|
||||
/*
|
||||
* Only attempt an autoexpand if the vdev size
|
||||
* changed. There are two different cases
|
||||
* to consider.
|
||||
*
|
||||
* 1. wholedisk=1
|
||||
* If you do a 'zpool create' on a whole disk
|
||||
* (like /dev/sda), then zfs will create
|
||||
* partitions on the disk (like /dev/sda1). In
|
||||
* that case, wholedisk=1 will be set in the
|
||||
* partition's nvlist config. So zed will need
|
||||
* to see if your parent device (/dev/sda)
|
||||
* expanded in size, and if so, then attempt
|
||||
* the autoexpand.
|
||||
*
|
||||
* 2. wholedisk=0
|
||||
* If you do a 'zpool create' on an existing
|
||||
* partition, or a device that doesn't allow
|
||||
* partitions, then wholedisk=0, and you will
|
||||
* simply need to check if the device itself
|
||||
* expanded in size.
|
||||
*/
|
||||
if (DEVICE_GREW(conf_size, udev_size) ||
|
||||
(wholedisk && DEVICE_GREW(conf_size,
|
||||
udev_parent_size))) {
|
||||
error = zpool_vdev_online(zhp, fullpath,
|
||||
0, &newstate);
|
||||
|
||||
zed_log_msg(LOG_INFO,
|
||||
"%s: autoexpanding '%s' from %llu"
|
||||
" to %llu bytes in pool '%s': %d",
|
||||
__func__, fullpath, conf_size,
|
||||
MAX(udev_size, udev_parent_size),
|
||||
zpool_get_name(zhp), error);
|
||||
}
|
||||
error = zpool_vdev_online(zhp, fullpath, 0,
|
||||
&newstate);
|
||||
zed_log_msg(LOG_INFO, "zfsdle_vdev_online: "
|
||||
"setting device '%s' to ONLINE state "
|
||||
"in pool '%s': %d", fullpath,
|
||||
zpool_get_name(zhp), error);
|
||||
}
|
||||
}
|
||||
zpool_close(zhp);
|
||||
@@ -1212,8 +794,7 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
|
||||
static int
|
||||
zfs_deliver_dle(nvlist_t *nvl)
|
||||
{
|
||||
const char *devname;
|
||||
char name[MAXPATHLEN];
|
||||
char *devname, name[MAXPATHLEN];
|
||||
uint64_t guid;
|
||||
|
||||
if (nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &guid) == 0) {
|
||||
@@ -1222,11 +803,10 @@ zfs_deliver_dle(nvlist_t *nvl)
|
||||
strlcpy(name, devname, MAXPATHLEN);
|
||||
zfs_append_partition(name, MAXPATHLEN);
|
||||
} else {
|
||||
sprintf(name, "unknown");
|
||||
zed_log_msg(LOG_INFO, "zfs_deliver_dle: no guid or physpath");
|
||||
}
|
||||
|
||||
if (zpool_iter(g_zfshdl, zfsdle_vdev_online, nvl) != 1) {
|
||||
if (zpool_iter(g_zfshdl, zfsdle_vdev_online, name) != 1) {
|
||||
zed_log_msg(LOG_INFO, "zfs_deliver_dle: device '%s' not "
|
||||
"found", name);
|
||||
return (1);
|
||||
@@ -1250,15 +830,18 @@ static int
|
||||
zfs_slm_deliver_event(const char *class, const char *subclass, nvlist_t *nvl)
|
||||
{
|
||||
int ret;
|
||||
boolean_t is_check = B_FALSE, is_dle = B_FALSE;
|
||||
boolean_t is_lofi = B_FALSE, is_check = B_FALSE, is_dle = B_FALSE;
|
||||
|
||||
if (strcmp(class, EC_DEV_ADD) == 0) {
|
||||
/*
|
||||
* We're mainly interested in disk additions, but we also listen
|
||||
* for new loop devices, to allow for simplified testing.
|
||||
*/
|
||||
if (strcmp(subclass, ESC_DISK) != 0 &&
|
||||
strcmp(subclass, ESC_LOFI) != 0)
|
||||
if (strcmp(subclass, ESC_DISK) == 0)
|
||||
is_lofi = B_FALSE;
|
||||
else if (strcmp(subclass, ESC_LOFI) == 0)
|
||||
is_lofi = B_TRUE;
|
||||
else
|
||||
return (0);
|
||||
|
||||
is_check = B_FALSE;
|
||||
@@ -1282,16 +865,15 @@ zfs_slm_deliver_event(const char *class, const char *subclass, nvlist_t *nvl)
|
||||
else if (is_check)
|
||||
ret = zfs_deliver_check(nvl);
|
||||
else
|
||||
ret = zfs_deliver_add(nvl);
|
||||
ret = zfs_deliver_add(nvl, is_lofi);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void *
|
||||
zfs_enum_pools(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
(void) zpool_iter(g_zfshdl, zfs_unavail_pool, (void *)&g_pool_list);
|
||||
/*
|
||||
* Linux - instead of using a thread pool, each list entry
|
||||
@@ -1310,7 +892,7 @@ zfs_enum_pools(void *arg)
|
||||
* For now, each agent has its own libzfs instance
|
||||
*/
|
||||
int
|
||||
zfs_slm_init(void)
|
||||
zfs_slm_init()
|
||||
{
|
||||
if ((g_zfshdl = libzfs_init()) == NULL)
|
||||
return (-1);
|
||||
@@ -1328,7 +910,6 @@ zfs_slm_init(void)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
pthread_setname_np(g_zfs_tid, "enum-pools");
|
||||
list_create(&g_device_list, sizeof (struct pendingdev),
|
||||
offsetof(struct pendingdev, pd_node));
|
||||
|
||||
@@ -1336,7 +917,7 @@ zfs_slm_init(void)
|
||||
}
|
||||
|
||||
void
|
||||
zfs_slm_fini(void)
|
||||
zfs_slm_fini()
|
||||
{
|
||||
unavailpool_t *pool;
|
||||
pendingdev_t *device;
|
||||
@@ -1349,14 +930,17 @@ zfs_slm_fini(void)
|
||||
tpool_destroy(g_tpool);
|
||||
}
|
||||
|
||||
while ((pool = list_remove_head(&g_pool_list)) != NULL) {
|
||||
while ((pool = (list_head(&g_pool_list))) != NULL) {
|
||||
list_remove(&g_pool_list, pool);
|
||||
zpool_close(pool->uap_zhp);
|
||||
free(pool);
|
||||
}
|
||||
list_destroy(&g_pool_list);
|
||||
|
||||
while ((device = list_remove_head(&g_device_list)) != NULL)
|
||||
while ((device = (list_head(&g_device_list))) != NULL) {
|
||||
list_remove(&g_device_list, device);
|
||||
free(device);
|
||||
}
|
||||
list_destroy(&g_device_list);
|
||||
|
||||
libzfs_fini(g_zfshdl);
|
||||
|
||||
+22
-136
@@ -6,7 +6,7 @@
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or https://opensource.org/licenses/CDDL-1.0.
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
@@ -38,10 +38,8 @@
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/fm/protocol.h>
|
||||
#include <sys/fm/fs/zfs.h>
|
||||
#include <libzutil.h>
|
||||
#include <libzfs.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "zfs_agents.h"
|
||||
#include "fmd_api.h"
|
||||
@@ -76,8 +74,6 @@ typedef struct find_cbdata {
|
||||
uint64_t cb_guid;
|
||||
zpool_handle_t *cb_zhp;
|
||||
nvlist_t *cb_vdev;
|
||||
uint64_t cb_vdev_guid;
|
||||
uint64_t cb_num_spares;
|
||||
} find_cbdata_t;
|
||||
|
||||
static int
|
||||
@@ -143,64 +139,6 @@ find_vdev(libzfs_handle_t *zhdl, nvlist_t *nv, uint64_t search_guid)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
remove_spares(zpool_handle_t *zhp, void *data)
|
||||
{
|
||||
nvlist_t *config, *nvroot;
|
||||
nvlist_t **spares;
|
||||
uint_t nspares;
|
||||
char *devname;
|
||||
find_cbdata_t *cbp = data;
|
||||
uint64_t spareguid = 0;
|
||||
vdev_stat_t *vs;
|
||||
unsigned int c;
|
||||
|
||||
config = zpool_get_config(zhp, NULL);
|
||||
if (nvlist_lookup_nvlist(config,
|
||||
ZPOOL_CONFIG_VDEV_TREE, &nvroot) != 0) {
|
||||
zpool_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
|
||||
&spares, &nspares) != 0) {
|
||||
zpool_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nspares; i++) {
|
||||
if (nvlist_lookup_uint64(spares[i], ZPOOL_CONFIG_GUID,
|
||||
&spareguid) == 0 && spareguid == cbp->cb_vdev_guid) {
|
||||
devname = zpool_vdev_name(NULL, zhp, spares[i],
|
||||
B_FALSE);
|
||||
nvlist_lookup_uint64_array(spares[i],
|
||||
ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &c);
|
||||
if (vs->vs_state != VDEV_STATE_REMOVED &&
|
||||
zpool_vdev_remove_wanted(zhp, devname) == 0)
|
||||
cbp->cb_num_spares++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
zpool_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a vdev guid, find and remove all spares associated with it.
|
||||
*/
|
||||
static int
|
||||
find_and_remove_spares(libzfs_handle_t *zhdl, uint64_t vdev_guid)
|
||||
{
|
||||
find_cbdata_t cb;
|
||||
|
||||
cb.cb_num_spares = 0;
|
||||
cb.cb_vdev_guid = vdev_guid;
|
||||
zpool_iter(zhdl, remove_spares, &cb);
|
||||
|
||||
return (cb.cb_num_spares);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a (pool, vdev) GUID pair, find the matching pool and vdev.
|
||||
*/
|
||||
@@ -281,31 +219,25 @@ replace_with_spare(fmd_hdl_t *hdl, zpool_handle_t *zhp, nvlist_t *vdev)
|
||||
* replace it.
|
||||
*/
|
||||
for (s = 0; s < nspares; s++) {
|
||||
boolean_t rebuild = B_FALSE;
|
||||
const char *spare_name, *type;
|
||||
char *spare_name;
|
||||
|
||||
if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
|
||||
&spare_name) != 0)
|
||||
continue;
|
||||
|
||||
/* prefer sequential resilvering for distributed spares */
|
||||
if ((nvlist_lookup_string(spares[s], ZPOOL_CONFIG_TYPE,
|
||||
&type) == 0) && strcmp(type, VDEV_TYPE_DRAID_SPARE) == 0)
|
||||
rebuild = B_TRUE;
|
||||
|
||||
/* if set, add the "ashift" pool property to the spare nvlist */
|
||||
if (source != ZPROP_SRC_DEFAULT)
|
||||
(void) nvlist_add_uint64(spares[s],
|
||||
ZPOOL_CONFIG_ASHIFT, ashift);
|
||||
|
||||
(void) nvlist_add_nvlist_array(replacement,
|
||||
ZPOOL_CONFIG_CHILDREN, (const nvlist_t **)&spares[s], 1);
|
||||
ZPOOL_CONFIG_CHILDREN, &spares[s], 1);
|
||||
|
||||
fmd_hdl_debug(hdl, "zpool_vdev_replace '%s' with spare '%s'",
|
||||
dev_name, zfs_basename(spare_name));
|
||||
dev_name, basename(spare_name));
|
||||
|
||||
if (zpool_vdev_attach(zhp, dev_name, spare_name,
|
||||
replacement, B_TRUE, rebuild) == 0) {
|
||||
replacement, B_TRUE, B_FALSE) == 0) {
|
||||
free(dev_name);
|
||||
nvlist_free(replacement);
|
||||
return (B_TRUE);
|
||||
@@ -323,6 +255,7 @@ replace_with_spare(fmd_hdl_t *hdl, zpool_handle_t *zhp, nvlist_t *vdev)
|
||||
* ASRU is now usable. ZFS has found the device to be present and
|
||||
* functioning.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
zfs_vdev_repair(fmd_hdl_t *hdl, nvlist_t *nvl)
|
||||
{
|
||||
@@ -361,11 +294,11 @@ zfs_vdev_repair(fmd_hdl_t *hdl, nvlist_t *nvl)
|
||||
vdev_guid, pool_guid);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
||||
const char *class)
|
||||
{
|
||||
(void) ep;
|
||||
uint64_t pool_guid, vdev_guid;
|
||||
zpool_handle_t *zhp;
|
||||
nvlist_t *resource, *fault;
|
||||
@@ -375,23 +308,18 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
||||
libzfs_handle_t *zhdl = zdp->zrd_hdl;
|
||||
boolean_t fault_device, degrade_device;
|
||||
boolean_t is_repair;
|
||||
boolean_t l2arc = B_FALSE;
|
||||
boolean_t spare = B_FALSE;
|
||||
const char *scheme;
|
||||
char *scheme;
|
||||
nvlist_t *vdev = NULL;
|
||||
const char *uuid;
|
||||
char *uuid;
|
||||
int repair_done = 0;
|
||||
boolean_t retire;
|
||||
boolean_t is_disk;
|
||||
vdev_aux_t aux;
|
||||
uint64_t state = 0;
|
||||
vdev_stat_t *vs;
|
||||
unsigned int c;
|
||||
|
||||
fmd_hdl_debug(hdl, "zfs_retire_recv: '%s'", class);
|
||||
|
||||
(void) nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE,
|
||||
&state);
|
||||
nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE, &state);
|
||||
|
||||
/*
|
||||
* If this is a resource notifying us of device removal then simply
|
||||
@@ -400,35 +328,14 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
||||
*/
|
||||
if (strcmp(class, "resource.fs.zfs.removed") == 0 ||
|
||||
(strcmp(class, "resource.fs.zfs.statechange") == 0 &&
|
||||
(state == VDEV_STATE_REMOVED || state == VDEV_STATE_FAULTED))) {
|
||||
const char *devtype;
|
||||
state == VDEV_STATE_REMOVED)) {
|
||||
char *devtype;
|
||||
char *devname;
|
||||
|
||||
if (nvlist_lookup_string(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE,
|
||||
&devtype) == 0) {
|
||||
if (strcmp(devtype, VDEV_TYPE_SPARE) == 0)
|
||||
spare = B_TRUE;
|
||||
else if (strcmp(devtype, VDEV_TYPE_L2CACHE) == 0)
|
||||
l2arc = B_TRUE;
|
||||
}
|
||||
|
||||
if (nvlist_lookup_uint64(nvl,
|
||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, &vdev_guid) != 0)
|
||||
return;
|
||||
|
||||
if (vdev_guid == 0) {
|
||||
fmd_hdl_debug(hdl, "Got a zero GUID");
|
||||
return;
|
||||
}
|
||||
|
||||
if (spare) {
|
||||
int nspares = find_and_remove_spares(zhdl, vdev_guid);
|
||||
fmd_hdl_debug(hdl, "%d spares removed", nspares);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_POOL_GUID,
|
||||
&pool_guid) != 0)
|
||||
&pool_guid) != 0 ||
|
||||
nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID,
|
||||
&vdev_guid) != 0)
|
||||
return;
|
||||
|
||||
if ((zhp = find_by_guid(zhdl, pool_guid, vdev_guid,
|
||||
@@ -437,30 +344,13 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
||||
|
||||
devname = zpool_vdev_name(NULL, zhp, vdev, B_FALSE);
|
||||
|
||||
nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
|
||||
(uint64_t **)&vs, &c);
|
||||
|
||||
/*
|
||||
* If state removed is requested for already removed vdev,
|
||||
* its a loopback event from spa_async_remove(). Just
|
||||
* ignore it.
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_REMOVED &&
|
||||
state == VDEV_STATE_REMOVED)
|
||||
return;
|
||||
|
||||
/* Remove the vdev since device is unplugged */
|
||||
int remove_status = 0;
|
||||
if (l2arc || (strcmp(class, "resource.fs.zfs.removed") == 0)) {
|
||||
remove_status = zpool_vdev_remove_wanted(zhp, devname);
|
||||
fmd_hdl_debug(hdl, "zpool_vdev_remove_wanted '%s'"
|
||||
", err:%d", devname, libzfs_errno(zhdl));
|
||||
}
|
||||
|
||||
/* Replace the vdev with a spare if its not a l2arc */
|
||||
if (!l2arc && !remove_status &&
|
||||
(!fmd_prop_get_int32(hdl, "spare_on_remove") ||
|
||||
replace_with_spare(hdl, zhp, vdev) == B_FALSE)) {
|
||||
/* Can't replace l2arc with a spare: offline the device */
|
||||
if (nvlist_lookup_string(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE,
|
||||
&devtype) == 0 && strcmp(devtype, VDEV_TYPE_L2CACHE) == 0) {
|
||||
fmd_hdl_debug(hdl, "zpool_vdev_offline '%s'", devname);
|
||||
zpool_vdev_offline(zhp, devname, B_TRUE);
|
||||
} else if (!fmd_prop_get_int32(hdl, "spare_on_remove") ||
|
||||
replace_with_spare(hdl, zhp, vdev) == B_FALSE) {
|
||||
/* Could not handle with spare */
|
||||
fmd_hdl_debug(hdl, "no spare for '%s'", devname);
|
||||
}
|
||||
@@ -523,9 +413,6 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
||||
} else if (fmd_nvl_class_match(hdl, fault,
|
||||
"fault.fs.zfs.vdev.checksum")) {
|
||||
degrade_device = B_TRUE;
|
||||
} else if (fmd_nvl_class_match(hdl, fault,
|
||||
"fault.fs.zfs.vdev.slow_io")) {
|
||||
degrade_device = B_TRUE;
|
||||
} else if (fmd_nvl_class_match(hdl, fault,
|
||||
"fault.fs.zfs.device")) {
|
||||
fault_device = B_FALSE;
|
||||
@@ -612,7 +499,6 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
||||
* Attempt to substitute a hot spare.
|
||||
*/
|
||||
(void) replace_with_spare(hdl, zhp, vdev);
|
||||
|
||||
zpool_close(zhp);
|
||||
}
|
||||
|
||||
|
||||
+24
-28
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
||||
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||
@@ -36,7 +36,6 @@ static volatile sig_atomic_t _got_hup = 0;
|
||||
static void
|
||||
_exit_handler(int signum)
|
||||
{
|
||||
(void) signum;
|
||||
_got_exit = 1;
|
||||
}
|
||||
|
||||
@@ -46,7 +45,6 @@ _exit_handler(int signum)
|
||||
static void
|
||||
_hup_handler(int signum)
|
||||
{
|
||||
(void) signum;
|
||||
_got_hup = 1;
|
||||
}
|
||||
|
||||
@@ -62,8 +60,8 @@ _setup_sig_handlers(void)
|
||||
zed_log_die("Failed to initialize sigset");
|
||||
|
||||
sa.sa_flags = SA_RESTART;
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
|
||||
if (sigaction(SIGPIPE, &sa, NULL) < 0)
|
||||
zed_log_die("Failed to ignore SIGPIPE");
|
||||
|
||||
@@ -77,10 +75,6 @@ _setup_sig_handlers(void)
|
||||
sa.sa_handler = _hup_handler;
|
||||
if (sigaction(SIGHUP, &sa, NULL) < 0)
|
||||
zed_log_die("Failed to register SIGHUP handler");
|
||||
|
||||
(void) sigaddset(&sa.sa_mask, SIGCHLD);
|
||||
if (pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL) < 0)
|
||||
zed_log_die("Failed to block SIGCHLD");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -218,20 +212,22 @@ _finish_daemonize(void)
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct zed_conf zcp;
|
||||
struct zed_conf *zcp;
|
||||
uint64_t saved_eid;
|
||||
int64_t saved_etime[2];
|
||||
|
||||
zed_log_init(argv[0]);
|
||||
zed_log_stderr_open(LOG_NOTICE);
|
||||
zed_conf_init(&zcp);
|
||||
zed_conf_parse_opts(&zcp, argc, argv);
|
||||
if (zcp.do_verbose)
|
||||
zcp = zed_conf_create();
|
||||
zed_conf_parse_opts(zcp, argc, argv);
|
||||
if (zcp->do_verbose)
|
||||
zed_log_stderr_open(LOG_INFO);
|
||||
|
||||
if (geteuid() != 0)
|
||||
zed_log_die("Must be run as root");
|
||||
|
||||
zed_conf_parse_file(zcp);
|
||||
|
||||
zed_file_close_from(STDERR_FILENO + 1);
|
||||
|
||||
(void) umask(0);
|
||||
@@ -239,32 +235,32 @@ main(int argc, char *argv[])
|
||||
if (chdir("/") < 0)
|
||||
zed_log_die("Failed to change to root directory");
|
||||
|
||||
if (zed_conf_scan_dir(&zcp) < 0)
|
||||
if (zed_conf_scan_dir(zcp) < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (!zcp.do_foreground) {
|
||||
if (!zcp->do_foreground) {
|
||||
_start_daemonize();
|
||||
zed_log_syslog_open(LOG_DAEMON);
|
||||
}
|
||||
_setup_sig_handlers();
|
||||
|
||||
if (zcp.do_memlock)
|
||||
if (zcp->do_memlock)
|
||||
_lock_memory();
|
||||
|
||||
if ((zed_conf_write_pid(&zcp) < 0) && (!zcp.do_force))
|
||||
if ((zed_conf_write_pid(zcp) < 0) && (!zcp->do_force))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (!zcp.do_foreground)
|
||||
if (!zcp->do_foreground)
|
||||
_finish_daemonize();
|
||||
|
||||
zed_log_msg(LOG_NOTICE,
|
||||
"ZFS Event Daemon %s-%s (PID %d)",
|
||||
ZFS_META_VERSION, ZFS_META_RELEASE, (int)getpid());
|
||||
|
||||
if (zed_conf_open_state(&zcp) < 0)
|
||||
if (zed_conf_open_state(zcp) < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (zed_conf_read_state(&zcp, &saved_eid, saved_etime) < 0)
|
||||
if (zed_conf_read_state(zcp, &saved_eid, saved_etime) < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
idle:
|
||||
@@ -273,38 +269,38 @@ idle:
|
||||
* successful.
|
||||
*/
|
||||
do {
|
||||
if (!zed_event_init(&zcp))
|
||||
if (!zed_event_init(zcp))
|
||||
break;
|
||||
/* Wait for some time and try again. tunable? */
|
||||
sleep(30);
|
||||
} while (!_got_exit && zcp.do_idle);
|
||||
} while (!_got_exit && zcp->do_idle);
|
||||
|
||||
if (_got_exit)
|
||||
goto out;
|
||||
|
||||
zed_event_seek(&zcp, saved_eid, saved_etime);
|
||||
zed_event_seek(zcp, saved_eid, saved_etime);
|
||||
|
||||
while (!_got_exit) {
|
||||
int rv;
|
||||
if (_got_hup) {
|
||||
_got_hup = 0;
|
||||
(void) zed_conf_scan_dir(&zcp);
|
||||
(void) zed_conf_scan_dir(zcp);
|
||||
}
|
||||
rv = zed_event_service(&zcp);
|
||||
rv = zed_event_service(zcp);
|
||||
|
||||
/* ENODEV: When kernel module is unloaded (osx) */
|
||||
if (rv != 0)
|
||||
if (rv == ENODEV)
|
||||
break;
|
||||
}
|
||||
|
||||
zed_log_msg(LOG_NOTICE, "Exiting");
|
||||
zed_event_fini(&zcp);
|
||||
zed_event_fini(zcp);
|
||||
|
||||
if (zcp.do_idle && !_got_exit)
|
||||
if (zcp->do_idle && !_got_exit)
|
||||
goto idle;
|
||||
|
||||
out:
|
||||
zed_conf_destroy(&zcp);
|
||||
zed_conf_destroy(zcp);
|
||||
zed_log_fini();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
+31
-37
@@ -1,59 +1,53 @@
|
||||
include $(top_srcdir)/config/Rules.am
|
||||
include $(top_srcdir)/config/Substfiles.am
|
||||
|
||||
EXTRA_DIST += README
|
||||
|
||||
zedconfdir = $(sysconfdir)/zfs/zed.d
|
||||
|
||||
dist_zedconf_DATA = \
|
||||
%D%/zed-functions.sh \
|
||||
%D%/zed.rc
|
||||
zed-functions.sh \
|
||||
zed.rc
|
||||
|
||||
zedexecdir = $(zfsexecdir)/zed.d
|
||||
|
||||
dist_zedexec_SCRIPTS = \
|
||||
%D%/all-debug.sh \
|
||||
%D%/all-syslog.sh \
|
||||
%D%/data-notify.sh \
|
||||
%D%/deadman-slot_off.sh \
|
||||
%D%/generic-notify.sh \
|
||||
%D%/pool_import-led.sh \
|
||||
%D%/resilver_finish-notify.sh \
|
||||
%D%/resilver_finish-start-scrub.sh \
|
||||
%D%/scrub_finish-notify.sh \
|
||||
%D%/statechange-led.sh \
|
||||
%D%/statechange-notify.sh \
|
||||
%D%/statechange-slot_off.sh \
|
||||
%D%/trim_finish-notify.sh \
|
||||
%D%/vdev_attach-led.sh \
|
||||
%D%/vdev_clear-led.sh
|
||||
all-debug.sh \
|
||||
all-syslog.sh \
|
||||
data-notify.sh \
|
||||
generic-notify.sh \
|
||||
resilver_finish-notify.sh \
|
||||
scrub_finish-notify.sh \
|
||||
statechange-led.sh \
|
||||
statechange-notify.sh \
|
||||
vdev_clear-led.sh \
|
||||
vdev_attach-led.sh \
|
||||
pool_import-led.sh \
|
||||
resilver_finish-start-scrub.sh \
|
||||
trim_finish-notify.sh
|
||||
|
||||
nodist_zedexec_SCRIPTS = \
|
||||
%D%/history_event-zfs-list-cacher.sh
|
||||
nodist_zedexec_SCRIPTS = history_event-zfs-list-cacher.sh
|
||||
|
||||
SUBSTFILES += $(nodist_zedexec_SCRIPTS)
|
||||
|
||||
zedconfdefaults = \
|
||||
all-syslog.sh \
|
||||
data-notify.sh \
|
||||
deadman-slot_off.sh \
|
||||
history_event-zfs-list-cacher.sh \
|
||||
pool_import-led.sh \
|
||||
resilver_finish-notify.sh \
|
||||
resilver_finish-start-scrub.sh \
|
||||
scrub_finish-notify.sh \
|
||||
statechange-led.sh \
|
||||
statechange-notify.sh \
|
||||
statechange-slot_off.sh \
|
||||
vdev_clear-led.sh \
|
||||
vdev_attach-led.sh \
|
||||
vdev_clear-led.sh
|
||||
pool_import-led.sh \
|
||||
resilver_finish-start-scrub.sh
|
||||
|
||||
dist_noinst_DATA += %D%/README
|
||||
|
||||
INSTALL_DATA_HOOKS += zed-install-data-hook
|
||||
zed-install-data-hook:
|
||||
install-data-hook:
|
||||
$(MKDIR_P) "$(DESTDIR)$(zedconfdir)"
|
||||
set -x; for f in $(zedconfdefaults); do \
|
||||
[ -f "$(DESTDIR)$(zedconfdir)/$${f}" ] ||\
|
||||
[ -L "$(DESTDIR)$(zedconfdir)/$${f}" ] || \
|
||||
$(LN_S) "$(zedexecdir)/$${f}" "$(DESTDIR)$(zedconfdir)"; \
|
||||
for f in $(zedconfdefaults); do \
|
||||
test -f "$(DESTDIR)$(zedconfdir)/$${f}" -o \
|
||||
-L "$(DESTDIR)$(zedconfdir)/$${f}" || \
|
||||
ln -s "$(zedexecdir)/$${f}" "$(DESTDIR)$(zedconfdir)"; \
|
||||
done
|
||||
|
||||
SHELLCHECKSCRIPTS += $(dist_zedconf_DATA) $(dist_zedexec_SCRIPTS) $(nodist_zedexec_SCRIPTS)
|
||||
$(call SHELLCHECK_OPTS,$(dist_zedconf_DATA) $(dist_zedexec_SCRIPTS) $(nodist_zedexec_SCRIPTS)): SHELLCHECK_SHELL = sh
|
||||
# False positive: 1>&"${ZED_FLOCK_FD}" looks suspiciously similar to a >&filename bash extension
|
||||
$(call SHELLCHECK_OPTS,$(dist_zedconf_DATA) $(dist_zedexec_SCRIPTS) $(nodist_zedexec_SCRIPTS)): CHECKBASHISMS_IGNORE = -e 'should be >word 2>&1' -e '&"$${ZED_FLOCK_FD}"'
|
||||
chmod 0600 "$(DESTDIR)$(zedconfdir)/zed.rc"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2154
|
||||
#
|
||||
# Log all environment variables to ZED_DEBUG_LOG.
|
||||
#
|
||||
@@ -13,11 +12,15 @@
|
||||
|
||||
zed_exit_if_ignoring_this_event
|
||||
|
||||
zed_lock "${ZED_DEBUG_LOG}"
|
||||
{
|
||||
env | sort
|
||||
echo
|
||||
} 1>&"${ZED_FLOCK_FD}"
|
||||
zed_unlock "${ZED_DEBUG_LOG}"
|
||||
lockfile="$(basename -- "${ZED_DEBUG_LOG}").lock"
|
||||
|
||||
umask 077
|
||||
zed_lock "${lockfile}"
|
||||
exec >> "${ZED_DEBUG_LOG}"
|
||||
|
||||
printenv | sort
|
||||
echo
|
||||
|
||||
exec >&-
|
||||
zed_unlock "${lockfile}"
|
||||
exit 0
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2154
|
||||
#
|
||||
# Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||
# Copyright (c) 2020 by Delphix. All rights reserved.
|
||||
@@ -22,7 +21,7 @@ if [ "${ZED_SYSLOG_DISPLAY_GUIDS}" = "1" ]; then
|
||||
[ -n "${ZEVENT_VDEV_GUID}" ] && msg="${msg} vdev_guid=${ZEVENT_VDEV_GUID}"
|
||||
else
|
||||
[ -n "${ZEVENT_POOL}" ] && msg="${msg} pool='${ZEVENT_POOL}'"
|
||||
[ -n "${ZEVENT_VDEV_PATH}" ] && msg="${msg} vdev=${ZEVENT_VDEV_PATH##*/}"
|
||||
[ -n "${ZEVENT_VDEV_PATH}" ] && msg="${msg} vdev=$(basename "${ZEVENT_VDEV_PATH}")"
|
||||
fi
|
||||
|
||||
# log pool state if state is anything other than 'ACTIVE'
|
||||
@@ -43,7 +42,6 @@ fi
|
||||
msg="${msg} delay=$((ZEVENT_ZIO_DELAY / 1000000))ms"
|
||||
|
||||
# list the bookmark data together
|
||||
# shellcheck disable=SC2153
|
||||
[ -n "${ZEVENT_ZIO_OBJSET}" ] && \
|
||||
msg="${msg} bookmark=${ZEVENT_ZIO_OBJSET}:${ZEVENT_ZIO_OBJECT}:${ZEVENT_ZIO_LEVEL}:${ZEVENT_ZIO_BLKID}"
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2154
|
||||
#
|
||||
# Send notification in response to a DATA error.
|
||||
#
|
||||
@@ -26,7 +25,7 @@ zed_rate_limit "${rate_limit_tag}" || exit 3
|
||||
|
||||
umask 077
|
||||
note_subject="ZFS ${ZEVENT_SUBCLASS} error for ${ZEVENT_POOL} on $(hostname)"
|
||||
note_pathname="$(mktemp)"
|
||||
note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
|
||||
{
|
||||
echo "ZFS has detected a data error:"
|
||||
echo
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC3014,SC2154,SC2086,SC2034
|
||||
#
|
||||
# Turn off disk's enclosure slot if an I/O is hung triggering the deadman.
|
||||
#
|
||||
# It's possible for outstanding I/O to a misbehaving SCSI disk to neither
|
||||
# promptly complete or return an error. This can occur due to retry and
|
||||
# recovery actions taken by the SCSI layer, driver, or disk. When it occurs
|
||||
# the pool will be unresponsive even though there may be sufficient redundancy
|
||||
# configured to proceeded without this single disk.
|
||||
#
|
||||
# When a hung I/O is detected by the kmods it will be posted as a deadman
|
||||
# event. By default an I/O is considered to be hung after 5 minutes. This
|
||||
# value can be changed with the zfs_deadman_ziotime_ms module parameter.
|
||||
# If ZED_POWER_OFF_ENCLOSURE_SLOT_ON_DEADMAN is set the disk's enclosure
|
||||
# slot will be powered off causing the outstanding I/O to fail. The ZED
|
||||
# will then handle this like a normal disk failure and FAULT the vdev.
|
||||
#
|
||||
# We assume the user will be responsible for turning the slot back on
|
||||
# after replacing the disk.
|
||||
#
|
||||
# Note that this script requires that your enclosure be supported by the
|
||||
# Linux SCSI Enclosure services (SES) driver. The script will do nothing
|
||||
# if you have no enclosure, or if your enclosure isn't supported.
|
||||
#
|
||||
# Exit codes:
|
||||
# 0: slot successfully powered off
|
||||
# 1: enclosure not available
|
||||
# 2: ZED_POWER_OFF_ENCLOSURE_SLOT_ON_DEADMAN disabled
|
||||
# 3: System not configured to wait on deadman
|
||||
# 4: The enclosure sysfs path passed from ZFS does not exist
|
||||
# 5: Enclosure slot didn't actually turn off after we told it to
|
||||
|
||||
[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
|
||||
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
||||
|
||||
if [ ! -d /sys/class/enclosure ] ; then
|
||||
# No JBOD enclosure or NVMe slots
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${ZED_POWER_OFF_ENCLOSURE_SLOT_ON_DEADMAN}" != "1" ] ; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$ZEVENT_POOL_FAILMODE" != "wait" ] ; then
|
||||
exit 3
|
||||
fi
|
||||
|
||||
if [ ! -f "$ZEVENT_VDEV_ENC_SYSFS_PATH/power_status" ] ; then
|
||||
exit 4
|
||||
fi
|
||||
|
||||
# Turn off the slot and wait for sysfs to report that the slot is off.
|
||||
# It can take ~400ms on some enclosures and multiple retries may be needed.
|
||||
for i in $(seq 1 20) ; do
|
||||
echo "off" | tee "$ZEVENT_VDEV_ENC_SYSFS_PATH/power_status"
|
||||
|
||||
for j in $(seq 1 5) ; do
|
||||
if [ "$(cat $ZEVENT_VDEV_ENC_SYSFS_PATH/power_status)" == "off" ] ; then
|
||||
break 2
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
done
|
||||
|
||||
if [ "$(cat $ZEVENT_VDEV_ENC_SYSFS_PATH/power_status)" != "off" ] ; then
|
||||
exit 5
|
||||
fi
|
||||
|
||||
zed_log_msg "powered down slot $ZEVENT_VDEV_ENC_SYSFS_PATH for $ZEVENT_VDEV_PATH"
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2154
|
||||
#
|
||||
# Send notification in response to a given zevent.
|
||||
#
|
||||
@@ -24,7 +23,7 @@
|
||||
|
||||
# Rate-limit the notification based in part on the filename.
|
||||
#
|
||||
rate_limit_tag="${ZEVENT_POOL};${ZEVENT_SUBCLASS};${0##*/}"
|
||||
rate_limit_tag="${ZEVENT_POOL};${ZEVENT_SUBCLASS};$(basename -- "$0")"
|
||||
rate_limit_interval="${ZED_NOTIFY_INTERVAL_SECS}"
|
||||
zed_rate_limit "${rate_limit_tag}" "${rate_limit_interval}" || exit 3
|
||||
|
||||
@@ -32,7 +31,7 @@ umask 077
|
||||
pool_str="${ZEVENT_POOL:+" for ${ZEVENT_POOL}"}"
|
||||
host_str=" on $(hostname)"
|
||||
note_subject="ZFS ${ZEVENT_SUBCLASS} event${pool_str}${host_str}"
|
||||
note_pathname="$(mktemp)"
|
||||
note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
|
||||
{
|
||||
echo "ZFS has posted the following event:"
|
||||
echo
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2154
|
||||
#
|
||||
# Track changes to enumerated pools for use in early-boot
|
||||
set -ef
|
||||
|
||||
FSLIST="@sysconfdir@/zfs/zfs-list.cache/${ZEVENT_POOL}"
|
||||
FSLIST_TMP="@runstatedir@/zfs-list.cache@${ZEVENT_POOL}"
|
||||
FSLIST_DIR="@sysconfdir@/zfs/zfs-list.cache"
|
||||
FSLIST_TMP="@runstatedir@/zfs-list.cache.new"
|
||||
FSLIST="${FSLIST_DIR}/${ZEVENT_POOL}"
|
||||
|
||||
# If the pool specific cache file is not writeable, abort
|
||||
[ -w "${FSLIST}" ] || exit 0
|
||||
@@ -14,20 +14,20 @@ FSLIST_TMP="@runstatedir@/zfs-list.cache@${ZEVENT_POOL}"
|
||||
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
||||
|
||||
[ "$ZEVENT_SUBCLASS" != "history_event" ] && exit 0
|
||||
zed_check_cmd "${ZFS}" sort diff
|
||||
zed_check_cmd "${ZFS}" sort diff grep
|
||||
|
||||
# If we are acting on a snapshot, we have nothing to do
|
||||
[ "${ZEVENT_HISTORY_DSNAME%@*}" = "${ZEVENT_HISTORY_DSNAME}" ] || exit 0
|
||||
printf '%s' "${ZEVENT_HISTORY_DSNAME}" | grep '@' && exit 0
|
||||
|
||||
# We lock the output file to avoid simultaneous writes.
|
||||
# We obtain a lock on zfs-list to avoid any simultaneous writes.
|
||||
# If we run into trouble, log and drop the lock
|
||||
abort_alter() {
|
||||
zed_log_msg "Error updating zfs-list.cache for ${ZEVENT_POOL}!"
|
||||
zed_unlock "${FSLIST}"
|
||||
zed_log_msg "Error updating zfs-list.cache!"
|
||||
zed_unlock zfs-list
|
||||
}
|
||||
|
||||
finished() {
|
||||
zed_unlock "${FSLIST}"
|
||||
zed_unlock zfs-list
|
||||
trap - EXIT
|
||||
exit 0
|
||||
}
|
||||
@@ -37,7 +37,7 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
|
||||
;;
|
||||
|
||||
export)
|
||||
zed_lock "${FSLIST}"
|
||||
zed_lock zfs-list
|
||||
trap abort_alter EXIT
|
||||
echo > "${FSLIST}"
|
||||
finished
|
||||
@@ -63,7 +63,7 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
|
||||
;;
|
||||
esac
|
||||
|
||||
zed_lock "${FSLIST}"
|
||||
zed_lock zfs-list
|
||||
trap abort_alter EXIT
|
||||
|
||||
PROPS="name,mountpoint,canmount,atime,relatime,devices,exec\
|
||||
@@ -73,13 +73,13 @@ PROPS="name,mountpoint,canmount,atime,relatime,devices,exec\
|
||||
,org.openzfs.systemd:wanted-by,org.openzfs.systemd:required-by\
|
||||
,org.openzfs.systemd:nofail,org.openzfs.systemd:ignore"
|
||||
|
||||
"${ZFS}" list -H -t filesystem -o "${PROPS}" -r "${ZEVENT_POOL}" > "${FSLIST_TMP}"
|
||||
"${ZFS}" list -H -t filesystem -o $PROPS -r "${ZEVENT_POOL}" > "${FSLIST_TMP}"
|
||||
|
||||
# Sort the output so that it is stable
|
||||
sort "${FSLIST_TMP}" -o "${FSLIST_TMP}"
|
||||
|
||||
# Don't modify the file if it hasn't changed
|
||||
diff -q "${FSLIST_TMP}" "${FSLIST}" || cat "${FSLIST_TMP}" > "${FSLIST}"
|
||||
diff -q "${FSLIST_TMP}" "${FSLIST}" || mv "${FSLIST_TMP}" "${FSLIST}"
|
||||
rm -f "${FSLIST_TMP}"
|
||||
|
||||
finished
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2154
|
||||
# resilver_finish-start-scrub.sh
|
||||
# Run a scrub after a resilver
|
||||
#
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2154
|
||||
#
|
||||
# Send notification in response to a RESILVER_FINISH or SCRUB_FINISH.
|
||||
#
|
||||
@@ -42,7 +41,7 @@ fi
|
||||
|
||||
umask 077
|
||||
note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)"
|
||||
note_pathname="$(mktemp)"
|
||||
note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
|
||||
{
|
||||
echo "ZFS has finished a ${action}:"
|
||||
echo
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2154
|
||||
#
|
||||
# Turn off/on vdevs' enclosure fault LEDs when their pool's state changes.
|
||||
# Turn off/on the VDEV's enclosure fault LEDs when the pool's state changes.
|
||||
#
|
||||
# Turn a vdev's fault LED on if it becomes FAULTED, DEGRADED or UNAVAIL.
|
||||
# Turn its LED off when it's back ONLINE again.
|
||||
# Turn the VDEV's fault LED on if it becomes FAULTED, DEGRADED or UNAVAIL.
|
||||
# Turn the LED off when it's back ONLINE again.
|
||||
#
|
||||
# This script run in two basic modes:
|
||||
#
|
||||
# 1. If $ZEVENT_VDEV_ENC_SYSFS_PATH and $ZEVENT_VDEV_STATE_STR are set, then
|
||||
# only set the LED for that particular vdev. This is the case for statechange
|
||||
# only set the LED for that particular VDEV. This is the case for statechange
|
||||
# events and some vdev_* events.
|
||||
#
|
||||
# 2. If those vars are not set, then check the state of all vdevs in the pool
|
||||
# 2. If those vars are not set, then check the state of all VDEVs in the pool
|
||||
# and set the LEDs accordingly. This is the case for pool_import events.
|
||||
#
|
||||
# Note that this script requires that your enclosure be supported by the
|
||||
# Linux SCSI Enclosure services (SES) driver. The script will do nothing
|
||||
# Linux SCSI enclosure services (ses) driver. The script will do nothing
|
||||
# if you have no enclosure, or if your enclosure isn't supported.
|
||||
#
|
||||
# Exit codes:
|
||||
@@ -30,8 +29,7 @@
|
||||
[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
|
||||
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
||||
|
||||
if [ ! -d /sys/class/enclosure ] && [ ! -d /sys/bus/pci/slots ] ; then
|
||||
# No JBOD enclosure or NVMe slots
|
||||
if [ ! -d /sys/class/enclosure ] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -61,10 +59,6 @@ check_and_set_led()
|
||||
file="$1"
|
||||
val="$2"
|
||||
|
||||
if [ -z "$val" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -e "$file" ] ; then
|
||||
return 3
|
||||
fi
|
||||
@@ -72,11 +66,11 @@ check_and_set_led()
|
||||
# If another process is accessing the LED when we attempt to update it,
|
||||
# the update will be lost so retry until the LED actually changes or we
|
||||
# timeout.
|
||||
for _ in 1 2 3 4 5; do
|
||||
for _ in $(seq 1 5); do
|
||||
# We want to check the current state first, since writing to the
|
||||
# 'fault' entry always causes a SES command, even if the
|
||||
# current state is already what you want.
|
||||
read -r current < "${file}"
|
||||
current=$(cat "${file}")
|
||||
|
||||
# On some enclosures if you write 1 to fault, and read it back,
|
||||
# it will return 2. Treat all non-zero values as 1 for
|
||||
@@ -91,85 +85,27 @@ check_and_set_led()
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Fault LEDs for JBODs and NVMe drives are handled a little differently.
|
||||
#
|
||||
# On JBODs the fault LED is called 'fault' and on a path like this:
|
||||
#
|
||||
# /sys/class/enclosure/0:0:1:0/SLOT 10/fault
|
||||
#
|
||||
# On NVMe it's called 'attention' and on a path like this:
|
||||
#
|
||||
# /sys/bus/pci/slot/0/attention
|
||||
#
|
||||
# This function returns the full path to the fault LED file for a given
|
||||
# enclosure/slot directory.
|
||||
#
|
||||
path_to_led()
|
||||
{
|
||||
dir=$1
|
||||
if [ -f "$dir/fault" ] ; then
|
||||
echo "$dir/fault"
|
||||
elif [ -f "$dir/attention" ] ; then
|
||||
echo "$dir/attention"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
state_to_val()
|
||||
{
|
||||
state="$1"
|
||||
case "$state" in
|
||||
FAULTED|DEGRADED|UNAVAIL|REMOVED)
|
||||
echo 1
|
||||
;;
|
||||
ONLINE)
|
||||
echo 0
|
||||
;;
|
||||
*)
|
||||
echo "invalid state: $state"
|
||||
;;
|
||||
esac
|
||||
if [ "$state" = "FAULTED" ] || [ "$state" = "DEGRADED" ] || \
|
||||
[ "$state" = "UNAVAIL" ] ; then
|
||||
echo 1
|
||||
elif [ "$state" = "ONLINE" ] ; then
|
||||
echo 0
|
||||
fi
|
||||
}
|
||||
|
||||
# process_pool ([pool])
|
||||
#
|
||||
# Given a nvme name like 'nvme0n1', pass back its slot directory
|
||||
# like "/sys/bus/pci/slots/0"
|
||||
#
|
||||
nvme_dev_to_slot()
|
||||
{
|
||||
dev="$1"
|
||||
|
||||
# Get the address "0000:01:00.0"
|
||||
read -r address < "/sys/class/block/$dev/device/address"
|
||||
|
||||
find /sys/bus/pci/slots -regex '.*/[0-9]+/address$' | \
|
||||
while read -r sys_addr; do
|
||||
read -r this_address < "$sys_addr"
|
||||
|
||||
# The format of address is a little different between
|
||||
# /sys/class/block/$dev/device/address and
|
||||
# /sys/bus/pci/slots/
|
||||
#
|
||||
# address= "0000:01:00.0"
|
||||
# this_address = "0000:01:00"
|
||||
#
|
||||
if echo "$address" | grep -Eq ^"$this_address" ; then
|
||||
echo "${sys_addr%/*}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# process_pool (pool)
|
||||
#
|
||||
# Iterate through a pool and set the vdevs' enclosure slot LEDs to
|
||||
# those vdevs' state.
|
||||
# Iterate through a pool (or pools) and set the VDEV's enclosure slot LEDs to
|
||||
# the VDEV's state.
|
||||
#
|
||||
# Arguments
|
||||
# pool: Pool name.
|
||||
# pool: Optional pool name. If not specified, iterate though all pools.
|
||||
#
|
||||
# Return
|
||||
# 0 on success, 3 on missing sysfs path
|
||||
@@ -177,27 +113,19 @@ nvme_dev_to_slot()
|
||||
process_pool()
|
||||
{
|
||||
pool="$1"
|
||||
|
||||
# The output will be the vdevs only (from "grep '/dev/'"):
|
||||
#
|
||||
# U45 ONLINE 0 0 0 /dev/sdk 0
|
||||
# U46 ONLINE 0 0 0 /dev/sdm 0
|
||||
# U47 ONLINE 0 0 0 /dev/sdn 0
|
||||
# U50 ONLINE 0 0 0 /dev/sdbn 0
|
||||
#
|
||||
ZPOOL_SCRIPTS_AS_ROOT=1 $ZPOOL status -c upath,fault_led "$pool" | grep '/dev/' | (
|
||||
rc=0
|
||||
while read -r vdev state _ _ _ therest; do
|
||||
# Read out current LED value and path
|
||||
# Get dev name (like 'sda')
|
||||
dev=$(basename "$(echo "$therest" | awk '{print $(NF-1)}')")
|
||||
vdev_enc_sysfs_path=$(realpath "/sys/class/block/$dev/device/enclosure_device"*)
|
||||
if [ ! -d "$vdev_enc_sysfs_path" ] ; then
|
||||
# This is not a JBOD disk, but it could be a PCI NVMe drive
|
||||
vdev_enc_sysfs_path=$(nvme_dev_to_slot "$dev")
|
||||
fi
|
||||
|
||||
current_val=$(echo "$therest" | awk '{print $NF}')
|
||||
# Lookup all the current LED values and paths in parallel
|
||||
#shellcheck disable=SC2016
|
||||
cmd='echo led_token=$(cat "$VDEV_ENC_SYSFS_PATH/fault"),"$VDEV_ENC_SYSFS_PATH",'
|
||||
out=$($ZPOOL status -vc "$cmd" "$pool" | grep 'led_token=')
|
||||
|
||||
#shellcheck disable=SC2034
|
||||
echo "$out" | while read -r vdev state read write chksum therest; do
|
||||
# Read out current LED value and path
|
||||
tmp=$(echo "$therest" | sed 's/^.*led_token=//g')
|
||||
vdev_enc_sysfs_path=$(echo "$tmp" | awk -F ',' '{print $2}')
|
||||
current_val=$(echo "$tmp" | awk -F ',' '{print $1}')
|
||||
|
||||
if [ "$current_val" != "0" ] ; then
|
||||
current_val=1
|
||||
@@ -208,33 +136,40 @@ process_pool()
|
||||
continue
|
||||
fi
|
||||
|
||||
led_path=$(path_to_led "$vdev_enc_sysfs_path")
|
||||
if [ ! -e "$led_path" ] ; then
|
||||
rc=3
|
||||
zed_log_msg "vdev $vdev '$led_path' doesn't exist"
|
||||
continue
|
||||
if [ ! -e "$vdev_enc_sysfs_path/fault" ] ; then
|
||||
#shellcheck disable=SC2030
|
||||
rc=1
|
||||
zed_log_msg "vdev $vdev '$file/fault' doesn't exist"
|
||||
continue;
|
||||
fi
|
||||
|
||||
val=$(state_to_val "$state")
|
||||
|
||||
if [ "$current_val" = "$val" ] ; then
|
||||
# LED is already set correctly
|
||||
continue
|
||||
continue;
|
||||
fi
|
||||
|
||||
if ! check_and_set_led "$led_path" "$val"; then
|
||||
rc=3
|
||||
if ! check_and_set_led "$vdev_enc_sysfs_path/fault" "$val"; then
|
||||
rc=1
|
||||
fi
|
||||
|
||||
done
|
||||
exit "$rc"; )
|
||||
|
||||
#shellcheck disable=SC2031
|
||||
if [ "$rc" = "0" ] ; then
|
||||
return 0
|
||||
else
|
||||
# We didn't see a sysfs entry that we wanted to set
|
||||
return 3
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -n "$ZEVENT_VDEV_ENC_SYSFS_PATH" ] && [ -n "$ZEVENT_VDEV_STATE_STR" ] ; then
|
||||
# Got a statechange for an individual vdev
|
||||
# Got a statechange for an individual VDEV
|
||||
val=$(state_to_val "$ZEVENT_VDEV_STATE_STR")
|
||||
vdev=$(basename "$ZEVENT_VDEV_PATH")
|
||||
ledpath=$(path_to_led "$ZEVENT_VDEV_ENC_SYSFS_PATH")
|
||||
check_and_set_led "$ledpath" "$val"
|
||||
check_and_set_led "$ZEVENT_VDEV_ENC_SYSFS_PATH/fault" "$val"
|
||||
else
|
||||
# Process the entire pool
|
||||
poolname=$(zed_guid_to_pool "$ZEVENT_POOL_GUID")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user