mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-24 03:08:51 +03:00
Compare commits
270 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a8c2b7ebc6 | |||
| 2af898ee24 | |||
| c32c2f17d0 | |||
| 2254b2bbbe | |||
| 5c4ec382a7 | |||
| e22bfd8149 | |||
| f45ad7bff6 | |||
| 0a3a4d067a | |||
| ba8024a284 | |||
| edc2675aed | |||
| 98bb45e27a | |||
| 44f463824b | |||
| b0d579bc55 | |||
| 7e5def8ae0 | |||
| 89019a846b | |||
| 41f7723e9c | |||
| 2b8c3cb0c8 | |||
| f325d76e96 | |||
| e3fb781c5f | |||
| 14a5e48fb9 | |||
| 01937958ce | |||
| edb504f9db | |||
| 2428fbbfcf | |||
| 16d298188f | |||
| f42f8702ce | |||
| 9e58d5ef38 | |||
| 320f9de8ab | |||
| 262275ab26 | |||
| 55f39a01e6 | |||
| b884768e46 | |||
| f8f4e13776 | |||
| 5f07d51751 | |||
| b2f003c4f4 | |||
| 9014da2b01 | |||
| 45579c9515 | |||
| b32f1279d4 | |||
| 1b0cd07131 | |||
| 8c6867dae4 | |||
| 99310c0aa0 | |||
| d126980e5f | |||
| 88ef5b238b | |||
| 30d8b85702 | |||
| 45f0437912 | |||
| dc3eea871a | |||
| d2c8103a68 | |||
| 3ea1f7f193 | |||
| 4356dd23a9 | |||
| 75318ec497 | |||
| c1629734ab | |||
| 778290d5bc | |||
| 98bc8e0b23 | |||
| caafa436eb | |||
| fe8de1c8a6 | |||
| 1bd93ea1e0 | |||
| 6857950e46 | |||
| 716ce2b89e | |||
| 9daae583d8 | |||
| b5ee3df776 | |||
| 17cd9a8e0c | |||
| 2a16d4cfaf | |||
| 3350a33908 | |||
| 3eef58c9b6 | |||
| 4805781c74 | |||
| b06f40ea9b | |||
| 6b5cc49d81 | |||
| ef7a79488a | |||
| a2f759146d | |||
| f79c0de208 | |||
| 1667816089 | |||
| d1ed1be3cd | |||
| e749242a99 | |||
| 9267ef84fd | |||
| 0ee129199f | |||
| 245be00597 | |||
| c38d702330 | |||
| 3f729907c8 | |||
| cca220d7c6 | |||
| 4ed30958ce | |||
| 2f118072cb | |||
| 7440f10ec1 | |||
| 8bb800d6b4 | |||
| bbf61c118f | |||
| d296b09456 | |||
| 5ac017fc04 | |||
| f5ecab3aef | |||
| fd01167ffd | |||
| 3b118f0a34 | |||
| ebe443c8ff | |||
| 63f3396233 | |||
| 2deb4526ee | |||
| a1662ffcaa | |||
| ea921bf6a6 | |||
| 6e627cc468 | |||
| 3eb3a13628 | |||
| c234706270 | |||
| 6059ba27c4 | |||
| 927f40d089 | |||
| 6356d50e67 | |||
| bd69ae3b53 | |||
| 9a2e90c9fc | |||
| 240ccfc13a | |||
| c30e716c81 | |||
| 267fd7b0f1 | |||
| dc0176eeec | |||
| 0a0af41bd9 | |||
| 3808006edf | |||
| c17922b8a9 | |||
| 8d7f17798d | |||
| 6dc40e2ada | |||
| 792f88131c | |||
| 33bb1e8256 | |||
| bcaba38e42 | |||
| 5e3085e360 | |||
| 99920d823e | |||
| 338523dd6e | |||
| 2644784f49 | |||
| b1f61f05b4 | |||
| e5ba614d05 | |||
| 30ac8de48a | |||
| c705d8386b | |||
| d5b10b3ef3 | |||
| 5a84c60fb9 | |||
| 26941ce90b | |||
| 07ce5d7390 | |||
| 1d805a534b | |||
| a9ff89e05c | |||
| d85011ed69 | |||
| b3da003ebf | |||
| 478754a8f5 | |||
| 31ff122aa2 | |||
| 18c662b845 | |||
| c797f0898e | |||
| 5e566c5772 | |||
| 23227313a2 | |||
| 3713b73335 | |||
| 310e63dfd1 | |||
| a196b3bc3d | |||
| a58e1284d8 | |||
| f1dde3fb20 | |||
| 5f38142e7b | |||
| 29b79dcfe9 | |||
| ecc972c7f0 | |||
| 6c891ade8b | |||
| 03658d5081 | |||
| 5d62588032 | |||
| 6897ea475f | |||
| 3790bfa80f | |||
| 6b278f3223 | |||
| f1236ebf35 | |||
| 184087f822 | |||
| 834815e9f7 | |||
| 0f1ff38476 | |||
| e3b28e16ce | |||
| 2f62fdd644 | |||
| 137b3e6cff | |||
| d1630dda58 | |||
| 701ebd014a | |||
| 5b8ec2cf39 | |||
| 9d1a39cec6 | |||
| 2a7b736dce | |||
| ecc8af1812 | |||
| 129e3e8dc3 | |||
| 9fb09f79e5 | |||
| a2ee6568c6 | |||
| 9c1a8eaa51 | |||
| a8fa31b50b | |||
| 8d82a19def | |||
| c2aacf2087 | |||
| 9a6c57845a | |||
| d27a40d28f | |||
| aebc5df418 | |||
| 7a8bef3983 | |||
| d486dee89e | |||
| 7de8fb33a2 | |||
| 904c03672b | |||
| 03955e3488 | |||
| 88e4e0d5dd | |||
| 03f638a8ef | |||
| 5dc25de668 | |||
| 53e5890cff | |||
| a94447ddf3 | |||
| 7192ec7942 | |||
| 06acbbc429 | |||
| 6116bbd744 | |||
| a803eacf26 | |||
| 504bfc8b49 | |||
| 53a8cbd70e | |||
| 505b97ae20 | |||
| 30a64ebaed | |||
| da16fc5739 | |||
| 3c7fa6ca33 | |||
| 36e0ddb744 | |||
| cf21b5b5b2 | |||
| 1030f807ba | |||
| d45702bcfa | |||
| ddd20dbe0b | |||
| 4a98780933 | |||
| 6db8f1a0d1 | |||
| e06711412b | |||
| 68ba1d2fa9 | |||
| 4e11137989 | |||
| be9be1cc3e | |||
| eab4536081 | |||
| 954516cec1 | |||
| 841cb5ee2a | |||
| d4cf31275b | |||
| fedc1d96a8 | |||
| 59511072b4 | |||
| a5c8119eba | |||
| d7881a6dca | |||
| 951e62169e | |||
| 9add19b37d | |||
| b2d633202d | |||
| 414f4a9c54 | |||
| 1c4f5e7d92 | |||
| 246e515cf8 | |||
| 2d41e75e52 | |||
| d834d6811b | |||
| 029a1b0c20 | |||
| c45254b0ec | |||
| 318fdeb51f | |||
| d3d20bf442 | |||
| 99598264fc | |||
| abe30b7b40 | |||
| f90ee0ca3d | |||
| 4ed955e280 | |||
| 1721f13e76 | |||
| 6e893ef62a | |||
| e0eaaf8144 | |||
| cb8a074dcb | |||
| c3ac4ccabb | |||
| 8d688ce66a | |||
| b544fe4123 | |||
| 926c6ec453 | |||
| 91b2f6ab1c | |||
| 851a7cd833 | |||
| 83d4d1a784 | |||
| 80cc2f6111 | |||
| b97948276d | |||
| 4cfc086e4d | |||
| 25d232f407 | |||
| edd7c24623 | |||
| bef6a8bc3a | |||
| 266b181e75 | |||
| c474f5e9a7 | |||
| 4e6a9e4598 | |||
| 661907e6bc | |||
| d3e7d981d4 | |||
| a2a0440918 | |||
| 45d1abc74d | |||
| 89950722c6 | |||
| 4810a108e8 | |||
| ae5b4a05ff | |||
| 3468fdbd34 | |||
| fb3f1fdbd6 | |||
| 426563be70 | |||
| aec4318870 | |||
| 2d9b57d39f | |||
| 4bdb8fcfa8 | |||
| 58c1c40a5e | |||
| 751575fe6f | |||
| 751941e248 | |||
| ef605a5517 | |||
| 8eb6dcec7d | |||
| 07cbcd5089 | |||
| 12acabe2a4 | |||
| 20c88dc3ef | |||
| 0c8fedeb35 | |||
| affb7141d7 | |||
| e0031d86b7 |
@@ -1,10 +0,0 @@
|
|||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.{c,h}]
|
|
||||||
tab_width = 8
|
|
||||||
indent_style = tab
|
|
||||||
+72
-124
@@ -1,12 +1,10 @@
|
|||||||
# Contributing to OpenZFS
|
# Contributing to ZFS on Linux
|
||||||
<p align="center">
|
<p align="center"><img src="http://zfsonlinux.org/images/zfs-linux.png"/></p>
|
||||||
<img alt="OpenZFS Logo"
|
|
||||||
src="https://openzfs.github.io/openzfs-docs/_static/img/logo/480px-Open-ZFS-Secondary-Logo-Colour-halfsize.png"/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
*First of all, thank you for taking the time to contribute!*
|
*First of all, thank you for taking the time to contribute!*
|
||||||
|
|
||||||
By using the following guidelines, you can help us make OpenZFS even better.
|
By using the following guidelines, you can help us make ZFS on Linux even
|
||||||
|
better.
|
||||||
|
|
||||||
## Table Of Contents
|
## Table Of Contents
|
||||||
[What should I know before I get
|
[What should I know before I get
|
||||||
@@ -29,22 +27,19 @@ started?](#what-should-i-know-before-i-get-started)
|
|||||||
* [Commit Message Formats](#commit-message-formats)
|
* [Commit Message Formats](#commit-message-formats)
|
||||||
* [New Changes](#new-changes)
|
* [New Changes](#new-changes)
|
||||||
* [OpenZFS Patch Ports](#openzfs-patch-ports)
|
* [OpenZFS Patch Ports](#openzfs-patch-ports)
|
||||||
* [Coverity Defect Fixes](#coverity-defect-fixes)
|
|
||||||
* [Signed Off By](#signed-off-by)
|
|
||||||
|
|
||||||
Helpful resources
|
Helpful resources
|
||||||
|
|
||||||
* [OpenZFS Documentation](https://openzfs.github.io/openzfs-docs/)
|
* [ZFS on Linux wiki](https://github.com/zfsonlinux/zfs/wiki)
|
||||||
* [OpenZFS Developer Resources](http://open-zfs.org/wiki/Developer_resources)
|
* [OpenZFS Documentation](http://open-zfs.org/wiki/Developer_resources)
|
||||||
* [Git and GitHub for beginners](https://openzfs.github.io/openzfs-docs/Developer%20Resources/Git%20and%20GitHub%20for%20beginners.html)
|
|
||||||
|
|
||||||
## What should I know before I get started?
|
## What should I know before I get started?
|
||||||
|
|
||||||
### Get ZFS
|
### Get ZFS
|
||||||
You can build zfs packages by following [these
|
You can build zfs packages by following [these
|
||||||
instructions](https://openzfs.github.io/openzfs-docs/Developer%20Resources/Building%20ZFS.html),
|
instructions](https://github.com/zfsonlinux/zfs/wiki/Building-ZFS),
|
||||||
or install stable packages from [your distribution's
|
or install stable packages from [your distribution's
|
||||||
repository](https://openzfs.github.io/openzfs-docs/Getting%20Started/index.html).
|
repository](https://github.com/zfsonlinux/zfs/wiki/Getting-Started).
|
||||||
|
|
||||||
### Debug ZFS
|
### Debug ZFS
|
||||||
A variety of methods and tools are available to aid ZFS developers.
|
A variety of methods and tools are available to aid ZFS developers.
|
||||||
@@ -53,30 +48,28 @@ configure option should be set. This will enable additional correctness
|
|||||||
checks and all the ASSERTs to help quickly catch potential issues.
|
checks and all the ASSERTs to help quickly catch potential issues.
|
||||||
|
|
||||||
In addition, there are numerous utilities and debugging files which
|
In addition, there are numerous utilities and debugging files which
|
||||||
provide visibility into the inner workings of ZFS. The most useful
|
provide visibility in to the inner workings of ZFS. The most useful
|
||||||
of these tools are discussed in detail on the [Troubleshooting
|
of these tools are discussed in detail on the [debugging ZFS wiki
|
||||||
page](https://openzfs.github.io/openzfs-docs/Basic%20Concepts/Troubleshooting.html).
|
page](https://github.com/zfsonlinux/zfs/wiki/Debugging).
|
||||||
|
|
||||||
### Where can I ask for help?
|
### Where can I ask for help?
|
||||||
The [zfs-discuss mailing
|
The [mailing list](https://github.com/zfsonlinux/zfs/wiki/Mailing-Lists)
|
||||||
list](https://openzfs.github.io/openzfs-docs/Project%20and%20Community/Mailing%20Lists.html)
|
is the best place to ask for help.
|
||||||
or IRC are the best places to ask for help. Please do not file
|
|
||||||
support requests on the GitHub issue tracker.
|
|
||||||
|
|
||||||
## How Can I Contribute?
|
## How Can I Contribute?
|
||||||
|
|
||||||
### Reporting Bugs
|
### Reporting Bugs
|
||||||
*Please* contact us via the [zfs-discuss mailing
|
*Please* contact us via the [mailing
|
||||||
list](https://openzfs.github.io/openzfs-docs/Project%20and%20Community/Mailing%20Lists.html)
|
list](https://github.com/zfsonlinux/zfs/wiki/Mailing-Lists) if you aren't
|
||||||
or IRC if you aren't certain that you are experiencing a bug.
|
certain that you are experiencing a bug.
|
||||||
|
|
||||||
If you run into an issue, please search our [issue
|
If you run into an issue, please search our [issue
|
||||||
tracker](https://github.com/openzfs/zfs/issues) *first* to ensure the
|
tracker](https://github.com/zfsonlinux/zfs/issues) *first* to ensure the
|
||||||
issue hasn't been reported before. Open a new issue only if you haven't
|
issue hasn't been reported before. Open a new issue only if you haven't
|
||||||
found anything similar to your issue.
|
found anything similar to your issue.
|
||||||
|
|
||||||
You can open a new issue and search existing issues using the public [issue
|
You can open a new issue and search existing issues using the public [issue
|
||||||
tracker](https://github.com/openzfs/zfs/issues).
|
tracker](https://github.com/zfsonlinux/zfs/issues).
|
||||||
|
|
||||||
#### When opening a new issue, please include the following information at the top of the issue:
|
#### When opening a new issue, please include the following information at the top of the issue:
|
||||||
* What distribution (with version) you are using.
|
* What distribution (with version) you are using.
|
||||||
@@ -108,13 +101,13 @@ information like:
|
|||||||
* Stack traces which may be logged to `dmesg`.
|
* Stack traces which may be logged to `dmesg`.
|
||||||
|
|
||||||
### Suggesting Enhancements
|
### Suggesting Enhancements
|
||||||
OpenZFS is a widely deployed production filesystem which is under active
|
ZFS on Linux is a widely deployed production filesystem which is under
|
||||||
development. The team's primary focus is on fixing known issues, improving
|
active development. The team's primary focus is on fixing known issues,
|
||||||
performance, and adding compelling new features.
|
improving performance, and adding compelling new features.
|
||||||
|
|
||||||
You can view the list of proposed features
|
You can view the list of proposed features
|
||||||
by filtering the issue tracker by the ["Type: Feature"
|
by filtering the issue tracker by the ["Feature"
|
||||||
label](https://github.com/openzfs/zfs/issues?q=is%3Aopen+is%3Aissue+label%3A%22Type%3A+Feature%22).
|
label](https://github.com/zfsonlinux/zfs/issues?q=is%3Aopen+is%3Aissue+label%3AFeature).
|
||||||
If you have an idea for a feature first check this list. If your idea already
|
If you have an idea for a feature first check this list. If your idea already
|
||||||
appears then add a +1 to the top most comment, this helps us gauge interest
|
appears then add a +1 to the top most comment, this helps us gauge interest
|
||||||
in that feature.
|
in that feature.
|
||||||
@@ -123,11 +116,8 @@ Otherwise, open a new issue and describe your proposed feature. Why is this
|
|||||||
feature needed? What problem does it solve?
|
feature needed? What problem does it solve?
|
||||||
|
|
||||||
### Pull Requests
|
### Pull Requests
|
||||||
|
* All pull requests must be based on the current master branch and apply
|
||||||
#### General
|
without conflicts.
|
||||||
|
|
||||||
* All pull requests, except backports and releases, must be based on the current master branch
|
|
||||||
and should apply without conflicts.
|
|
||||||
* Please attempt to limit pull requests to a single commit which resolves
|
* Please attempt to limit pull requests to a single commit which resolves
|
||||||
one specific issue.
|
one specific issue.
|
||||||
* Make sure your commit messages are in the correct format. See the
|
* Make sure your commit messages are in the correct format. See the
|
||||||
@@ -139,24 +129,16 @@ logically independent patches which build on each other. This makes large
|
|||||||
changes easier to review and approve which speeds up the merging process.
|
changes easier to review and approve which speeds up the merging process.
|
||||||
* Try to keep pull requests simple. Simple code with comments is much easier
|
* Try to keep pull requests simple. Simple code with comments is much easier
|
||||||
to review and approve.
|
to review and approve.
|
||||||
* All proposed changes must be approved by an OpenZFS organization member.
|
* Test cases should be provided when appropriate.
|
||||||
* If you have an idea you'd like to discuss or which requires additional testing, consider opening it as a draft pull request.
|
|
||||||
Once everything is in good shape and the details have been worked out you can remove its draft status.
|
|
||||||
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](
|
|
||||||
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.
|
|
||||||
* If your pull request improves performance, please include some benchmarks.
|
* 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/zfsonlinux/zfs/issues?q=is%3Aissue+is%3Aopen+label%3A%22Test+Suite%22).
|
||||||
|
There are also various [buildbot options](https://github.com/zfsonlinux/zfs/wiki/Buildbot-Options)
|
||||||
|
to control how changes are tested.
|
||||||
|
* All proposed changes must be approved by a ZFS on Linux organization member.
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
All help is appreciated! If you're in a position to run the latest code
|
All help is appreciated! If you're in a position to run the latest code
|
||||||
@@ -166,41 +148,16 @@ range of realistic workloads, configurations and architectures we're better
|
|||||||
able quickly identify and resolve potential issues.
|
able quickly identify and resolve potential issues.
|
||||||
|
|
||||||
Users can also run the [ZFS Test
|
Users can also run the [ZFS Test
|
||||||
Suite](https://github.com/openzfs/zfs/tree/master/tests) on their systems
|
Suite](https://github.com/zfsonlinux/zfs/tree/master/tests) on their systems
|
||||||
to verify ZFS is behaving as intended.
|
to verify ZFS is behaving as intended.
|
||||||
|
|
||||||
## Style Guides
|
## Style Guides
|
||||||
|
|
||||||
### Repository Structure
|
|
||||||
|
|
||||||
OpenZFS uses a standardised branching structure.
|
|
||||||
- The "development and main branch", is the branch all development should be based on.
|
|
||||||
- "Release branches" contain the latest released code for said version.
|
|
||||||
- "Staging branches" contain selected commits prior to being released.
|
|
||||||
|
|
||||||
**Branch Names:**
|
|
||||||
- Development and Main branch: `master`
|
|
||||||
- Release branches: `zfs-$VERSION-release`
|
|
||||||
- Staging branches: `zfs-$VERSION-staging`
|
|
||||||
|
|
||||||
`$VERSION` should be replaced with the `major.minor` version number.
|
|
||||||
_(This is the version number without the `.patch` version at the end)_
|
|
||||||
|
|
||||||
### Coding Conventions
|
### Coding Conventions
|
||||||
We currently use [C Style and Coding Standards for
|
We currently use [C Style and Coding Standards for
|
||||||
SunOS](http://www.cis.upenn.edu/%7Elee/06cse480/data/cstyle.ms.pdf) as our
|
SunOS](http://www.cis.upenn.edu/%7Elee/06cse480/data/cstyle.ms.pdf) as our
|
||||||
coding convention.
|
coding convention.
|
||||||
|
|
||||||
This repository has an `.editorconfig` file. If your editor [supports
|
|
||||||
editorconfig](https://editorconfig.org/#download), it will
|
|
||||||
automatically respect most of this project's whitespace preferences.
|
|
||||||
|
|
||||||
Additionally, Git can help warn on whitespace problems as well:
|
|
||||||
|
|
||||||
```
|
|
||||||
git config --local core.whitespace trailing-space,space-before-tab,indent-with-non-tab,-tab-in-indent
|
|
||||||
```
|
|
||||||
|
|
||||||
### Commit Message Formats
|
### Commit Message Formats
|
||||||
#### New Changes
|
#### New Changes
|
||||||
Commit messages for new changes must meet the following guidelines:
|
Commit messages for new changes must meet the following guidelines:
|
||||||
@@ -210,10 +167,18 @@ first line in the commit message.
|
|||||||
please summarize important information such as why the proposed
|
please summarize important information such as why the proposed
|
||||||
approach was chosen or a brief description of the bug you are resolving.
|
approach was chosen or a brief description of the bug you are resolving.
|
||||||
Each line of the body must be 72 characters or less.
|
Each line of the body must be 72 characters or less.
|
||||||
* The last line must be a `Signed-off-by:` tag. See the
|
* The last line must be a `Signed-off-by:` tag with the developer's
|
||||||
[Signed Off By](#signed-off-by) section for more information.
|
name followed by their email. This is the developer's certification
|
||||||
|
that they have the right to submit the patch for inclusion into
|
||||||
|
the code base and indicates agreement to the [Developer's Certificate
|
||||||
|
of Origin](https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin).
|
||||||
|
Code without a proper signoff cannot be merged.
|
||||||
|
|
||||||
An example commit message for new changes is provided below.
|
Git can append the `Signed-off-by` line to your commit messages. Simply
|
||||||
|
provide the `-s` or `--signoff` option when performing a `git commit`.
|
||||||
|
For more information about writing commit messages, visit [How to Write
|
||||||
|
a Git Commit Message](https://chris.beams.io/posts/git-commit/).
|
||||||
|
An example commit message is provided below.
|
||||||
|
|
||||||
```
|
```
|
||||||
This line is a brief summary of your change
|
This line is a brief summary of your change
|
||||||
@@ -226,52 +191,35 @@ attempting to solve.
|
|||||||
Signed-off-by: Contributor <contributor@email.com>
|
Signed-off-by: Contributor <contributor@email.com>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Coverity Defect Fixes
|
#### OpenZFS Patch Ports
|
||||||
If you are submitting a fix to a
|
If you are porting an OpenZFS patch, the commit message must meet
|
||||||
[Coverity defect](https://scan.coverity.com/projects/zfsonlinux-zfs),
|
the following guidelines:
|
||||||
the commit message should meet the following guidelines:
|
* The first line must be the summary line from the OpenZFS commit.
|
||||||
* Provides a subject line in the format of
|
It must begin with `OpenZFS dddd - ` where `dddd` is the OpenZFS issue number.
|
||||||
`Fix coverity defects: CID dddd, dddd...` where `dddd` represents
|
* Provides a `Authored by:` line to attribute the patch to the original author.
|
||||||
each CID fixed by the commit.
|
* Provides the `Reviewed by:` and `Approved by:` lines from the original
|
||||||
* Provides a body which lists each Coverity defect and how it was corrected.
|
OpenZFS commit.
|
||||||
* The last line must be a `Signed-off-by:` tag. See the
|
* Provides a `Ported-by:` line with the developer's name followed by
|
||||||
[Signed Off By](#signed-off-by) section for more information.
|
their email.
|
||||||
|
* Provides a `OpenZFS-issue:` line which is a link to the original illumos
|
||||||
|
issue.
|
||||||
|
* Provides a `OpenZFS-commit:` line which links back to the original OpenZFS
|
||||||
|
commit.
|
||||||
|
* If necessary, provide some porting notes to describe any deviations from
|
||||||
|
the original OpenZFS commit.
|
||||||
|
|
||||||
An example Coverity defect fix commit message is provided below.
|
An example OpenZFS patch port commit message is provided below.
|
||||||
```
|
```
|
||||||
Fix coverity defects: CID 12345, 67890
|
OpenZFS 1234 - Summary from the original OpenZFS commit
|
||||||
|
|
||||||
CID 12345: Logically dead code (DEADCODE)
|
Authored by: Original Author <original@email.com>
|
||||||
|
Reviewed by: Reviewer One <reviewer1@email.com>
|
||||||
|
Reviewed by: Reviewer Two <reviewer2@email.com>
|
||||||
|
Approved by: Approver One <approver1@email.com>
|
||||||
|
Ported-by: ZFS Contributor <contributor@email.com>
|
||||||
|
|
||||||
Removed the if(var != 0) block because the condition could never be
|
Provide some porting notes here if necessary.
|
||||||
satisfied.
|
|
||||||
|
|
||||||
CID 67890: Resource Leak (RESOURCE_LEAK)
|
OpenZFS-issue: https://www.illumos.org/issues/1234
|
||||||
|
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/abcd1234
|
||||||
Ensure free is called after allocating memory in function().
|
|
||||||
|
|
||||||
Signed-off-by: Contributor <contributor@email.com>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Signed Off By
|
|
||||||
A line tagged as `Signed-off-by:` must contain the developer's
|
|
||||||
name followed by their email. This is the developer's certification
|
|
||||||
that they have the right to submit the patch for inclusion into
|
|
||||||
the code base and indicates agreement to the [Developer's Certificate
|
|
||||||
of Origin](https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin).
|
|
||||||
Code without a proper signoff cannot be merged.
|
|
||||||
|
|
||||||
Git can append the `Signed-off-by` line to your commit messages. Simply
|
|
||||||
provide the `-s` or `--signoff` option when performing a `git commit`.
|
|
||||||
For more information about writing commit messages, visit [How to Write
|
|
||||||
a Git Commit Message](https://chris.beams.io/posts/git-commit/).
|
|
||||||
|
|
||||||
#### Co-authored By
|
|
||||||
If someone else had part in your pull request, please add the following to the commit:
|
|
||||||
`Co-authored-by: Name <gitregistered@email.address>`
|
|
||||||
This is useful if their authorship was lost during squashing, rebasing, etc.,
|
|
||||||
but may be used in any situation where there are co-authors.
|
|
||||||
|
|
||||||
The email address used here should be the same as on the GitHub profile of said user.
|
|
||||||
If said user does not have their email address public, please use the following instead:
|
|
||||||
`Co-authored-by: Name <[username]@users.noreply.github.com>`
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<!--
|
||||||
|
Thank you for reporting an issue.
|
||||||
|
|
||||||
|
*IMPORTANT* - Please search our issue tracker *before* making a new issue.
|
||||||
|
If you cannot find a similar issue, then create a new issue.
|
||||||
|
https://github.com/zfsonlinux/zfs/issues
|
||||||
|
|
||||||
|
*IMPORTANT* - This issue tracker is for *bugs* and *issues* only.
|
||||||
|
Please search the wiki and the mailing list archives before asking
|
||||||
|
questions on the mailing list.
|
||||||
|
https://github.com/zfsonlinux/zfs/wiki/Mailing-Lists
|
||||||
|
|
||||||
|
Please fill in as much of the template as possible.
|
||||||
|
-->
|
||||||
|
|
||||||
|
### System information
|
||||||
|
<!-- add version after "|" character -->
|
||||||
|
Type | Version/Name
|
||||||
|
--- | ---
|
||||||
|
Distribution Name |
|
||||||
|
Distribution Version |
|
||||||
|
Linux Kernel |
|
||||||
|
Architecture |
|
||||||
|
ZFS Version |
|
||||||
|
SPL Version |
|
||||||
|
<!--
|
||||||
|
Commands to find ZFS/SPL versions:
|
||||||
|
modinfo zfs | grep -iw version
|
||||||
|
modinfo spl | grep -iw version
|
||||||
|
-->
|
||||||
|
|
||||||
|
### Describe the problem you're observing
|
||||||
|
|
||||||
|
### Describe how to reproduce the problem
|
||||||
|
|
||||||
|
### Include any warning/errors/backtraces from the system logs
|
||||||
|
<!--
|
||||||
|
*IMPORTANT* - Please mark logs and text output from terminal commands
|
||||||
|
or else Github will not display them correctly.
|
||||||
|
An example is provided below.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
this is an example how log text should be marked (wrap it with ```)
|
||||||
|
```
|
||||||
|
-->
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve OpenZFS
|
|
||||||
title: ''
|
|
||||||
labels: 'Type: Defect'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- Please fill out the following template, which will help other contributors address your issue. -->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Thank you for reporting an issue.
|
|
||||||
|
|
||||||
*IMPORTANT* - Please check our issue tracker before opening a new issue.
|
|
||||||
Additional valuable information can be found in the OpenZFS documentation
|
|
||||||
and mailing list archives.
|
|
||||||
|
|
||||||
Please fill in as much of the template as possible.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### System information
|
|
||||||
<!-- add version after "|" character -->
|
|
||||||
Type | Version/Name
|
|
||||||
--- | ---
|
|
||||||
Distribution Name |
|
|
||||||
Distribution Version |
|
|
||||||
Kernel Version |
|
|
||||||
Architecture |
|
|
||||||
OpenZFS Version |
|
|
||||||
<!--
|
|
||||||
Command to find OpenZFS version:
|
|
||||||
zfs version
|
|
||||||
|
|
||||||
Commands to find kernel version:
|
|
||||||
uname -r # Linux
|
|
||||||
freebsd-version -r # FreeBSD
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Describe the problem you're observing
|
|
||||||
|
|
||||||
### Describe how to reproduce the problem
|
|
||||||
|
|
||||||
### Include any warning/errors/backtraces from the system logs
|
|
||||||
<!--
|
|
||||||
*IMPORTANT* - Please mark logs and text output from terminal commands
|
|
||||||
or else Github will not display them correctly.
|
|
||||||
An example is provided below.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```
|
|
||||||
this is an example how log text should be marked (wrap it with ```)
|
|
||||||
```
|
|
||||||
-->
|
|
||||||
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
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
|
|
||||||
- name: FreeBSD Community Support Mailing list
|
|
||||||
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
|
|
||||||
about: Use IRC to get community support for OpenZFS
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest a feature for OpenZFS
|
|
||||||
title: ''
|
|
||||||
labels: 'Type: Feature'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Thank you for suggesting a feature.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Provide a clear and concise description of the feature.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### How will this feature improve OpenZFS?
|
|
||||||
|
|
||||||
<!--
|
|
||||||
What problem does this feature solve?
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Additional context
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Any additional information you can add about the proposal?
|
|
||||||
-->
|
|
||||||
@@ -1,20 +1,22 @@
|
|||||||
<!--- Please fill out the following template, which will help other contributors review your Pull Request. -->
|
|
||||||
|
|
||||||
<!--- Provide a general summary of your changes in the Title above -->
|
<!--- Provide a general summary of your changes in the Title above -->
|
||||||
|
|
||||||
|
<!---
|
||||||
|
Documentation on ZFS Buildbot options can be found at
|
||||||
|
https://github.com/zfsonlinux/zfs/wiki/Buildbot-Options
|
||||||
|
-->
|
||||||
|
|
||||||
|
### Description
|
||||||
|
<!--- Describe your changes in detail -->
|
||||||
|
|
||||||
### Motivation and Context
|
### Motivation and Context
|
||||||
<!--- Why is this change required? What problem does it solve? -->
|
<!--- Why is this change required? What problem does it solve? -->
|
||||||
<!--- If it fixes an open issue, please link to the issue here. -->
|
<!--- If it fixes an open issue, please link to the issue here. -->
|
||||||
|
|
||||||
### Description
|
|
||||||
<!--- Describe your changes in detail -->
|
|
||||||
|
|
||||||
### How Has This Been Tested?
|
### How Has This Been Tested?
|
||||||
<!--- Please describe in detail how you tested your changes. -->
|
<!--- Please describe in detail how you tested your changes. -->
|
||||||
<!--- Include details of your testing environment, and the tests you ran to -->
|
<!--- Include details of your testing environment, and the tests you ran to -->
|
||||||
<!--- see how your change affects other areas of the code, etc. -->
|
<!--- see how your change affects other areas of the code, etc. -->
|
||||||
<!--- If your change is a performance enhancement, please provide benchmarks here. -->
|
<!--- If your change is a performance enhancement, please provide benchmarks here. -->
|
||||||
<!--- Please think about using the draft PR feature if appropriate -->
|
|
||||||
|
|
||||||
### Types of changes
|
### Types of changes
|
||||||
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
||||||
@@ -22,17 +24,16 @@
|
|||||||
- [ ] New feature (non-breaking change which adds functionality)
|
- [ ] New feature (non-breaking change which adds functionality)
|
||||||
- [ ] Performance enhancement (non-breaking change which improves efficiency)
|
- [ ] Performance enhancement (non-breaking change which improves efficiency)
|
||||||
- [ ] Code cleanup (non-breaking change which makes code smaller or more readable)
|
- [ ] 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)
|
- [ ] 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)
|
- [ ] Documentation (a change to man pages or other documentation)
|
||||||
|
|
||||||
### Checklist:
|
### Checklist:
|
||||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
<!--- 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! -->
|
<!--- 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.
|
||||||
- [ ] I have updated the documentation accordingly.
|
- [ ] I have updated the documentation accordingly.
|
||||||
- [ ] I have read the [**contributing** document](https://github.com/openzfs/zfs/blob/master/.github/CONTRIBUTING.md).
|
- [ ] I have read the **CONTRIBUTING** document.
|
||||||
- [ ] I have added [tests](https://github.com/openzfs/zfs/tree/master/tests) to cover my changes.
|
- [ ] I have added tests to cover my changes.
|
||||||
- [ ] I have run the ZFS Test Suite with this change applied.
|
- [ ] All new and existing tests passed.
|
||||||
- [ ] 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`.
|
||||||
|
- [ ] Change has been approved by a ZFS on Linux member.
|
||||||
|
|||||||
+17
-12
@@ -1,25 +1,30 @@
|
|||||||
codecov:
|
codecov:
|
||||||
notify:
|
notify:
|
||||||
require_ci_to_pass: false # always post
|
require_ci_to_pass: no
|
||||||
after_n_builds: 2 # user and kernel
|
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
precision: 0 # 0 decimals of precision
|
precision: 2
|
||||||
round: nearest # Round to nearest precision point
|
round: down
|
||||||
range: "50...90" # red -> yellow -> green
|
range: "50...100"
|
||||||
|
|
||||||
status:
|
status:
|
||||||
project:
|
project:
|
||||||
default:
|
default:
|
||||||
threshold: 1% # allow 1% coverage variance
|
threshold: 1%
|
||||||
|
|
||||||
patch:
|
patch:
|
||||||
default:
|
default:
|
||||||
threshold: 1% # allow 1% coverage variance
|
threshold: 1%
|
||||||
|
|
||||||
|
parsers:
|
||||||
|
gcov:
|
||||||
|
branch_detection:
|
||||||
|
conditional: yes
|
||||||
|
loop: yes
|
||||||
|
method: no
|
||||||
|
macro: no
|
||||||
|
|
||||||
comment:
|
comment:
|
||||||
layout: "reach, diff, flags, footer"
|
layout: "header, sunburst, diff"
|
||||||
behavior: once # update if exists; post new; skip if deleted
|
behavior: default
|
||||||
require_changes: yes # only post when coverage changes
|
require_changes: no
|
||||||
|
|
||||||
# ignore: Please place any ignores in config/ax_code_coverage.m4 instead
|
|
||||||
|
|||||||
@@ -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,26 +0,0 @@
|
|||||||
# Number of days of inactivity before an issue becomes stale
|
|
||||||
daysUntilStale: 365
|
|
||||||
# Number of days of inactivity before a stale issue is closed
|
|
||||||
daysUntilClose: 90
|
|
||||||
# Limit to only `issues` or `pulls`
|
|
||||||
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
|
|
||||||
# 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
|
|
||||||
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
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
preprocessorErrorDirective:./module/zfs/vdev_raidz_math_avx512f.c:243
|
||||||
|
preprocessorErrorDirective:./module/zfs/vdev_raidz_math_sse2.c:266
|
||||||
|
|
||||||
@@ -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.
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
name: checkstyle
|
|
||||||
|
|
||||||
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
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
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
|
|
||||||
- name: Prepare
|
|
||||||
run: |
|
|
||||||
sed -i '/DEBUG_CFLAGS="-Werror"/s/^/#/' config/zfs-build.m4
|
|
||||||
./autogen.sh
|
|
||||||
- name: Configure
|
|
||||||
run: |
|
|
||||||
./configure
|
|
||||||
- name: Make
|
|
||||||
run: |
|
|
||||||
make -j$(nproc) --no-print-directory --silent
|
|
||||||
- name: Checkstyle
|
|
||||||
run: |
|
|
||||||
make -j$(nproc) --no-print-directory --silent checkstyle
|
|
||||||
- name: Lint
|
|
||||||
run: |
|
|
||||||
make -j$(nproc) --no-print-directory --silent 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 -cjf abi_files.tar.bz2 -T -
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
if: failure() && steps.CheckABI.outcome == 'failure'
|
|
||||||
with:
|
|
||||||
name: New ABI files (use only if you're sure about interface changes)
|
|
||||||
path: abi_files.tar.bz2
|
|
||||||
archive: false
|
|
||||||
@@ -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@v6
|
|
||||||
|
|
||||||
- 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,121 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
"""
|
|
||||||
Determine the CI type based on the change list and commit message.
|
|
||||||
|
|
||||||
Output format: "<type> <source>" where source is "manual" (from
|
|
||||||
ZFS-CI-Type commit tag) or "auto" (from file change heuristics).
|
|
||||||
|
|
||||||
Prints "quick manual" if:
|
|
||||||
- the *last* commit message contains 'ZFS-CI-Type: quick'
|
|
||||||
or "quick auto" 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 auto" (or "<type> manual" if explicitly requested).
|
|
||||||
"""
|
|
||||||
|
|
||||||
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, source, reason):
|
|
||||||
print(f'{prog}: will run {type} CI ({source}): {reason}',
|
|
||||||
file=sys.stderr)
|
|
||||||
print(f'{type} {source}')
|
|
||||||
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', 'manual',
|
|
||||||
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', 'manual',
|
|
||||||
f'requested by commit {commit_ref}')
|
|
||||||
if line.strip().lower() == 'zfs-ci-type: linux':
|
|
||||||
output_type('linux', 'manual',
|
|
||||||
f'requested by commit {commit_ref}')
|
|
||||||
if line.strip().lower() == 'zfs-ci-type: full':
|
|
||||||
output_type('full', 'manual',
|
|
||||||
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', 'auto',
|
|
||||||
f'changed file "{f}" matches pattern "{r.pattern}"'
|
|
||||||
)
|
|
||||||
|
|
||||||
# catch-all
|
|
||||||
output_type('quick', 'auto',
|
|
||||||
'no changed file matches full CI patterns')
|
|
||||||
@@ -1,147 +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
|
|
||||||
killed=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}}
|
|
||||||
|
|
||||||
# If the test was killed, you'll get a line like:
|
|
||||||
#
|
|
||||||
# [2026-04-22T03:34:17.694616] Test (Linux): /usr/share/zfs/zfs-tests/tests/functional/io/setup (run as root) [10:00] [KILLED]
|
|
||||||
#
|
|
||||||
# Parse out the test name minus the /usr/share/zfs/zfs-tests/tests/functional/'
|
|
||||||
# part, and include the optional "(Linux): " line, as you can have the killed
|
|
||||||
# tests in two categories, like:
|
|
||||||
#
|
|
||||||
# KILLED (Linux): io/setup
|
|
||||||
# KILLED io/setup
|
|
||||||
#
|
|
||||||
/KILLED/{
|
|
||||||
extra=""
|
|
||||||
for(i=1; i<=NF; i++) {
|
|
||||||
# Look for optional "(Linux):" field
|
|
||||||
if ($i ~ "\\("){
|
|
||||||
extra=$i" "}
|
|
||||||
|
|
||||||
# Look for a field with a '/' in it. It is the test name.
|
|
||||||
if($i ~ "/") {
|
|
||||||
testname=$i
|
|
||||||
# Remove /usr/share/zfs/zfs-test/test/functional string
|
|
||||||
sub(/\/usr\/share\/zfs\/zfs-tests\/tests\/functional\//,"",testname)
|
|
||||||
testname=extra""testname
|
|
||||||
killed_tests[killed] = testname
|
|
||||||
killed++
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/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]
|
|
||||||
|
|
||||||
# We don't want to sort killed tests, as the first test that was killed
|
|
||||||
# most likely caused the others to be killed.
|
|
||||||
print "\n\nTests that were killed:"
|
|
||||||
for (j in killed_tests)
|
|
||||||
print " KILLED "killed_tests[j]
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# 1) setup qemu instance on action runner
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
# The default runner has a bunch of development tools and other things
|
|
||||||
# that we do not need. Remove them here to free up a total of 35GB.
|
|
||||||
#
|
|
||||||
# First remove packages - this frees up ~10GB
|
|
||||||
echo "Disk space before purge:"
|
|
||||||
df -h /
|
|
||||||
sudo docker image prune --all --force
|
|
||||||
sudo docker builder prune -a
|
|
||||||
unneeded="microsoft-edge-stable|azure-cli|google-cloud|google-chrome-stable|"\
|
|
||||||
"temurin|llvm|firefox|mysql-server|snapd|android|dotnet|haskell|ghcup|"\
|
|
||||||
"powershell|julia|swift|miniconda|chromium"
|
|
||||||
sudo apt-get -y remove $(dpkg-query -f '${binary:Package}\n' -W | grep -E "'$unneeded'")
|
|
||||||
sudo apt-get -y autoremove
|
|
||||||
|
|
||||||
# Next, remove unneeded files in /usr. This frees up an additional 25GB.
|
|
||||||
sudo rm -fr /usr/local/lib/android /usr/share/dotnet /usr/local/.ghcup \
|
|
||||||
/usr/share/swift /usr/local/share/powershell /usr/local/julia* \
|
|
||||||
/usr/share/miniconda /usr/local/share/chromium
|
|
||||||
echo "Disk space after:"
|
|
||||||
df -h /
|
|
||||||
|
|
||||||
# The default 'azure.archive.ubuntu.com' mirrors can be really slow.
|
|
||||||
# Prioritize the official Ubuntu mirrors.
|
|
||||||
#
|
|
||||||
# The normal apt-mirrors.txt will look like:
|
|
||||||
#
|
|
||||||
# http://azure.archive.ubuntu.com/ubuntu/ priority:1
|
|
||||||
# https://archive.ubuntu.com/ubuntu/ priority:2
|
|
||||||
# https://security.ubuntu.com/ubuntu/ priority:3
|
|
||||||
#
|
|
||||||
# Just delete the 'azure.archive.ubuntu.com' line.
|
|
||||||
sudo sed -i '/azure.archive.ubuntu.com/d' /etc/apt/apt-mirrors.txt
|
|
||||||
echo "Using mirrors:"
|
|
||||||
cat /etc/apt/apt-mirrors.txt
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
sudo swapoff -a
|
|
||||||
|
|
||||||
# Special case:
|
|
||||||
#
|
|
||||||
# For reasons unknown, the runner can boot-up with two different block device
|
|
||||||
# configurations. On one config you get two 75GB block devices, and on the
|
|
||||||
# other you get a single 150GB block device. Here's what both look like:
|
|
||||||
#
|
|
||||||
# --- One 150GB block device ---
|
|
||||||
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
|
||||||
# sda 8:0 0 150G 0 disk
|
|
||||||
# ├─sda1 8:1 0 149G 0 part /
|
|
||||||
# ├─sda14 8:14 0 4M 0 part
|
|
||||||
# ├─sda15 8:15 0 106M 0 part /boot/efi
|
|
||||||
# └─sda16 259:0 0 913M 0 part /boot
|
|
||||||
#
|
|
||||||
# lrwxrwxrwx 1 root root 9 Jan 29 18:07 azure_root -> ../../sda
|
|
||||||
# lrwxrwxrwx 1 root root 10 Jan 29 18:07 azure_root-part1 -> ../../sda1
|
|
||||||
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part14 -> ../../sda14
|
|
||||||
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part15 -> ../../sda15
|
|
||||||
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part16 -> ../../sda16
|
|
||||||
#
|
|
||||||
# --- Two 75GB block devices ---
|
|
||||||
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
|
||||||
# sda 8:0 0 75G 0 disk
|
|
||||||
# ├─sda1 8:1 0 74G 0 part /
|
|
||||||
# ├─sda14 8:14 0 4M 0 part
|
|
||||||
# ├─sda15 8:15 0 106M 0 part /boot/efi
|
|
||||||
# └─sda16 259:0 0 913M 0 part /boot
|
|
||||||
# sdb 8:16 0 75G 0 disk
|
|
||||||
# └─sdb1 8:17 0 75G 0 part
|
|
||||||
#
|
|
||||||
# lrwxrwxrwx 1 root root 9 Jan 29 18:07 azure_resource -> ../../sdb
|
|
||||||
# lrwxrwxrwx 1 root root 10 Jan 29 18:07 azure_resource-part1 -> ../../sdb1
|
|
||||||
# lrwxrwxrwx 1 root root 9 Jan 29 18:07 azure_root -> ../../sda
|
|
||||||
# lrwxrwxrwx 1 root root 10 Jan 29 18:07 azure_root-part1 -> ../../sda1
|
|
||||||
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part14 -> ../../sda14
|
|
||||||
# lrwxrwxrwx 1 root root 11 Jan 29 18:07 azure_root-part15 -> ../../sda15
|
|
||||||
#
|
|
||||||
# If we have the azure_resource-part1 partition, umount it, partition it, and
|
|
||||||
# use it as our ZFS disk and swap partition. If not, just create a file VDEV
|
|
||||||
# and swap file and use that instead.
|
|
||||||
|
|
||||||
# remove default swapfile and /mnt
|
|
||||||
if [ -e /dev/disk/cloud/azure_resource-part1 ] ; then
|
|
||||||
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
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo modprobe loop
|
|
||||||
sudo modprobe zfs
|
|
||||||
|
|
||||||
if [ -e /dev/disk/cloud/azure_resource-part1 ] ; then
|
|
||||||
echo "We have two 75GB block devices"
|
|
||||||
# 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
|
|
||||||
|
|
||||||
sudo fallocate -l 12G /test.ssd2
|
|
||||||
DISKS="$DISK-part2 /test.ssd2"
|
|
||||||
|
|
||||||
SWAP=$DISK-part1
|
|
||||||
else
|
|
||||||
echo "We have a single 150GB block device"
|
|
||||||
sudo fallocate -l 72G /test.ssd2
|
|
||||||
SWAP=/swapfile.ssd
|
|
||||||
sudo fallocate -l 16G $SWAP
|
|
||||||
sudo chmod 600 $SWAP
|
|
||||||
DISKS="/test.ssd2"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# swap with same size as RAM (16GiB)
|
|
||||||
sudo mkswap $SWAP
|
|
||||||
sudo swapon $SWAP
|
|
||||||
|
|
||||||
echo "Block devices:"
|
|
||||||
lsblk
|
|
||||||
|
|
||||||
# adjust zfs module parameter and create pool
|
|
||||||
ARC_MIN=$((1024*1024*256))
|
|
||||||
ARC_MAX=$((1024*1024*512))
|
|
||||||
echo $ARC_MIN | sudo tee /sys/module/zfs/parameters/zfs_arc_min >/dev/null
|
|
||||||
echo $ARC_MAX | sudo tee /sys/module/zfs/parameters/zfs_arc_max >/dev/null
|
|
||||||
echo 1 | sudo tee /sys/module/zfs/parameters/zvol_use_blk_mq >/dev/null
|
|
||||||
sudo zpool create -f -o ashift=12 zpool $DISKS -O relatime=off \
|
|
||||||
-O atime=off -O xattr=sa -O compression=lz4 -O sync=disabled \
|
|
||||||
-O redundant_metadata=none -O mountpoint=/mnt/tests
|
|
||||||
echo "Status:"
|
|
||||||
zpool status
|
|
||||||
|
|
||||||
echo "Last dmesg:"
|
|
||||||
sudo dmesg | tail -n 10
|
|
||||||
@@ -1,380 +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"
|
|
||||||
;;
|
|
||||||
alpine3-23)
|
|
||||||
OSNAME="Alpine Linux 3.23.2"
|
|
||||||
# Alpine Linux v3.22 and v3.23 are unknown to osinfo as of 2025-12-26.
|
|
||||||
OSv="alpinelinux3.21"
|
|
||||||
URL="https://dl-cdn.alpinelinux.org/alpine/v3.23/releases/cloud/generic_alpine-3.23.2-x86_64-bios-cloudinit-r0.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"
|
|
||||||
;;
|
|
||||||
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"
|
|
||||||
;;
|
|
||||||
fedora44)
|
|
||||||
OSNAME="Fedora 44"
|
|
||||||
OSv="fedora-unknown"
|
|
||||||
URL="https://download.fedoraproject.org/pub/fedora/linux/releases/44/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-44-1.7.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-4r)
|
|
||||||
FreeBSD="14.4-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"
|
|
||||||
;;
|
|
||||||
freebsd15-0r)
|
|
||||||
FreeBSD="15.0-RELEASE"
|
|
||||||
OSNAME="FreeBSD $FreeBSD"
|
|
||||||
OSv="freebsd15.0"
|
|
||||||
URLxz="$FREEBSD_REL/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.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-4s)
|
|
||||||
FreeBSD="14.4-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-1s)
|
|
||||||
FreeBSD="15.1-PRERELEASE"
|
|
||||||
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 first try to download with 'axel', which is faster than curl, but fallback
|
|
||||||
# to curl if that doesn't work. It is hoped that the curl fallback will get
|
|
||||||
# around the occasional "ERROR 502: Bad Gateway" errors.
|
|
||||||
IMG="/mnt/tests/cloud-image"
|
|
||||||
for cmd in 'axel -q -o' 'curl --fail -LSs -o' ; do
|
|
||||||
if [ ! -z "$URLxz" ]; then
|
|
||||||
echo "Loading $URLxz with $cmd..."
|
|
||||||
time eval "$cmd $IMG $URLxz" || true
|
|
||||||
|
|
||||||
if [ ! -s ~/src.txz ] ; then
|
|
||||||
echo "Loading $KSRC with $cmd..."
|
|
||||||
time eval "$cmd ~/src.txz $KSRC" || true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "Loading $URL with $cmd..."
|
|
||||||
time eval "$cmd $IMG $URL" || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -s "$IMG" ] ; then
|
|
||||||
# Successful download
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# SPECIAL CASE
|
|
||||||
# FreeBSD sometimes has broken links in their "current/" URL. Go back up a
|
|
||||||
# level and look for other images that might work. For example:
|
|
||||||
#
|
|
||||||
# https://download.freebsd.org/snapshots/CI-IMAGES/16.0-CURRENT/amd64/:
|
|
||||||
#
|
|
||||||
# 20251110/
|
|
||||||
# 20251209/
|
|
||||||
# 20260420/
|
|
||||||
# current/
|
|
||||||
#
|
|
||||||
# In this case let's say the raw.xz link in current/ is bad, so look though the
|
|
||||||
# other snapshot links for the newest existing raw.xz file.
|
|
||||||
if [ ! -z "$URLxz" ] && [ ! -s "$IMG" ] ; then
|
|
||||||
URLxz=$(wget --accept "*.raw.xz" --spider -np --recursive --no-verbose \
|
|
||||||
$(dirname $(dirname $URLxz)) 2>&1 | awk '/200 OK/{print $(NF-2)}' | \
|
|
||||||
sort -n | tail -n 1)
|
|
||||||
echo "Couldn't download FreeBSD raw.xz. Trying fallback snapshot $URLxz"
|
|
||||||
curl --fail -LSs -o $IMG $URLxz
|
|
||||||
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: /bin/bash
|
|
||||||
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
|
||||||
- name: zfs
|
|
||||||
shell: /bin/bash
|
|
||||||
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
|
||||||
ssh_authorized_keys:
|
|
||||||
- $PUBKEY
|
|
||||||
# Workaround for Alpine Linux.
|
|
||||||
lock_passwd: false
|
|
||||||
passwd: '*'
|
|
||||||
|
|
||||||
packages:
|
|
||||||
- sudo
|
|
||||||
- bash
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
#
|
|
||||||
# Config for Alpine Linux similar to FreeBSD.
|
|
||||||
#
|
|
||||||
if [ ${OS:0:6} == "alpine" ]; then
|
|
||||||
while pidof /usr/bin/qemu-system-x86_64 >/dev/null; do
|
|
||||||
ssh 2>/dev/null zfs@vm0 "uname -a" && break
|
|
||||||
done
|
|
||||||
# Enable community and testing repositories.
|
|
||||||
ssh zfs@vm0 "sudo rm -rf /etc/apk/repositories"
|
|
||||||
ssh zfs@vm0 "sudo setup-apkrepos -c1"
|
|
||||||
ssh zfs@vm0 "echo '@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing' | sudo tee -a /etc/apk/repositories"
|
|
||||||
# Upgrade to edge or latest-stable.
|
|
||||||
#ssh zfs@vm0 "sudo sed -i 's#/v[0-9]\+\.[0-9]\+/#/edge/#g' /etc/apk/repositories"
|
|
||||||
#ssh zfs@vm0 "sudo sed -i 's#/v[0-9]\+\.[0-9]\+/#/latest-stable/#g' /etc/apk/repositories"
|
|
||||||
# Update and upgrade after repository setup.
|
|
||||||
ssh zfs@vm0 "sudo apk update"
|
|
||||||
ssh zfs@vm0 "sudo apk add --upgrade apk-tools"
|
|
||||||
ssh zfs@vm0 "sudo apk upgrade --available"
|
|
||||||
fi
|
|
||||||
@@ -1,326 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# 3) install dependencies for compiling and loading
|
|
||||||
#
|
|
||||||
# qemu-3-deps-vm.sh [--poweroff] OS_NAME [FEDORA_VERSION]
|
|
||||||
#
|
|
||||||
# --poweroff: Power off the VM after installing dependencies
|
|
||||||
# OS_NAME: OS name (like 'fedora41')
|
|
||||||
# FEDORA_VERSION: (optional) Experimental Fedora kernel version, like "6.14" to
|
|
||||||
# install instead of Fedora defaults.
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
function alpine() {
|
|
||||||
echo "##[group]Install Development Tools"
|
|
||||||
sudo apk add \
|
|
||||||
acl alpine-sdk attr autoconf automake bash build-base clang21 coreutils \
|
|
||||||
cpio cryptsetup curl curl-dev dhcpcd eudev eudev-dev eudev-libs findutils \
|
|
||||||
fio gawk gdb gettext-dev git grep jq libaio libaio-dev libcurl \
|
|
||||||
libtirpc-dev libtool libunwind libunwind-dev linux-headers linux-tools \
|
|
||||||
linux-virt linux-virt-dev lsscsi m4 make nfs-utils openssl-dev parted \
|
|
||||||
pax procps py3-cffi py3-distlib py3-packaging py3-setuptools python3 \
|
|
||||||
python3-dev qemu-guest-agent rng-tools rsync samba samba-server sed \
|
|
||||||
strace sysstat util-linux util-linux-dev wget words xfsprogs xxhash \
|
|
||||||
zlib-dev pamtester@testing
|
|
||||||
echo "##[endgroup]"
|
|
||||||
|
|
||||||
echo "##[group]Switch to eudev"
|
|
||||||
sudo setup-devd udev
|
|
||||||
echo "##[endgroup]"
|
|
||||||
|
|
||||||
echo "##[group]Install ksh93 from Source"
|
|
||||||
git clone --depth 1 https://github.com/ksh93/ksh.git /tmp/ksh
|
|
||||||
cd /tmp/ksh
|
|
||||||
./bin/package make
|
|
||||||
sudo ./bin/package install /
|
|
||||||
echo "##[endgroup]"
|
|
||||||
}
|
|
||||||
|
|
||||||
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]Wait for cloud-init to finish"
|
|
||||||
cloud-init status --wait
|
|
||||||
echo "##[endgroup]"
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# These are needed for building Lustre. We only install these on EL VMs since
|
|
||||||
# we don't plan to test build Lustre on other platforms.
|
|
||||||
sudo dnf install -y libnl3-devel libyaml-devel libmount-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
|
|
||||||
}
|
|
||||||
|
|
||||||
POWEROFF=""
|
|
||||||
if [ "$1" == "--poweroff" ] ; then
|
|
||||||
POWEROFF=1
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 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]"
|
|
||||||
;;
|
|
||||||
alpine*)
|
|
||||||
alpine
|
|
||||||
;;
|
|
||||||
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
|
|
||||||
|
|
||||||
# Need 'build-essential' explicitly for ARM builder
|
|
||||||
# https://github.com/actions/runner-images/issues/9946
|
|
||||||
sudo apt-get install -yq build-essential
|
|
||||||
|
|
||||||
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
|
|
||||||
alpine*)
|
|
||||||
sudo -E rc-update add qemu-guest-agent
|
|
||||||
sudo -E rc-update add nfs
|
|
||||||
sudo -E rc-update add samba
|
|
||||||
sudo -E rc-update add dhcpcd
|
|
||||||
# Remove services related to cloud-init.
|
|
||||||
sudo -E rc-update del cloud-init default
|
|
||||||
sudo -E rc-update del cloud-final default
|
|
||||||
sudo -E rc-update del cloud-config default
|
|
||||||
;;
|
|
||||||
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
|
|
||||||
alpine*|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
|
|
||||||
if [ "$POWEROFF" == "1" ] ; then
|
|
||||||
sleep 2 && sudo poweroff &
|
|
||||||
fi
|
|
||||||
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,405 +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$(nproc)
|
|
||||||
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
|
|
||||||
|
|
||||||
# Check if we're running this script from within a VM or on the runner itself.
|
|
||||||
# Most of the time we will be running in a VM, but the ARM builder actually
|
|
||||||
# runs this script on the runner. If we happen to be running on the ARM
|
|
||||||
# runner, we will start in the ZFS source directory. If we're running on a VM
|
|
||||||
# then we'll just start in our home directory, and will need to 'cd' into our
|
|
||||||
# source directory.
|
|
||||||
if [ ! -e META ] ; then
|
|
||||||
cd $HOME/zfs
|
|
||||||
fi
|
|
||||||
|
|
||||||
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,145 +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: /bin/bash
|
|
||||||
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
|
||||||
- name: zfs
|
|
||||||
shell: /bin/bash
|
|
||||||
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
|
||||||
ssh_authorized_keys:
|
|
||||||
- $PUBKEY
|
|
||||||
# Workaround for Alpine Linux.
|
|
||||||
lock_passwd: false
|
|
||||||
passwd: '*'
|
|
||||||
|
|
||||||
packages:
|
|
||||||
- sudo
|
|
||||||
- bash
|
|
||||||
|
|
||||||
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,51 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# 6) Test if Lustre can still build against ZFS
|
|
||||||
######################################################################
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Build from the latest Lustre tag rather than the master branch. We do this
|
|
||||||
# under the assumption that master is going to have a lot of churn thus will be
|
|
||||||
# more prone to breaking the build than a point release. We don't want ZFS
|
|
||||||
# PR's reporting bad test results simply because upstream Lustre accidentally
|
|
||||||
# broke their build.
|
|
||||||
#
|
|
||||||
# Skip any RC tags, or any tags where the last version digit is 50 or more.
|
|
||||||
# Versions with 50 or more are development versions of Lustre.
|
|
||||||
repo=https://github.com/lustre/lustre-release.git
|
|
||||||
tag="$(git ls-remote --refs --exit-code --sort=version:refname --tags $repo | \
|
|
||||||
awk -F '_' '/-RC/{next}; /refs\/tags\/v/{if ($NF < 50){print}}' | \
|
|
||||||
tail -n 1 | sed 's/.*\///')"
|
|
||||||
|
|
||||||
echo "Cloning Lustre tag $tag"
|
|
||||||
git clone --depth 1 --branch "$tag" "$repo"
|
|
||||||
|
|
||||||
cd lustre-release
|
|
||||||
|
|
||||||
# Include Lustre patches to build against master/zfs-2.4.x. Once these
|
|
||||||
# patches are merged we can remove these lines.
|
|
||||||
patches=('https://review.whamcloud.com/changes/fs%2Flustre-release~62101/revisions/2/patch?download'
|
|
||||||
'https://review.whamcloud.com/changes/fs%2Flustre-release~63267/revisions/9/patch?download')
|
|
||||||
|
|
||||||
for p in "${patches[@]}" ; do
|
|
||||||
curl $p | base64 -d > patch
|
|
||||||
patch -p1 < patch || true
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Configure Lustre"
|
|
||||||
./autogen.sh
|
|
||||||
# EL 9 needs '--disable-gss-keyring'
|
|
||||||
./configure --with-zfs --disable-gss-keyring
|
|
||||||
echo "Building Lustre RPMs"
|
|
||||||
make rpms
|
|
||||||
ls *.rpm
|
|
||||||
|
|
||||||
# There's only a handful of Lustre RPMs we actually need to install
|
|
||||||
lustrerpms="$(ls *.rpm | grep -E 'kmod-lustre-osd-zfs-[0-9]|kmod-lustre-[0-9]|lustre-osd-zfs-mount-[0-9]')"
|
|
||||||
echo "Installing: $lustrerpms"
|
|
||||||
sudo dnf -y install $lustrerpms
|
|
||||||
sudo modprobe -v lustre
|
|
||||||
|
|
||||||
# Should see some Lustre lines in dmesg
|
|
||||||
sudo dmesg | grep -Ei 'lnet|lustre'
|
|
||||||
@@ -1,231 +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 [--lustre|--builtin] [quick|default]
|
|
||||||
#
|
|
||||||
# --lustre: Test build lustre in addition to the normal tests
|
|
||||||
# --builtin: Test build ZFS as a kernel built-in in addition to the normal tests
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
function do_lustre_build() {
|
|
||||||
local rc=0
|
|
||||||
$HOME/zfs/.github/workflows/scripts/qemu-6-lustre-tests-vm.sh &> /var/tmp/lustre.txt || rc=$?
|
|
||||||
echo "$rc" > /var/tmp/lustre-exitcode.txt
|
|
||||||
if [ "$rc" != "0" ] ; then
|
|
||||||
echo "$rc" > /var/tmp/tests-exitcode.txt
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
export -f do_lustre_build
|
|
||||||
|
|
||||||
# Test build ZFS into the kernel directly
|
|
||||||
function do_builtin_build() {
|
|
||||||
local rc=0
|
|
||||||
# Get currently full kernel version (like '6.18.8')
|
|
||||||
fullver=$(uname -r | grep -Eo '^[0-9]+\.[0-9]+\.[0-9]+')
|
|
||||||
|
|
||||||
# Get just the major ('6')
|
|
||||||
major=$(echo $fullver | grep -Eo '^[0-9]+')
|
|
||||||
(
|
|
||||||
set -e
|
|
||||||
|
|
||||||
wget https://cdn.kernel.org/pub/linux/kernel/v${major}.x/linux-$fullver.tar.xz
|
|
||||||
tar -xf $HOME/linux-$fullver.tar.xz
|
|
||||||
cd $HOME/linux-$fullver
|
|
||||||
make tinyconfig
|
|
||||||
./scripts/config --enable EFI_PARTITON
|
|
||||||
./scripts/config --enable BLOCK
|
|
||||||
# BTRFS_FS is easiest config option to enable CONFIG_ZLIB_INFLATE|DEFLATE
|
|
||||||
./scripts/config --enable BTRFS_FS
|
|
||||||
yes "" | make oldconfig
|
|
||||||
make prepare
|
|
||||||
|
|
||||||
cd $HOME/zfs
|
|
||||||
./configure --with-linux=$HOME/linux-$fullver --enable-linux-builtin --enable-debug
|
|
||||||
./copy-builtin $HOME/linux-$fullver
|
|
||||||
|
|
||||||
cd $HOME/linux-$fullver
|
|
||||||
./scripts/config --enable ZFS
|
|
||||||
yes "" | make oldconfig
|
|
||||||
make -j `nproc`
|
|
||||||
) &> /var/tmp/builtin.txt || rc=$?
|
|
||||||
echo "$rc" > /var/tmp/builtin-exitcode.txt
|
|
||||||
if [ "$rc" != "0" ] ; then
|
|
||||||
echo "$rc" > /var/tmp/tests-exitcode.txt
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
export -f do_builtin_build
|
|
||||||
|
|
||||||
# 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"
|
|
||||||
|
|
||||||
# We do an additional test build of Lustre against ZFS if we're vm2
|
|
||||||
# on almalinux*. At the time of writing, the vm2 tests were
|
|
||||||
# completing roughly 15min before the vm1 tests, so it makes sense
|
|
||||||
# to have vm2 do the build.
|
|
||||||
#
|
|
||||||
# In addition, we do an additional test build of ZFS as a Linux
|
|
||||||
# kernel built-in on Fedora. Again, we do it on vm2 to exploit vm2's
|
|
||||||
# early finish time.
|
|
||||||
extra=""
|
|
||||||
if [[ "$OS" == almalinux* ]] && [[ "$i" == "2" ]] ; then
|
|
||||||
extra="--lustre"
|
|
||||||
elif [[ "$OS" == fedora* ]] && [[ "$i" == "2" ]] ; then
|
|
||||||
extra="--builtin"
|
|
||||||
fi
|
|
||||||
|
|
||||||
daemonize -c /var/tmp -p vm${i}.pid -o vm${i}log.txt -- \
|
|
||||||
$SSH zfs@$IP $TESTS $OS $i $VMs $extra $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
|
|
||||||
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# Everything from here on runs inside qemu vm
|
|
||||||
#############################################
|
|
||||||
|
|
||||||
# Process cmd line args
|
|
||||||
OS="$1"
|
|
||||||
shift
|
|
||||||
NUM="$1"
|
|
||||||
shift
|
|
||||||
DEN="$1"
|
|
||||||
shift
|
|
||||||
|
|
||||||
BUILD_LUSTRE=0
|
|
||||||
BUILD_BUILTIN=0
|
|
||||||
if [ "$1" == "--lustre" ] ; then
|
|
||||||
BUILD_LUSTRE=1
|
|
||||||
shift
|
|
||||||
elif [ "$1" == "--builtin" ] ; then
|
|
||||||
BUILD_BUILTIN=1
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$1" == "quick" ] ; then
|
|
||||||
export RUNFILES="sanity.run"
|
|
||||||
fi
|
|
||||||
|
|
||||||
export PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/usr/local/bin"
|
|
||||||
case "$OS" 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
|
|
||||||
|
|
||||||
# Distribution-specific settings.
|
|
||||||
case "$OS" in
|
|
||||||
almalinux9|almalinux10|centos-stream*)
|
|
||||||
# Enable io_uring on Enterprise Linux 9 and 10.
|
|
||||||
sudo sysctl kernel.io_uring_disabled=0 > /dev/null
|
|
||||||
;;
|
|
||||||
alpine*)
|
|
||||||
# Ensure `/etc/zfs/zpool.cache` exists.
|
|
||||||
sudo mkdir -p /etc/zfs
|
|
||||||
sudo touch /etc/zfs/zpool.cache
|
|
||||||
sudo chmod 644 /etc/zfs/zpool.cache
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Lustre calls a number of exported ZFS module symbols. To make sure we don't
|
|
||||||
# change the symbols and break Lustre, do a quick Lustre build of the latest
|
|
||||||
# released Lustre against ZFS.
|
|
||||||
#
|
|
||||||
# Note that we do the Lustre test build in parallel with ZTS. ZTS isn't very
|
|
||||||
# CPU intensive, so we can use idle CPU cycles "guilt free" for the build.
|
|
||||||
# The Lustre build on its own takes ~15min.
|
|
||||||
if [ "$BUILD_LUSTRE" == "1" ] ; then
|
|
||||||
do_lustre_build &
|
|
||||||
elif [ "$BUILD_BUILTIN" == "1" ] ; then
|
|
||||||
# Try building ZFS directly into the Linux kernel (not as a module)
|
|
||||||
do_builtin_build &
|
|
||||||
fi
|
|
||||||
|
|
||||||
# run functional testings and save exitcode
|
|
||||||
cd /var/tmp
|
|
||||||
TAGS=$NUM/$DEN
|
|
||||||
sudo dmesg -c > dmesg-prerun.txt
|
|
||||||
mount > mount.txt
|
|
||||||
df -h > df-prerun.txt
|
|
||||||
RV=0
|
|
||||||
$TDIR/zfs-tests.sh -vKO -s 3GB -T $TAGS || RV=$?
|
|
||||||
|
|
||||||
df -h > df-postrun.txt
|
|
||||||
echo $RV > tests-exitcode.txt
|
|
||||||
sync
|
|
||||||
exit 0
|
|
||||||
@@ -1,157 +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
|
|
||||||
|
|
||||||
TARNAME=qemu-$OS
|
|
||||||
|
|
||||||
# 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 .
|
|
||||||
|
|
||||||
# rename /var/tmp/test_results to /var/tmp/qemu-$OS
|
|
||||||
mv $RESPATH $(dirname $RESPATH)/$TARNAME
|
|
||||||
tar cjf /tmp/$TARNAME.tar.bz2 -C $(dirname $RESPATH) -h $TARNAME || true
|
|
||||||
# move it back to /var/tmp/test_results (needed for next script)
|
|
||||||
mv $(dirname $RESPATH)/$TARNAME $RESPATH
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! grep -q vm /etc/hosts ; then
|
|
||||||
echo "No vm* hostnames, VMs probably didn't startup"
|
|
||||||
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
|
|
||||||
|
|
||||||
# no results, VM either didn't start or was unreachable, create
|
|
||||||
# the missing directory which is expected by subsequent steps
|
|
||||||
test -d vm$i || mkdir -p vm$i
|
|
||||||
|
|
||||||
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
|
|
||||||
# Print in bold red
|
|
||||||
echo -e "\033[1;31mVM$i didn't finish ZTS and may have crashed!\033[0m" >> extra
|
|
||||||
|
|
||||||
# ENOENT=2
|
|
||||||
echo 2 > "$file"
|
|
||||||
fi
|
|
||||||
rv=$(cat "$file")
|
|
||||||
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
|
|
||||||
|
|
||||||
# Add in additional 'extra' text at the end, if file is present.
|
|
||||||
if [ -s extra ] ; then
|
|
||||||
echo "" >> /tmp/summary.txt
|
|
||||||
cat extra >> /tmp/summary.txt
|
|
||||||
rm -f extra
|
|
||||||
fi
|
|
||||||
|
|
||||||
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
|
|
||||||
#
|
|
||||||
# rename /var/tmp/test_results to /var/tmp/qemu-$OS
|
|
||||||
mv $RESPATH $(dirname $RESPATH)/$TARNAME
|
|
||||||
tar cjf /tmp/$TARNAME.tar.bz2 -C $(dirname $RESPATH) -h $TARNAME || true
|
|
||||||
# move it back to /var/tmp/test_results (needed for next script)
|
|
||||||
mv $(dirname $RESPATH)/$TARNAME $RESPATH
|
|
||||||
@@ -1,105 +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$$
|
|
||||||
}
|
|
||||||
|
|
||||||
function showfile_tail() {
|
|
||||||
echo "##[group]$2 (final lines)"
|
|
||||||
tail -n 80 $1
|
|
||||||
echo "##[endgroup]"
|
|
||||||
}
|
|
||||||
|
|
||||||
# overview if available
|
|
||||||
if [ -f /tmp/summary.txt -a -s /tmp/summary.txt ]; then
|
|
||||||
cat /tmp/summary.txt
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# Print Lustre build test results (the build is only done on vm2)
|
|
||||||
if [ -f vm$i/lustre-exitcode.txt ] ; then
|
|
||||||
rv=$(< vm$i/lustre-exitcode.txt)
|
|
||||||
if [ $rv = 0 ]; then
|
|
||||||
vm="[92mvm$i[0m"
|
|
||||||
else
|
|
||||||
vm="[1;91mvm$i[0m"
|
|
||||||
touch /tmp/have_failed_tests
|
|
||||||
fi
|
|
||||||
file="vm$i/lustre.txt"
|
|
||||||
test -s "$file" && showfile_tail "$file" "$vm: Lustre build"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f vm$i/builtin-exitcode.txt ] ; then
|
|
||||||
rv=$(< vm$i/builtin-exitcode.txt)
|
|
||||||
if [ $rv = 0 ]; then
|
|
||||||
vm="[92mvm$i[0m"
|
|
||||||
else
|
|
||||||
vm="[1;91mvm$i[0m"
|
|
||||||
touch /tmp/have_failed_tests
|
|
||||||
fi
|
|
||||||
file="vm$i/builtin.txt"
|
|
||||||
test -s "$file" && showfile_tail "$file" "$vm: Linux built-in build"
|
|
||||||
fi
|
|
||||||
|
|
||||||
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,59 +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"
|
|
||||||
# The bz2 files are put into directories with the same name, like:
|
|
||||||
# "qemu-debian12.tar.bz2/qemu-debian12.tar.bz2"
|
|
||||||
for tarfile in qemu-*.tar.bz2/qemu-*.tar.bz2; 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,115 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Do a test install of ZFS from an external repository.
|
|
||||||
#
|
|
||||||
# USAGE:
|
|
||||||
#
|
|
||||||
# ./qemu-test-repo-vm [--install] [URL]
|
|
||||||
#
|
|
||||||
# --lookup: When testing a repo, only lookup the latest package versions,
|
|
||||||
# don't try to install them. Installing all of them takes over
|
|
||||||
# an hour, so this is much quicker.
|
|
||||||
#
|
|
||||||
# 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"
|
|
||||||
|
|
||||||
|
|
||||||
LOOKUP=""
|
|
||||||
if [ -n "$1" ] && [ "$1" == "--lookup" ] ; then
|
|
||||||
LOOKUP=1
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
baseurl=$(grep -A 5 "\[$repo\]" /etc/yum.repos.d/zfs.repo | awk -F'=' '/baseurl=/{print $2; exit}')
|
|
||||||
|
|
||||||
# Just do a version lookup - don't try to install any RPMs
|
|
||||||
if [ "$LOOKUP" == "1" ] ; then
|
|
||||||
package="$(dnf list $args zfs | tail -n 1 | awk '{print $2}')"
|
|
||||||
echo "$repo ${package} $baseurl" >> $SUMMARY
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! sudo dnf -y install $args zfs zfs-test ; then
|
|
||||||
echo "$repo ${package}...[FAILED] $baseurl" >> $SUMMARY
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 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
|
|
||||||
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
|
|
||||||
for i in zfs zfs-kmod zfs-testing zfs-testing-kmod zfs-latest \
|
|
||||||
zfs-latest-kmod zfs-legacy zfs-legacy-kmod zfs-2.2 \
|
|
||||||
zfs-2.2-kmod zfs-2.3 zfs-2.3-kmod zfs-2.4 zfs-2.4-kmod; do
|
|
||||||
test_install $i $ALTHOST
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
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
|
|
||||||
for i in zfs zfs-latest zfs-legacy zfs-2.2 zfs-2.3 zfs-2.4 ; do
|
|
||||||
test_install $i $ALTHOST
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
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,52 +0,0 @@
|
|||||||
name: smatch
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
smatch:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout smatch
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
repository: error27/smatch
|
|
||||||
ref: master
|
|
||||||
path: smatch
|
|
||||||
- name: Install smatch dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt-get install -y llvm gcc make sqlite3 libsqlite3-dev libdbd-sqlite3-perl libssl-dev libtry-tiny-perl
|
|
||||||
- name: Make smatch
|
|
||||||
run: |
|
|
||||||
cd $GITHUB_WORKSPACE/smatch
|
|
||||||
make -j$(nproc)
|
|
||||||
- name: Checkout OpenZFS
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
path: zfs
|
|
||||||
- name: Install OpenZFS dependencies
|
|
||||||
run: |
|
|
||||||
cd $GITHUB_WORKSPACE/zfs
|
|
||||||
sudo apt-get purge -y snapd google-chrome-stable firefox
|
|
||||||
ONLY_DEPS=1 .github/workflows/scripts/qemu-3-deps-vm.sh ubuntu24
|
|
||||||
- name: Autogen.sh OpenZFS
|
|
||||||
run: |
|
|
||||||
cd $GITHUB_WORKSPACE/zfs
|
|
||||||
./autogen.sh
|
|
||||||
- name: Configure OpenZFS
|
|
||||||
run: |
|
|
||||||
cd $GITHUB_WORKSPACE/zfs
|
|
||||||
./configure --enable-debug
|
|
||||||
- name: Make OpenZFS
|
|
||||||
run: |
|
|
||||||
cd $GITHUB_WORKSPACE/zfs
|
|
||||||
make -j$(nproc) CHECK="$GITHUB_WORKSPACE/smatch/smatch" CC=$GITHUB_WORKSPACE/smatch/cgcc | tee $GITHUB_WORKSPACE/smatch.log
|
|
||||||
- name: Smatch results log
|
|
||||||
run: |
|
|
||||||
grep -E 'error:|warn:|warning:' $GITHUB_WORKSPACE/smatch.log
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
name: zfs-arm
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
zfs-arm:
|
|
||||||
name: ZFS ARM build
|
|
||||||
runs-on: ubuntu-24.04-arm
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
- name: Install dependencies
|
|
||||||
timeout-minutes: 20
|
|
||||||
run: |
|
|
||||||
sudo apt-get -y remove firefox || true
|
|
||||||
.github/workflows/scripts/qemu-3-deps-vm.sh ubuntu24
|
|
||||||
|
|
||||||
# We're running the VM scripts locally on the runner, so need to fix
|
|
||||||
# up hostnames to make it work.
|
|
||||||
for ((i=0; i<=3; i++)); do
|
|
||||||
echo "127.0.0.1 vm$i" | sudo tee -a /etc/hosts
|
|
||||||
done
|
|
||||||
- name: Build modules
|
|
||||||
timeout-minutes: 30
|
|
||||||
run: |
|
|
||||||
.github/workflows/scripts/qemu-4-build-vm.sh --enable-debug ubuntu24
|
|
||||||
|
|
||||||
# Quick sanity test since we're not running the full ZTS
|
|
||||||
sudo modprobe zfs
|
|
||||||
sudo dmesg | grep -i zfs
|
|
||||||
truncate -s 100M file
|
|
||||||
sudo zpool create tank ./file
|
|
||||||
zpool status
|
|
||||||
|
|
||||||
echo "Built ZFS successfully on ARM"
|
|
||||||
@@ -1,158 +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)"
|
|
||||||
lookup:
|
|
||||||
type: boolean
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
description: "(optional) do version lookup only on repo test"
|
|
||||||
|
|
||||||
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', 'fedora42', 'fedora43', 'fedora44']
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
|
|
||||||
- name: Setup QEMU
|
|
||||||
run: .github/workflows/scripts/qemu-1-setup.sh
|
|
||||||
|
|
||||||
- name: Start build machine
|
|
||||||
run: .github/workflows/scripts/qemu-2-start.sh ${{ matrix.os }}
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
.github/workflows/scripts/qemu-3-deps.sh --poweroff ${{ matrix.os }}
|
|
||||||
|
|
||||||
- name: Build modules or Test repo
|
|
||||||
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
|
|
||||||
EXTRA=""
|
|
||||||
if [ "${{ github.event.inputs.lookup }}" == 'true' ] ; then
|
|
||||||
EXTRA="--lookup"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ssh zfs@vm0 '$HOME/zfs/.github/workflows/scripts/qemu-test-repo-vm.sh' $EXTRA ${{ 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()
|
|
||||||
run: |
|
|
||||||
rsync -a zfs@vm0:/tmp/repo /tmp || true
|
|
||||||
.github/workflows/scripts/replace-dupes-with-symlinks.sh /tmp/repo
|
|
||||||
tar -cjf ${{ matrix.os }}-repo.tar.bz2 -C /tmp repo
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
id: artifact-upload
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: ${{ matrix.os }}-repo
|
|
||||||
path: ${{ matrix.os }}-repo.tar.bz2
|
|
||||||
compression-level: 0
|
|
||||||
retention-days: 2
|
|
||||||
if-no-files-found: ignore
|
|
||||||
archive: false
|
|
||||||
|
|
||||||
combine_repos:
|
|
||||||
if: always()
|
|
||||||
needs: [zfs-qemu-packages-jobs]
|
|
||||||
name: "Results"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/download-artifact@v8
|
|
||||||
id: artifact-download
|
|
||||||
if: always()
|
|
||||||
- name: Test Summary
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
for i in $(find . -type f -iname "*.tar.bz2") ; do
|
|
||||||
tar -xf $i -C /tmp
|
|
||||||
done
|
|
||||||
tar -cjf all-repo.tar.bz2 -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@v7
|
|
||||||
id: artifact-upload2
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: all-repo
|
|
||||||
path: all-repo.tar.bz2
|
|
||||||
retention-days: 5
|
|
||||||
if-no-files-found: ignore
|
|
||||||
archive: false
|
|
||||||
@@ -1,208 +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')"
|
|
||||||
specific_os:
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
default: ""
|
|
||||||
description: "(optional) Only run on this specific OS (like 'fedora42' or 'alpine3-23')"
|
|
||||||
|
|
||||||
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@v6
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Generate OS config and CI type
|
|
||||||
id: os
|
|
||||||
run: |
|
|
||||||
ci_type="default"
|
|
||||||
ci_source="auto"
|
|
||||||
|
|
||||||
# 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 }}
|
|
||||||
read ci_type ci_source <<< "$(python3 .github/workflows/scripts/generate-ci-type.py $head $base)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$ci_type" in
|
|
||||||
quick)
|
|
||||||
os_selection='["almalinux8", "almalinux9", "almalinux10", "debian12", "fedora42", "freebsd15-1s", "ubuntu24"]'
|
|
||||||
;;
|
|
||||||
linux)
|
|
||||||
os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian11", "debian12", "debian13", "fedora42", "fedora43", "fedora44", "ubuntu22", "ubuntu24"]'
|
|
||||||
;;
|
|
||||||
freebsd)
|
|
||||||
os_selection='["freebsd13-5r", "freebsd14-4r", "freebsd13-5s", "freebsd14-4s", "freebsd15-1s", "freebsd16-0c"]'
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# default list
|
|
||||||
os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian12", "debian13", "fedora42", "fedora43", "fedora44", "freebsd14-4r", "freebsd15-1s", "freebsd16-0c", "ubuntu22", "ubuntu24"]'
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Repository-level override for OS selection.
|
|
||||||
# Set vars.ZTS_OS_OVERRIDE in repo settings to restrict targets
|
|
||||||
# (e.g. '["debian13"]' or '["debian13", "fedora42"]').
|
|
||||||
# Manual ZFS-CI-Type in commit messages bypasses the override.
|
|
||||||
if [ -n "${{ vars.ZTS_OS_OVERRIDE }}" ] && [ "$ci_source" != "manual" ]; then
|
|
||||||
override='${{ vars.ZTS_OS_OVERRIDE }}'
|
|
||||||
if echo "$override" | jq -e 'type == "array"' >/dev/null 2>&1; then
|
|
||||||
os_selection="$override"
|
|
||||||
else
|
|
||||||
echo "::warning::Invalid ZTS_OS_OVERRIDE, using default"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
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"))]')
|
|
||||||
elif ${{ github.event.inputs.specific_os != '' }}; then
|
|
||||||
# Use only the specified runner.
|
|
||||||
os_json=$(jq -cn --arg os "${{ github.event.inputs.specific_os }}" '[ $os ]')
|
|
||||||
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-4r, freebsd15-0r
|
|
||||||
# FreeBSD Stable: freebsd13-5s, freebsd14-4s, freebsd15-1s
|
|
||||||
# FreeBSD Current: freebsd16-0c
|
|
||||||
os: ${{ fromJson(needs.test-config.outputs.test_os) }}
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
|
|
||||||
- name: Setup QEMU
|
|
||||||
timeout-minutes: 60
|
|
||||||
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: 60
|
|
||||||
run: .github/workflows/scripts/qemu-3-deps.sh --poweroff ${{ 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@v7
|
|
||||||
id: artifact-upload
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: Logs-functional-${{ matrix.os }}
|
|
||||||
path: /tmp/qemu-${{ matrix.os }}.tar.bz2
|
|
||||||
archive: false
|
|
||||||
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@v6
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
- uses: actions/download-artifact@v8
|
|
||||||
- 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@v7
|
|
||||||
with:
|
|
||||||
name: Summary Files
|
|
||||||
path: out-*
|
|
||||||
archive: true
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
name: zloop
|
|
||||||
|
|
||||||
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
|
|
||||||
env:
|
|
||||||
WORK_DIR: /mnt/zloop
|
|
||||||
CORE_DIR: /mnt/zloop/cores
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
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
|
|
||||||
- name: Autogen.sh
|
|
||||||
run: |
|
|
||||||
sed -i '/DEBUG_CFLAGS="-Werror"/s/^/#/' config/zfs-build.m4
|
|
||||||
./autogen.sh
|
|
||||||
- name: Configure
|
|
||||||
run: |
|
|
||||||
./configure --prefix=/usr --enable-debug --enable-debuginfo \
|
|
||||||
--enable-asan --enable-ubsan \
|
|
||||||
--enable-debug-kmem --enable-debug-kmem-tracking
|
|
||||||
- name: Make
|
|
||||||
run: |
|
|
||||||
make -j$(nproc)
|
|
||||||
- name: Install
|
|
||||||
run: |
|
|
||||||
sudo make install
|
|
||||||
sudo depmod
|
|
||||||
sudo modprobe zfs
|
|
||||||
- name: Tests
|
|
||||||
run: |
|
|
||||||
[ -r /etc/hostid ] && [ -s /etc/hostid ] || sudo zgenhostid -f
|
|
||||||
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
|
|
||||||
- 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@v7
|
|
||||||
if: failure()
|
|
||||||
with:
|
|
||||||
name: Logs
|
|
||||||
path: |
|
|
||||||
/mnt/zloop/*/
|
|
||||||
!/mnt/zloop/cores/*/vdev/
|
|
||||||
if-no-files-found: ignore
|
|
||||||
- uses: actions/upload-artifact@v7
|
|
||||||
if: failure()
|
|
||||||
with:
|
|
||||||
name: Pool files
|
|
||||||
path: |
|
|
||||||
/mnt/zloop/cores/*/vdev/
|
|
||||||
if-no-files-found: ignore
|
|
||||||
+31
-60
@@ -1,7 +1,6 @@
|
|||||||
#
|
#
|
||||||
# This is the top-level .gitignore file:
|
# N.B.
|
||||||
# ignore everything except a list of allowed files.
|
# This is the toplevel .gitignore file.
|
||||||
#
|
|
||||||
# This is not the place for entries that are specific to
|
# This is not the place for entries that are specific to
|
||||||
# a subdirectory. Instead add those files to the
|
# a subdirectory. Instead add those files to the
|
||||||
# .gitignore file in that subdirectory.
|
# .gitignore file in that subdirectory.
|
||||||
@@ -11,62 +10,10 @@
|
|||||||
# command after changing this file, to see if there are
|
# command after changing this file, to see if there are
|
||||||
# any tracked files which get ignored after the change.
|
# 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
|
# Normal rules
|
||||||
#
|
#
|
||||||
*.[oa]
|
*.[oa]
|
||||||
*.o.ur-safe
|
|
||||||
*.lo
|
*.lo
|
||||||
*.la
|
*.la
|
||||||
*.mod.c
|
*.mod.c
|
||||||
@@ -74,8 +21,6 @@
|
|||||||
*.swp
|
*.swp
|
||||||
*.gcno
|
*.gcno
|
||||||
*.gcda
|
*.gcda
|
||||||
*.pyc
|
|
||||||
*.pyo
|
|
||||||
.deps
|
.deps
|
||||||
.libs
|
.libs
|
||||||
.dirstamp
|
.dirstamp
|
||||||
@@ -83,8 +28,34 @@
|
|||||||
modules.order
|
modules.order
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
changelog
|
|
||||||
|
#
|
||||||
|
# Top level generated files specific to this top level dir
|
||||||
|
#
|
||||||
|
/bin
|
||||||
|
/configure
|
||||||
|
/config.log
|
||||||
|
/config.status
|
||||||
|
/libtool
|
||||||
|
/zfs_config.h
|
||||||
|
/zfs_config.h.in
|
||||||
|
/zfs.release
|
||||||
|
/stamp-h1
|
||||||
|
/.script-config
|
||||||
|
/zfs-script-config.sh
|
||||||
|
/aclocal.m4
|
||||||
|
/autom4te.cache
|
||||||
|
|
||||||
|
#
|
||||||
|
# Top level generic files
|
||||||
|
#
|
||||||
|
!.gitignore
|
||||||
|
tags
|
||||||
|
TAGS
|
||||||
|
current
|
||||||
|
cscope.*
|
||||||
|
*.rpm
|
||||||
|
*.deb
|
||||||
|
*.tar.gz
|
||||||
*.patch
|
*.patch
|
||||||
*.orig
|
*.orig
|
||||||
*.tmp
|
|
||||||
*.log
|
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
[submodule "scripts/zfs-images"]
|
[submodule "scripts/zfs-images"]
|
||||||
path = scripts/zfs-images
|
path = scripts/zfs-images
|
||||||
url = https://github.com/openzfs/zfs-images
|
url = https://github.com/zfsonlinux/zfs-images
|
||||||
|
|||||||
@@ -1,237 +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.
|
|
||||||
Achill Gilgenast <achill@achill.org>
|
|
||||||
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>
|
|
||||||
Diwakar Kristappagari <diwakar-k@hpe.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>
|
|
||||||
Jo Zzsi <jozzsicsataban@gmail.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 <io@r-ricci.it>
|
|
||||||
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>
|
|
||||||
Sebastian Wuerl <s.wuerl@mailbox.org>
|
|
||||||
SHENGYI HONG <aokblast@FreeBSD.org>
|
|
||||||
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:
|
|
||||||
Alexander Ziaee <ziaee@FreeBSD.org> <concussious@runbox.com>
|
|
||||||
Felix Schmidt <felixschmidt20@aol.com> <f.sch.prototype@gmail.com>
|
|
||||||
Jean-Sébastien Pédron <dumbbell@FreeBSD.org> <jean-sebastien.pedron@dumbbell.fr>
|
|
||||||
Konstantin Belousov <kib@FreeBSD.org> <kib@kib.kiev.ua>
|
|
||||||
Olivier Certner <olce@FreeBSD.org> <olce.freebsd@certner.fr>
|
|
||||||
Patrick Xia <patrickx@google.com> <octalc0de@aim.com>
|
|
||||||
Phil Sutter <phil@nwl.cc> <p.github@nwl.cc>
|
|
||||||
poscat <poscat@poscat.moe> <poscat0x04@outlook.com>
|
|
||||||
Qiuhao Chen <chenqiuhao1997@gmail.com> <haohao0924@126.com>
|
|
||||||
Ryan <errornointernet@envs.net> <error.nointernet@gmail.com>
|
|
||||||
Sietse <sietse@wizdom.nu> <uglymotha@wizdom.nu>
|
|
||||||
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>
|
|
||||||
Aleksandr Liber <aleksandr.liber@perforce.com> <61714074+AleksandrLiber@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>
|
|
||||||
classabbyamp <dev@placeviolette.net> <5366828+classabbyamp@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>
|
|
||||||
Friedrich Weber <f.weber@proxmox.com> <56110206+frwbr@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>
|
|
||||||
Germano Massullo <germano.massullo@gmail.com> <Germano0@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>
|
|
||||||
Kaitlin Hoang <kthoang@amazon.com> <khoang98@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>
|
|
||||||
nav1s <nav1s@proton.me> <42621369+nav1s@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>
|
|
||||||
Shreshth Srivastava <shreshthsrivastava2@gmail.com> <66148173+Shreshth3@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>
|
|
||||||
Vandana Rungta <vrungta@amazon.com> <46906819+vandanarungta@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>
|
|
||||||
XDTG <click1799@163.com> <35128600+XDTG@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>
|
|
||||||
@@ -1,729 +1,95 @@
|
|||||||
MAINTAINERS:
|
Brian Behlendorf is the principal developer of the ZFS on Linux port.
|
||||||
|
He works full time as a computer scientist at Lawrence Livermore
|
||||||
|
National Laboratory on the ZFS and Lustre filesystems. However,
|
||||||
|
this port would not have been possible without the help of many
|
||||||
|
others who have contributed their time, effort, and insight.
|
||||||
|
|
||||||
Brian Behlendorf <behlendorf1@llnl.gov>
|
Brian Behlendorf <behlendorf1@llnl.gov>
|
||||||
Tony Hutter <hutter2@llnl.gov>
|
|
||||||
|
|
||||||
PAST MAINTAINERS:
|
First and foremost the hard working ZFS developers at Sun/Oracle.
|
||||||
|
They are responsible for the bulk of the code in this project and
|
||||||
|
without their efforts there never would have been a ZFS filesystem.
|
||||||
|
|
||||||
Ned Bass <bass6@llnl.gov>
|
The ZFS Development Team at Sun/Oracle
|
||||||
|
|
||||||
CONTRIBUTORS:
|
Next all the developers at KQ Infotech who implemented a prototype
|
||||||
|
ZFS Posix Layer (ZPL). Their implementation provided an excellent
|
||||||
|
reference for adding the ZPL functionality.
|
||||||
|
|
||||||
Aaron Fineman <abyxcos@gmail.com>
|
Anand Mitra <mitra@kqinfotech.com>
|
||||||
Achill Gilgenast <achill@achill.org>
|
Anurag Agarwal <anurag@kqinfotech.com>
|
||||||
Adam D. Moss <c@yotes.com>
|
Neependra Khare <neependra@kqinfotech.com>
|
||||||
Adam Leventhal <ahl@delphix.com>
|
Prasad Joshi <prasad@kqinfotech.com>
|
||||||
Adam Stevko <adam.stevko@gmail.com>
|
Rohan Puri <rohan@kqinfotech.com>
|
||||||
adisbladis <adis@blad.is>
|
Sandip Divekar <sandipd@kqinfotech.com>
|
||||||
Adrian Chadd <adrian@freebsd.org>
|
Shoaib <shoaib@kqinfotech.com>
|
||||||
Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
|
Shrirang <shrirang@kqinfotech.com>
|
||||||
Ahmed G <ahmedg@delphix.com>
|
|
||||||
Aidan Harris <me@aidanharr.is>
|
Additionally the following individuals have all made contributions
|
||||||
AJ Jordan <alex@strugee.net>
|
to the project and deserve to be acknowledged.
|
||||||
ajs124 <git@ajs124.de>
|
|
||||||
Akash Ayare <aayare@delphix.com>
|
Albert Lee <trisk@nexenta.com>
|
||||||
Akash B <akash-b@hpe.com>
|
Alejandro R. Sedeño <asedeno@mit.edu>
|
||||||
Alan Somers <asomers@gmail.com>
|
Alex Zhuravlev <bzzz@whamcloud.com>
|
||||||
Alar Aun <spamtoaun@gmail.com>
|
Alexander Eremin <a.eremin@nexenta.com>
|
||||||
Albert Lee <trisk@nexenta.com>
|
Alexander Stetsenko <ams@nexenta.com>
|
||||||
Alec Salazar <alec.j.salazar@gmail.com>
|
Alexey Shvetsov <alexxy@gentoo.org>
|
||||||
Alejandro Colomar <Colomar.6.4.3@GMail.com>
|
Andreas Dilger <adilger@whamcloud.com>
|
||||||
Alejandro R. Sedeño <asedeno@mit.edu>
|
Andrew Reid <ColdCanuck@nailedtotheperch.com>
|
||||||
Alek Pinchuk <alek@nexenta.com>
|
Andrew Stormont <andrew.stormont@nexenta.com>
|
||||||
Aleksandr Liber <aleksandr.liber@perforce.com>
|
Andrew Tselischev <andrewtselischev@gmail.com>
|
||||||
Aleksa Sarai <cyphar@cyphar.com>
|
Andriy Gapon <avg@FreeBSD.org>
|
||||||
Alexander Eremin <a.eremin@nexenta.com>
|
Aniruddha Shankar <k@191a.net>
|
||||||
Alexander Lobakin <alobakin@pm.me>
|
Bill Pijewski <wdp@joyent.com>
|
||||||
Alexander Motin <mav@freebsd.org>
|
Chris Dunlap <cdunlap@llnl.gov>
|
||||||
Alexander Pyhalov <apyhalov@gmail.com>
|
Chris Dunlop <chris@onthe.net.au>
|
||||||
Alexander Richardson <Alexander.Richardson@cl.cam.ac.uk>
|
Chris Siden <chris.siden@delphix.com>
|
||||||
Alexander Stetsenko <ams@nexenta.com>
|
Chris Wedgwood <cw@f00f.org>
|
||||||
Alexander Ziaee <ziaee@FreeBSD.org>
|
Christian Kohlschütter <christian@kohlschutter.com>
|
||||||
Alex Braunegg <alex.braunegg@gmail.com>
|
Christopher Siden <chris.siden@delphix.com>
|
||||||
Alexey Shvetsov <alexxy@gentoo.org>
|
Craig Sanders <github@taz.net.au>
|
||||||
Alexey Smirnoff <fling@member.fsf.org>
|
Cyril Plisko <cyril.plisko@mountall.com>
|
||||||
Alex John <alex@stty.io>
|
Dan McDonald <danmcd@nexenta.com>
|
||||||
Alex McWhirter <alexmcwhirter@triadic.us>
|
Daniel Verite <daniel@verite.pro>
|
||||||
Alex Reece <alex@delphix.com>
|
Darik Horn <dajhorn@vanadac.com>
|
||||||
Alex Wilson <alex.wilson@joyent.com>
|
Eric Schrock <Eric.Schrock@delphix.com>
|
||||||
Alex Zhuravlev <alexey.zhuravlev@intel.com>
|
Etienne Dechamps <etienne.dechamps@ovh.net>
|
||||||
Allan Jude <allanjude@freebsd.org>
|
Fajar A. Nugraha <github@fajar.net>
|
||||||
Allen Holl <allen.m.holl@gmail.com>
|
Frederik Wessels <wessels147@gmail.com>
|
||||||
Alphan Yılmaz <alphanyilmaz@gmail.com>
|
Garrett D'Amore <garrett@nexenta.com>
|
||||||
alteriks <alteriks@gmail.com>
|
George Wilson <george.wilson@delphix.com>
|
||||||
Alyssa Ross <hi@alyssa.is>
|
Gordon Ross <gwr@nexenta.com>
|
||||||
Ameer Hamza <ahamza@ixsystems.com>
|
Gregor Kopka <mailfrom-github.com@kopka.net>
|
||||||
Anatoly Borodin <anatoly.borodin@gmail.com>
|
Gunnar Beutner <gunnar@beutner.name>
|
||||||
AndCycle <andcycle@andcycle.idv.tw>
|
James H <james@kagisoft.co.uk>
|
||||||
Andrea Gelmini <andrea.gelmini@gelma.net>
|
Javen Wu <wu.javen@gmail.com>
|
||||||
Andrea Righi <andrea.righi@canonical.com>
|
Jeremy Gill <jgill@parallax-innovations.com>
|
||||||
Andreas Buschmann <andreas.buschmann@tech.net.de>
|
Jorgen Lundman <lundman@lundman.net>
|
||||||
Andreas Dilger <adilger@intel.com>
|
KORN Andras <korn@elan.rulez.org>
|
||||||
Andreas Vögele <andreas@andreasvoegele.com>
|
Kyle Fuller <inbox@kylefuller.co.uk>
|
||||||
Andres <a-d-j-i@users.noreply.github.com>
|
Manuel Amador (Rudd-O) <rudd-o@rudd-o.com>
|
||||||
Andrew Barnes <barnes333@gmail.com>
|
Martin Matuska <mm@FreeBSD.org>
|
||||||
Andrew Hamilton <ahamilto@tjhsst.edu>
|
Massimo Maggi <massimo@mmmm.it>
|
||||||
Andrew Innes <andrew.c12@gmail.com>
|
Matthew Ahrens <mahrens@delphix.com>
|
||||||
Andrew J. Hesford <ajh@sideband.org>
|
Michael Martin <mgmartin.mgm@gmail.com>
|
||||||
Andrew Reid <ColdCanuck@nailedtotheperch.com>
|
Mike Harsch <mike@harschsystems.com>
|
||||||
Andrew Stormont <andrew.stormont@nexenta.com>
|
Ned Bass <bass6@llnl.gov>
|
||||||
Andrew Sun <me@andrewsun.com>
|
Oleg Stepura <oleg@stepura.com>
|
||||||
Andrew Tselischev <andrewtselischev@gmail.com>
|
P.SCH <p88@yahoo.com>
|
||||||
Andrew Turner <andrew@fubar.geek.nz>
|
Pawel Jakub Dawidek <pawel@dawidek.net>
|
||||||
Andrew Walker <awalker@ixsystems.com>
|
Prakash Surya <surya1@llnl.gov>
|
||||||
Andrey Prokopenko <job@terem.fr>
|
Prasad Joshi <pjoshi@stec-inc.com>
|
||||||
Andrey Vesnovaty <andrey.vesnovaty@gmail.com>
|
Ricardo M. Correia <Ricardo.M.Correia@Sun.COM>
|
||||||
Andriy Gapon <avg@freebsd.org>
|
Richard Laager <rlaager@wiktel.com>
|
||||||
Andriy Tkachuk <andriy.tkachuk@seagate.com>
|
Richard Lowe <richlowe@richlowe.net>
|
||||||
Andy Bakun <github@thwartedefforts.org>
|
Richard Yao <ryao@cs.stonybrook.edu>
|
||||||
Andy Fiddaman <omnios@citrus-it.co.uk>
|
Rohan Puri <rohan.puri15@gmail.com>
|
||||||
Aniruddha Shankar <k@191a.net>
|
Shampavman <sham.pavman@nexenta.com>
|
||||||
Anton Gubarkov <anton.gubarkov@gmail.com>
|
Simon Klinkert <klinkert@webgods.de>
|
||||||
Antonio Russo <antonio.e.russo@gmail.com>
|
Suman Chakravartula <suman@gogrid.com>
|
||||||
Arkadiusz Bubała <arkadiusz.bubala@open-e.com>
|
Tim Haley <Tim.Haley@Sun.COM>
|
||||||
Armin Wehrfritz <dkxls23@gmail.com>
|
Turbo Fredriksson <turbo@bayour.com>
|
||||||
Arne Jansen <arne@die-jansens.de>
|
Xin Li <delphij@FreeBSD.org>
|
||||||
Aron Xu <happyaron.xu@gmail.com>
|
Yuxuan Shui <yshuiv7@gmail.com>
|
||||||
Arshad Hussain <arshad.hussain@aeoncomputing.com>
|
Zachary Bedell <zac@thebedells.org>
|
||||||
Artem <artem.vlasenko@ossrevival.org>
|
nordaux <nordaux@gmail.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>
|
|
||||||
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>
|
|
||||||
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>
|
|
||||||
Carl George <carlwgeorge@gmail.com>
|
|
||||||
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>
|
|
||||||
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>
|
|
||||||
classabbyamp <dev@placeviolette.net>
|
|
||||||
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>
|
|
||||||
Cong Zhang <congzhangzh@users.noreply.github.com>
|
|
||||||
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>
|
|
||||||
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>
|
|
||||||
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>
|
|
||||||
Diwakar Kristappagari <diwakar-k@hpe.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 A. Borisch <eborisch@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>
|
|
||||||
Felix Schmidt <felixschmidt20@aol.com>
|
|
||||||
Feng Sun <loyou85@gmail.com>
|
|
||||||
Finix Yan <yancw@info2soft.com>
|
|
||||||
Francesco Mazzoli <f@mazzo.li>
|
|
||||||
Frederik Wessels <wessels147@gmail.com>
|
|
||||||
Friedrich Weber <f.weber@proxmox.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>
|
|
||||||
Germano Massullo <germano.massullo@gmail.com>
|
|
||||||
Gian-Carlo DeFazio <defazio1@llnl.gov>
|
|
||||||
Gionatan Danti <g.danti@assyoma.it>
|
|
||||||
Giuseppe Di Natale <guss80@gmail.com>
|
|
||||||
Gleb Smirnoff <glebius@FreeBSD.org>
|
|
||||||
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>
|
|
||||||
hoshinomori <hoshinomorimorimo@gmail.com>
|
|
||||||
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>
|
|
||||||
Igor Ostapenko <pm@igoro.pro>
|
|
||||||
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>
|
|
||||||
Ivan Shapovalov <intelfx@intelfx.name>
|
|
||||||
Ivan Volosyuk <Ivan.Volosyuk@gmail.com>
|
|
||||||
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 Reilly <jreilly1821@gmail.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>
|
|
||||||
Jaydeep Kshirsagar <jkshirsagar@maxlinear.com>
|
|
||||||
Jean-Baptiste Lallement <jean-baptiste@ubuntu.com>
|
|
||||||
Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
|
|
||||||
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>
|
|
||||||
Jerzy Kołosowski <jerzy@kolosowscy.pl>
|
|
||||||
Jessica Clarke <jrtc27@jrtc27.com>
|
|
||||||
Jinshan Xiong <jinshan.xiong@intel.com>
|
|
||||||
Jitendra Patidar <jitendra.patidar@nutanix.com>
|
|
||||||
JK Dingwall <james@dingwall.me.uk>
|
|
||||||
Joel Low <joel@joelsplace.sg>
|
|
||||||
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 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>
|
|
||||||
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 Zzsi <jozzsicsataban@gmail.com>
|
|
||||||
João Carlos Mendes Luís <jonny@jonny.eng.br>
|
|
||||||
JT Pennington <jt.pennington@klarasystems.com>
|
|
||||||
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>
|
|
||||||
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>
|
|
||||||
khoang98 <khoang98@users.noreply.github.com>
|
|
||||||
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 Belousov <kib@FreeBSD.org>
|
|
||||||
Konstantin Khorenko <khorenko@virtuozzo.com>
|
|
||||||
KORN Andras <korn@elan.rulez.org>
|
|
||||||
kotauskas <v.toncharov@gmail.com>
|
|
||||||
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>
|
|
||||||
Lukas Wunner <lukas@wunner.de>
|
|
||||||
luozhengzheng <luo.zhengzheng@zte.com.cn>
|
|
||||||
Luís Henriques <henrix@camandro.org>
|
|
||||||
Madhav Suresh <madhav.suresh@delphix.com>
|
|
||||||
Maksym Shkolnyi <maksym.shkolnyi@workato.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 Heller <matthew.f.heller@gmail.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>
|
|
||||||
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>
|
|
||||||
Meriel Luna Mittelbach <lunarlambda@gmail.com>
|
|
||||||
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>
|
|
||||||
mnrx <mnrx@users.noreply.github.com>
|
|
||||||
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>
|
|
||||||
nav1s <nav1s@proton.me>
|
|
||||||
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.org>
|
|
||||||
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 Fasano <patrick@patrickfasano.com>
|
|
||||||
Patrick Mooney <pmooney@pfmooney.com>
|
|
||||||
Patrick Xia <patrickx@google.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>
|
|
||||||
Peng Liu <littlenewton6@gmail.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>
|
|
||||||
Phil Sutter <phil@nwl.cc>
|
|
||||||
Ping Huang <huangping@smartx.com>
|
|
||||||
Piotr Kubaj <pkubaj@anongoth.pl>
|
|
||||||
Piotr P. Stefaniak <pstef@freebsd.org>
|
|
||||||
poscat <poscat@poscat.moe>
|
|
||||||
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 Thébault <quentin.thebault@defenso.fr>
|
|
||||||
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>
|
|
||||||
René Wirnata <rene.wirnata@pandascience.net>
|
|
||||||
Ricardo M. Correia <ricardo.correia@oracle.com>
|
|
||||||
Riccardo Schirone <rschirone91@gmail.com>
|
|
||||||
Richard Allen <belperite@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>
|
|
||||||
Sebastian Pauka <me@spauka.se>
|
|
||||||
Sebastian Wuerl <s.wuerl@mailbox.org>
|
|
||||||
Sebastien Roy <seb@delphix.com>
|
|
||||||
Sen Haerens <sen@senhaerens.be>
|
|
||||||
Serapheim Dimitropoulos <serapheim@delphix.com>
|
|
||||||
Seth Forshee <seth.forshee@canonical.com>
|
|
||||||
Seth Hoffert <Seth.Hoffert@gmail.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>
|
|
||||||
SHENGYI HONG <aokblast@FreeBSD.org>
|
|
||||||
Shen Yan <shenyanxxxy@qq.com>
|
|
||||||
Shreshth Srivastava <shreshthsrivastava2@gmail.com>
|
|
||||||
Sietse <sietse@wizdom.nu>
|
|
||||||
Simon Guest <simon.guest@tesujimath.org>
|
|
||||||
Simon Howard <fraggle@soulsphere.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>
|
|
||||||
Syed Shahrukh Hussain <syed.shahrukh@ossrevival.org>
|
|
||||||
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>
|
|
||||||
Theera K. <tkittich@hotmail.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>
|
|
||||||
Tim Smith <tim@mondoo.com>
|
|
||||||
Tino Reichardt <milky-zfs@mcmilk.de>
|
|
||||||
tleydxdy <shironeko.github@tesaguri.club>
|
|
||||||
Tobin Harding <me@tobin.cc>
|
|
||||||
Todd Seidelmann <seidelma@users.noreply.github.com>
|
|
||||||
Todd Zullinger <tmz@pobox.com>
|
|
||||||
Tom Caputi <tcaputi@datto.com>
|
|
||||||
Tom Matthews <tom@axiom-partners.com>
|
|
||||||
Tomohiro Kusumi <kusumi.tomohiro@gmail.com>
|
|
||||||
Tom Prince <tom.prince@ualberta.net>
|
|
||||||
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>
|
|
||||||
trick2011 <trick2011@users.noreply.github.com>
|
|
||||||
Troels Nørgaard <tnn@tradeshift.com>
|
|
||||||
tstabrawa <tstabrawa@users.noreply.github.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>
|
|
||||||
Vandana Rungta <vrungta@amazon.com>
|
|
||||||
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>
|
|
||||||
XDTG <click1799@163.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,2 +0,0 @@
|
|||||||
The [OpenZFS Code of Conduct](https://openzfs.org/wiki/Code_of_Conduct)
|
|
||||||
applies to spaces associated with the OpenZFS project, including GitHub.
|
|
||||||
@@ -1,31 +1,33 @@
|
|||||||
Refer to the git commit log for authoritative copyright attribution.
|
The majority of the code in the ZFS on Linux port comes from OpenSolaris
|
||||||
|
which has been released under the terms of the CDDL open source license.
|
||||||
|
This includes the core ZFS code, libavl, libnvpair, libefi, libunicode,
|
||||||
|
and libutil. The original OpenSolaris source can be downloaded from:
|
||||||
|
|
||||||
The original ZFS source code was obtained from Open Solaris which was
|
http://dlc.sun.com/osol/on/downloads/b121/on-src.tar.bz2
|
||||||
released under the terms of the CDDL open source license. Additional
|
|
||||||
changes have been included from OpenZFS and the Illumos project which
|
|
||||||
are similarly licensed. These projects can be found on Github at:
|
|
||||||
|
|
||||||
* https://github.com/illumos/illumos-gate
|
Files which do not originate from OpenSolaris are noted in the file header
|
||||||
* https://github.com/openzfs/openzfs
|
and attributed properly. These exceptions include, but are not limited
|
||||||
|
to, the vdev_disk.c and zvol.c implementation which are licensed under
|
||||||
|
the CDDL.
|
||||||
|
|
||||||
|
The zpios test code is originally derived from the Lustre pios test code
|
||||||
|
which is licensed under the GPLv2. As such the heavily modified zpios
|
||||||
|
kernel test code also remains licensed under the GPLv2.
|
||||||
|
|
||||||
|
The latest stable and development versions of this port can be downloaded
|
||||||
|
from the official ZFS on Linux site located at:
|
||||||
|
|
||||||
|
http://zfsonlinux.org/
|
||||||
|
|
||||||
|
This ZFS on Linux port was produced at the Lawrence Livermore National
|
||||||
|
Laboratory (LLNL) under Contract No. DE-AC52-07NA27344 (Contract 44)
|
||||||
|
between the U.S. Department of Energy (DOE) and Lawrence Livermore
|
||||||
|
National Security, LLC (LLNS) for the operation of LLNL. It has been
|
||||||
|
approved for release under LLNL-CODE-403049.
|
||||||
|
|
||||||
Unless otherwise noted, all files in this distribution are released
|
Unless otherwise noted, all files in this distribution are released
|
||||||
under the Common Development and Distribution License (CDDL).
|
under the Common Development and Distribution License (CDDL).
|
||||||
|
Exceptions are noted within the associated source files. See the file
|
||||||
|
OPENSOLARIS.LICENSE for more information.
|
||||||
|
|
||||||
Exceptions are noted within the associated source files headers and
|
Refer to the git commit log for authoritative copyright attribution.
|
||||||
by including a THIRDPARTYLICENSE file with the license terms. A few
|
|
||||||
notable exceptions and their respective licenses include:
|
|
||||||
|
|
||||||
* Skein Checksum Implementation: module/icp/algs/skein/THIRDPARTYLICENSE
|
|
||||||
* AES Implementation: module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman
|
|
||||||
* AES Implementation: module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl
|
|
||||||
* PBKDF2 Implementation: lib/libzfs/THIRDPARTYLICENSE.openssl
|
|
||||||
* SPL Implementation: module/os/linux/spl/THIRDPARTYLICENSE.gplv2
|
|
||||||
* GCM Implementation: module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.cryptogams
|
|
||||||
* GCM Implementation: module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.openssl
|
|
||||||
* GHASH Implementation: module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.cryptogams
|
|
||||||
* GHASH Implementation: module/icp/asm-x86_64/modes/THIRDPARTYLICENSE.openssl
|
|
||||||
|
|
||||||
This product includes software developed by the OpenSSL Project for use
|
|
||||||
in the OpenSSL Toolkit (http://www.openssl.org/)
|
|
||||||
|
|
||||||
See the LICENSE and NOTICE for more information.
|
|
||||||
|
|||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
This work was produced at the Lawrence Livermore National Laboratory
|
||||||
|
(LLNL) under Contract No. DE-AC52-07NA27344 (Contract 44) between
|
||||||
|
the U.S. Department of Energy (DOE) and Lawrence Livermore National
|
||||||
|
Security, LLC (LLNS) for the operation of LLNL.
|
||||||
|
|
||||||
|
This work was prepared as an account of work sponsored by an agency of
|
||||||
|
the United States Government. Neither the United States Government nor
|
||||||
|
Lawrence Livermore National Security, LLC nor any of their employees,
|
||||||
|
makes any warranty, express or implied, or assumes any liability or
|
||||||
|
responsibility for the accuracy, completeness, or usefulness of any
|
||||||
|
information, apparatus, product, or process disclosed, or represents
|
||||||
|
that its use would not infringe privately-owned rights.
|
||||||
|
|
||||||
|
Reference herein to any specific commercial products, process, or
|
||||||
|
services by trade name, trademark, manufacturer or otherwise does
|
||||||
|
not necessarily constitute or imply its endorsement, recommendation,
|
||||||
|
or favoring by the United States Government or Lawrence Livermore
|
||||||
|
National Security, LLC. The views and opinions of authors expressed
|
||||||
|
herein do not necessarily state or reflect those of the United States
|
||||||
|
Government or Lawrence Livermore National Security, LLC, and shall
|
||||||
|
not be used for advertising or product endorsement purposes.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution, and
|
||||||
|
modification are specified in the file OPENSOLARIS.LICENSE.
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
Meta: 1
|
Meta: 1
|
||||||
Name: zfs
|
Name: zfs
|
||||||
Branch: 1.0
|
Branch: 1.0
|
||||||
Version: 2.4.2
|
Version: 0.7.13
|
||||||
Release: 1
|
Release: 1
|
||||||
Release-Tags: relext
|
Release-Tags: relext
|
||||||
License: CDDL
|
License: CDDL
|
||||||
Author: OpenZFS
|
Author: OpenZFS on Linux
|
||||||
Linux-Maximum: 7.0
|
|
||||||
Linux-Minimum: 4.18
|
|
||||||
|
|||||||
+46
-163
@@ -1,88 +1,32 @@
|
|||||||
# SPDX-License-Identifier: CDDL-1.0
|
|
||||||
CLEANFILES =
|
|
||||||
dist_noinst_DATA =
|
|
||||||
INSTALL_DATA_HOOKS =
|
|
||||||
INSTALL_EXEC_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
|
ACLOCAL_AMFLAGS = -I config
|
||||||
|
|
||||||
SUBDIRS = include
|
include config/rpm.am
|
||||||
if BUILD_LINUX
|
include config/deb.am
|
||||||
include $(srcdir)/%D%/rpm/Makefile.am
|
include config/tgz.am
|
||||||
endif
|
|
||||||
|
|
||||||
|
SUBDIRS = include rpm
|
||||||
if CONFIG_USER
|
if CONFIG_USER
|
||||||
include $(srcdir)/%D%/cmd/Makefile.am
|
SUBDIRS += udev etc man scripts lib tests cmd contrib
|
||||||
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
|
|
||||||
if BUILD_LINUX
|
|
||||||
include $(srcdir)/%D%/udev/Makefile.am
|
|
||||||
endif
|
endif
|
||||||
endif
|
|
||||||
CPPCHECKDIRS += module
|
|
||||||
if CONFIG_KERNEL
|
if CONFIG_KERNEL
|
||||||
SUBDIRS += module
|
SUBDIRS += module
|
||||||
|
|
||||||
extradir = $(prefix)/src/zfs-$(VERSION)
|
extradir = @prefix@/src/zfs-$(VERSION)
|
||||||
extra_HEADERS = zfs.release.in zfs_config.h.in
|
extra_HEADERS = zfs.release.in zfs_config.h.in
|
||||||
|
|
||||||
|
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
|
AUTOMAKE_OPTIONS = foreign
|
||||||
dist_noinst_DATA += AUTHORS CODE_OF_CONDUCT.md COPYRIGHT LICENSE META NEWS NOTICE
|
EXTRA_DIST = autogen.sh copy-builtin
|
||||||
dist_noinst_DATA += README.md RELEASES.md
|
EXTRA_DIST += config/config.awk config/rpm.am config/deb.am config/tgz.am
|
||||||
dist_noinst_DATA += module/lua/README.zfs module/os/linux/spl/README.md
|
EXTRA_DIST += META DISCLAIMER COPYRIGHT README.markdown OPENSOLARIS.LICENSE
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
@CODE_COVERAGE_RULES@
|
@CODE_COVERAGE_RULES@
|
||||||
|
|
||||||
GITREV = include/zfs_gitrev.h
|
distclean-local::
|
||||||
CLEANFILES += $(GITREV)
|
-$(RM) -R autom4te*.cache
|
||||||
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 += install-exec-hook $(INSTALL_EXEC_HOOKS)
|
|
||||||
install-exec-hook: $(INSTALL_EXEC_HOOKS)
|
|
||||||
|
|
||||||
PHONY += maintainer-clean-local
|
|
||||||
maintainer-clean-local:
|
|
||||||
-$(RM) $(GITREV)
|
|
||||||
|
|
||||||
PHONY += distclean-local
|
|
||||||
distclean-local:
|
|
||||||
-$(RM) -R autom4te*.cache build
|
|
||||||
-find . \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \
|
-find . \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \
|
||||||
-o -name .pc -o -name .hg -o -name .git \) -prune -o \
|
-o -name .pc -o -name .hg -o -name .git \) -prune -o \
|
||||||
\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
|
\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
|
||||||
@@ -91,126 +35,65 @@ distclean-local:
|
|||||||
-o -name 'core' -o -name 'Makefile' -o -name 'Module.symvers' \
|
-o -name 'core' -o -name 'Makefile' -o -name 'Module.symvers' \
|
||||||
-o -name '*.order' -o -name '*.markers' -o -name '*.gcda' \
|
-o -name '*.order' -o -name '*.markers' -o -name '*.gcda' \
|
||||||
-o -name '*.gcno' \) \
|
-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)
|
|
||||||
|
|
||||||
dist-hook:
|
dist-hook:
|
||||||
$(top_srcdir)/scripts/make_gitrev.sh -D $(distdir) $(GITREV)
|
sed -i 's/Release:[[:print:]]*/Release: $(RELEASE)/' \
|
||||||
$(SED) $(ac_inplace) 's/\(Release:[[:space:]]*\).*/\1$(RELEASE)/' $(distdir)/META
|
$(distdir)/META
|
||||||
|
|
||||||
PHONY += codecheck $(CHECKS)
|
checkstyle: cstyle shellcheck flake8 commitcheck
|
||||||
codecheck: $(CHECKS)
|
|
||||||
|
|
||||||
SHELLCHECKSCRIPTS += autogen.sh
|
|
||||||
|
|
||||||
PHONY += checkstyle
|
|
||||||
checkstyle: codecheck commitcheck
|
|
||||||
|
|
||||||
PHONY += commitcheck
|
|
||||||
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; \
|
scripts/commitcheck.sh; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CHECKS += spdxcheck
|
|
||||||
spdxcheck:
|
|
||||||
$(AM_V_at)$(top_srcdir)/scripts/spdxcheck.pl
|
|
||||||
|
|
||||||
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
|
|
||||||
cstyle:
|
cstyle:
|
||||||
$(AM_V_at)find $(top_srcdir) -name build -prune \
|
@find ${top_srcdir} -name '*.[hc]' ! -name 'zfs_config.*' \
|
||||||
-o -type f -name '*.[hc]' \
|
! -name '*.mod.c' -type f -exec scripts/cstyle.pl -cpP {} \+
|
||||||
! -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)
|
|
||||||
|
|
||||||
filter_executable = -exec test -x '{}' \; -print
|
shellcheck:
|
||||||
CHECKS += testscheck
|
@if type shellcheck > /dev/null 2>&1; then \
|
||||||
testscheck:
|
shellcheck --exclude=SC1090 --format=gcc scripts/paxcheck.sh \
|
||||||
$(AM_V_at)[ $$(find $(top_srcdir)/tests/zfs-tests -type f \
|
scripts/zloop.sh \
|
||||||
\( -name '*.ksh' -not $(filter_executable) \) -o \
|
scripts/zfs-tests.sh \
|
||||||
\( -name '*.kshlib' $(filter_executable) \) -o \
|
scripts/zfs.sh \
|
||||||
\( -name '*.shlib' $(filter_executable) \) -o \
|
scripts/commitcheck.sh \
|
||||||
\( -name '*.cfg' $(filter_executable) \) | \
|
$$(find cmd/zed/zed.d/*.sh -type f) \
|
||||||
tee /dev/stderr | wc -l) -eq 0 ]
|
$$(find cmd/zpool/zpool.d/* -executable); \
|
||||||
|
|
||||||
CHECKS += vcscheck
|
|
||||||
vcscheck:
|
|
||||||
$(AM_V_at)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
|
fi
|
||||||
|
|
||||||
CHECKS += zstdcheck
|
|
||||||
zstdcheck:
|
|
||||||
@$(MAKE) -C module check-zstd-symbols
|
|
||||||
|
|
||||||
PHONY += lint
|
|
||||||
lint: cppcheck paxcheck
|
lint: cppcheck paxcheck
|
||||||
|
|
||||||
PHONY += paxcheck
|
cppcheck:
|
||||||
|
@if type cppcheck > /dev/null 2>&1; then \
|
||||||
|
cppcheck --quiet --force --error-exitcode=2 --inline-suppr \
|
||||||
|
--suppressions-list=.github/suppressions.txt \
|
||||||
|
-UHAVE_SSE2 -UHAVE_AVX512F -UHAVE_UIO_ZEROCOPY \
|
||||||
|
-UHAVE_DNLC ${top_srcdir}; \
|
||||||
|
fi
|
||||||
|
|
||||||
paxcheck:
|
paxcheck:
|
||||||
$(AM_V_at)if type scanelf > /dev/null 2>&1; then \
|
@if type scanelf > /dev/null 2>&1; then \
|
||||||
$(top_srcdir)/scripts/paxcheck.sh $(top_builddir); \
|
scripts/paxcheck.sh ${top_srcdir}; \
|
||||||
else \
|
|
||||||
echo "skipping paxcheck because scanelf is not installed"; \
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CHECKS += flake8
|
|
||||||
flake8:
|
flake8:
|
||||||
$(AM_V_at)if type flake8 > /dev/null 2>&1; then \
|
@if type flake8 > /dev/null 2>&1; then \
|
||||||
flake8 $(top_srcdir); \
|
flake8 ${top_srcdir}; \
|
||||||
else \
|
|
||||||
echo "skipping flake8 because flake8 is not installed"; \
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PHONY += regen-tests
|
|
||||||
regen-tests:
|
|
||||||
@$(MAKE) -C tests/zfs-tests/tests regen
|
|
||||||
|
|
||||||
PHONY += ctags
|
|
||||||
ctags:
|
ctags:
|
||||||
$(RM) tags
|
$(RM) tags
|
||||||
find $(top_srcdir) -name '.?*' -prune \
|
find $(top_srcdir) -name .git -prune -o -name '*.[hc]' | xargs ctags
|
||||||
-o -type f -name '*.[hcS]' -exec ctags -a {} +
|
|
||||||
|
|
||||||
PHONY += etags
|
|
||||||
etags:
|
etags:
|
||||||
$(RM) TAGS
|
$(RM) TAGS
|
||||||
find $(top_srcdir) -name '.?*' -prune \
|
find $(top_srcdir) -name .pc -prune -o -name '*.[hc]' | xargs etags -a
|
||||||
-o -type f -name '*.[hcS]' -exec etags -a {} +
|
|
||||||
|
|
||||||
PHONY += cscopelist
|
|
||||||
cscopelist:
|
|
||||||
find $(top_srcdir) -name '.?*' -prune \
|
|
||||||
-o -type f -name '*.[hc]' -print >cscope.files
|
|
||||||
|
|
||||||
PHONY += tags
|
|
||||||
tags: ctags etags
|
tags: ctags etags
|
||||||
|
|
||||||
PHONY += pkg pkg-dkms pkg-kmod pkg-utils
|
|
||||||
pkg: @DEFAULT_PACKAGE@
|
pkg: @DEFAULT_PACKAGE@
|
||||||
pkg-dkms: @DEFAULT_PACKAGE@-dkms
|
pkg-dkms: @DEFAULT_PACKAGE@-dkms
|
||||||
pkg-kmod: @DEFAULT_PACKAGE@-kmod
|
pkg-kmod: @DEFAULT_PACKAGE@-kmod
|
||||||
pkg-utils: @DEFAULT_PACKAGE@-utils
|
pkg-utils: @DEFAULT_PACKAGE@-utils
|
||||||
|
|
||||||
include config/rpm.am
|
|
||||||
include config/deb.am
|
|
||||||
include config/tgz.am
|
|
||||||
|
|
||||||
.PHONY: $(PHONY)
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
Descriptions of all releases can be found on github:
|
|
||||||
|
|
||||||
https://github.com/openzfs/zfs/releases
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
This work was produced under the auspices of the U.S. Department of Energy by
|
|
||||||
Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344.
|
|
||||||
|
|
||||||
This work was prepared as an account of work sponsored by an agency of the
|
|
||||||
United States Government. Neither the United States Government nor Lawrence
|
|
||||||
Livermore National Security, LLC, nor any of their employees makes any warranty,
|
|
||||||
expressed or implied, or assumes any legal liability or responsibility for the
|
|
||||||
accuracy, completeness, or usefulness of any information, apparatus, product, or
|
|
||||||
process disclosed, or represents that its use would not infringe privately owned
|
|
||||||
rights. Reference herein to any specific commercial product, process, or service
|
|
||||||
by trade name, trademark, manufacturer, or otherwise does not necessarily
|
|
||||||
constitute or imply its endorsement, recommendation, or favoring by the United
|
|
||||||
States Government or Lawrence Livermore National Security, LLC. The views and
|
|
||||||
opinions of authors expressed herein do not necessarily state or reflect those
|
|
||||||
of the United States Government or Lawrence Livermore National Security, LLC,
|
|
||||||
and shall not be used for advertising or product endorsement purposes.
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|

|
||||||
|
|
||||||
|
ZFS on Linux is an advanced file system and volume manager which was originally
|
||||||
|
developed for Solaris and is now maintained by the OpenZFS community.
|
||||||
|
|
||||||
|
[](https://codecov.io/gh/zfsonlinux/zfs)
|
||||||
|
|
||||||
|
# Official Resources
|
||||||
|
* [Site](http://zfsonlinux.org)
|
||||||
|
* [Wiki](https://github.com/zfsonlinux/zfs/wiki)
|
||||||
|
* [Mailing lists](https://github.com/zfsonlinux/zfs/wiki/Mailing-Lists)
|
||||||
|
* [OpenZFS site](http://open-zfs.org/)
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
Full documentation for installing ZoL on your favorite Linux distribution can
|
||||||
|
be found at [our site](http://zfsonlinux.org/).
|
||||||
|
|
||||||
|
# Contribute & Develop
|
||||||
|
We have a separate document with [contribution guidelines](./.github/CONTRIBUTING.md).
|
||||||
@@ -1,71 +0,0 @@
|
|||||||

|
|
||||||
|
|
||||||
OpenZFS is an advanced file system and volume manager which was originally
|
|
||||||
developed for Solaris and is now maintained by the OpenZFS community.
|
|
||||||
This repository contains the code for running OpenZFS on Linux and FreeBSD.
|
|
||||||
|
|
||||||
[](https://codecov.io/gh/openzfs/zfs)
|
|
||||||
[](https://scan.coverity.com/projects/openzfs-zfs)
|
|
||||||
|
|
||||||
# Official Resources
|
|
||||||
|
|
||||||
* [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)
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
Full documentation for installing OpenZFS on your favorite operating system can
|
|
||||||
be found at the [Getting Started Page](https://openzfs.github.io/openzfs-docs/Getting%20Started/index.html).
|
|
||||||
|
|
||||||
# Contribute & Develop
|
|
||||||
|
|
||||||
We have a separate document with [contribution guidelines](./.github/CONTRIBUTING.md).
|
|
||||||
|
|
||||||
We have a [Code of Conduct](./CODE_OF_CONDUCT.md).
|
|
||||||
|
|
||||||
# Release
|
|
||||||
|
|
||||||
OpenZFS is released under a CDDL license.
|
|
||||||
For more details see the NOTICE, LICENSE and COPYRIGHT files; `UCRL-CODE-235197`
|
|
||||||
|
|
||||||
# Supported Kernels and Distributions
|
|
||||||
|
|
||||||
## Linux
|
|
||||||
|
|
||||||
Given the wide variety of Linux environments, we prioritize development and testing on stable, supported kernels and distributions.
|
|
||||||
|
|
||||||
### Kernel ([kernel.org](https://kernel.org))
|
|
||||||
|
|
||||||
All **longterm** kernels from [kernel.org](https://kernel.org) are supported. **stable** kernels are usually supported in the next OpenZFS release.
|
|
||||||
|
|
||||||
**Supported longterm kernels**: **6.18**, **6.12**, **6.6**, **6.1**, **5.15**, **5.10**.
|
|
||||||
|
|
||||||
### Red Hat Enterprise Linux (RHEL)
|
|
||||||
|
|
||||||
All RHEL (and compatible systems: AlmaLinux OS, Rocky Linux, etc) on the **full** or **maintenance** support tracks are supported.
|
|
||||||
|
|
||||||
**Supported RHEL releases**: **8.10**, **9.7**, **10.1**.
|
|
||||||
|
|
||||||
### Ubuntu
|
|
||||||
|
|
||||||
All Ubuntu **LTS** releases are supported.
|
|
||||||
|
|
||||||
**Supported Ubuntu releases**: **24.04 “Noble”**, **22.04 “Jammy”**.
|
|
||||||
|
|
||||||
### Debian
|
|
||||||
|
|
||||||
All Debian **stable** and **LTS** releases are supported.
|
|
||||||
|
|
||||||
**Supported Debian releases**: **13 “Trixie”**, **12 “Bookworm”**, **11 “Bullseye”**.
|
|
||||||
|
|
||||||
### Other Distributions
|
|
||||||
|
|
||||||
Generally, if a distribution is following an LTS kernel, it should work well with OpenZFS.
|
|
||||||
|
|
||||||
## FreeBSD
|
|
||||||
|
|
||||||
All FreeBSD releases receiving **security support** are supported by OpenZFS.
|
|
||||||
|
|
||||||
**Supported FreeBSD releases**: **15.0**, **14.3**, **13.5**.
|
|
||||||
-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.2.
|
|
||||||
|
|
||||||
* 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.
|
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
### prepare
|
### prepare
|
||||||
#TEST_PREPARE_WATCHDOG="yes"
|
#TEST_PREPARE_WATCHDOG="no"
|
||||||
#TEST_PREPARE_SHARES="yes"
|
|
||||||
|
### SPLAT
|
||||||
|
#TEST_SPLAT_SKIP="yes"
|
||||||
|
#TEST_SPLAT_OPTIONS="-acvx"
|
||||||
|
|
||||||
### ztest
|
### ztest
|
||||||
#TEST_ZTEST_SKIP="yes"
|
#TEST_ZTEST_SKIP="yes"
|
||||||
#TEST_ZTEST_TIMEOUT=1800
|
#TEST_ZTEST_TIMEOUT=1800
|
||||||
#TEST_ZTEST_DIR="/var/tmp/"
|
#TEST_ZTEST_DIR="/var/tmp/"
|
||||||
#TEST_ZTEST_OPTIONS="-V"
|
#TEST_ZTEST_OPTIONS="-V"
|
||||||
#TEST_ZTEST_CORE_DIR="/mnt/zloop"
|
|
||||||
|
|
||||||
### zimport
|
### zimport
|
||||||
#TEST_ZIMPORT_SKIP="yes"
|
#TEST_ZIMPORT_SKIP="yes"
|
||||||
@@ -29,13 +31,9 @@
|
|||||||
|
|
||||||
### zfs-tests.sh
|
### zfs-tests.sh
|
||||||
#TEST_ZFSTESTS_SKIP="yes"
|
#TEST_ZFSTESTS_SKIP="yes"
|
||||||
#TEST_ZFSTESTS_DIR="/mnt/"
|
|
||||||
#TEST_ZFSTESTS_DISKS="vdb vdc vdd"
|
#TEST_ZFSTESTS_DISKS="vdb vdc vdd"
|
||||||
#TEST_ZFSTESTS_DISKSIZE="8G"
|
#TEST_ZFSTESTS_DISKSIZE="8G"
|
||||||
#TEST_ZFSTESTS_ITERS="1"
|
|
||||||
#TEST_ZFSTESTS_OPTIONS="-vx"
|
|
||||||
#TEST_ZFSTESTS_RUNFILE="linux.run"
|
#TEST_ZFSTESTS_RUNFILE="linux.run"
|
||||||
#TEST_ZFSTESTS_TAGS="functional"
|
|
||||||
|
|
||||||
### zfsstress
|
### zfsstress
|
||||||
#TEST_ZFSSTRESS_SKIP="yes"
|
#TEST_ZFSSTRESS_SKIP="yes"
|
||||||
@@ -44,7 +42,53 @@
|
|||||||
#TEST_ZFSSTRESS_RUNTIME=300
|
#TEST_ZFSSTRESS_RUNTIME=300
|
||||||
#TEST_ZFSSTRESS_POOL="tank"
|
#TEST_ZFSSTRESS_POOL="tank"
|
||||||
#TEST_ZFSSTRESS_FS="fish"
|
#TEST_ZFSSTRESS_FS="fish"
|
||||||
#TEST_ZFSSTRESS_FSOPT="-o overlay=on"
|
|
||||||
#TEST_ZFSSTRESS_VDEV="/var/tmp/vdev"
|
#TEST_ZFSSTRESS_VDEV="/var/tmp/vdev"
|
||||||
#TEST_ZFSSTRESS_DIR="/$TEST_ZFSSTRESS_POOL/$TEST_ZFSSTRESS_FS"
|
#TEST_ZFSSTRESS_DIR="/$TEST_ZFSSTRESS_POOL/$TEST_ZFSSTRESS_FS"
|
||||||
#TEST_ZFSSTRESS_OPTIONS=""
|
#TEST_ZFSSTRESS_OPTIONS=""
|
||||||
|
|
||||||
|
### per-builder customization
|
||||||
|
#
|
||||||
|
# BB_NAME=builder-name <distribution-version-architecture-type>
|
||||||
|
# - distribution=Amazon,Debian,Fedora,RHEL,SUSE,Ubuntu
|
||||||
|
# - version=x.y
|
||||||
|
# - architecture=x86_64,i686,arm,aarch64
|
||||||
|
# - type=build,test
|
||||||
|
#
|
||||||
|
case "$BB_NAME" in
|
||||||
|
Amazon*)
|
||||||
|
# ZFS enabled xfstests fails to build
|
||||||
|
TEST_XFSTESTS_SKIP="yes"
|
||||||
|
;;
|
||||||
|
CentOS-7*)
|
||||||
|
# ZFS enabled xfstests fails to build
|
||||||
|
TEST_XFSTESTS_SKIP="yes"
|
||||||
|
;;
|
||||||
|
CentOS-6*)
|
||||||
|
;;
|
||||||
|
Debian*)
|
||||||
|
;;
|
||||||
|
Fedora*)
|
||||||
|
;;
|
||||||
|
RHEL*)
|
||||||
|
;;
|
||||||
|
SUSE*)
|
||||||
|
;;
|
||||||
|
Ubuntu-16.04*)
|
||||||
|
# ZFS enabled xfstests fails to build
|
||||||
|
TEST_XFSTESTS_SKIP="yes"
|
||||||
|
;;
|
||||||
|
Ubuntu*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# Disable the following test suites on 32-bit systems.
|
||||||
|
#
|
||||||
|
if [ $(getconf LONG_BIT) = "32" ]; then
|
||||||
|
TEST_ZTEST_SKIP="yes"
|
||||||
|
TEST_XFSTESTS_SKIP="yes"
|
||||||
|
TEST_ZFSSTRESS_SKIP="yes"
|
||||||
|
fi
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SPDX-License-Identifier: CDDL-1.0
|
|
||||||
|
|
||||||
autoreconf -fiv "$(dirname "$0")" && rm -rf "$(dirname "$0")"/autom4te.cache
|
autoreconf -fiv
|
||||||
|
rm -Rf autom4te.cache
|
||||||
|
|||||||
+3
-114
@@ -1,114 +1,3 @@
|
|||||||
# SPDX-License-Identifier: CDDL-1.0
|
SUBDIRS = zfs zpool zdb zhack zinject zstreamdump ztest zpios
|
||||||
bin_SCRIPTS =
|
SUBDIRS += mount_zfs fsck_zfs zvol_id vdev_id arcstat dbufstat zed
|
||||||
bin_PROGRAMS =
|
SUBDIRS += arc_summary raidz_test zgenhostid
|
||||||
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) $(LIBZPOOL_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)
|
|
||||||
ztest_CPPFLAGS = $(AM_CPPFLAGS) $(LIBZPOOL_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
|
|
||||||
|
|
||||||
|
|
||||||
if USING_PYTHON
|
|
||||||
bin_SCRIPTS += zarcsummary zarcstat dbufstat zilstat
|
|
||||||
CLEANFILES += zarcsummary zarcstat dbufstat zilstat
|
|
||||||
dist_noinst_DATA += %D%/zarcsummary %D%/zarcstat.in %D%/dbufstat.in %D%/zilstat.in
|
|
||||||
|
|
||||||
$(call SUBST,zarcstat,%D%/)
|
|
||||||
$(call SUBST,dbufstat,%D%/)
|
|
||||||
$(call SUBST,zilstat,%D%/)
|
|
||||||
zarcsummary: %D%/zarcsummary
|
|
||||||
$(AM_V_at)cp $< $@
|
|
||||||
endif
|
|
||||||
|
|
||||||
PHONY += cmd
|
|
||||||
cmd: $(bin_SCRIPTS) $(bin_PROGRAMS) $(sbin_SCRIPTS) $(sbin_PROGRAMS) $(dist_bin_SCRIPTS) $(zfsexec_PROGRAMS) $(mounthelper_PROGRAMS)
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
dist_bin_SCRIPTS = arc_summary.py
|
||||||
Executable
+1039
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
|||||||
|
dist_bin_SCRIPTS = arcstat.py
|
||||||
Executable
+462
@@ -0,0 +1,462 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Print out ZFS ARC Statistics exported via kstat(1)
|
||||||
|
# For a definition of fields, or usage, use arctstat.pl -v
|
||||||
|
#
|
||||||
|
# This script is a fork of the original arcstat.pl (0.1) by
|
||||||
|
# Neelakanth Nadgir, originally published on his Sun blog on
|
||||||
|
# 09/18/2007
|
||||||
|
# http://blogs.sun.com/realneel/entry/zfs_arc_statistics
|
||||||
|
#
|
||||||
|
# This version aims to improve upon the original by adding features
|
||||||
|
# and fixing bugs as needed. This version is maintained by
|
||||||
|
# Mike Harsch and is hosted in a public open source repository:
|
||||||
|
# http://github.com/mharsch/arcstat
|
||||||
|
#
|
||||||
|
# Comments, Questions, or Suggestions are always welcome.
|
||||||
|
# Contact the maintainer at ( mike at harschsystems dot com )
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License, Version 1.0 only
|
||||||
|
# (the "License"). 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 http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Fields have a fixed width. Every interval, we fill the "v"
|
||||||
|
# hash with its corresponding value (v[field]=value) using calculate().
|
||||||
|
# @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.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import getopt
|
||||||
|
import re
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
from signal import signal, SIGINT, SIGWINCH, SIG_DFL
|
||||||
|
|
||||||
|
cols = {
|
||||||
|
# HDR: [Size, Scale, Description]
|
||||||
|
"time": [8, -1, "Time"],
|
||||||
|
"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"],
|
||||||
|
"miss%": [5, 100, "ARC miss percentage"],
|
||||||
|
"dhit": [4, 1000, "Demand hits per second"],
|
||||||
|
"dmis": [4, 1000, "Demand misses per second"],
|
||||||
|
"dh%": [3, 100, "Demand hit percentage"],
|
||||||
|
"dm%": [3, 100, "Demand miss percentage"],
|
||||||
|
"phit": [4, 1000, "Prefetch hits per second"],
|
||||||
|
"pmis": [4, 1000, "Prefetch misses per second"],
|
||||||
|
"ph%": [3, 100, "Prefetch hits percentage"],
|
||||||
|
"pm%": [3, 100, "Prefetch miss percentage"],
|
||||||
|
"mhit": [4, 1000, "Metadata hits per second"],
|
||||||
|
"mmis": [4, 1000, "Metadata misses per second"],
|
||||||
|
"mread": [4, 1000, "Metadata accesses per second"],
|
||||||
|
"mh%": [3, 100, "Metadata hit percentage"],
|
||||||
|
"mm%": [3, 100, "Metadata miss percentage"],
|
||||||
|
"arcsz": [5, 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"],
|
||||||
|
"eskip": [5, 1000, "evict_skip per second"],
|
||||||
|
"mtxmis": [6, 1000, "mutex_miss per second"],
|
||||||
|
"dread": [5, 1000, "Demand accesses per second"],
|
||||||
|
"pread": [5, 1000, "Prefetch 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"],
|
||||||
|
"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"],
|
||||||
|
}
|
||||||
|
|
||||||
|
v = {}
|
||||||
|
hdr = ["time", "read", "miss", "miss%", "dmis", "dm%", "pmis", "pm%", "mmis",
|
||||||
|
"mm%", "arcsz", "c"]
|
||||||
|
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.py [-hvx] [-f fields] [-o file] [-s string] [interval "
|
||||||
|
"[count]]\n")
|
||||||
|
cur = {}
|
||||||
|
d = {}
|
||||||
|
out = None
|
||||||
|
kstat = None
|
||||||
|
|
||||||
|
|
||||||
|
def detailed_usage():
|
||||||
|
sys.stderr.write("%s\n" % cmd)
|
||||||
|
sys.stderr.write("Field definitions are as follows:\n")
|
||||||
|
for key in cols:
|
||||||
|
sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
|
||||||
|
sys.stderr.write("\n")
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
sys.stderr.write("%s\n" % cmd)
|
||||||
|
sys.stderr.write("\t -h : Print this help message\n")
|
||||||
|
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 -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 "
|
||||||
|
"character or string\n")
|
||||||
|
sys.stderr.write("\nExamples:\n")
|
||||||
|
sys.stderr.write("\tarcstat.py -o /tmp/a.log 2 10\n")
|
||||||
|
sys.stderr.write("\tarcstat.py -s \",\" -o /tmp/a.log 2 10\n")
|
||||||
|
sys.stderr.write("\tarcstat.py -v\n")
|
||||||
|
sys.stderr.write("\tarcstat.py -f time,hit%,dh%,ph%,mh% 1\n")
|
||||||
|
sys.stderr.write("\n")
|
||||||
|
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def kstat_update():
|
||||||
|
global kstat
|
||||||
|
|
||||||
|
k = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')]
|
||||||
|
|
||||||
|
if not k:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
del k[0:2]
|
||||||
|
kstat = {}
|
||||||
|
|
||||||
|
for s in k:
|
||||||
|
if not s:
|
||||||
|
continue
|
||||||
|
|
||||||
|
name, unused, value = s.split()
|
||||||
|
kstat[name] = Decimal(value)
|
||||||
|
|
||||||
|
|
||||||
|
def snap_stats():
|
||||||
|
global cur
|
||||||
|
global kstat
|
||||||
|
|
||||||
|
prev = copy.deepcopy(cur)
|
||||||
|
kstat_update()
|
||||||
|
|
||||||
|
cur = kstat
|
||||||
|
for key in cur:
|
||||||
|
if re.match(key, "class"):
|
||||||
|
continue
|
||||||
|
if key in prev:
|
||||||
|
d[key] = cur[key] - prev[key]
|
||||||
|
else:
|
||||||
|
d[key] = cur[key]
|
||||||
|
|
||||||
|
|
||||||
|
def prettynum(sz, scale, num=0):
|
||||||
|
suffix = [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
|
||||||
|
index = 0
|
||||||
|
save = 0
|
||||||
|
|
||||||
|
# Special case for date field
|
||||||
|
if scale == -1:
|
||||||
|
return "%s" % num
|
||||||
|
|
||||||
|
# Rounding error, return 0
|
||||||
|
elif 0 < num < 1:
|
||||||
|
num = 0
|
||||||
|
|
||||||
|
while num > scale and index < 5:
|
||||||
|
save = num
|
||||||
|
num = num / scale
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
if index == 0:
|
||||||
|
return "%*d" % (sz, num)
|
||||||
|
|
||||||
|
if (save / scale) < 10:
|
||||||
|
return "%*.1f%s" % (sz - 1, num, suffix[index])
|
||||||
|
else:
|
||||||
|
return "%*d%s" % (sz - 1, num, suffix[index])
|
||||||
|
|
||||||
|
|
||||||
|
def print_values():
|
||||||
|
global hdr
|
||||||
|
global sep
|
||||||
|
global v
|
||||||
|
|
||||||
|
for col in hdr:
|
||||||
|
sys.stdout.write("%s%s" % (
|
||||||
|
prettynum(cols[col][0], cols[col][1], v[col]),
|
||||||
|
sep
|
||||||
|
))
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def print_header():
|
||||||
|
global hdr
|
||||||
|
global sep
|
||||||
|
|
||||||
|
for col in hdr:
|
||||||
|
sys.stdout.write("%*s%s" % (cols[col][0], col, sep))
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
|
||||||
|
|
||||||
|
def get_terminal_lines():
|
||||||
|
try:
|
||||||
|
import fcntl
|
||||||
|
import termios
|
||||||
|
import struct
|
||||||
|
data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
|
||||||
|
sz = struct.unpack('hh', data)
|
||||||
|
return sz[0]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def update_hdr_intr():
|
||||||
|
global hdr_intr
|
||||||
|
|
||||||
|
lines = get_terminal_lines()
|
||||||
|
if lines and lines > 3:
|
||||||
|
hdr_intr = lines - 3
|
||||||
|
|
||||||
|
|
||||||
|
def resize_handler(signum, frame):
|
||||||
|
update_hdr_intr()
|
||||||
|
|
||||||
|
|
||||||
|
def init():
|
||||||
|
global sint
|
||||||
|
global count
|
||||||
|
global hdr
|
||||||
|
global xhdr
|
||||||
|
global opfile
|
||||||
|
global sep
|
||||||
|
global out
|
||||||
|
global l2exist
|
||||||
|
|
||||||
|
desired_cols = None
|
||||||
|
xflag = False
|
||||||
|
hflag = False
|
||||||
|
vflag = False
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
opts, args = getopt.getopt(
|
||||||
|
sys.argv[1:],
|
||||||
|
"xo:hvs:f:",
|
||||||
|
[
|
||||||
|
"extended",
|
||||||
|
"outfile",
|
||||||
|
"help",
|
||||||
|
"verbose",
|
||||||
|
"separator",
|
||||||
|
"columns"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
except getopt.error as msg:
|
||||||
|
sys.stderr.write("Error: %s\n" % str(msg))
|
||||||
|
usage()
|
||||||
|
opts = None
|
||||||
|
|
||||||
|
for opt, arg in opts:
|
||||||
|
if opt in ('-x', '--extended'):
|
||||||
|
xflag = True
|
||||||
|
if opt in ('-o', '--outfile'):
|
||||||
|
opfile = arg
|
||||||
|
i += 1
|
||||||
|
if opt in ('-h', '--help'):
|
||||||
|
hflag = True
|
||||||
|
if opt in ('-v', '--verbose'):
|
||||||
|
vflag = True
|
||||||
|
if opt in ('-s', '--separator'):
|
||||||
|
sep = arg
|
||||||
|
i += 1
|
||||||
|
if opt in ('-f', '--columns'):
|
||||||
|
desired_cols = arg
|
||||||
|
i += 1
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
argv = sys.argv[i:]
|
||||||
|
sint = Decimal(argv[0]) if argv else sint
|
||||||
|
count = int(argv[1]) if len(argv) > 1 else count
|
||||||
|
|
||||||
|
if len(argv) > 1:
|
||||||
|
sint = Decimal(argv[0])
|
||||||
|
count = int(argv[1])
|
||||||
|
|
||||||
|
elif len(argv) > 0:
|
||||||
|
sint = Decimal(argv[0])
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
if hflag or (xflag and desired_cols):
|
||||||
|
usage()
|
||||||
|
|
||||||
|
if vflag:
|
||||||
|
detailed_usage()
|
||||||
|
|
||||||
|
if xflag:
|
||||||
|
hdr = xhdr
|
||||||
|
|
||||||
|
update_hdr_intr()
|
||||||
|
|
||||||
|
# check if L2ARC exists
|
||||||
|
snap_stats()
|
||||||
|
l2_size = cur.get("l2_size")
|
||||||
|
if l2_size:
|
||||||
|
l2exist = True
|
||||||
|
|
||||||
|
if desired_cols:
|
||||||
|
hdr = desired_cols.split(",")
|
||||||
|
|
||||||
|
invalid = []
|
||||||
|
incompat = []
|
||||||
|
for ele in hdr:
|
||||||
|
if ele not in cols:
|
||||||
|
invalid.append(ele)
|
||||||
|
elif not l2exist and ele.startswith("l2"):
|
||||||
|
sys.stdout.write("No L2ARC Here\n%s\n" % ele)
|
||||||
|
incompat.append(ele)
|
||||||
|
|
||||||
|
if len(invalid) > 0:
|
||||||
|
sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
|
||||||
|
usage()
|
||||||
|
|
||||||
|
if len(incompat) > 0:
|
||||||
|
sys.stderr.write("Incompatible field specified! -- %s\n" %
|
||||||
|
incompat)
|
||||||
|
usage()
|
||||||
|
|
||||||
|
if opfile:
|
||||||
|
try:
|
||||||
|
out = open(opfile, "w")
|
||||||
|
sys.stdout = out
|
||||||
|
|
||||||
|
except IOError:
|
||||||
|
sys.stderr.write("Cannot open %s for writing\n" % opfile)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def calculate():
|
||||||
|
global d
|
||||||
|
global v
|
||||||
|
global l2exist
|
||||||
|
|
||||||
|
v = dict()
|
||||||
|
v["time"] = time.strftime("%H:%M:%S", time.localtime())
|
||||||
|
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["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) / sint
|
||||||
|
|
||||||
|
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["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) / sint
|
||||||
|
v["pmis"] = (d["prefetch_data_misses"] +
|
||||||
|
d["prefetch_metadata_misses"]) / sint
|
||||||
|
|
||||||
|
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["mmis"] = (d["prefetch_metadata_misses"] +
|
||||||
|
d["demand_metadata_misses"]) / sint
|
||||||
|
|
||||||
|
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["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["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["l2read"] = v["l2hits"] + v["l2miss"]
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global sint
|
||||||
|
global count
|
||||||
|
global hdr_intr
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
count_flag = 0
|
||||||
|
|
||||||
|
init()
|
||||||
|
if count > 0:
|
||||||
|
count_flag = 1
|
||||||
|
|
||||||
|
signal(SIGINT, SIG_DFL)
|
||||||
|
signal(SIGWINCH, resize_handler)
|
||||||
|
while True:
|
||||||
|
if i == 0:
|
||||||
|
print_header()
|
||||||
|
|
||||||
|
snap_stats()
|
||||||
|
calculate()
|
||||||
|
print_values()
|
||||||
|
|
||||||
|
if count_flag == 1:
|
||||||
|
if count <= 1:
|
||||||
|
break
|
||||||
|
count -= 1
|
||||||
|
|
||||||
|
i = 0 if i >= hdr_intr else i + 1
|
||||||
|
time.sleep(sint)
|
||||||
|
|
||||||
|
if out:
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
-687
@@ -1,687 +0,0 @@
|
|||||||
#!/usr/bin/env @PYTHON_SHEBANG@
|
|
||||||
# SPDX-License-Identifier: CDDL-1.0
|
|
||||||
#
|
|
||||||
# Print out statistics for all cached dmu buffers. This information
|
|
||||||
# is available through the dbufs kstat and may be post-processed as
|
|
||||||
# needed by the script.
|
|
||||||
#
|
|
||||||
# CDDL HEADER START
|
|
||||||
#
|
|
||||||
# The contents of this file are subject to the terms of the
|
|
||||||
# Common Development and Distribution License, Version 1.0 only
|
|
||||||
# (the "License"). 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.
|
|
||||||
# See the License for the specific language governing permissions
|
|
||||||
# and limitations under the License.
|
|
||||||
#
|
|
||||||
# When distributing Covered Code, include this CDDL HEADER in each
|
|
||||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
||||||
# If applicable, add the following below this CDDL HEADER, with the
|
|
||||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
|
||||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
|
||||||
#
|
|
||||||
# CDDL HEADER END
|
|
||||||
#
|
|
||||||
# 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+.
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import getopt
|
|
||||||
import errno
|
|
||||||
import re
|
|
||||||
|
|
||||||
bhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize"]
|
|
||||||
bxhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize",
|
|
||||||
"usize", "meta", "state", "dbholds", "dbc", "list", "atype", "flags",
|
|
||||||
"count", "asize", "access", "mru", "gmru", "mfu", "gmfu", "l2",
|
|
||||||
"l2_dattr", "l2_asize", "l2_comp", "aholds", "dtype", "btype",
|
|
||||||
"data_bs", "meta_bs", "bsize", "lvls", "dholds", "blocks", "dsize"]
|
|
||||||
bincompat = ["cached", "direct", "indirect", "bonus", "spill"]
|
|
||||||
|
|
||||||
dhdr = ["pool", "objset", "object", "dtype", "cached"]
|
|
||||||
dxhdr = ["pool", "objset", "object", "dtype", "btype", "data_bs", "meta_bs",
|
|
||||||
"bsize", "lvls", "dholds", "blocks", "dsize", "cached", "direct",
|
|
||||||
"indirect", "bonus", "spill"]
|
|
||||||
dincompat = ["level", "blkid", "offset", "dbsize", "usize", "meta", "state",
|
|
||||||
"dbholds", "dbc", "list", "atype", "flags", "count", "asize",
|
|
||||||
"access", "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr",
|
|
||||||
"l2_asize", "l2_comp", "aholds"]
|
|
||||||
|
|
||||||
thdr = ["pool", "objset", "dtype", "cached"]
|
|
||||||
txhdr = ["pool", "objset", "dtype", "cached", "direct", "indirect",
|
|
||||||
"bonus", "spill"]
|
|
||||||
tincompat = ["object", "level", "blkid", "offset", "dbsize", "usize", "meta",
|
|
||||||
"state", "dbc", "dbholds", "list", "atype", "flags", "count",
|
|
||||||
"asize", "access", "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr",
|
|
||||||
"l2_asize", "l2_comp", "aholds", "btype", "data_bs", "meta_bs",
|
|
||||||
"bsize", "lvls", "dholds", "blocks", "dsize"]
|
|
||||||
|
|
||||||
cols = {
|
|
||||||
# hdr: [size, scale, description]
|
|
||||||
"pool": [15, -1, "pool name"],
|
|
||||||
"objset": [6, -1, "dataset identification number"],
|
|
||||||
"object": [10, -1, "object number"],
|
|
||||||
"level": [5, -1, "indirection level of buffer"],
|
|
||||||
"blkid": [8, -1, "block number of buffer"],
|
|
||||||
"offset": [12, 1024, "offset in object of buffer"],
|
|
||||||
"dbsize": [7, 1024, "size of buffer"],
|
|
||||||
"usize": [7, 1024, "size of attached user data"],
|
|
||||||
"meta": [4, -1, "is this buffer metadata?"],
|
|
||||||
"state": [5, -1, "state of buffer (read, cached, etc)"],
|
|
||||||
"dbholds": [7, 1000, "number of holds on buffer"],
|
|
||||||
"dbc": [3, -1, "in dbuf cache"],
|
|
||||||
"list": [4, -1, "which ARC list contains this buffer"],
|
|
||||||
"atype": [7, -1, "ARC header type (data or metadata)"],
|
|
||||||
"flags": [9, -1, "ARC read flags"],
|
|
||||||
"count": [5, -1, "ARC data count"],
|
|
||||||
"asize": [7, 1024, "size of this ARC buffer"],
|
|
||||||
"access": [10, -1, "time this ARC buffer was last accessed"],
|
|
||||||
"mru": [5, 1000, "hits while on the ARC's MRU list"],
|
|
||||||
"gmru": [5, 1000, "hits while on the ARC's MRU ghost list"],
|
|
||||||
"mfu": [5, 1000, "hits while on the ARC's MFU list"],
|
|
||||||
"gmfu": [5, 1000, "hits while on the ARC's MFU ghost list"],
|
|
||||||
"l2": [5, 1000, "hits while on the L2ARC"],
|
|
||||||
"l2_dattr": [8, -1, "L2ARC disk address/offset"],
|
|
||||||
"l2_asize": [8, 1024, "L2ARC alloc'd size (depending on compression)"],
|
|
||||||
"l2_comp": [21, -1, "L2ARC compression algorithm for buffer"],
|
|
||||||
"aholds": [6, 1000, "number of holds on this ARC buffer"],
|
|
||||||
"dtype": [27, -1, "dnode type"],
|
|
||||||
"btype": [27, -1, "bonus buffer type"],
|
|
||||||
"data_bs": [7, 1024, "data block size"],
|
|
||||||
"meta_bs": [7, 1024, "metadata block size"],
|
|
||||||
"bsize": [6, 1024, "bonus buffer size"],
|
|
||||||
"lvls": [6, -1, "number of indirection levels"],
|
|
||||||
"dholds": [6, 1000, "number of holds on dnode"],
|
|
||||||
"blocks": [8, 1000, "number of allocated blocks"],
|
|
||||||
"dsize": [12, 1024, "size of dnode"],
|
|
||||||
"cached": [6, 1024, "bytes cached for all blocks"],
|
|
||||||
"direct": [6, 1024, "bytes cached for direct blocks"],
|
|
||||||
"indirect": [8, 1024, "bytes cached for indirect blocks"],
|
|
||||||
"bonus": [5, 1024, "bytes cached for bonus buffer"],
|
|
||||||
"spill": [5, 1024, "bytes cached for spill block"],
|
|
||||||
}
|
|
||||||
|
|
||||||
hdr = None
|
|
||||||
xhdr = None
|
|
||||||
sep = " " # Default separator is 2 spaces
|
|
||||||
cmd = ("Usage: dbufstat [-bdhnrtvx] [-i file] [-f fields] [-o file] "
|
|
||||||
"[-s string] [-F filter]\n")
|
|
||||||
raw = 0
|
|
||||||
|
|
||||||
|
|
||||||
if sys.platform.startswith("freebsd"):
|
|
||||||
import io
|
|
||||||
# Requires py-sysctl on FreeBSD
|
|
||||||
import sysctl
|
|
||||||
|
|
||||||
def default_ifile():
|
|
||||||
dbufs = sysctl.filter("kstat.zfs.misc.dbufs")[0].value
|
|
||||||
sys.stdin = io.StringIO(dbufs)
|
|
||||||
return "-"
|
|
||||||
|
|
||||||
elif sys.platform.startswith("linux"):
|
|
||||||
def default_ifile():
|
|
||||||
return "/proc/spl/kstat/zfs/dbufs"
|
|
||||||
|
|
||||||
|
|
||||||
def print_incompat_helper(incompat):
|
|
||||||
cnt = 0
|
|
||||||
for key in sorted(incompat):
|
|
||||||
if cnt == 0:
|
|
||||||
sys.stderr.write("\t")
|
|
||||||
elif cnt > 8:
|
|
||||||
sys.stderr.write(",\n\t")
|
|
||||||
cnt = 0
|
|
||||||
else:
|
|
||||||
sys.stderr.write(", ")
|
|
||||||
|
|
||||||
sys.stderr.write("%s" % key)
|
|
||||||
cnt += 1
|
|
||||||
|
|
||||||
sys.stderr.write("\n\n")
|
|
||||||
|
|
||||||
|
|
||||||
def detailed_usage():
|
|
||||||
sys.stderr.write("%s\n" % cmd)
|
|
||||||
|
|
||||||
sys.stderr.write("Field definitions incompatible with '-b' option:\n")
|
|
||||||
print_incompat_helper(bincompat)
|
|
||||||
|
|
||||||
sys.stderr.write("Field definitions incompatible with '-d' option:\n")
|
|
||||||
print_incompat_helper(dincompat)
|
|
||||||
|
|
||||||
sys.stderr.write("Field definitions incompatible with '-t' option:\n")
|
|
||||||
print_incompat_helper(tincompat)
|
|
||||||
|
|
||||||
sys.stderr.write("Field definitions are as follows:\n")
|
|
||||||
for key in sorted(cols.keys()):
|
|
||||||
sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
|
|
||||||
sys.stderr.write("\n")
|
|
||||||
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
def usage():
|
|
||||||
sys.stderr.write("%s\n" % cmd)
|
|
||||||
sys.stderr.write("\t -b : Print table of information for each dbuf\n")
|
|
||||||
sys.stderr.write("\t -d : Print table of information for each dnode\n")
|
|
||||||
sys.stderr.write("\t -h : Print this help message\n")
|
|
||||||
sys.stderr.write("\t -n : Exclude header from output\n")
|
|
||||||
sys.stderr.write("\t -r : Print raw values\n")
|
|
||||||
sys.stderr.write("\t -t : Print table of information for each dnode type"
|
|
||||||
"\n")
|
|
||||||
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 -i : Redirect input from the specified file\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 "
|
|
||||||
"character or string\n")
|
|
||||||
sys.stderr.write("\t -F : Filter output by value or regex\n")
|
|
||||||
sys.stderr.write("\nExamples:\n")
|
|
||||||
sys.stderr.write("\tdbufstat -d -o /tmp/d.log\n")
|
|
||||||
sys.stderr.write("\tdbufstat -t -s \",\" -o /tmp/t.log\n")
|
|
||||||
sys.stderr.write("\tdbufstat -v\n")
|
|
||||||
sys.stderr.write("\tdbufstat -d -f pool,object,objset,dsize,cached\n")
|
|
||||||
sys.stderr.write("\tdbufstat -bx -F dbc=1,objset=54,pool=testpool\n")
|
|
||||||
sys.stderr.write("\n")
|
|
||||||
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def prettynum(sz, scale, num=0):
|
|
||||||
global raw
|
|
||||||
|
|
||||||
suffix = [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
|
|
||||||
index = 0
|
|
||||||
save = 0
|
|
||||||
|
|
||||||
if raw or scale == -1:
|
|
||||||
return "%*s" % (sz, num)
|
|
||||||
|
|
||||||
# Rounding error, return 0
|
|
||||||
elif 0 < num < 1:
|
|
||||||
num = 0
|
|
||||||
|
|
||||||
while num > scale and index < 5:
|
|
||||||
save = num
|
|
||||||
num = num / scale
|
|
||||||
index += 1
|
|
||||||
|
|
||||||
if index == 0:
|
|
||||||
return "%*d" % (sz, num)
|
|
||||||
|
|
||||||
if (save / scale) < 10:
|
|
||||||
return "%*.1f%s" % (sz - 1, num, suffix[index])
|
|
||||||
else:
|
|
||||||
return "%*d%s" % (sz - 1, num, suffix[index])
|
|
||||||
|
|
||||||
|
|
||||||
def print_values(v):
|
|
||||||
global hdr
|
|
||||||
global sep
|
|
||||||
|
|
||||||
try:
|
|
||||||
for col in hdr:
|
|
||||||
sys.stdout.write("%s%s" % (
|
|
||||||
prettynum(cols[col][0], cols[col][1], v[col]), sep))
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
except IOError as e:
|
|
||||||
if e.errno == errno.EPIPE:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def print_header():
|
|
||||||
global hdr
|
|
||||||
global sep
|
|
||||||
|
|
||||||
try:
|
|
||||||
for col in hdr:
|
|
||||||
sys.stdout.write("%*s%s" % (cols[col][0], col, sep))
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
except IOError as e:
|
|
||||||
if e.errno == errno.EPIPE:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def get_typestring(t):
|
|
||||||
ot_strings = [
|
|
||||||
"DMU_OT_NONE",
|
|
||||||
# general:
|
|
||||||
"DMU_OT_OBJECT_DIRECTORY",
|
|
||||||
"DMU_OT_OBJECT_ARRAY",
|
|
||||||
"DMU_OT_PACKED_NVLIST",
|
|
||||||
"DMU_OT_PACKED_NVLIST_SIZE",
|
|
||||||
"DMU_OT_BPOBJ",
|
|
||||||
"DMU_OT_BPOBJ_HDR",
|
|
||||||
# spa:
|
|
||||||
"DMU_OT_SPACE_MAP_HEADER",
|
|
||||||
"DMU_OT_SPACE_MAP",
|
|
||||||
# zil:
|
|
||||||
"DMU_OT_INTENT_LOG",
|
|
||||||
# dmu:
|
|
||||||
"DMU_OT_DNODE",
|
|
||||||
"DMU_OT_OBJSET",
|
|
||||||
# dsl:
|
|
||||||
"DMU_OT_DSL_DIR",
|
|
||||||
"DMU_OT_DSL_DIR_CHILD_MAP",
|
|
||||||
"DMU_OT_DSL_DS_SNAP_MAP",
|
|
||||||
"DMU_OT_DSL_PROPS",
|
|
||||||
"DMU_OT_DSL_DATASET",
|
|
||||||
# zpl:
|
|
||||||
"DMU_OT_ZNODE",
|
|
||||||
"DMU_OT_OLDACL",
|
|
||||||
"DMU_OT_PLAIN_FILE_CONTENTS",
|
|
||||||
"DMU_OT_DIRECTORY_CONTENTS",
|
|
||||||
"DMU_OT_MASTER_NODE",
|
|
||||||
"DMU_OT_UNLINKED_SET",
|
|
||||||
# zvol:
|
|
||||||
"DMU_OT_ZVOL",
|
|
||||||
"DMU_OT_ZVOL_PROP",
|
|
||||||
# other; for testing only!
|
|
||||||
"DMU_OT_PLAIN_OTHER",
|
|
||||||
"DMU_OT_UINT64_OTHER",
|
|
||||||
"DMU_OT_ZAP_OTHER",
|
|
||||||
# new object types:
|
|
||||||
"DMU_OT_ERROR_LOG",
|
|
||||||
"DMU_OT_SPA_HISTORY",
|
|
||||||
"DMU_OT_SPA_HISTORY_OFFSETS",
|
|
||||||
"DMU_OT_POOL_PROPS",
|
|
||||||
"DMU_OT_DSL_PERMS",
|
|
||||||
"DMU_OT_ACL",
|
|
||||||
"DMU_OT_SYSACL",
|
|
||||||
"DMU_OT_FUID",
|
|
||||||
"DMU_OT_FUID_SIZE",
|
|
||||||
"DMU_OT_NEXT_CLONES",
|
|
||||||
"DMU_OT_SCAN_QUEUE",
|
|
||||||
"DMU_OT_USERGROUP_USED",
|
|
||||||
"DMU_OT_USERGROUP_QUOTA",
|
|
||||||
"DMU_OT_USERREFS",
|
|
||||||
"DMU_OT_DDT_ZAP",
|
|
||||||
"DMU_OT_DDT_STATS",
|
|
||||||
"DMU_OT_SA",
|
|
||||||
"DMU_OT_SA_MASTER_NODE",
|
|
||||||
"DMU_OT_SA_ATTR_REGISTRATION",
|
|
||||||
"DMU_OT_SA_ATTR_LAYOUTS",
|
|
||||||
"DMU_OT_SCAN_XLATE",
|
|
||||||
"DMU_OT_DEDUP",
|
|
||||||
"DMU_OT_DEADLIST",
|
|
||||||
"DMU_OT_DEADLIST_HDR",
|
|
||||||
"DMU_OT_DSL_CLONES",
|
|
||||||
"DMU_OT_BPOBJ_SUBOBJ"]
|
|
||||||
otn_strings = {
|
|
||||||
0x80: "DMU_OTN_UINT8_DATA",
|
|
||||||
0xc0: "DMU_OTN_UINT8_METADATA",
|
|
||||||
0x81: "DMU_OTN_UINT16_DATA",
|
|
||||||
0xc1: "DMU_OTN_UINT16_METADATA",
|
|
||||||
0x82: "DMU_OTN_UINT32_DATA",
|
|
||||||
0xc2: "DMU_OTN_UINT32_METADATA",
|
|
||||||
0x83: "DMU_OTN_UINT64_DATA",
|
|
||||||
0xc3: "DMU_OTN_UINT64_METADATA",
|
|
||||||
0x84: "DMU_OTN_ZAP_DATA",
|
|
||||||
0xc4: "DMU_OTN_ZAP_METADATA",
|
|
||||||
0xa0: "DMU_OTN_UINT8_ENC_DATA",
|
|
||||||
0xe0: "DMU_OTN_UINT8_ENC_METADATA",
|
|
||||||
0xa1: "DMU_OTN_UINT16_ENC_DATA",
|
|
||||||
0xe1: "DMU_OTN_UINT16_ENC_METADATA",
|
|
||||||
0xa2: "DMU_OTN_UINT32_ENC_DATA",
|
|
||||||
0xe2: "DMU_OTN_UINT32_ENC_METADATA",
|
|
||||||
0xa3: "DMU_OTN_UINT64_ENC_DATA",
|
|
||||||
0xe3: "DMU_OTN_UINT64_ENC_METADATA",
|
|
||||||
0xa4: "DMU_OTN_ZAP_ENC_DATA",
|
|
||||||
0xe4: "DMU_OTN_ZAP_ENC_METADATA"}
|
|
||||||
|
|
||||||
# If "-rr" option is used, don't convert to string representation
|
|
||||||
if raw > 1:
|
|
||||||
return "%i" % t
|
|
||||||
|
|
||||||
try:
|
|
||||||
if t < len(ot_strings):
|
|
||||||
return ot_strings[t]
|
|
||||||
else:
|
|
||||||
return otn_strings[t]
|
|
||||||
except (IndexError, KeyError):
|
|
||||||
return "(UNKNOWN)"
|
|
||||||
|
|
||||||
|
|
||||||
def get_compstring(c):
|
|
||||||
comp_strings = ["ZIO_COMPRESS_INHERIT", "ZIO_COMPRESS_ON",
|
|
||||||
"ZIO_COMPRESS_OFF", "ZIO_COMPRESS_LZJB",
|
|
||||||
"ZIO_COMPRESS_EMPTY", "ZIO_COMPRESS_GZIP_1",
|
|
||||||
"ZIO_COMPRESS_GZIP_2", "ZIO_COMPRESS_GZIP_3",
|
|
||||||
"ZIO_COMPRESS_GZIP_4", "ZIO_COMPRESS_GZIP_5",
|
|
||||||
"ZIO_COMPRESS_GZIP_6", "ZIO_COMPRESS_GZIP_7",
|
|
||||||
"ZIO_COMPRESS_GZIP_8", "ZIO_COMPRESS_GZIP_9",
|
|
||||||
"ZIO_COMPRESS_ZLE", "ZIO_COMPRESS_LZ4",
|
|
||||||
"ZIO_COMPRESS_ZSTD", "ZIO_COMPRESS_FUNCTION"]
|
|
||||||
|
|
||||||
# If "-rr" option is used, don't convert to string representation
|
|
||||||
if raw > 1:
|
|
||||||
return "%i" % c
|
|
||||||
|
|
||||||
try:
|
|
||||||
return comp_strings[c]
|
|
||||||
except IndexError:
|
|
||||||
return "%i" % c
|
|
||||||
|
|
||||||
|
|
||||||
def parse_line(line, labels):
|
|
||||||
global hdr
|
|
||||||
|
|
||||||
new = dict()
|
|
||||||
val = None
|
|
||||||
for col in hdr:
|
|
||||||
# These are "special" fields computed in the update_dict
|
|
||||||
# function, prevent KeyError exception on labels[col] for these.
|
|
||||||
if col not in ['bonus', 'cached', 'direct', 'indirect', 'spill']:
|
|
||||||
val = line[labels[col]]
|
|
||||||
|
|
||||||
if col in ['pool', 'flags']:
|
|
||||||
new[col] = str(val)
|
|
||||||
elif col in ['dtype', 'btype']:
|
|
||||||
new[col] = get_typestring(int(val))
|
|
||||||
elif col in ['l2_comp']:
|
|
||||||
new[col] = get_compstring(int(val))
|
|
||||||
else:
|
|
||||||
new[col] = int(val)
|
|
||||||
|
|
||||||
return new
|
|
||||||
|
|
||||||
|
|
||||||
def update_dict(d, k, line, labels):
|
|
||||||
pool = line[labels['pool']]
|
|
||||||
objset = line[labels['objset']]
|
|
||||||
key = line[labels[k]]
|
|
||||||
|
|
||||||
dbsize = int(line[labels['dbsize']])
|
|
||||||
usize = int(line[labels['usize']])
|
|
||||||
blkid = int(line[labels['blkid']])
|
|
||||||
level = int(line[labels['level']])
|
|
||||||
|
|
||||||
if pool not in d:
|
|
||||||
d[pool] = dict()
|
|
||||||
|
|
||||||
if objset not in d[pool]:
|
|
||||||
d[pool][objset] = dict()
|
|
||||||
|
|
||||||
if key not in d[pool][objset]:
|
|
||||||
d[pool][objset][key] = parse_line(line, labels)
|
|
||||||
d[pool][objset][key]['bonus'] = 0
|
|
||||||
d[pool][objset][key]['cached'] = 0
|
|
||||||
d[pool][objset][key]['direct'] = 0
|
|
||||||
d[pool][objset][key]['indirect'] = 0
|
|
||||||
d[pool][objset][key]['spill'] = 0
|
|
||||||
|
|
||||||
d[pool][objset][key]['cached'] += dbsize + usize
|
|
||||||
|
|
||||||
if blkid == -1:
|
|
||||||
d[pool][objset][key]['bonus'] += dbsize
|
|
||||||
elif blkid == -2:
|
|
||||||
d[pool][objset][key]['spill'] += dbsize
|
|
||||||
else:
|
|
||||||
if level == 0:
|
|
||||||
d[pool][objset][key]['direct'] += dbsize
|
|
||||||
else:
|
|
||||||
d[pool][objset][key]['indirect'] += dbsize
|
|
||||||
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
def skip_line(vals, filters):
|
|
||||||
'''
|
|
||||||
Determines if a line should be skipped during printing
|
|
||||||
based on a set of filters
|
|
||||||
'''
|
|
||||||
if len(filters) == 0:
|
|
||||||
return False
|
|
||||||
|
|
||||||
for key in vals:
|
|
||||||
if key in filters:
|
|
||||||
val = prettynum(cols[key][0], cols[key][1], vals[key]).strip()
|
|
||||||
# we want a full match here
|
|
||||||
if re.match("(?:" + filters[key] + r")\Z", val) is None:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def print_dict(d, filters, noheader):
|
|
||||||
if not noheader:
|
|
||||||
print_header()
|
|
||||||
for pool in list(d.keys()):
|
|
||||||
for objset in list(d[pool].keys()):
|
|
||||||
for v in list(d[pool][objset].values()):
|
|
||||||
if not skip_line(v, filters):
|
|
||||||
print_values(v)
|
|
||||||
|
|
||||||
|
|
||||||
def dnodes_build_dict(filehandle):
|
|
||||||
labels = dict()
|
|
||||||
dnodes = dict()
|
|
||||||
|
|
||||||
# First 3 lines are header information, skip the first two
|
|
||||||
for i in range(2):
|
|
||||||
next(filehandle)
|
|
||||||
|
|
||||||
# The third line contains the labels and index locations
|
|
||||||
for i, v in enumerate(next(filehandle).split()):
|
|
||||||
labels[v] = i
|
|
||||||
|
|
||||||
# The rest of the file is buffer information
|
|
||||||
for line in filehandle:
|
|
||||||
update_dict(dnodes, 'object', line.split(), labels)
|
|
||||||
|
|
||||||
return dnodes
|
|
||||||
|
|
||||||
|
|
||||||
def types_build_dict(filehandle):
|
|
||||||
labels = dict()
|
|
||||||
types = dict()
|
|
||||||
|
|
||||||
# First 3 lines are header information, skip the first two
|
|
||||||
for i in range(2):
|
|
||||||
next(filehandle)
|
|
||||||
|
|
||||||
# The third line contains the labels and index locations
|
|
||||||
for i, v in enumerate(next(filehandle).split()):
|
|
||||||
labels[v] = i
|
|
||||||
|
|
||||||
# The rest of the file is buffer information
|
|
||||||
for line in filehandle:
|
|
||||||
update_dict(types, 'dtype', line.split(), labels)
|
|
||||||
|
|
||||||
return types
|
|
||||||
|
|
||||||
|
|
||||||
def buffers_print_all(filehandle, filters, noheader):
|
|
||||||
labels = dict()
|
|
||||||
|
|
||||||
# First 3 lines are header information, skip the first two
|
|
||||||
for i in range(2):
|
|
||||||
next(filehandle)
|
|
||||||
|
|
||||||
# The third line contains the labels and index locations
|
|
||||||
for i, v in enumerate(next(filehandle).split()):
|
|
||||||
labels[v] = i
|
|
||||||
|
|
||||||
if not noheader:
|
|
||||||
print_header()
|
|
||||||
|
|
||||||
# The rest of the file is buffer information
|
|
||||||
for line in filehandle:
|
|
||||||
vals = parse_line(line.split(), labels)
|
|
||||||
if not skip_line(vals, filters):
|
|
||||||
print_values(vals)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
global hdr
|
|
||||||
global sep
|
|
||||||
global raw
|
|
||||||
|
|
||||||
desired_cols = None
|
|
||||||
bflag = False
|
|
||||||
dflag = False
|
|
||||||
hflag = False
|
|
||||||
ifile = None
|
|
||||||
ofile = None
|
|
||||||
tflag = False
|
|
||||||
vflag = False
|
|
||||||
xflag = False
|
|
||||||
nflag = False
|
|
||||||
filters = dict()
|
|
||||||
|
|
||||||
try:
|
|
||||||
opts, args = getopt.getopt(
|
|
||||||
sys.argv[1:],
|
|
||||||
"bdf:hi:o:rs:tvxF:n",
|
|
||||||
[
|
|
||||||
"buffers",
|
|
||||||
"dnodes",
|
|
||||||
"columns",
|
|
||||||
"help",
|
|
||||||
"infile",
|
|
||||||
"outfile",
|
|
||||||
"separator",
|
|
||||||
"types",
|
|
||||||
"verbose",
|
|
||||||
"extended",
|
|
||||||
"filter"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
except getopt.error:
|
|
||||||
usage()
|
|
||||||
opts = None
|
|
||||||
|
|
||||||
for opt, arg in opts:
|
|
||||||
if opt in ('-b', '--buffers'):
|
|
||||||
bflag = True
|
|
||||||
if opt in ('-d', '--dnodes'):
|
|
||||||
dflag = True
|
|
||||||
if opt in ('-f', '--columns'):
|
|
||||||
desired_cols = arg
|
|
||||||
if opt in ('-h', '--help'):
|
|
||||||
hflag = True
|
|
||||||
if opt in ('-i', '--infile'):
|
|
||||||
ifile = arg
|
|
||||||
if opt in ('-o', '--outfile'):
|
|
||||||
ofile = arg
|
|
||||||
if opt in ('-r', '--raw'):
|
|
||||||
raw += 1
|
|
||||||
if opt in ('-s', '--separator'):
|
|
||||||
sep = arg
|
|
||||||
if opt in ('-t', '--types'):
|
|
||||||
tflag = True
|
|
||||||
if opt in ('-v', '--verbose'):
|
|
||||||
vflag = True
|
|
||||||
if opt in ('-x', '--extended'):
|
|
||||||
xflag = True
|
|
||||||
if opt in ('-n', '--noheader'):
|
|
||||||
nflag = True
|
|
||||||
if opt in ('-F', '--filter'):
|
|
||||||
fils = [x.strip() for x in arg.split(",")]
|
|
||||||
|
|
||||||
for fil in fils:
|
|
||||||
f = [x.strip() for x in fil.split("=")]
|
|
||||||
|
|
||||||
if len(f) != 2:
|
|
||||||
sys.stderr.write("Invalid filter '%s'.\n" % fil)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if f[0] not in cols:
|
|
||||||
sys.stderr.write("Invalid field '%s' in filter.\n" % f[0])
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if f[0] in filters:
|
|
||||||
sys.stderr.write("Field '%s' specified multiple times in "
|
|
||||||
"filter.\n" % f[0])
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
re.compile("(?:" + f[1] + r")\Z")
|
|
||||||
except re.error:
|
|
||||||
sys.stderr.write("Invalid regex for field '%s' in "
|
|
||||||
"filter.\n" % f[0])
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
filters[f[0]] = f[1]
|
|
||||||
|
|
||||||
if hflag or (xflag and desired_cols):
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if vflag:
|
|
||||||
detailed_usage()
|
|
||||||
|
|
||||||
# Ensure at most only one of b, d, or t flags are set
|
|
||||||
if (bflag and dflag) or (bflag and tflag) or (dflag and tflag):
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if bflag:
|
|
||||||
hdr = bxhdr if xflag else bhdr
|
|
||||||
elif tflag:
|
|
||||||
hdr = txhdr if xflag else thdr
|
|
||||||
else: # Even if dflag is False, it's the default if none set
|
|
||||||
dflag = True
|
|
||||||
hdr = dxhdr if xflag else dhdr
|
|
||||||
|
|
||||||
if desired_cols:
|
|
||||||
hdr = desired_cols.split(",")
|
|
||||||
|
|
||||||
invalid = []
|
|
||||||
incompat = []
|
|
||||||
for ele in hdr:
|
|
||||||
if ele not in cols:
|
|
||||||
invalid.append(ele)
|
|
||||||
elif ((bflag and bincompat and ele in bincompat) or
|
|
||||||
(dflag and dincompat and ele in dincompat) or
|
|
||||||
(tflag and tincompat and ele in tincompat)):
|
|
||||||
incompat.append(ele)
|
|
||||||
|
|
||||||
if len(invalid) > 0:
|
|
||||||
sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if len(incompat) > 0:
|
|
||||||
sys.stderr.write("Incompatible field specified! -- %s\n" %
|
|
||||||
incompat)
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if ofile:
|
|
||||||
try:
|
|
||||||
tmp = open(ofile, "w")
|
|
||||||
sys.stdout = tmp
|
|
||||||
|
|
||||||
except IOError:
|
|
||||||
sys.stderr.write("Cannot open %s for writing\n" % ofile)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if not ifile:
|
|
||||||
ifile = default_ifile()
|
|
||||||
|
|
||||||
if ifile != "-":
|
|
||||||
try:
|
|
||||||
tmp = open(ifile, "r")
|
|
||||||
sys.stdin = tmp
|
|
||||||
except IOError:
|
|
||||||
sys.stderr.write("Cannot open %s for reading\n" % ifile)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if bflag:
|
|
||||||
buffers_print_all(sys.stdin, filters, nflag)
|
|
||||||
|
|
||||||
if dflag:
|
|
||||||
print_dict(dnodes_build_dict(sys.stdin), filters, nflag)
|
|
||||||
|
|
||||||
if tflag:
|
|
||||||
print_dict(types_build_dict(sys.stdin), filters, nflag)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
dist_bin_SCRIPTS = dbufstat.py
|
||||||
Executable
+582
@@ -0,0 +1,582 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Print out statistics for all cached dmu buffers. This information
|
||||||
|
# is available through the dbufs kstat and may be post-processed as
|
||||||
|
# needed by the script.
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License, Version 1.0 only
|
||||||
|
# (the "License"). 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 http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 Lawrence Livermore National Security, LLC.
|
||||||
|
# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import getopt
|
||||||
|
import errno
|
||||||
|
|
||||||
|
bhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize"]
|
||||||
|
bxhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize",
|
||||||
|
"meta", "state", "dbholds", "list", "atype", "flags",
|
||||||
|
"count", "asize", "access", "mru", "gmru", "mfu", "gmfu", "l2",
|
||||||
|
"l2_dattr", "l2_asize", "l2_comp", "aholds", "dtype", "btype",
|
||||||
|
"data_bs", "meta_bs", "bsize", "lvls", "dholds", "blocks", "dsize"]
|
||||||
|
bincompat = ["cached", "direct", "indirect", "bonus", "spill"]
|
||||||
|
|
||||||
|
dhdr = ["pool", "objset", "object", "dtype", "cached"]
|
||||||
|
dxhdr = ["pool", "objset", "object", "dtype", "btype", "data_bs", "meta_bs",
|
||||||
|
"bsize", "lvls", "dholds", "blocks", "dsize", "cached", "direct",
|
||||||
|
"indirect", "bonus", "spill"]
|
||||||
|
dincompat = ["level", "blkid", "offset", "dbsize", "meta", "state", "dbholds",
|
||||||
|
"list", "atype", "flags", "count", "asize", "access",
|
||||||
|
"mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr", "l2_asize",
|
||||||
|
"l2_comp", "aholds"]
|
||||||
|
|
||||||
|
thdr = ["pool", "objset", "dtype", "cached"]
|
||||||
|
txhdr = ["pool", "objset", "dtype", "cached", "direct", "indirect",
|
||||||
|
"bonus", "spill"]
|
||||||
|
tincompat = ["object", "level", "blkid", "offset", "dbsize", "meta", "state",
|
||||||
|
"dbholds", "list", "atype", "flags", "count", "asize",
|
||||||
|
"access", "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr",
|
||||||
|
"l2_asize", "l2_comp", "aholds", "btype", "data_bs", "meta_bs",
|
||||||
|
"bsize", "lvls", "dholds", "blocks", "dsize"]
|
||||||
|
|
||||||
|
cols = {
|
||||||
|
# hdr: [size, scale, description]
|
||||||
|
"pool": [15, -1, "pool name"],
|
||||||
|
"objset": [6, -1, "dataset identification number"],
|
||||||
|
"object": [10, -1, "object number"],
|
||||||
|
"level": [5, -1, "indirection level of buffer"],
|
||||||
|
"blkid": [8, -1, "block number of buffer"],
|
||||||
|
"offset": [12, 1024, "offset in object of buffer"],
|
||||||
|
"dbsize": [7, 1024, "size of buffer"],
|
||||||
|
"meta": [4, -1, "is this buffer metadata?"],
|
||||||
|
"state": [5, -1, "state of buffer (read, cached, etc)"],
|
||||||
|
"dbholds": [7, 1000, "number of holds on buffer"],
|
||||||
|
"list": [4, -1, "which ARC list contains this buffer"],
|
||||||
|
"atype": [7, -1, "ARC header type (data or metadata)"],
|
||||||
|
"flags": [8, -1, "ARC read flags"],
|
||||||
|
"count": [5, -1, "ARC data count"],
|
||||||
|
"asize": [7, 1024, "size of this ARC buffer"],
|
||||||
|
"access": [10, -1, "time this ARC buffer was last accessed"],
|
||||||
|
"mru": [5, 1000, "hits while on the ARC's MRU list"],
|
||||||
|
"gmru": [5, 1000, "hits while on the ARC's MRU ghost list"],
|
||||||
|
"mfu": [5, 1000, "hits while on the ARC's MFU list"],
|
||||||
|
"gmfu": [5, 1000, "hits while on the ARC's MFU ghost list"],
|
||||||
|
"l2": [5, 1000, "hits while on the L2ARC"],
|
||||||
|
"l2_dattr": [8, -1, "L2ARC disk address/offset"],
|
||||||
|
"l2_asize": [8, 1024, "L2ARC alloc'd size (depending on compression)"],
|
||||||
|
"l2_comp": [21, -1, "L2ARC compression algorithm for buffer"],
|
||||||
|
"aholds": [6, 1000, "number of holds on this ARC buffer"],
|
||||||
|
"dtype": [27, -1, "dnode type"],
|
||||||
|
"btype": [27, -1, "bonus buffer type"],
|
||||||
|
"data_bs": [7, 1024, "data block size"],
|
||||||
|
"meta_bs": [7, 1024, "metadata block size"],
|
||||||
|
"bsize": [6, 1024, "bonus buffer size"],
|
||||||
|
"lvls": [6, -1, "number of indirection levels"],
|
||||||
|
"dholds": [6, 1000, "number of holds on dnode"],
|
||||||
|
"blocks": [8, 1000, "number of allocated blocks"],
|
||||||
|
"dsize": [12, 1024, "size of dnode"],
|
||||||
|
"cached": [6, 1024, "bytes cached for all blocks"],
|
||||||
|
"direct": [6, 1024, "bytes cached for direct blocks"],
|
||||||
|
"indirect": [8, 1024, "bytes cached for indirect blocks"],
|
||||||
|
"bonus": [5, 1024, "bytes cached for bonus buffer"],
|
||||||
|
"spill": [5, 1024, "bytes cached for spill block"],
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr = None
|
||||||
|
xhdr = None
|
||||||
|
sep = " " # Default separator is 2 spaces
|
||||||
|
cmd = ("Usage: dbufstat.py [-bdhrtvx] [-i file] [-f fields] [-o file] "
|
||||||
|
"[-s string]\n")
|
||||||
|
raw = 0
|
||||||
|
|
||||||
|
|
||||||
|
def print_incompat_helper(incompat):
|
||||||
|
cnt = 0
|
||||||
|
for key in sorted(incompat):
|
||||||
|
if cnt is 0:
|
||||||
|
sys.stderr.write("\t")
|
||||||
|
elif cnt > 8:
|
||||||
|
sys.stderr.write(",\n\t")
|
||||||
|
cnt = 0
|
||||||
|
else:
|
||||||
|
sys.stderr.write(", ")
|
||||||
|
|
||||||
|
sys.stderr.write("%s" % key)
|
||||||
|
cnt += 1
|
||||||
|
|
||||||
|
sys.stderr.write("\n\n")
|
||||||
|
|
||||||
|
|
||||||
|
def detailed_usage():
|
||||||
|
sys.stderr.write("%s\n" % cmd)
|
||||||
|
|
||||||
|
sys.stderr.write("Field definitions incompatible with '-b' option:\n")
|
||||||
|
print_incompat_helper(bincompat)
|
||||||
|
|
||||||
|
sys.stderr.write("Field definitions incompatible with '-d' option:\n")
|
||||||
|
print_incompat_helper(dincompat)
|
||||||
|
|
||||||
|
sys.stderr.write("Field definitions incompatible with '-t' option:\n")
|
||||||
|
print_incompat_helper(tincompat)
|
||||||
|
|
||||||
|
sys.stderr.write("Field definitions are as follows:\n")
|
||||||
|
for key in sorted(cols.keys()):
|
||||||
|
sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
|
||||||
|
sys.stderr.write("\n")
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
sys.stderr.write("%s\n" % cmd)
|
||||||
|
sys.stderr.write("\t -b : Print table of information for each dbuf\n")
|
||||||
|
sys.stderr.write("\t -d : Print table of information for each dnode\n")
|
||||||
|
sys.stderr.write("\t -h : Print this help message\n")
|
||||||
|
sys.stderr.write("\t -r : Print raw values\n")
|
||||||
|
sys.stderr.write("\t -t : Print table of information for each dnode type"
|
||||||
|
"\n")
|
||||||
|
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 -i : Redirect input from the specified file\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 "
|
||||||
|
"character or string\n")
|
||||||
|
sys.stderr.write("\nExamples:\n")
|
||||||
|
sys.stderr.write("\tdbufstat.py -d -o /tmp/d.log\n")
|
||||||
|
sys.stderr.write("\tdbufstat.py -t -s \",\" -o /tmp/t.log\n")
|
||||||
|
sys.stderr.write("\tdbufstat.py -v\n")
|
||||||
|
sys.stderr.write("\tdbufstat.py -d -f pool,object,objset,dsize,cached\n")
|
||||||
|
sys.stderr.write("\n")
|
||||||
|
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def prettynum(sz, scale, num=0):
|
||||||
|
global raw
|
||||||
|
|
||||||
|
suffix = [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
|
||||||
|
index = 0
|
||||||
|
save = 0
|
||||||
|
|
||||||
|
if raw or scale == -1:
|
||||||
|
return "%*s" % (sz, num)
|
||||||
|
|
||||||
|
# Rounding error, return 0
|
||||||
|
elif 0 < num < 1:
|
||||||
|
num = 0
|
||||||
|
|
||||||
|
while num > scale and index < 5:
|
||||||
|
save = num
|
||||||
|
num = num / scale
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
if index == 0:
|
||||||
|
return "%*d" % (sz, num)
|
||||||
|
|
||||||
|
if (save / scale) < 10:
|
||||||
|
return "%*.1f%s" % (sz - 1, num, suffix[index])
|
||||||
|
else:
|
||||||
|
return "%*d%s" % (sz - 1, num, suffix[index])
|
||||||
|
|
||||||
|
|
||||||
|
def print_values(v):
|
||||||
|
global hdr
|
||||||
|
global sep
|
||||||
|
|
||||||
|
try:
|
||||||
|
for col in hdr:
|
||||||
|
sys.stdout.write("%s%s" % (
|
||||||
|
prettynum(cols[col][0], cols[col][1], v[col]), sep))
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
except IOError as e:
|
||||||
|
if e.errno == errno.EPIPE:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def print_header():
|
||||||
|
global hdr
|
||||||
|
global sep
|
||||||
|
|
||||||
|
try:
|
||||||
|
for col in hdr:
|
||||||
|
sys.stdout.write("%*s%s" % (cols[col][0], col, sep))
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
except IOError as e:
|
||||||
|
if e.errno == errno.EPIPE:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_typestring(t):
|
||||||
|
type_strings = ["DMU_OT_NONE",
|
||||||
|
# general:
|
||||||
|
"DMU_OT_OBJECT_DIRECTORY",
|
||||||
|
"DMU_OT_OBJECT_ARRAY",
|
||||||
|
"DMU_OT_PACKED_NVLIST",
|
||||||
|
"DMU_OT_PACKED_NVLIST_SIZE",
|
||||||
|
"DMU_OT_BPOBJ",
|
||||||
|
"DMU_OT_BPOBJ_HDR",
|
||||||
|
# spa:
|
||||||
|
"DMU_OT_SPACE_MAP_HEADER",
|
||||||
|
"DMU_OT_SPACE_MAP",
|
||||||
|
# zil:
|
||||||
|
"DMU_OT_INTENT_LOG",
|
||||||
|
# dmu:
|
||||||
|
"DMU_OT_DNODE",
|
||||||
|
"DMU_OT_OBJSET",
|
||||||
|
# dsl:
|
||||||
|
"DMU_OT_DSL_DIR",
|
||||||
|
"DMU_OT_DSL_DIR_CHILD_MAP",
|
||||||
|
"DMU_OT_DSL_DS_SNAP_MAP",
|
||||||
|
"DMU_OT_DSL_PROPS",
|
||||||
|
"DMU_OT_DSL_DATASET",
|
||||||
|
# zpl:
|
||||||
|
"DMU_OT_ZNODE",
|
||||||
|
"DMU_OT_OLDACL",
|
||||||
|
"DMU_OT_PLAIN_FILE_CONTENTS",
|
||||||
|
"DMU_OT_DIRECTORY_CONTENTS",
|
||||||
|
"DMU_OT_MASTER_NODE",
|
||||||
|
"DMU_OT_UNLINKED_SET",
|
||||||
|
# zvol:
|
||||||
|
"DMU_OT_ZVOL",
|
||||||
|
"DMU_OT_ZVOL_PROP",
|
||||||
|
# other; for testing only!
|
||||||
|
"DMU_OT_PLAIN_OTHER",
|
||||||
|
"DMU_OT_UINT64_OTHER",
|
||||||
|
"DMU_OT_ZAP_OTHER",
|
||||||
|
# new object types:
|
||||||
|
"DMU_OT_ERROR_LOG",
|
||||||
|
"DMU_OT_SPA_HISTORY",
|
||||||
|
"DMU_OT_SPA_HISTORY_OFFSETS",
|
||||||
|
"DMU_OT_POOL_PROPS",
|
||||||
|
"DMU_OT_DSL_PERMS",
|
||||||
|
"DMU_OT_ACL",
|
||||||
|
"DMU_OT_SYSACL",
|
||||||
|
"DMU_OT_FUID",
|
||||||
|
"DMU_OT_FUID_SIZE",
|
||||||
|
"DMU_OT_NEXT_CLONES",
|
||||||
|
"DMU_OT_SCAN_QUEUE",
|
||||||
|
"DMU_OT_USERGROUP_USED",
|
||||||
|
"DMU_OT_USERGROUP_QUOTA",
|
||||||
|
"DMU_OT_USERREFS",
|
||||||
|
"DMU_OT_DDT_ZAP",
|
||||||
|
"DMU_OT_DDT_STATS",
|
||||||
|
"DMU_OT_SA",
|
||||||
|
"DMU_OT_SA_MASTER_NODE",
|
||||||
|
"DMU_OT_SA_ATTR_REGISTRATION",
|
||||||
|
"DMU_OT_SA_ATTR_LAYOUTS",
|
||||||
|
"DMU_OT_SCAN_XLATE",
|
||||||
|
"DMU_OT_DEDUP",
|
||||||
|
"DMU_OT_DEADLIST",
|
||||||
|
"DMU_OT_DEADLIST_HDR",
|
||||||
|
"DMU_OT_DSL_CLONES",
|
||||||
|
"DMU_OT_BPOBJ_SUBOBJ"]
|
||||||
|
|
||||||
|
# If "-rr" option is used, don't convert to string representation
|
||||||
|
if raw > 1:
|
||||||
|
return "%i" % t
|
||||||
|
|
||||||
|
try:
|
||||||
|
return type_strings[t]
|
||||||
|
except IndexError:
|
||||||
|
return "%i" % t
|
||||||
|
|
||||||
|
|
||||||
|
def get_compstring(c):
|
||||||
|
comp_strings = ["ZIO_COMPRESS_INHERIT", "ZIO_COMPRESS_ON",
|
||||||
|
"ZIO_COMPRESS_OFF", "ZIO_COMPRESS_LZJB",
|
||||||
|
"ZIO_COMPRESS_EMPTY", "ZIO_COMPRESS_GZIP_1",
|
||||||
|
"ZIO_COMPRESS_GZIP_2", "ZIO_COMPRESS_GZIP_3",
|
||||||
|
"ZIO_COMPRESS_GZIP_4", "ZIO_COMPRESS_GZIP_5",
|
||||||
|
"ZIO_COMPRESS_GZIP_6", "ZIO_COMPRESS_GZIP_7",
|
||||||
|
"ZIO_COMPRESS_GZIP_8", "ZIO_COMPRESS_GZIP_9",
|
||||||
|
"ZIO_COMPRESS_ZLE", "ZIO_COMPRESS_LZ4",
|
||||||
|
"ZIO_COMPRESS_FUNCTION"]
|
||||||
|
|
||||||
|
# If "-rr" option is used, don't convert to string representation
|
||||||
|
if raw > 1:
|
||||||
|
return "%i" % c
|
||||||
|
|
||||||
|
try:
|
||||||
|
return comp_strings[c]
|
||||||
|
except IndexError:
|
||||||
|
return "%i" % c
|
||||||
|
|
||||||
|
|
||||||
|
def parse_line(line, labels):
|
||||||
|
global hdr
|
||||||
|
|
||||||
|
new = dict()
|
||||||
|
val = None
|
||||||
|
for col in hdr:
|
||||||
|
# These are "special" fields computed in the update_dict
|
||||||
|
# function, prevent KeyError exception on labels[col] for these.
|
||||||
|
if col not in ['bonus', 'cached', 'direct', 'indirect', 'spill']:
|
||||||
|
val = line[labels[col]]
|
||||||
|
|
||||||
|
if col in ['pool', 'flags']:
|
||||||
|
new[col] = str(val)
|
||||||
|
elif col in ['dtype', 'btype']:
|
||||||
|
new[col] = get_typestring(int(val))
|
||||||
|
elif col in ['l2_comp']:
|
||||||
|
new[col] = get_compstring(int(val))
|
||||||
|
else:
|
||||||
|
new[col] = int(val)
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
|
||||||
|
def update_dict(d, k, line, labels):
|
||||||
|
pool = line[labels['pool']]
|
||||||
|
objset = line[labels['objset']]
|
||||||
|
key = line[labels[k]]
|
||||||
|
|
||||||
|
dbsize = int(line[labels['dbsize']])
|
||||||
|
blkid = int(line[labels['blkid']])
|
||||||
|
level = int(line[labels['level']])
|
||||||
|
|
||||||
|
if pool not in d:
|
||||||
|
d[pool] = dict()
|
||||||
|
|
||||||
|
if objset not in d[pool]:
|
||||||
|
d[pool][objset] = dict()
|
||||||
|
|
||||||
|
if key not in d[pool][objset]:
|
||||||
|
d[pool][objset][key] = parse_line(line, labels)
|
||||||
|
d[pool][objset][key]['bonus'] = 0
|
||||||
|
d[pool][objset][key]['cached'] = 0
|
||||||
|
d[pool][objset][key]['direct'] = 0
|
||||||
|
d[pool][objset][key]['indirect'] = 0
|
||||||
|
d[pool][objset][key]['spill'] = 0
|
||||||
|
|
||||||
|
d[pool][objset][key]['cached'] += dbsize
|
||||||
|
|
||||||
|
if blkid == -1:
|
||||||
|
d[pool][objset][key]['bonus'] += dbsize
|
||||||
|
elif blkid == -2:
|
||||||
|
d[pool][objset][key]['spill'] += dbsize
|
||||||
|
else:
|
||||||
|
if level == 0:
|
||||||
|
d[pool][objset][key]['direct'] += dbsize
|
||||||
|
else:
|
||||||
|
d[pool][objset][key]['indirect'] += dbsize
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def print_dict(d):
|
||||||
|
print_header()
|
||||||
|
for pool in list(d.keys()):
|
||||||
|
for objset in list(d[pool].keys()):
|
||||||
|
for v in list(d[pool][objset].values()):
|
||||||
|
print_values(v)
|
||||||
|
|
||||||
|
|
||||||
|
def dnodes_build_dict(filehandle):
|
||||||
|
labels = dict()
|
||||||
|
dnodes = dict()
|
||||||
|
|
||||||
|
# First 3 lines are header information, skip the first two
|
||||||
|
for i in range(2):
|
||||||
|
next(filehandle)
|
||||||
|
|
||||||
|
# The third line contains the labels and index locations
|
||||||
|
for i, v in enumerate(next(filehandle).split()):
|
||||||
|
labels[v] = i
|
||||||
|
|
||||||
|
# The rest of the file is buffer information
|
||||||
|
for line in filehandle:
|
||||||
|
update_dict(dnodes, 'object', line.split(), labels)
|
||||||
|
|
||||||
|
return dnodes
|
||||||
|
|
||||||
|
|
||||||
|
def types_build_dict(filehandle):
|
||||||
|
labels = dict()
|
||||||
|
types = dict()
|
||||||
|
|
||||||
|
# First 3 lines are header information, skip the first two
|
||||||
|
for i in range(2):
|
||||||
|
next(filehandle)
|
||||||
|
|
||||||
|
# The third line contains the labels and index locations
|
||||||
|
for i, v in enumerate(next(filehandle).split()):
|
||||||
|
labels[v] = i
|
||||||
|
|
||||||
|
# The rest of the file is buffer information
|
||||||
|
for line in filehandle:
|
||||||
|
update_dict(types, 'dtype', line.split(), labels)
|
||||||
|
|
||||||
|
return types
|
||||||
|
|
||||||
|
|
||||||
|
def buffers_print_all(filehandle):
|
||||||
|
labels = dict()
|
||||||
|
|
||||||
|
# First 3 lines are header information, skip the first two
|
||||||
|
for i in range(2):
|
||||||
|
next(filehandle)
|
||||||
|
|
||||||
|
# The third line contains the labels and index locations
|
||||||
|
for i, v in enumerate(next(filehandle).split()):
|
||||||
|
labels[v] = i
|
||||||
|
|
||||||
|
print_header()
|
||||||
|
|
||||||
|
# The rest of the file is buffer information
|
||||||
|
for line in filehandle:
|
||||||
|
print_values(parse_line(line.split(), labels))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global hdr
|
||||||
|
global sep
|
||||||
|
global raw
|
||||||
|
|
||||||
|
desired_cols = None
|
||||||
|
bflag = False
|
||||||
|
dflag = False
|
||||||
|
hflag = False
|
||||||
|
ifile = None
|
||||||
|
ofile = None
|
||||||
|
tflag = False
|
||||||
|
vflag = False
|
||||||
|
xflag = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
opts, args = getopt.getopt(
|
||||||
|
sys.argv[1:],
|
||||||
|
"bdf:hi:o:rs:tvx",
|
||||||
|
[
|
||||||
|
"buffers",
|
||||||
|
"dnodes",
|
||||||
|
"columns",
|
||||||
|
"help",
|
||||||
|
"infile",
|
||||||
|
"outfile",
|
||||||
|
"separator",
|
||||||
|
"types",
|
||||||
|
"verbose",
|
||||||
|
"extended"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
except getopt.error:
|
||||||
|
usage()
|
||||||
|
opts = None
|
||||||
|
|
||||||
|
for opt, arg in opts:
|
||||||
|
if opt in ('-b', '--buffers'):
|
||||||
|
bflag = True
|
||||||
|
if opt in ('-d', '--dnodes'):
|
||||||
|
dflag = True
|
||||||
|
if opt in ('-f', '--columns'):
|
||||||
|
desired_cols = arg
|
||||||
|
if opt in ('-h', '--help'):
|
||||||
|
hflag = True
|
||||||
|
if opt in ('-i', '--infile'):
|
||||||
|
ifile = arg
|
||||||
|
if opt in ('-o', '--outfile'):
|
||||||
|
ofile = arg
|
||||||
|
if opt in ('-r', '--raw'):
|
||||||
|
raw += 1
|
||||||
|
if opt in ('-s', '--separator'):
|
||||||
|
sep = arg
|
||||||
|
if opt in ('-t', '--types'):
|
||||||
|
tflag = True
|
||||||
|
if opt in ('-v', '--verbose'):
|
||||||
|
vflag = True
|
||||||
|
if opt in ('-x', '--extended'):
|
||||||
|
xflag = True
|
||||||
|
|
||||||
|
if hflag or (xflag and desired_cols):
|
||||||
|
usage()
|
||||||
|
|
||||||
|
if vflag:
|
||||||
|
detailed_usage()
|
||||||
|
|
||||||
|
# Ensure at most only one of b, d, or t flags are set
|
||||||
|
if (bflag and dflag) or (bflag and tflag) or (dflag and tflag):
|
||||||
|
usage()
|
||||||
|
|
||||||
|
if bflag:
|
||||||
|
hdr = bxhdr if xflag else bhdr
|
||||||
|
elif tflag:
|
||||||
|
hdr = txhdr if xflag else thdr
|
||||||
|
else: # Even if dflag is False, it's the default if none set
|
||||||
|
dflag = True
|
||||||
|
hdr = dxhdr if xflag else dhdr
|
||||||
|
|
||||||
|
if desired_cols:
|
||||||
|
hdr = desired_cols.split(",")
|
||||||
|
|
||||||
|
invalid = []
|
||||||
|
incompat = []
|
||||||
|
for ele in hdr:
|
||||||
|
if ele not in cols:
|
||||||
|
invalid.append(ele)
|
||||||
|
elif ((bflag and bincompat and ele in bincompat) or
|
||||||
|
(dflag and dincompat and ele in dincompat) or
|
||||||
|
(tflag and tincompat and ele in tincompat)):
|
||||||
|
incompat.append(ele)
|
||||||
|
|
||||||
|
if len(invalid) > 0:
|
||||||
|
sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
|
||||||
|
usage()
|
||||||
|
|
||||||
|
if len(incompat) > 0:
|
||||||
|
sys.stderr.write("Incompatible field specified! -- %s\n" %
|
||||||
|
incompat)
|
||||||
|
usage()
|
||||||
|
|
||||||
|
if ofile:
|
||||||
|
try:
|
||||||
|
tmp = open(ofile, "w")
|
||||||
|
sys.stdout = tmp
|
||||||
|
|
||||||
|
except IOError:
|
||||||
|
sys.stderr.write("Cannot open %s for writing\n" % ofile)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not ifile:
|
||||||
|
ifile = '/proc/spl/kstat/zfs/dbufs'
|
||||||
|
|
||||||
|
if ifile is not "-":
|
||||||
|
try:
|
||||||
|
tmp = open(ifile, "r")
|
||||||
|
sys.stdin = tmp
|
||||||
|
except IOError:
|
||||||
|
sys.stderr.write("Cannot open %s for reading\n" % ifile)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if bflag:
|
||||||
|
buffers_print_all(sys.stdin)
|
||||||
|
|
||||||
|
if dflag:
|
||||||
|
print_dict(dnodes_build_dict(sys.stdin))
|
||||||
|
|
||||||
|
if tflag:
|
||||||
|
print_dict(types_build_dict(sys.stdin))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -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 accomidate 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
|
||||||
-410
@@ -1,410 +0,0 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
|
||||||
* CDDL HEADER START
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the terms of the
|
|
||||||
* Common Development and Distribution License (the "License").
|
|
||||||
* 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.
|
|
||||||
* See the License for the specific language governing permissions
|
|
||||||
* and limitations under the License.
|
|
||||||
*
|
|
||||||
* When distributing Covered Code, include this CDDL HEADER in each
|
|
||||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
||||||
* If applicable, add the following below this CDDL HEADER, with the
|
|
||||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
||||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
||||||
*
|
|
||||||
* CDDL HEADER END
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* Copyright (c) 2011 Lawrence Livermore National Security, LLC.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <libintl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/file.h>
|
|
||||||
#include <sys/mount.h>
|
|
||||||
#include <sys/mntent.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <libzfs.h>
|
|
||||||
#include <libzutil.h>
|
|
||||||
#include <locale.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#define ZS_COMMENT 0x00000000 /* comment */
|
|
||||||
#define ZS_ZFSUTIL 0x00000001 /* caller is zfs(8) */
|
|
||||||
|
|
||||||
libzfs_handle_t *g_zfs;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Opportunistically convert a target string into a pool name. If the
|
|
||||||
* string does not represent a block device with a valid zfs label
|
|
||||||
* then it is passed through without modification.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
parse_dataset(const char *target, char **dataset)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Prior to util-linux 2.36.2, if a file or directory in the
|
|
||||||
* current working directory was named 'dataset' then mount(8)
|
|
||||||
* would prepend the current working directory to the dataset.
|
|
||||||
* Check for it and strip the prepended path when it is added.
|
|
||||||
*/
|
|
||||||
char cwd[PATH_MAX];
|
|
||||||
if (getcwd(cwd, PATH_MAX) == NULL) {
|
|
||||||
perror("getcwd");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int len = strlen(cwd);
|
|
||||||
if (strncmp(cwd, target, len) == 0)
|
|
||||||
target += len;
|
|
||||||
|
|
||||||
/* Assume pool/dataset is more likely */
|
|
||||||
strlcpy(*dataset, target, PATH_MAX);
|
|
||||||
|
|
||||||
int fd = open(target, O_RDONLY | O_CLOEXEC);
|
|
||||||
if (fd < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
nvlist_t *cfg = NULL;
|
|
||||||
if (zpool_read_label(fd, &cfg, NULL) == 0) {
|
|
||||||
const char *nm = NULL;
|
|
||||||
if (!nvlist_lookup_string(cfg, ZPOOL_CONFIG_POOL_NAME, &nm))
|
|
||||||
strlcpy(*dataset, nm, PATH_MAX);
|
|
||||||
nvlist_free(cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (close(fd))
|
|
||||||
perror("close");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update the mtab_* code to use the libmount library when it is commonly
|
|
||||||
* available otherwise fallback to legacy mode. The mount(8) utility will
|
|
||||||
* manage the lock file for us to prevent racing updates to /etc/mtab.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
mtab_is_writeable(void)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
int error, fd;
|
|
||||||
|
|
||||||
error = lstat("/etc/mtab", &st);
|
|
||||||
if (error || S_ISLNK(st.st_mode))
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
fd = open("/etc/mtab", O_RDWR | O_CREAT, 0644);
|
|
||||||
if (fd < 0)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
mtab_update(const char *dataset, const char *mntpoint, const char *type,
|
|
||||||
const 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_freq = 0;
|
|
||||||
mnt.mnt_passno = 0;
|
|
||||||
|
|
||||||
fp = setmntent("/etc/mtab", "a+e");
|
|
||||||
if (!fp) {
|
|
||||||
(void) fprintf(stderr, gettext(
|
|
||||||
"filesystem '%s' was mounted, but /etc/mtab "
|
|
||||||
"could not be opened due to error: %s\n"),
|
|
||||||
dataset, strerror(errno));
|
|
||||||
return (MOUNT_FILEIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
error = addmntent(fp, &mnt);
|
|
||||||
if (error) {
|
|
||||||
(void) fprintf(stderr, gettext(
|
|
||||||
"filesystem '%s' was mounted, but /etc/mtab "
|
|
||||||
"could not be updated due to error: %s\n"),
|
|
||||||
dataset, strerror(errno));
|
|
||||||
return (MOUNT_FILEIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) endmntent(fp);
|
|
||||||
|
|
||||||
return (MOUNT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
zfs_handle_t *zhp;
|
|
||||||
char prop[ZFS_MAXPROPLEN];
|
|
||||||
uint64_t zfs_version = 0;
|
|
||||||
char mntopts[MNT_LINE_MAX] = { '\0' };
|
|
||||||
char badopt[MNT_LINE_MAX] = { '\0' };
|
|
||||||
char mtabopt[MNT_LINE_MAX] = { '\0' };
|
|
||||||
char mntpoint[PATH_MAX];
|
|
||||||
char dataset[PATH_MAX], *pdataset = dataset;
|
|
||||||
unsigned long mntflags = 0, zfsflags = 0, remount = 0;
|
|
||||||
int sloppy = 0, fake = 0, verbose = 0, nomtab = 0, zfsutil = 0;
|
|
||||||
int error, c;
|
|
||||||
|
|
||||||
(void) setlocale(LC_ALL, "");
|
|
||||||
(void) setlocale(LC_NUMERIC, "C");
|
|
||||||
(void) textdomain(TEXT_DOMAIN);
|
|
||||||
|
|
||||||
opterr = 0;
|
|
||||||
|
|
||||||
/* check options */
|
|
||||||
while ((c = getopt_long(argc, argv, "sfnvo:h?", 0, 0)) != -1) {
|
|
||||||
switch (c) {
|
|
||||||
case 's':
|
|
||||||
sloppy = 1;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
fake = 1;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
nomtab = 1;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
verbose++;
|
|
||||||
break;
|
|
||||||
case 'o':
|
|
||||||
(void) strlcpy(mntopts, optarg, sizeof (mntopts));
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
case '?':
|
|
||||||
if (optopt)
|
|
||||||
(void) fprintf(stderr,
|
|
||||||
gettext("Invalid option '%c'\n"), optopt);
|
|
||||||
(void) fprintf(stderr, gettext("Usage: mount.zfs "
|
|
||||||
"[-sfnvh] [-o options] <dataset> <mountpoint>\n"));
|
|
||||||
return (MOUNT_USAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argc -= optind;
|
|
||||||
argv += optind;
|
|
||||||
|
|
||||||
/* check that we only have two arguments */
|
|
||||||
if (argc != 2) {
|
|
||||||
if (argc == 0)
|
|
||||||
(void) fprintf(stderr, gettext("missing dataset "
|
|
||||||
"argument\n"));
|
|
||||||
else if (argc == 1)
|
|
||||||
(void) fprintf(stderr,
|
|
||||||
gettext("missing mountpoint argument\n"));
|
|
||||||
else
|
|
||||||
(void) fprintf(stderr, gettext("too many arguments\n"));
|
|
||||||
(void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n");
|
|
||||||
return (MOUNT_USAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_dataset(argv[0], &pdataset);
|
|
||||||
|
|
||||||
/* canonicalize the mount point */
|
|
||||||
if (realpath(argv[1], mntpoint) == NULL) {
|
|
||||||
(void) fprintf(stderr, gettext("filesystem '%s' cannot be "
|
|
||||||
"mounted at '%s' due to canonicalization error: %s\n"),
|
|
||||||
dataset, argv[1], strerror(errno));
|
|
||||||
return (MOUNT_SYSERR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* validate mount options and set mntflags */
|
|
||||||
error = zfs_parse_mount_options(mntopts, &mntflags, &zfsflags, sloppy,
|
|
||||||
badopt, mtabopt);
|
|
||||||
if (error) {
|
|
||||||
switch (error) {
|
|
||||||
case ENOMEM:
|
|
||||||
(void) fprintf(stderr, gettext("filesystem '%s' "
|
|
||||||
"cannot be mounted due to a memory allocation "
|
|
||||||
"failure.\n"), dataset);
|
|
||||||
return (MOUNT_SYSERR);
|
|
||||||
case ENOENT:
|
|
||||||
(void) fprintf(stderr, gettext("filesystem '%s' "
|
|
||||||
"cannot be mounted due to invalid option "
|
|
||||||
"'%s'.\n"), dataset, badopt);
|
|
||||||
(void) fprintf(stderr, gettext("Use the '-s' option "
|
|
||||||
"to ignore the bad mount option.\n"));
|
|
||||||
return (MOUNT_USAGE);
|
|
||||||
default:
|
|
||||||
(void) fprintf(stderr, gettext("filesystem '%s' "
|
|
||||||
"cannot be mounted due to internal error %d.\n"),
|
|
||||||
dataset, error);
|
|
||||||
return (MOUNT_SOFTWARE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mntflags & MS_REMOUNT) {
|
|
||||||
nomtab = 1;
|
|
||||||
remount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zfsflags & ZS_ZFSUTIL)
|
|
||||||
zfsutil = 1;
|
|
||||||
|
|
||||||
if ((g_zfs = libzfs_init()) == NULL) {
|
|
||||||
(void) fprintf(stderr, "%s\n", libzfs_error_init(errno));
|
|
||||||
return (MOUNT_SYSERR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* try to open the dataset to access the mount point */
|
|
||||||
if ((zhp = zfs_open(g_zfs, dataset,
|
|
||||||
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT)) == NULL) {
|
|
||||||
(void) fprintf(stderr, gettext("filesystem '%s' cannot be "
|
|
||||||
"mounted, unable to open the dataset\n"), dataset);
|
|
||||||
libzfs_fini(g_zfs);
|
|
||||||
return (MOUNT_USAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sloppy || libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
|
|
||||||
zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* treat all snapshots as legacy mount points */
|
|
||||||
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
|
|
||||||
(void) strlcpy(prop, ZFS_MOUNTPOINT_LEGACY, ZFS_MAXPROPLEN);
|
|
||||||
else
|
|
||||||
(void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop,
|
|
||||||
sizeof (prop), NULL, NULL, 0, B_FALSE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fetch the max supported zfs version in case we get ENOTSUP
|
|
||||||
* back from the mount command, since we need the zfs handle
|
|
||||||
* to do so.
|
|
||||||
*/
|
|
||||||
zfs_version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Legacy mount points may only be mounted using 'mount', never using
|
|
||||||
* 'zfs mount'. However, since 'zfs mount' actually invokes 'mount'
|
|
||||||
* we differentiate the two cases using the 'zfsutil' mount option.
|
|
||||||
* This mount option should only be supplied by the 'zfs mount' util.
|
|
||||||
*
|
|
||||||
* The only exception to the above rule is '-o remount' which is
|
|
||||||
* always allowed for non-legacy datasets. This is done because when
|
|
||||||
* using zfs as your root file system both rc.sysinit/umountroot and
|
|
||||||
* systemd depend on 'mount -o remount <mountpoint>' to work.
|
|
||||||
*/
|
|
||||||
if (zfsutil && (strcmp(prop, ZFS_MOUNTPOINT_LEGACY) == 0)) {
|
|
||||||
(void) fprintf(stderr, gettext(
|
|
||||||
"filesystem '%s' cannot be mounted using 'zfs mount'.\n"
|
|
||||||
"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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!zfsutil && !(remount || fake) &&
|
|
||||||
strcmp(prop, ZFS_MOUNTPOINT_LEGACY)) {
|
|
||||||
(void) fprintf(stderr, gettext(
|
|
||||||
"filesystem '%s' cannot be mounted using 'mount'.\n"
|
|
||||||
"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 (!remount && !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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zfs_close(zhp);
|
|
||||||
libzfs_fini(g_zfs);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
switch (errno) {
|
|
||||||
case ENOENT:
|
|
||||||
(void) fprintf(stderr, gettext("mount point "
|
|
||||||
"'%s' does not exist\n"), mntpoint);
|
|
||||||
return (MOUNT_SYSERR);
|
|
||||||
case EBUSY:
|
|
||||||
(void) fprintf(stderr, gettext("filesystem "
|
|
||||||
"'%s' is already mounted\n"), dataset);
|
|
||||||
return (MOUNT_BUSY);
|
|
||||||
case ENOTSUP:
|
|
||||||
if (zfs_version > ZPL_VERSION) {
|
|
||||||
(void) fprintf(stderr,
|
|
||||||
gettext("filesystem '%s' (v%d) is not "
|
|
||||||
"supported by this implementation of "
|
|
||||||
"ZFS (max v%d).\n"), dataset,
|
|
||||||
(int)zfs_version, (int)ZPL_VERSION);
|
|
||||||
} else {
|
|
||||||
(void) fprintf(stderr,
|
|
||||||
gettext("filesystem '%s' mount "
|
|
||||||
"failed for unknown reason.\n"), dataset);
|
|
||||||
}
|
|
||||||
return (MOUNT_SYSERR);
|
|
||||||
#ifdef MS_MANDLOCK
|
|
||||||
case EPERM:
|
|
||||||
if (mntflags & MS_MANDLOCK) {
|
|
||||||
(void) fprintf(stderr, gettext("filesystem "
|
|
||||||
"'%s' has the 'nbmand=on' property set, "
|
|
||||||
"this mount\noption may be disabled in "
|
|
||||||
"your kernel. Use 'zfs set nbmand=off'\n"
|
|
||||||
"to disable this option and try to "
|
|
||||||
"mount the filesystem again.\n"), dataset);
|
|
||||||
return (MOUNT_SYSERR);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
zfs_fallthrough;
|
|
||||||
default:
|
|
||||||
(void) fprintf(stderr, gettext("filesystem "
|
|
||||||
"'%s' can not be mounted: %s\n"), dataset,
|
|
||||||
strerror(errno));
|
|
||||||
return (MOUNT_USAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nomtab && mtab_is_writeable()) {
|
|
||||||
error = mtab_update(dataset, mntpoint, MNTTYPE_ZFS, mtabopt);
|
|
||||||
if (error)
|
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (MOUNT_SUCCESS);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
mount.zfs
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
DEFAULT_INCLUDES += \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
|
-I$(top_srcdir)/lib/libspl/include
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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 = \
|
||||||
|
$(top_builddir)/lib/libnvpair/libnvpair.la \
|
||||||
|
$(top_builddir)/lib/libuutil/libuutil.la \
|
||||||
|
$(top_builddir)/lib/libzpool/libzpool.la \
|
||||||
|
$(top_builddir)/lib/libzfs/libzfs.la \
|
||||||
|
$(top_builddir)/lib/libzfs_core/libzfs_core.la
|
||||||
@@ -0,0 +1,638 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* 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 http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* Copyright (c) 2011 Lawrence Livermore National Security, LLC.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libintl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/mntent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <libzfs.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#define ZS_COMMENT 0x00000000 /* comment */
|
||||||
|
#define ZS_ZFSUTIL 0x00000001 /* caller is zfs(8) */
|
||||||
|
|
||||||
|
libzfs_handle_t *g_zfs;
|
||||||
|
|
||||||
|
typedef struct option_map {
|
||||||
|
const char *name;
|
||||||
|
unsigned long mntmask;
|
||||||
|
unsigned long zfsmask;
|
||||||
|
} option_map_t;
|
||||||
|
|
||||||
|
static const option_map_t option_map[] = {
|
||||||
|
/* Canonicalized filesystem independent options from mount(8) */
|
||||||
|
{ MNTOPT_NOAUTO, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_DEFAULTS, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_NODEVICES, MS_NODEV, ZS_COMMENT },
|
||||||
|
{ MNTOPT_DIRSYNC, MS_DIRSYNC, ZS_COMMENT },
|
||||||
|
{ MNTOPT_NOEXEC, MS_NOEXEC, ZS_COMMENT },
|
||||||
|
{ MNTOPT_GROUP, MS_GROUP, ZS_COMMENT },
|
||||||
|
{ MNTOPT_NETDEV, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_NOFAIL, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_NOSUID, MS_NOSUID, ZS_COMMENT },
|
||||||
|
{ MNTOPT_OWNER, MS_OWNER, ZS_COMMENT },
|
||||||
|
{ MNTOPT_REMOUNT, MS_REMOUNT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_RO, MS_RDONLY, ZS_COMMENT },
|
||||||
|
{ MNTOPT_RW, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_SYNC, MS_SYNCHRONOUS, ZS_COMMENT },
|
||||||
|
{ MNTOPT_USER, MS_USERS, ZS_COMMENT },
|
||||||
|
{ MNTOPT_USERS, MS_USERS, ZS_COMMENT },
|
||||||
|
/* acl flags passed with util-linux-2.24 mount command */
|
||||||
|
{ MNTOPT_ACL, MS_POSIXACL, ZS_COMMENT },
|
||||||
|
{ MNTOPT_NOACL, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_POSIXACL, MS_POSIXACL, ZS_COMMENT },
|
||||||
|
#ifdef MS_NOATIME
|
||||||
|
{ MNTOPT_NOATIME, MS_NOATIME, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
#ifdef MS_NODIRATIME
|
||||||
|
{ MNTOPT_NODIRATIME, MS_NODIRATIME, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
#ifdef MS_RELATIME
|
||||||
|
{ MNTOPT_RELATIME, MS_RELATIME, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
#ifdef MS_STRICTATIME
|
||||||
|
{ MNTOPT_STRICTATIME, MS_STRICTATIME, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
#ifdef MS_LAZYTIME
|
||||||
|
{ MNTOPT_LAZYTIME, MS_LAZYTIME, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
{ MNTOPT_CONTEXT, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_FSCONTEXT, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_DEFCONTEXT, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_ROOTCONTEXT, MS_COMMENT, ZS_COMMENT },
|
||||||
|
#ifdef MS_I_VERSION
|
||||||
|
{ MNTOPT_IVERSION, MS_I_VERSION, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
#ifdef MS_MANDLOCK
|
||||||
|
{ MNTOPT_NBMAND, MS_MANDLOCK, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
/* Valid options not found in mount(8) */
|
||||||
|
{ MNTOPT_BIND, MS_BIND, ZS_COMMENT },
|
||||||
|
#ifdef MS_REC
|
||||||
|
{ MNTOPT_RBIND, MS_BIND|MS_REC, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
{ MNTOPT_COMMENT, MS_COMMENT, ZS_COMMENT },
|
||||||
|
#ifdef MS_NOSUB
|
||||||
|
{ MNTOPT_NOSUB, MS_NOSUB, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
#ifdef MS_SILENT
|
||||||
|
{ MNTOPT_QUIET, MS_SILENT, ZS_COMMENT },
|
||||||
|
#endif
|
||||||
|
/* Custom zfs options */
|
||||||
|
{ MNTOPT_XATTR, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_NOXATTR, MS_COMMENT, ZS_COMMENT },
|
||||||
|
{ MNTOPT_ZFSUTIL, MS_COMMENT, ZS_ZFSUTIL },
|
||||||
|
{ NULL, 0, 0 } };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Break the mount option in to a name/value pair. The name is
|
||||||
|
* validated against the option map and mount flags set accordingly.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_option(char *mntopt, unsigned long *mntflags,
|
||||||
|
unsigned long *zfsflags, int sloppy)
|
||||||
|
{
|
||||||
|
const option_map_t *opt;
|
||||||
|
char *ptr, *name, *value = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
name = strdup(mntopt);
|
||||||
|
if (name == NULL)
|
||||||
|
return (ENOMEM);
|
||||||
|
|
||||||
|
for (ptr = name; ptr && *ptr; ptr++) {
|
||||||
|
if (*ptr == '=') {
|
||||||
|
*ptr = '\0';
|
||||||
|
value = ptr+1;
|
||||||
|
VERIFY3P(value, !=, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (opt = option_map; opt->name != NULL; opt++) {
|
||||||
|
if (strncmp(name, opt->name, strlen(name)) == 0) {
|
||||||
|
*mntflags |= opt->mntmask;
|
||||||
|
*zfsflags |= opt->zfsmask;
|
||||||
|
error = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sloppy)
|
||||||
|
error = ENOENT;
|
||||||
|
out:
|
||||||
|
/* If required further process on the value may be done here */
|
||||||
|
free(name);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translate the mount option string in to MS_* mount flags for the
|
||||||
|
* kernel vfs. When sloppy is non-zero unknown options will be ignored
|
||||||
|
* otherwise they are considered fatal are copied in to badopt.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_options(char *mntopts, unsigned long *mntflags, unsigned long *zfsflags,
|
||||||
|
int sloppy, char *badopt, char *mtabopt)
|
||||||
|
{
|
||||||
|
int error = 0, quote = 0, flag = 0, count = 0;
|
||||||
|
char *ptr, *opt, *opts;
|
||||||
|
|
||||||
|
opts = strdup(mntopts);
|
||||||
|
if (opts == NULL)
|
||||||
|
return (ENOMEM);
|
||||||
|
|
||||||
|
*mntflags = 0;
|
||||||
|
opt = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan through all mount options which must be comma delimited.
|
||||||
|
* We must be careful to notice regions which are double quoted
|
||||||
|
* and skip commas in these regions. Each option is then checked
|
||||||
|
* to determine if it is a known option.
|
||||||
|
*/
|
||||||
|
for (ptr = opts; ptr && !flag; ptr++) {
|
||||||
|
if (opt == NULL)
|
||||||
|
opt = ptr;
|
||||||
|
|
||||||
|
if (*ptr == '"')
|
||||||
|
quote = !quote;
|
||||||
|
|
||||||
|
if (quote)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (*ptr == '\0')
|
||||||
|
flag = 1;
|
||||||
|
|
||||||
|
if ((*ptr == ',') || (*ptr == '\0')) {
|
||||||
|
*ptr = '\0';
|
||||||
|
|
||||||
|
error = parse_option(opt, mntflags, zfsflags, sloppy);
|
||||||
|
if (error) {
|
||||||
|
strcpy(badopt, opt);
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(*mntflags & MS_REMOUNT) &&
|
||||||
|
!(*zfsflags & ZS_ZFSUTIL)) {
|
||||||
|
if (count > 0)
|
||||||
|
strlcat(mtabopt, ",", MNT_LINE_MAX);
|
||||||
|
|
||||||
|
strlcat(mtabopt, opt, MNT_LINE_MAX);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
opt = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(opts);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the pool/dataset to mount given the name passed to mount. This
|
||||||
|
* is expected to be of the form pool/dataset, however may also refer to
|
||||||
|
* a block device if that device contains a valid zfs label.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
parse_dataset(char *dataset)
|
||||||
|
{
|
||||||
|
char cwd[PATH_MAX];
|
||||||
|
struct stat64 statbuf;
|
||||||
|
int error;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We expect a pool/dataset to be provided, however if we're
|
||||||
|
* given a device which is a member of a zpool we attempt to
|
||||||
|
* extract the pool name stored in the label. Given the pool
|
||||||
|
* name we can mount the root dataset.
|
||||||
|
*/
|
||||||
|
error = stat64(dataset, &statbuf);
|
||||||
|
if (error == 0) {
|
||||||
|
nvlist_t *config;
|
||||||
|
char *name;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(dataset, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error = zpool_read_label(fd, &config, NULL);
|
||||||
|
(void) close(fd);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error = nvlist_lookup_string(config,
|
||||||
|
ZPOOL_CONFIG_POOL_NAME, &name);
|
||||||
|
if (error) {
|
||||||
|
nvlist_free(config);
|
||||||
|
} else {
|
||||||
|
dataset = strdup(name);
|
||||||
|
nvlist_free(config);
|
||||||
|
return (dataset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
/*
|
||||||
|
* If a file or directory in your current working directory is
|
||||||
|
* named 'dataset' then mount(8) will prepend your current working
|
||||||
|
* directory to the dataset. There is no way to prevent this
|
||||||
|
* behavior so we simply check for it and strip the prepended
|
||||||
|
* patch when it is added.
|
||||||
|
*/
|
||||||
|
if (getcwd(cwd, PATH_MAX) == NULL)
|
||||||
|
return (dataset);
|
||||||
|
|
||||||
|
len = strlen(cwd);
|
||||||
|
|
||||||
|
/* Do not add one when cwd already ends in a trailing '/' */
|
||||||
|
if (strncmp(cwd, dataset, len) == 0)
|
||||||
|
return (dataset + len + (cwd[len-1] != '/'));
|
||||||
|
|
||||||
|
return (dataset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the mtab_* code to use the libmount library when it is commonly
|
||||||
|
* available otherwise fallback to legacy mode. The mount(8) utility will
|
||||||
|
* manage the lock file for us to prevent racing updates to /etc/mtab.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mtab_is_writeable(void)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int error, fd;
|
||||||
|
|
||||||
|
error = lstat("/etc/mtab", &st);
|
||||||
|
if (error || S_ISLNK(st.st_mode))
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
fd = open("/etc/mtab", O_RDWR | O_CREAT, 0644);
|
||||||
|
if (fd < 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts)
|
||||||
|
{
|
||||||
|
struct mntent mnt;
|
||||||
|
FILE *fp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
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+");
|
||||||
|
if (!fp) {
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"filesystem '%s' was mounted, but /etc/mtab "
|
||||||
|
"could not be opened due to error %d\n"),
|
||||||
|
dataset, errno);
|
||||||
|
return (MOUNT_FILEIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = addmntent(fp, &mnt);
|
||||||
|
if (error) {
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"filesystem '%s' was mounted, but /etc/mtab "
|
||||||
|
"could not be updated due to error %d\n"),
|
||||||
|
dataset, errno);
|
||||||
|
return (MOUNT_FILEIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) endmntent(fp);
|
||||||
|
|
||||||
|
return (MOUNT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
append_mntopt(const char *name, const char *val, char *mntopts,
|
||||||
|
char *mtabopt, boolean_t quote)
|
||||||
|
{
|
||||||
|
char tmp[MNT_LINE_MAX];
|
||||||
|
|
||||||
|
snprintf(tmp, MNT_LINE_MAX, quote ? ",%s=\"%s\"" : ",%s=%s", name, val);
|
||||||
|
|
||||||
|
if (mntopts)
|
||||||
|
strlcat(mntopts, tmp, MNT_LINE_MAX);
|
||||||
|
|
||||||
|
if (mtabopt)
|
||||||
|
strlcat(mtabopt, tmp, MNT_LINE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
zfs_selinux_setcontext(zfs_handle_t *zhp, zfs_prop_t zpt, const char *name,
|
||||||
|
char *mntopts, char *mtabopt)
|
||||||
|
{
|
||||||
|
char context[ZFS_MAXPROPLEN];
|
||||||
|
|
||||||
|
if (zfs_prop_get(zhp, zpt, context, sizeof (context),
|
||||||
|
NULL, NULL, 0, B_FALSE) == 0) {
|
||||||
|
if (strcmp(context, "none") != 0)
|
||||||
|
append_mntopt(name, context, mntopts, mtabopt, B_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
zfs_handle_t *zhp;
|
||||||
|
char prop[ZFS_MAXPROPLEN];
|
||||||
|
uint64_t zfs_version = 0;
|
||||||
|
char mntopts[MNT_LINE_MAX] = { '\0' };
|
||||||
|
char badopt[MNT_LINE_MAX] = { '\0' };
|
||||||
|
char mtabopt[MNT_LINE_MAX] = { '\0' };
|
||||||
|
char mntpoint[PATH_MAX];
|
||||||
|
char *dataset;
|
||||||
|
unsigned long mntflags = 0, zfsflags = 0, remount = 0;
|
||||||
|
int sloppy = 0, fake = 0, verbose = 0, nomtab = 0, zfsutil = 0;
|
||||||
|
int error, c;
|
||||||
|
|
||||||
|
(void) setlocale(LC_ALL, "");
|
||||||
|
(void) textdomain(TEXT_DOMAIN);
|
||||||
|
|
||||||
|
opterr = 0;
|
||||||
|
|
||||||
|
/* check options */
|
||||||
|
while ((c = getopt_long(argc, argv, "sfnvo:h?", 0, 0)) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 's':
|
||||||
|
sloppy = 1;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
fake = 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
nomtab = 1;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
verbose++;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
(void) strlcpy(mntopts, optarg, sizeof (mntopts));
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case '?':
|
||||||
|
(void) fprintf(stderr, gettext("Invalid option '%c'\n"),
|
||||||
|
optopt);
|
||||||
|
(void) fprintf(stderr, gettext("Usage: mount.zfs "
|
||||||
|
"[-sfnv] [-o options] <dataset> <mountpoint>\n"));
|
||||||
|
return (MOUNT_USAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
/* check that we only have two arguments */
|
||||||
|
if (argc != 2) {
|
||||||
|
if (argc == 0)
|
||||||
|
(void) fprintf(stderr, gettext("missing dataset "
|
||||||
|
"argument\n"));
|
||||||
|
else if (argc == 1)
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("missing mountpoint argument\n"));
|
||||||
|
else
|
||||||
|
(void) fprintf(stderr, gettext("too many arguments\n"));
|
||||||
|
(void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n");
|
||||||
|
return (MOUNT_USAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataset = parse_dataset(argv[0]);
|
||||||
|
|
||||||
|
/* canonicalize the mount point */
|
||||||
|
if (realpath(argv[1], mntpoint) == NULL) {
|
||||||
|
(void) fprintf(stderr, gettext("filesystem '%s' cannot be "
|
||||||
|
"mounted at '%s' due to canonicalization error %d.\n"),
|
||||||
|
dataset, argv[1], errno);
|
||||||
|
return (MOUNT_SYSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* validate mount options and set mntflags */
|
||||||
|
error = parse_options(mntopts, &mntflags, &zfsflags, sloppy,
|
||||||
|
badopt, mtabopt);
|
||||||
|
if (error) {
|
||||||
|
switch (error) {
|
||||||
|
case ENOMEM:
|
||||||
|
(void) fprintf(stderr, gettext("filesystem '%s' "
|
||||||
|
"cannot be mounted due to a memory allocation "
|
||||||
|
"failure.\n"), dataset);
|
||||||
|
return (MOUNT_SYSERR);
|
||||||
|
case ENOENT:
|
||||||
|
(void) fprintf(stderr, gettext("filesystem '%s' "
|
||||||
|
"cannot be mounted due to invalid option "
|
||||||
|
"'%s'.\n"), dataset, badopt);
|
||||||
|
(void) fprintf(stderr, gettext("Use the '-s' option "
|
||||||
|
"to ignore the bad mount option.\n"));
|
||||||
|
return (MOUNT_USAGE);
|
||||||
|
default:
|
||||||
|
(void) fprintf(stderr, gettext("filesystem '%s' "
|
||||||
|
"cannot be mounted due to internal error %d.\n"),
|
||||||
|
dataset, error);
|
||||||
|
return (MOUNT_SOFTWARE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zfsflags & ZS_ZFSUTIL)
|
||||||
|
zfsutil = 1;
|
||||||
|
|
||||||
|
if ((g_zfs = libzfs_init()) == NULL) {
|
||||||
|
(void) fprintf(stderr, "%s", libzfs_error_init(errno));
|
||||||
|
return (MOUNT_SYSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to open the dataset to access the mount point */
|
||||||
|
if ((zhp = zfs_open(g_zfs, dataset,
|
||||||
|
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT)) == NULL) {
|
||||||
|
(void) fprintf(stderr, gettext("filesystem '%s' cannot be "
|
||||||
|
"mounted, unable to open the dataset\n"), dataset);
|
||||||
|
libzfs_fini(g_zfs);
|
||||||
|
return (MOUNT_USAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks to see if the ZFS_PROP_SELINUX_CONTEXT exists
|
||||||
|
* if it does, create a tmp variable in case it's needed
|
||||||
|
* checks to see if the selinux context is set to the default
|
||||||
|
* if it is, allow the setting of the other context properties
|
||||||
|
* this is needed because the 'context' property overrides others
|
||||||
|
* if it is not the default, set the 'context' property
|
||||||
|
*/
|
||||||
|
if (zfs_prop_get(zhp, ZFS_PROP_SELINUX_CONTEXT, prop, sizeof (prop),
|
||||||
|
NULL, NULL, 0, B_FALSE) == 0) {
|
||||||
|
if (strcmp(prop, "none") == 0) {
|
||||||
|
zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_FSCONTEXT,
|
||||||
|
MNTOPT_FSCONTEXT, mntopts, mtabopt);
|
||||||
|
zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_DEFCONTEXT,
|
||||||
|
MNTOPT_DEFCONTEXT, mntopts, mtabopt);
|
||||||
|
zfs_selinux_setcontext(zhp,
|
||||||
|
ZFS_PROP_SELINUX_ROOTCONTEXT, MNTOPT_ROOTCONTEXT,
|
||||||
|
mntopts, mtabopt);
|
||||||
|
} else {
|
||||||
|
append_mntopt(MNTOPT_CONTEXT, prop,
|
||||||
|
mntopts, mtabopt, B_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A hint used to determine an auto-mounted snapshot mount point */
|
||||||
|
append_mntopt(MNTOPT_MNTPOINT, mntpoint, mntopts, NULL, B_FALSE);
|
||||||
|
|
||||||
|
/* treat all snapshots as legacy mount points */
|
||||||
|
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
|
||||||
|
(void) strlcpy(prop, ZFS_MOUNTPOINT_LEGACY, ZFS_MAXPROPLEN);
|
||||||
|
else
|
||||||
|
(void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop,
|
||||||
|
sizeof (prop), NULL, NULL, 0, B_FALSE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch the max supported zfs version in case we get ENOTSUP
|
||||||
|
* back from the mount command, since we need the zfs handle
|
||||||
|
* to do so.
|
||||||
|
*/
|
||||||
|
zfs_version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
|
||||||
|
if (zfs_version == 0) {
|
||||||
|
fprintf(stderr, gettext("unable to fetch "
|
||||||
|
"ZFS version for filesystem '%s'\n"), dataset);
|
||||||
|
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'
|
||||||
|
* we differentiate the two cases using the 'zfsutil' mount option.
|
||||||
|
* This mount option should only be supplied by the 'zfs mount' util.
|
||||||
|
*
|
||||||
|
* The only exception to the above rule is '-o remount' which is
|
||||||
|
* always allowed for non-legacy datasets. This is done because when
|
||||||
|
* using zfs as your root file system both rc.sysinit/umountroot and
|
||||||
|
* systemd depend on 'mount -o remount <mountpoint>' to work.
|
||||||
|
*/
|
||||||
|
if (zfsutil && (strcmp(prop, ZFS_MOUNTPOINT_LEGACY) == 0)) {
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"filesystem '%s' cannot be mounted using 'zfs mount'.\n"
|
||||||
|
"Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n"
|
||||||
|
"See zfs(8) for more information.\n"),
|
||||||
|
dataset, mntpoint, dataset, mntpoint);
|
||||||
|
return (MOUNT_USAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!zfsutil && !(remount || fake) &&
|
||||||
|
strcmp(prop, ZFS_MOUNTPOINT_LEGACY)) {
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"filesystem '%s' cannot be mounted using 'mount'.\n"
|
||||||
|
"Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n"
|
||||||
|
"See zfs(8) for more information.\n"),
|
||||||
|
dataset, "legacy", dataset);
|
||||||
|
return (MOUNT_USAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fake) {
|
||||||
|
error = mount(dataset, mntpoint, MNTTYPE_ZFS,
|
||||||
|
mntflags, mntopts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
switch (errno) {
|
||||||
|
case ENOENT:
|
||||||
|
(void) fprintf(stderr, gettext("mount point "
|
||||||
|
"'%s' does not exist\n"), mntpoint);
|
||||||
|
return (MOUNT_SYSERR);
|
||||||
|
case EBUSY:
|
||||||
|
(void) fprintf(stderr, gettext("filesystem "
|
||||||
|
"'%s' is already mounted\n"), dataset);
|
||||||
|
return (MOUNT_BUSY);
|
||||||
|
case ENOTSUP:
|
||||||
|
if (zfs_version > ZPL_VERSION) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("filesystem '%s' (v%d) is not "
|
||||||
|
"supported by this implementation of "
|
||||||
|
"ZFS (max v%d).\n"), dataset,
|
||||||
|
(int)zfs_version, (int)ZPL_VERSION);
|
||||||
|
} else {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("filesystem '%s' mount "
|
||||||
|
"failed for unknown reason.\n"), dataset);
|
||||||
|
}
|
||||||
|
return (MOUNT_SYSERR);
|
||||||
|
#ifdef MS_MANDLOCK
|
||||||
|
case EPERM:
|
||||||
|
if (mntflags & MS_MANDLOCK) {
|
||||||
|
(void) fprintf(stderr, gettext("filesystem "
|
||||||
|
"'%s' has the 'nbmand=on' property set, "
|
||||||
|
"this mount\noption may be disabled in "
|
||||||
|
"your kernel. Use 'zfs set nbmand=off'\n"
|
||||||
|
"to disable this option and try to "
|
||||||
|
"mount the filesystem again.\n"), dataset);
|
||||||
|
return (MOUNT_SYSERR);
|
||||||
|
}
|
||||||
|
/* fallthru */
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
(void) fprintf(stderr, gettext("filesystem "
|
||||||
|
"'%s' can not be mounted: %s\n"), dataset,
|
||||||
|
strerror(errno));
|
||||||
|
return (MOUNT_USAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nomtab && mtab_is_writeable()) {
|
||||||
|
error = mtab_update(dataset, mntpoint, MNTTYPE_ZFS, mtabopt);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (MOUNT_SUCCESS);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/raidz_test
|
||||||
+16
-11
@@ -1,17 +1,22 @@
|
|||||||
# SPDX-License-Identifier: CDDL-1.0
|
include $(top_srcdir)/config/Rules.am
|
||||||
raidz_test_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS)
|
|
||||||
raidz_test_CPPFLAGS = $(AM_CPPFLAGS) $(LIBZPOOL_CPPFLAGS)
|
|
||||||
|
|
||||||
bin_PROGRAMS += raidz_test
|
AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
|
||||||
CPPCHECKTARGETS += raidz_test
|
AM_CPPFLAGS += -DDEBUG
|
||||||
|
|
||||||
|
DEFAULT_INCLUDES += \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
|
-I$(top_srcdir)/lib/libspl/include
|
||||||
|
|
||||||
|
bin_PROGRAMS = raidz_test
|
||||||
|
|
||||||
raidz_test_SOURCES = \
|
raidz_test_SOURCES = \
|
||||||
%D%/raidz_bench.c \
|
raidz_test.h \
|
||||||
%D%/raidz_test.c \
|
raidz_test.c \
|
||||||
%D%/raidz_test.h
|
raidz_bench.c
|
||||||
|
|
||||||
raidz_test_LDADD = \
|
raidz_test_LDADD = \
|
||||||
libzpool.la \
|
$(top_builddir)/lib/libnvpair/libnvpair.la \
|
||||||
libzfs_core.la
|
$(top_builddir)/lib/libuutil/libuutil.la \
|
||||||
|
$(top_builddir)/lib/libzpool/libzpool.la
|
||||||
|
|
||||||
raidz_test_LDADD += -lm
|
raidz_test_LDADD += -lm -ldl
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -7,7 +6,7 @@
|
|||||||
* You may not use this file except in compliance with the License.
|
* 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
|
* 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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -32,6 +31,8 @@
|
|||||||
#include <sys/vdev_raidz_impl.h>
|
#include <sys/vdev_raidz_impl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "raidz_test.h"
|
#include "raidz_test.h"
|
||||||
|
|
||||||
#define GEN_BENCH_MEMORY (((uint64_t)1ULL)<<32)
|
#define GEN_BENCH_MEMORY (((uint64_t)1ULL)<<32)
|
||||||
@@ -64,7 +65,7 @@ bench_fini_raidz_maps(void)
|
|||||||
{
|
{
|
||||||
/* tear down golden zio */
|
/* tear down golden zio */
|
||||||
raidz_free(zio_bench.io_abd, max_data_size);
|
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
|
static inline void
|
||||||
@@ -82,17 +83,8 @@ run_gen_bench_impl(const char *impl)
|
|||||||
/* create suitable raidz_map */
|
/* create suitable raidz_map */
|
||||||
ncols = rto_opts.rto_dcols + fn + 1;
|
ncols = rto_opts.rto_dcols + fn + 1;
|
||||||
zio_bench.io_size = 1ULL << ds;
|
zio_bench.io_size = 1ULL << ds;
|
||||||
|
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
||||||
if (rto_opts.rto_expand) {
|
BENCH_ASHIFT, ncols, fn+1);
|
||||||
rm_bench = vdev_raidz_map_alloc_expanded(
|
|
||||||
&zio_bench,
|
|
||||||
rto_opts.rto_ashift, ncols+1, ncols,
|
|
||||||
fn+1, rto_opts.rto_expand_offset,
|
|
||||||
0, B_FALSE);
|
|
||||||
} else {
|
|
||||||
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
|
||||||
BENCH_ASHIFT, ncols, fn+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* estimate iteration count */
|
/* estimate iteration count */
|
||||||
iter_cnt = GEN_BENCH_MEMORY;
|
iter_cnt = GEN_BENCH_MEMORY;
|
||||||
@@ -121,7 +113,7 @@ run_gen_bench_impl(const char *impl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
run_gen_bench(void)
|
run_gen_bench(void)
|
||||||
{
|
{
|
||||||
char **impl_name;
|
char **impl_name;
|
||||||
@@ -171,16 +163,8 @@ run_rec_bench_impl(const char *impl)
|
|||||||
(1ULL << BENCH_ASHIFT))
|
(1ULL << BENCH_ASHIFT))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (rto_opts.rto_expand) {
|
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
||||||
rm_bench = vdev_raidz_map_alloc_expanded(
|
BENCH_ASHIFT, ncols, PARITY_PQR);
|
||||||
&zio_bench,
|
|
||||||
BENCH_ASHIFT, ncols+1, ncols,
|
|
||||||
PARITY_PQR,
|
|
||||||
rto_opts.rto_expand_offset, 0, B_FALSE);
|
|
||||||
} else {
|
|
||||||
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
|
||||||
BENCH_ASHIFT, ncols, PARITY_PQR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* estimate iteration count */
|
/* estimate iteration count */
|
||||||
iter_cnt = (REC_BENCH_MEMORY);
|
iter_cnt = (REC_BENCH_MEMORY);
|
||||||
@@ -213,7 +197,7 @@ run_rec_bench_impl(const char *impl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
run_rec_bench(void)
|
run_rec_bench(void)
|
||||||
{
|
{
|
||||||
char **impl_name;
|
char **impl_name;
|
||||||
|
|||||||
+74
-146
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -7,7 +6,7 @@
|
|||||||
* You may not use this file except in compliance with the License.
|
* 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
|
* 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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -38,11 +37,11 @@
|
|||||||
static int *rand_data;
|
static int *rand_data;
|
||||||
raidz_test_opts_t rto_opts;
|
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)
|
static void sig_handler(int signo)
|
||||||
{
|
{
|
||||||
int old_errno = errno;
|
|
||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
/*
|
/*
|
||||||
* Restore default action and re-raise signal so SIGSEGV and
|
* Restore default action and re-raise signal so SIGSEGV and
|
||||||
@@ -53,32 +52,22 @@ static void sig_handler(int signo)
|
|||||||
action.sa_flags = 0;
|
action.sa_flags = 0;
|
||||||
(void) sigaction(signo, &action, NULL);
|
(void) sigaction(signo, &action, NULL);
|
||||||
|
|
||||||
if (rto_opts.rto_gdb) {
|
if (rto_opts.rto_gdb)
|
||||||
pid_t pid = fork();
|
if (system(gdb)) { }
|
||||||
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)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
raise(signo);
|
raise(signo);
|
||||||
errno = old_errno;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_opts(raidz_test_opts_t *opts, boolean_t force)
|
static void print_opts(raidz_test_opts_t *opts, boolean_t force)
|
||||||
{
|
{
|
||||||
const char *verbose;
|
char *verbose;
|
||||||
switch (opts->rto_v) {
|
switch (opts->rto_v) {
|
||||||
case D_ALL:
|
case 0:
|
||||||
verbose = "no";
|
verbose = "no";
|
||||||
break;
|
break;
|
||||||
case D_INFO:
|
case 1:
|
||||||
verbose = "info";
|
verbose = "info";
|
||||||
break;
|
break;
|
||||||
case D_DEBUG:
|
|
||||||
default:
|
default:
|
||||||
verbose = "debug";
|
verbose = "debug";
|
||||||
break;
|
break;
|
||||||
@@ -88,20 +77,16 @@ static void print_opts(raidz_test_opts_t *opts, boolean_t force)
|
|||||||
(void) fprintf(stdout, DBLSEP "Running with options:\n"
|
(void) fprintf(stdout, DBLSEP "Running with options:\n"
|
||||||
" (-a) zio ashift : %zu\n"
|
" (-a) zio ashift : %zu\n"
|
||||||
" (-o) zio offset : 1 << %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"
|
" (-d) number of raidz data columns : %zu\n"
|
||||||
" (-s) size of DATA : 1 << %zu\n"
|
" (-s) size of DATA : 1 << %zu\n"
|
||||||
" (-S) sweep parameters : %s \n"
|
" (-S) sweep parameters : %s \n"
|
||||||
" (-v) verbose : %s \n\n",
|
" (-v) verbose : %s \n\n",
|
||||||
opts->rto_ashift, /* -a */
|
opts->rto_ashift, /* -a */
|
||||||
ilog2(opts->rto_offset), /* -o */
|
ilog2(opts->rto_offset), /* -o */
|
||||||
opts->rto_expand ? "yes" : "no", /* -e */
|
opts->rto_dcols, /* -d */
|
||||||
(u_longlong_t)opts->rto_expand_offset, /* -r */
|
ilog2(opts->rto_dsize), /* -s */
|
||||||
opts->rto_dcols, /* -d */
|
opts->rto_sweep ? "yes" : "no", /* -S */
|
||||||
ilog2(opts->rto_dsize), /* -s */
|
verbose); /* -v */
|
||||||
opts->rto_sweep ? "yes" : "no", /* -S */
|
|
||||||
verbose); /* -v */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,9 +104,7 @@ static void usage(boolean_t requested)
|
|||||||
"\t[-S parameter sweep (default: %s)]\n"
|
"\t[-S parameter sweep (default: %s)]\n"
|
||||||
"\t[-t timeout for parameter sweep test]\n"
|
"\t[-t timeout for parameter sweep test]\n"
|
||||||
"\t[-B benchmark all raidz implementations]\n"
|
"\t[-B benchmark all raidz implementations]\n"
|
||||||
"\t[-e use expanded raidz map (default: %s)]\n"
|
"\t[-v increase verbosity (default: %zu)]\n"
|
||||||
"\t[-r expanded raidz map reflow offset (default: %llx)]\n"
|
|
||||||
"\t[-v increase verbosity (default: %d)]\n"
|
|
||||||
"\t[-h (print help)]\n"
|
"\t[-h (print help)]\n"
|
||||||
"\t[-T test the test, see if failure would be detected]\n"
|
"\t[-T test the test, see if failure would be detected]\n"
|
||||||
"\t[-D debug (attach gdb on SIGSEGV)]\n"
|
"\t[-D debug (attach gdb on SIGSEGV)]\n"
|
||||||
@@ -131,9 +114,7 @@ static void usage(boolean_t requested)
|
|||||||
o->rto_dcols, /* -d */
|
o->rto_dcols, /* -d */
|
||||||
ilog2(o->rto_dsize), /* -s */
|
ilog2(o->rto_dsize), /* -s */
|
||||||
rto_opts.rto_sweep ? "yes" : "no", /* -S */
|
rto_opts.rto_sweep ? "yes" : "no", /* -S */
|
||||||
rto_opts.rto_expand ? "yes" : "no", /* -e */
|
o->rto_v); /* -d */
|
||||||
(u_longlong_t)o->rto_expand_offset, /* -r */
|
|
||||||
o->rto_v); /* -v */
|
|
||||||
|
|
||||||
exit(requested ? 0 : 1);
|
exit(requested ? 0 : 1);
|
||||||
}
|
}
|
||||||
@@ -142,22 +123,19 @@ static void process_options(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
size_t value;
|
size_t value;
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
raidz_test_opts_t *o = &rto_opts;
|
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) {
|
switch (opt) {
|
||||||
case 'a':
|
case 'a':
|
||||||
value = strtoull(optarg, NULL, 0);
|
value = strtoull(optarg, NULL, 0);
|
||||||
o->rto_ashift = MIN(13, MAX(9, value));
|
o->rto_ashift = MIN(13, MAX(9, value));
|
||||||
break;
|
break;
|
||||||
case 'e':
|
|
||||||
o->rto_expand = 1;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
o->rto_expand_offset = strtoull(optarg, NULL, 0);
|
|
||||||
break;
|
|
||||||
case 'o':
|
case 'o':
|
||||||
value = strtoull(optarg, NULL, 0);
|
value = strtoull(optarg, NULL, 0);
|
||||||
o->rto_offset = ((1ULL << MIN(12, value)) >> 9) << 9;
|
o->rto_offset = ((1ULL << MIN(12, value)) >> 9) << 9;
|
||||||
@@ -201,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(rm, i) ((rm)->rm_col[raidz_parity(rm) + (i)].rc_abd)
|
||||||
#define DATA_COL_SIZE(rr, i) ((rr)->rr_col[rr->rr_firstdatacol + (i)].rc_size)
|
#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(rm, i) ((rm)->rm_col[(i)].rc_abd)
|
||||||
#define CODE_COL_SIZE(rr, i) ((rr)->rr_col[(i)].rc_size)
|
#define CODE_COL_SIZE(rm, i) ((rm)->rm_col[(i)].rc_size)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cmp_code(raidz_test_opts_t *opts, const raidz_map_t *rm, const int parity)
|
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);
|
VERIFY(parity >= 1 && parity <= 3);
|
||||||
|
|
||||||
for (r = 0; r < rm->rm_nrows; r++) {
|
for (i = 0; i < parity; i++) {
|
||||||
raidz_row_t * const rr = rm->rm_row[r];
|
if (abd_cmp(CODE_COL(rm, i), CODE_COL(opts->rm_golden, i))
|
||||||
raidz_row_t * const rrg = opts->rm_golden->rm_row[r];
|
!= 0) {
|
||||||
for (i = 0; i < parity; i++) {
|
ret++;
|
||||||
if (CODE_COL_SIZE(rrg, i) == 0) {
|
LOG_OPT(D_DEBUG, opts,
|
||||||
VERIFY0(CODE_COL_SIZE(rr, i));
|
"\nParity block [%d] different!\n", 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (ret);
|
return (ret);
|
||||||
@@ -237,26 +206,16 @@ cmp_code(raidz_test_opts_t *opts, const raidz_map_t *rm, const int parity)
|
|||||||
static int
|
static int
|
||||||
cmp_data(raidz_test_opts_t *opts, raidz_map_t *rm)
|
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++) {
|
for (i = 0; i < dcols; i++) {
|
||||||
raidz_row_t *rr = rm->rm_row[r];
|
if (abd_cmp(DATA_COL(opts->rm_golden, i), DATA_COL(rm, i))
|
||||||
raidz_row_t *rrg = opts->rm_golden->rm_row[r];
|
!= 0) {
|
||||||
dcols = opts->rm_golden->rm_row[0]->rr_cols -
|
ret++;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abd_cmp(DATA_COL(rrg, i),
|
LOG_OPT(D_DEBUG, opts,
|
||||||
DATA_COL(rr, i)) != 0) {
|
"\nData block [%d] different!\n", i);
|
||||||
ret++;
|
|
||||||
|
|
||||||
LOG_OPT(D_DEBUG, opts,
|
|
||||||
"\nData block [%d] different!\n", i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (ret);
|
return (ret);
|
||||||
@@ -265,41 +224,31 @@ cmp_data(raidz_test_opts_t *opts, raidz_map_t *rm)
|
|||||||
static int
|
static int
|
||||||
init_rand(void *data, size_t size, void *private)
|
init_rand(void *data, size_t size, void *private)
|
||||||
{
|
{
|
||||||
size_t *offsetp = (size_t *)private;
|
int i;
|
||||||
size_t offset = *offsetp;
|
int *dst = (int *)data;
|
||||||
|
|
||||||
VERIFY3U(offset + size, <=, SPA_MAXBLOCKSIZE);
|
for (i = 0; i < size / sizeof (int); i++)
|
||||||
memcpy(data, (char *)rand_data + offset, size);
|
dst[i] = rand_data[i];
|
||||||
*offsetp = offset + size;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
corrupt_rand_fill(void *data, size_t size, void *private)
|
|
||||||
{
|
|
||||||
(void) private;
|
|
||||||
memset(data, 0xAA, size);
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)
|
corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)
|
||||||
{
|
{
|
||||||
for (int r = 0; r < rm->rm_nrows; r++) {
|
int i;
|
||||||
raidz_row_t *rr = rm->rm_row[r];
|
raidz_col_t *col;
|
||||||
for (int i = 0; i < cnt; i++) {
|
|
||||||
raidz_col_t *col = &rr->rr_col[tgts[i]];
|
for (i = 0; i < cnt; i++) {
|
||||||
abd_iterate_func(col->rc_abd, 0, col->rc_size,
|
col = &rm->rm_col[tgts[i]];
|
||||||
corrupt_rand_fill, NULL);
|
abd_iterate_func(col->rc_abd, 0, col->rc_size, init_rand, NULL);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
init_zio_abd(zio_t *zio)
|
init_zio_abd(zio_t *zio)
|
||||||
{
|
{
|
||||||
size_t offset = 0;
|
abd_iterate_func(zio->io_abd, 0, zio->io_size, init_rand, NULL);
|
||||||
abd_iterate_func(zio->io_abd, 0, zio->io_size, init_rand, &offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -339,20 +288,10 @@ init_raidz_golden_map(raidz_test_opts_t *opts, const int parity)
|
|||||||
|
|
||||||
VERIFY0(vdev_raidz_impl_set("original"));
|
VERIFY0(vdev_raidz_impl_set("original"));
|
||||||
|
|
||||||
if (opts->rto_expand) {
|
opts->rm_golden = vdev_raidz_map_alloc(opts->zio_golden,
|
||||||
opts->rm_golden =
|
opts->rto_ashift, total_ncols, parity);
|
||||||
vdev_raidz_map_alloc_expanded(opts->zio_golden,
|
rm_test = vdev_raidz_map_alloc(zio_test,
|
||||||
opts->rto_ashift, total_ncols+1, total_ncols,
|
opts->rto_ashift, total_ncols, parity);
|
||||||
parity, opts->rto_expand_offset, 0, B_FALSE);
|
|
||||||
rm_test = vdev_raidz_map_alloc_expanded(zio_test,
|
|
||||||
opts->rto_ashift, total_ncols+1, total_ncols,
|
|
||||||
parity, opts->rto_expand_offset, 0, B_FALSE);
|
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
VERIFY(opts->zio_golden);
|
VERIFY(opts->zio_golden);
|
||||||
VERIFY(opts->rm_golden);
|
VERIFY(opts->rm_golden);
|
||||||
@@ -386,19 +325,13 @@ init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)
|
|||||||
|
|
||||||
*zio = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
|
*zio = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
|
||||||
|
|
||||||
(*zio)->io_offset = opts->rto_offset;
|
(*zio)->io_offset = 0;
|
||||||
(*zio)->io_size = alloc_dsize;
|
(*zio)->io_size = alloc_dsize;
|
||||||
(*zio)->io_abd = raidz_alloc(alloc_dsize);
|
(*zio)->io_abd = raidz_alloc(alloc_dsize);
|
||||||
init_zio_abd(*zio);
|
init_zio_abd(*zio);
|
||||||
|
|
||||||
if (opts->rto_expand) {
|
rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,
|
||||||
rm = vdev_raidz_map_alloc_expanded(*zio,
|
total_ncols, parity);
|
||||||
opts->rto_ashift, total_ncols+1, total_ncols,
|
|
||||||
parity, opts->rto_expand_offset, 0, B_FALSE);
|
|
||||||
} else {
|
|
||||||
rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,
|
|
||||||
total_ncols, parity);
|
|
||||||
}
|
|
||||||
VERIFY(rm);
|
VERIFY(rm);
|
||||||
|
|
||||||
/* Make sure code columns are destroyed */
|
/* Make sure code columns are destroyed */
|
||||||
@@ -487,7 +420,7 @@ run_rec_check_impl(raidz_test_opts_t *opts, raidz_map_t *rm, const int fn)
|
|||||||
if (fn < RAIDZ_REC_PQ) {
|
if (fn < RAIDZ_REC_PQ) {
|
||||||
/* can reconstruct 1 failed data disk */
|
/* can reconstruct 1 failed data disk */
|
||||||
for (x0 = 0; x0 < opts->rto_dcols; x0++) {
|
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;
|
continue;
|
||||||
|
|
||||||
/* Check if should stop */
|
/* Check if should stop */
|
||||||
@@ -512,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) {
|
} else if (fn < RAIDZ_REC_PQR) {
|
||||||
/* can reconstruct 2 failed data disk */
|
/* can reconstruct 2 failed data disk */
|
||||||
for (x0 = 0; x0 < opts->rto_dcols; x0++) {
|
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;
|
continue;
|
||||||
for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {
|
for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {
|
||||||
if (x1 >= rm->rm_row[0]->rr_cols -
|
if (x1 >= rm->rm_cols - raidz_parity(rm))
|
||||||
raidz_parity(rm))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Check if should stop */
|
/* Check if should stop */
|
||||||
@@ -543,15 +475,14 @@ run_rec_check_impl(raidz_test_opts_t *opts, raidz_map_t *rm, const int fn)
|
|||||||
} else {
|
} else {
|
||||||
/* can reconstruct 3 failed data disk */
|
/* can reconstruct 3 failed data disk */
|
||||||
for (x0 = 0; x0 < opts->rto_dcols; x0++) {
|
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;
|
continue;
|
||||||
for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {
|
for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {
|
||||||
if (x1 >= rm->rm_row[0]->rr_cols -
|
if (x1 >= rm->rm_cols - raidz_parity(rm))
|
||||||
raidz_parity(rm))
|
|
||||||
continue;
|
continue;
|
||||||
for (x2 = x1 + 1; x2 < opts->rto_dcols; x2++) {
|
for (x2 = x1 + 1; x2 < opts->rto_dcols; x2++) {
|
||||||
if (x2 >= rm->rm_row[0]->rr_cols -
|
if (x2 >=
|
||||||
raidz_parity(rm))
|
rm->rm_cols - raidz_parity(rm))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Check if should stop */
|
/* Check if should stop */
|
||||||
@@ -667,7 +598,7 @@ static kcondvar_t sem_cv;
|
|||||||
static int max_free_slots;
|
static int max_free_slots;
|
||||||
static int free_slots;
|
static int free_slots;
|
||||||
|
|
||||||
static __attribute__((noreturn)) void
|
static void
|
||||||
sweep_thread(void *arg)
|
sweep_thread(void *arg)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
@@ -767,14 +698,14 @@ run_sweep(void)
|
|||||||
opts = umem_zalloc(sizeof (raidz_test_opts_t), UMEM_NOFAIL);
|
opts = umem_zalloc(sizeof (raidz_test_opts_t), UMEM_NOFAIL);
|
||||||
opts->rto_ashift = ashift_v[a];
|
opts->rto_ashift = ashift_v[a];
|
||||||
opts->rto_dcols = dcols_v[d];
|
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_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 */
|
opts->rto_v = 0; /* be quiet */
|
||||||
|
|
||||||
VERIFY3P(thread_create(NULL, 0, sweep_thread, (void *) opts,
|
VERIFY3P(zk_thread_create(NULL, 0,
|
||||||
0, NULL, TS_RUN, defclsyspri), !=, NULL);
|
(thread_func_t)sweep_thread,
|
||||||
|
(void *) opts, 0, NULL, TS_RUN, 0,
|
||||||
|
PTHREAD_CREATE_JOINABLE), !=, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
@@ -803,7 +734,6 @@ exit:
|
|||||||
return (sweep_state == SWEEP_ERROR ? SWEEP_ERROR : 0);
|
return (sweep_state == SWEEP_ERROR ? SWEEP_ERROR : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -811,8 +741,8 @@ main(int argc, char **argv)
|
|||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/* init gdb pid string early */
|
/* init gdb string early */
|
||||||
(void) sprintf(pid_s, "%d", getpid());
|
(void) sprintf(gdb, gdb_tmpl, getpid());
|
||||||
|
|
||||||
action.sa_handler = sig_handler;
|
action.sa_handler = sig_handler;
|
||||||
sigemptyset(&action.sa_mask);
|
sigemptyset(&action.sa_mask);
|
||||||
@@ -829,7 +759,7 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
process_options(argc, argv);
|
process_options(argc, argv);
|
||||||
|
|
||||||
kernel_init(SPA_MODE_READ);
|
kernel_init(FREAD);
|
||||||
|
|
||||||
/* setup random data because rand() is not reentrant */
|
/* setup random data because rand() is not reentrant */
|
||||||
rand_data = (int *)umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
|
rand_data = (int *)umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
|
||||||
@@ -847,8 +777,6 @@ main(int argc, char **argv)
|
|||||||
err = run_test(NULL);
|
err = run_test(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
mprotect(rand_data, SPA_MAXBLOCKSIZE, PROT_READ | PROT_WRITE);
|
|
||||||
|
|
||||||
umem_free(rand_data, SPA_MAXBLOCKSIZE);
|
umem_free(rand_data, SPA_MAXBLOCKSIZE);
|
||||||
kernel_fini();
|
kernel_fini();
|
||||||
|
|
||||||
|
|||||||
+15
-23
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -7,7 +6,7 @@
|
|||||||
* You may not use this file except in compliance with the License.
|
* 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
|
* 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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -29,7 +28,7 @@
|
|||||||
|
|
||||||
#include <sys/spa.h>
|
#include <sys/spa.h>
|
||||||
|
|
||||||
static const char *const raidz_impl_names[] = {
|
static const char *raidz_impl_names[] = {
|
||||||
"original",
|
"original",
|
||||||
"scalar",
|
"scalar",
|
||||||
"sse2",
|
"sse2",
|
||||||
@@ -39,27 +38,18 @@ static const char *const raidz_impl_names[] = {
|
|||||||
"avx512bw",
|
"avx512bw",
|
||||||
"aarch64_neon",
|
"aarch64_neon",
|
||||||
"aarch64_neonx2",
|
"aarch64_neonx2",
|
||||||
"powerpc_altivec",
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
enum raidz_verbosity {
|
|
||||||
D_ALL,
|
|
||||||
D_INFO,
|
|
||||||
D_DEBUG,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct raidz_test_opts {
|
typedef struct raidz_test_opts {
|
||||||
size_t rto_ashift;
|
size_t rto_ashift;
|
||||||
uint64_t rto_offset;
|
size_t rto_offset;
|
||||||
size_t rto_dcols;
|
size_t rto_dcols;
|
||||||
size_t rto_dsize;
|
size_t rto_dsize;
|
||||||
enum raidz_verbosity rto_v;
|
size_t rto_v;
|
||||||
size_t rto_sweep;
|
size_t rto_sweep;
|
||||||
size_t rto_sweep_timeout;
|
size_t rto_sweep_timeout;
|
||||||
size_t rto_benchmark;
|
size_t rto_benchmark;
|
||||||
size_t rto_expand;
|
|
||||||
uint64_t rto_expand_offset;
|
|
||||||
size_t rto_sanity;
|
size_t rto_sanity;
|
||||||
size_t rto_gdb;
|
size_t rto_gdb;
|
||||||
|
|
||||||
@@ -72,14 +62,12 @@ typedef struct raidz_test_opts {
|
|||||||
|
|
||||||
static const raidz_test_opts_t rto_opts_defaults = {
|
static const raidz_test_opts_t rto_opts_defaults = {
|
||||||
.rto_ashift = 9,
|
.rto_ashift = 9,
|
||||||
.rto_offset = 0,
|
.rto_offset = 1ULL << 0,
|
||||||
.rto_dcols = 8,
|
.rto_dcols = 8,
|
||||||
.rto_dsize = 1<<19,
|
.rto_dsize = 1<<19,
|
||||||
.rto_v = D_ALL,
|
.rto_v = 0,
|
||||||
.rto_sweep = 0,
|
.rto_sweep = 0,
|
||||||
.rto_benchmark = 0,
|
.rto_benchmark = 0,
|
||||||
.rto_expand = 0,
|
|
||||||
.rto_expand_offset = -1ULL,
|
|
||||||
.rto_sanity = 0,
|
.rto_sanity = 0,
|
||||||
.rto_gdb = 0,
|
.rto_gdb = 0,
|
||||||
.rto_should_stop = B_FALSE
|
.rto_should_stop = B_FALSE
|
||||||
@@ -93,19 +81,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) \
|
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) \
|
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"
|
#define DBLSEP "================\n"
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
dist_udev_SCRIPTS = vdev_id
|
||||||
Executable
+606
@@ -0,0 +1,606 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# vdev_id: udev helper to generate user-friendly names for JBOD disks
|
||||||
|
#
|
||||||
|
# This script parses the file /etc/zfs/vdev_id.conf to map a
|
||||||
|
# physical path in a storage topology to a channel name. The
|
||||||
|
# channel name is combined with a disk enclosure slot number to
|
||||||
|
# create an alias that reflects the physical location of the drive.
|
||||||
|
# This is particularly helpful when it comes to tasks like replacing
|
||||||
|
# failed drives. Slot numbers may also be re-mapped in case the
|
||||||
|
# default numbering is unsatisfactory. The drive aliases will be
|
||||||
|
# created as symbolic links in /dev/disk/by-vdev.
|
||||||
|
#
|
||||||
|
# The currently supported topologies are sas_direct and sas_switch.
|
||||||
|
# A multipath mode is supported in which dm-mpath devices are
|
||||||
|
# handled by examining the first-listed running component disk. In
|
||||||
|
# multipath mode the configuration file should contain a channel
|
||||||
|
# definition with the same name for each path to a given enclosure.
|
||||||
|
#
|
||||||
|
# The alias keyword provides a simple way to map already-existing
|
||||||
|
# device symlinks to more convenient names. It is suitable for
|
||||||
|
# small, static configurations or for sites that have some automated
|
||||||
|
# way to generate the mapping file.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Some example configuration files are given below.
|
||||||
|
|
||||||
|
# #
|
||||||
|
# # Example vdev_id.conf - sas_direct.
|
||||||
|
# #
|
||||||
|
#
|
||||||
|
# multipath no
|
||||||
|
# topology sas_direct
|
||||||
|
# phys_per_port 4
|
||||||
|
# slot bay
|
||||||
|
#
|
||||||
|
# # PCI_ID HBA PORT CHANNEL NAME
|
||||||
|
# channel 85:00.0 1 A
|
||||||
|
# channel 85:00.0 0 B
|
||||||
|
# channel 86:00.0 1 C
|
||||||
|
# channel 86:00.0 0 D
|
||||||
|
#
|
||||||
|
# # Custom mapping for Channel A
|
||||||
|
#
|
||||||
|
# # Linux Mapped
|
||||||
|
# # Slot Slot Channel
|
||||||
|
# slot 1 7 A
|
||||||
|
# slot 2 10 A
|
||||||
|
# slot 3 3 A
|
||||||
|
# slot 4 6 A
|
||||||
|
#
|
||||||
|
# # Default mapping for B, C, and D
|
||||||
|
# slot 1 4
|
||||||
|
# slot 2 2
|
||||||
|
# slot 3 1
|
||||||
|
# slot 4 3
|
||||||
|
|
||||||
|
# #
|
||||||
|
# # Example vdev_id.conf - sas_switch
|
||||||
|
# #
|
||||||
|
#
|
||||||
|
# topology sas_switch
|
||||||
|
#
|
||||||
|
# # SWITCH PORT CHANNEL NAME
|
||||||
|
# channel 1 A
|
||||||
|
# channel 2 B
|
||||||
|
# channel 3 C
|
||||||
|
# channel 4 D
|
||||||
|
|
||||||
|
# #
|
||||||
|
# # Example vdev_id.conf - multipath
|
||||||
|
# #
|
||||||
|
#
|
||||||
|
# multipath 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 - alias
|
||||||
|
# #
|
||||||
|
#
|
||||||
|
# # by-vdev
|
||||||
|
# # name fully qualified or base name of device link
|
||||||
|
# alias d1 /dev/disk/by-id/wwn-0x5000c5002de3b9ca
|
||||||
|
# alias d2 wwn-0x5000c5002def789e
|
||||||
|
|
||||||
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin
|
||||||
|
CONFIG=/etc/zfs/vdev_id.conf
|
||||||
|
PHYS_PER_PORT=
|
||||||
|
DEV=
|
||||||
|
MULTIPATH=
|
||||||
|
TOPOLOGY=
|
||||||
|
BAY=
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat << EOF
|
||||||
|
Usage: vdev_id [-h]
|
||||||
|
vdev_id <-d device> [-c config_file] [-p phys_per_port]
|
||||||
|
[-g sas_direct|sas_switch|scsi] [-m]
|
||||||
|
|
||||||
|
-c specify name of alernate config file [default=$CONFIG]
|
||||||
|
-d specify basename of device (i.e. sda)
|
||||||
|
-e Create enclose device symlinks only (/dev/by-enclosure)
|
||||||
|
-g Storage network topology [default="$TOPOLOGY"]
|
||||||
|
-m Run in multipath mode
|
||||||
|
-p number of phy's per switch port [default=$PHYS_PER_PORT]
|
||||||
|
-h show this summary
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
map_slot() {
|
||||||
|
local LINUX_SLOT=$1
|
||||||
|
local CHANNEL=$2
|
||||||
|
local MAPPED_SLOT=
|
||||||
|
|
||||||
|
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}
|
||||||
|
}
|
||||||
|
|
||||||
|
map_channel() {
|
||||||
|
local MAPPED_CHAN=
|
||||||
|
local PCI_ID=$1
|
||||||
|
local PORT=$2
|
||||||
|
|
||||||
|
case $TOPOLOGY in
|
||||||
|
"sas_switch")
|
||||||
|
MAPPED_CHAN=`awk "\\$1 == \"channel\" && \\$2 == ${PORT} \
|
||||||
|
{ print \\$3; exit }" $CONFIG`
|
||||||
|
;;
|
||||||
|
"sas_direct"|"scsi")
|
||||||
|
MAPPED_CHAN=`awk "\\$1 == \"channel\" && \
|
||||||
|
\\$2 == \"${PCI_ID}\" && \\$3 == ${PORT} \
|
||||||
|
{ print \\$4; exit }" $CONFIG`
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
printf "%s" ${MAPPED_CHAN}
|
||||||
|
}
|
||||||
|
|
||||||
|
sas_handler() {
|
||||||
|
if [ -z "$PHYS_PER_PORT" ] ; then
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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 |
|
||||||
|
awk "/\/$DEV$/{print \\$9}"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For raw disks udev exports DEVTYPE=partition when
|
||||||
|
# handling partitions, and the rules can be written to
|
||||||
|
# take advantage of this to append a -part suffix. For
|
||||||
|
# dm devices we get DEVTYPE=disk even for partitions so
|
||||||
|
# we have to append the -part suffix directly in the
|
||||||
|
# helper.
|
||||||
|
if [ "$DEVTYPE" != "partition" ] ; then
|
||||||
|
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]*$//'`
|
||||||
|
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}'`
|
||||||
|
if [ -z "$DEV" ] ; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo $DEV | grep -q ^/devices/ ; then
|
||||||
|
sys_path=$DEV
|
||||||
|
else
|
||||||
|
sys_path=`udevadm info -q path -p /sys/block/$DEV 2>/dev/null`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use positional parameters as an ad-hoc array
|
||||||
|
set -- $(echo "$sys_path" | tr / ' ')
|
||||||
|
num_dirs=$#
|
||||||
|
scsi_host_dir="/sys"
|
||||||
|
|
||||||
|
# Get path up to /sys/.../hostX
|
||||||
|
i=1
|
||||||
|
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))
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $i = $num_dirs ] ; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
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)) ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
i=$(($i + 1))
|
||||||
|
while [ $i -le $j ] ; do
|
||||||
|
port_dir="$port_dir/$(eval echo \${$i})"
|
||||||
|
i=$(($i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
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 ))
|
||||||
|
|
||||||
|
# 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})
|
||||||
|
end_device_dir="$end_device_dir/$d"
|
||||||
|
if echo $d | grep -q '^end_device' ; then
|
||||||
|
end_device_dir="$end_device_dir/sas_device/$d"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
i=$(($i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
SLOT=
|
||||||
|
case $BAY in
|
||||||
|
"bay")
|
||||||
|
SLOT=`cat $end_device_dir/bay_identifier 2>/dev/null`
|
||||||
|
;;
|
||||||
|
"phy")
|
||||||
|
SLOT=`cat $end_device_dir/phy_identifier 2>/dev/null`
|
||||||
|
;;
|
||||||
|
"port")
|
||||||
|
d=$(eval echo \${$i})
|
||||||
|
SLOT=`echo $d | sed -e 's/^.*://'`
|
||||||
|
;;
|
||||||
|
"id")
|
||||||
|
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/^.*://'`
|
||||||
|
;;
|
||||||
|
"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'`
|
||||||
|
for enclosure in $enclosures; do
|
||||||
|
set -- $(sg_ses -p aes $enclosure | \
|
||||||
|
awk "/device slot number:/{slot=\$12} \
|
||||||
|
/SAS address: $sas_address/\
|
||||||
|
{print slot}")
|
||||||
|
SLOT=$1
|
||||||
|
if [ -n "$SLOT" ] ; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [ -z "$SLOT" ] ; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
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`
|
||||||
|
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`
|
||||||
|
fi
|
||||||
|
PHYS_PER_PORT=${PHYS_PER_PORT:-4}
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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 |
|
||||||
|
awk "/\/$DEV$/{print \\$9}"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For raw disks udev exports DEVTYPE=partition when
|
||||||
|
# handling partitions, and the rules can be written to
|
||||||
|
# take advantage of this to append a -part suffix. For
|
||||||
|
# dm devices we get DEVTYPE=disk even for partitions so
|
||||||
|
# we have to append the -part suffix directly in the
|
||||||
|
# helper.
|
||||||
|
if [ "$DEVTYPE" != "partition" ] ; then
|
||||||
|
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]*$//'`
|
||||||
|
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}'`
|
||||||
|
if [ -z "$DEV" ] ; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo $DEV | grep -q ^/devices/ ; then
|
||||||
|
sys_path=$DEV
|
||||||
|
else
|
||||||
|
sys_path=`udevadm info -q path -p /sys/block/$DEV 2>/dev/null`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# expect sys_path like this, for example:
|
||||||
|
# /devices/pci0000:00/0000:00:0b.0/0000:09:00.0/0000:0a:05.0/0000:0c:00.0/host3/target3:1:0/3:1:0:21/block/sdv
|
||||||
|
|
||||||
|
# Use positional parameters as an ad-hoc array
|
||||||
|
set -- $(echo "$sys_path" | tr / ' ')
|
||||||
|
num_dirs=$#
|
||||||
|
scsi_host_dir="/sys"
|
||||||
|
|
||||||
|
# Get path up to /sys/.../hostX
|
||||||
|
i=1
|
||||||
|
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))
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $i = $num_dirs ] ; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
i=$(($i + 1))
|
||||||
|
while [ $i -le $j ] ; do
|
||||||
|
port_dir="$port_dir/$(eval echo \${$i})"
|
||||||
|
i=$(($i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
set -- $(echo $port_dir | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/')
|
||||||
|
PORT=$1
|
||||||
|
SLOT=$(($2 + $FIRST_BAY_NUMBER))
|
||||||
|
|
||||||
|
if [ -z "$SLOT" ] ; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
CHAN=`map_channel $PCI_ID $PORT`
|
||||||
|
SLOT=`map_slot $SLOT $CHAN`
|
||||||
|
if [ -z "$CHAN" ] ; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo ${CHAN}${SLOT}${PART}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Figure out the name for the enclosure symlink
|
||||||
|
enclosure_handler () {
|
||||||
|
# We get all the info we need from udev's DEVPATH variable:
|
||||||
|
#
|
||||||
|
# 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=$(basename $(readlink -m "/sys/$DEVPATH/../.."))
|
||||||
|
if [ ! -d /sys/class/enclosure/$ENC ] ; then
|
||||||
|
# Not an enclosure, bail out
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# 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]+')
|
||||||
|
|
||||||
|
# Get the port number
|
||||||
|
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=$(basename $(readlink -m "/sys/$PORT_DIR/../.."))
|
||||||
|
|
||||||
|
# Strip down the PCI address from 0000:05:00.0 to 05:00.0
|
||||||
|
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 \$4int(count[\$4])}; count[\$4]++}" $CONFIG)
|
||||||
|
|
||||||
|
echo "${NAME}"
|
||||||
|
}
|
||||||
|
|
||||||
|
alias_handler () {
|
||||||
|
# Special handling is needed to correctly append a -part suffix
|
||||||
|
# to partitions of device mapper devices. The DEVTYPE attribute
|
||||||
|
# is normally set to "disk" instead of "partition" in this case,
|
||||||
|
# so the udev rules won't handle that for us as they do for
|
||||||
|
# "plain" block devices.
|
||||||
|
#
|
||||||
|
# For example, we may have the following links for a device and its
|
||||||
|
# partitions,
|
||||||
|
#
|
||||||
|
# /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0 -> ../../dm-0
|
||||||
|
# /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p1 -> ../../dm-1
|
||||||
|
# /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p2 -> ../../dm-3
|
||||||
|
#
|
||||||
|
# and the following alias in vdev_id.conf.
|
||||||
|
#
|
||||||
|
# alias A0 dm-name-isw_dibgbfcije_ARRAY0
|
||||||
|
#
|
||||||
|
# The desired outcome is for the following links to be created
|
||||||
|
# without having explicitly defined aliases for the partitions.
|
||||||
|
#
|
||||||
|
# /dev/disk/by-vdev/A0 -> ../../dm-0
|
||||||
|
# /dev/disk/by-vdev/A0-part1 -> ../../dm-1
|
||||||
|
# /dev/disk/by-vdev/A0-part2 -> ../../dm-3
|
||||||
|
#
|
||||||
|
# Warning: The following grep pattern will misidentify whole-disk
|
||||||
|
# devices whose names end with 'p' followed by a string of
|
||||||
|
# digits as partitions, causing alias creation to fail. This
|
||||||
|
# ambiguity seems unavoidable, so devices using this facility
|
||||||
|
# must not use such names.
|
||||||
|
local DM_PART=
|
||||||
|
if echo $DM_NAME | grep -q -E 'p[0-9][0-9]*$' ; then
|
||||||
|
if [ "$DEVTYPE" != "partition" ] ; then
|
||||||
|
DM_PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# DEVLINKS attribute must have been populated by already-run udev rules.
|
||||||
|
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]*$//'`
|
||||||
|
fi
|
||||||
|
# Check both the fully qualified and the base name of link.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
while getopts 'c:d:eg:mp:h' OPTION; do
|
||||||
|
case ${OPTION} in
|
||||||
|
c)
|
||||||
|
CONFIG=${OPTARG}
|
||||||
|
;;
|
||||||
|
d)
|
||||||
|
DEV=${OPTARG}
|
||||||
|
;;
|
||||||
|
e)
|
||||||
|
# When udev sees a scsi_generic device, it calls this script with -e to
|
||||||
|
# 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)
|
||||||
|
if [ "$ENCLOSURE_MODE" != "yes" ] ; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
g)
|
||||||
|
TOPOLOGY=$OPTARG
|
||||||
|
;;
|
||||||
|
p)
|
||||||
|
PHYS_PER_PORT=${OPTARG}
|
||||||
|
;;
|
||||||
|
m)
|
||||||
|
MULTIPATH_MODE=yes
|
||||||
|
;;
|
||||||
|
h)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! -r $CONFIG ] ; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$DEV" -a -z "$ENCLOSURE_MODE" ] ; then
|
||||||
|
echo "Error: missing required option -d"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$TOPOLOGY" ] ; then
|
||||||
|
TOPOLOGY=`awk "\\$1 == \"topology\" {print \\$2; exit}" $CONFIG`
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$BAY" ] ; then
|
||||||
|
BAY=`awk "\\$1 == \"slot\" {print \\$2; exit}" $CONFIG`
|
||||||
|
fi
|
||||||
|
|
||||||
|
TOPOLOGY=${TOPOLOGY:-sas_direct}
|
||||||
|
|
||||||
|
# Should we create /dev/by-enclosure symlinks?
|
||||||
|
if [ "$ENCLOSURE_MODE" = "yes" -a "$TOPOLOGY" = "sas_direct" ] ; then
|
||||||
|
ID_ENCLOSURE=$(enclosure_handler)
|
||||||
|
if [ -z "$ID_ENCLOSURE" ] ; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Just create the symlinks to the enclosure devices and then exit.
|
||||||
|
ENCLOSURE_PREFIX=$(awk '/enclosure_symlinks_prefix/{print $2}' $CONFIG)
|
||||||
|
if [ -z "$ENCLOSURE_PREFIX" ] ; then
|
||||||
|
ENCLOSURE_PREFIX="enc"
|
||||||
|
fi
|
||||||
|
echo "ID_ENCLOSURE=$ID_ENCLOSURE"
|
||||||
|
echo "ID_ENCLOSURE_PATH=by-enclosure/$ENCLOSURE_PREFIX-$ID_ENCLOSURE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# First check if an alias was defined for this device.
|
||||||
|
ID_VDEV=`alias_handler`
|
||||||
|
|
||||||
|
if [ -z "$ID_VDEV" ] ; then
|
||||||
|
BAY=${BAY:-bay}
|
||||||
|
case $TOPOLOGY in
|
||||||
|
sas_direct|sas_switch)
|
||||||
|
ID_VDEV=`sas_handler`
|
||||||
|
;;
|
||||||
|
scsi)
|
||||||
|
ID_VDEV=`scsi_handler`
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Error: unknown topology $TOPOLOGY"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$ID_VDEV" ] ; then
|
||||||
|
echo "ID_VDEV=${ID_VDEV}"
|
||||||
|
echo "ID_VDEV_PATH=disk/by-vdev/${ID_VDEV}"
|
||||||
|
fi
|
||||||
-805
@@ -1,805 +0,0 @@
|
|||||||
#!/usr/bin/env @PYTHON_SHEBANG@
|
|
||||||
# SPDX-License-Identifier: CDDL-1.0
|
|
||||||
#
|
|
||||||
# Print out ZFS ARC Statistics exported via kstat(1)
|
|
||||||
# For a definition of fields, or usage, use zarcstat -v
|
|
||||||
#
|
|
||||||
# This script was originally a fork of the original arcstat.pl (0.1)
|
|
||||||
# by Neelakanth Nadgir, originally published on his Sun blog on
|
|
||||||
# 09/18/2007
|
|
||||||
# http://blogs.sun.com/realneel/entry/zfs_arc_statistics
|
|
||||||
#
|
|
||||||
# A new version aimed to improve upon the original by adding features
|
|
||||||
# and fixing bugs as needed. This version was maintained by Mike
|
|
||||||
# Harsch and was hosted in a public open source repository:
|
|
||||||
# http://github.com/mharsch/arcstat
|
|
||||||
#
|
|
||||||
# but has since moved to the illumos-gate repository.
|
|
||||||
#
|
|
||||||
# This Python port was written by John Hixson for FreeNAS, introduced
|
|
||||||
# in commit e2c29f:
|
|
||||||
# https://github.com/freenas/freenas
|
|
||||||
#
|
|
||||||
# and has been improved by many people since.
|
|
||||||
#
|
|
||||||
# CDDL HEADER START
|
|
||||||
#
|
|
||||||
# The contents of this file are subject to the terms of the
|
|
||||||
# Common Development and Distribution License, Version 1.0 only
|
|
||||||
# (the "License"). 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.
|
|
||||||
# See the License for the specific language governing permissions
|
|
||||||
# and limitations under the License.
|
|
||||||
#
|
|
||||||
# When distributing Covered Code, include this CDDL HEADER in each
|
|
||||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
||||||
# If applicable, add the following below this CDDL HEADER, with the
|
|
||||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
|
||||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
|
||||||
#
|
|
||||||
# CDDL HEADER END
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Fields have a fixed width. Every interval, we fill the "v"
|
|
||||||
# hash with its corresponding value (v[field]=value) using calculate().
|
|
||||||
# @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+.
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import getopt
|
|
||||||
import re
|
|
||||||
import copy
|
|
||||||
import os
|
|
||||||
|
|
||||||
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"],
|
|
||||||
"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"],
|
|
||||||
"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"],
|
|
||||||
"l2wbytes": [8, 1024, "Bytes written per second to the L2ARC"],
|
|
||||||
"grow": [4, 1000, "ARC grow disabled"],
|
|
||||||
"need": [5, 1024, "ARC reclaim need"],
|
|
||||||
"free": [5, 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"],
|
|
||||||
}
|
|
||||||
|
|
||||||
# ARC structural breakdown from zarcsummary
|
|
||||||
structfields = {
|
|
||||||
"cmp": ["compressed", "Compressed"],
|
|
||||||
"ovh": ["overhead", "Overhead"],
|
|
||||||
"bon": ["bonus", "Bonus"],
|
|
||||||
"dno": ["dnode", "Dnode"],
|
|
||||||
"dbu": ["dbuf", "Dbuf"],
|
|
||||||
"hdr": ["hdr", "Header"],
|
|
||||||
"l2h": ["l2_hdr", "L2 header"],
|
|
||||||
"abd": ["abd_chunk_waste", "ABD chunk waste"],
|
|
||||||
}
|
|
||||||
structstats = { # size stats
|
|
||||||
"percent": "size", # percentage of this value
|
|
||||||
"sz": ["_size", "size"],
|
|
||||||
}
|
|
||||||
|
|
||||||
# ARC types breakdown from zarcsummary
|
|
||||||
typefields = {
|
|
||||||
"data": ["data", "ARC data"],
|
|
||||||
"meta": ["metadata", "ARC metadata"],
|
|
||||||
}
|
|
||||||
typestats = { # size stats
|
|
||||||
"percent": "cachessz", # percentage of this value
|
|
||||||
"tg": ["_target", "target"],
|
|
||||||
"sz": ["_size", "size"],
|
|
||||||
}
|
|
||||||
|
|
||||||
# ARC states breakdown from zarcsummary
|
|
||||||
statefields = {
|
|
||||||
"ano": ["anon", "Anonymous"],
|
|
||||||
"mfu": ["mfu", "MFU"],
|
|
||||||
"mru": ["mru", "MRU"],
|
|
||||||
"unc": ["uncached", "Uncached"],
|
|
||||||
}
|
|
||||||
targetstats = {
|
|
||||||
"percent": "cachessz", # percentage of this value
|
|
||||||
"fields": ["mfu", "mru"], # only applicable to these fields
|
|
||||||
"tg": ["_target", "target"],
|
|
||||||
"dt": ["_data_target", "data target"],
|
|
||||||
"mt": ["_metadata_target", "metadata target"],
|
|
||||||
}
|
|
||||||
statestats = { # size stats
|
|
||||||
"percent": "cachessz", # percentage of this value
|
|
||||||
"sz": ["_size", "size"],
|
|
||||||
"da": ["_data", "data size"],
|
|
||||||
"me": ["_metadata", "metadata size"],
|
|
||||||
"ed": ["_evictable_data", "evictable data size"],
|
|
||||||
"em": ["_evictable_metadata", "evictable metadata size"],
|
|
||||||
}
|
|
||||||
ghoststats = {
|
|
||||||
"fields": ["mfu", "mru"], # only applicable to these fields
|
|
||||||
"gsz": ["_ghost_size", "ghost size"],
|
|
||||||
"gd": ["_ghost_data", "ghost data size"],
|
|
||||||
"gm": ["_ghost_metadata", "ghost metadata size"],
|
|
||||||
}
|
|
||||||
|
|
||||||
# fields and stats
|
|
||||||
fieldstats = [
|
|
||||||
[structfields, structstats],
|
|
||||||
[typefields, typestats],
|
|
||||||
[statefields, targetstats, statestats, ghoststats],
|
|
||||||
]
|
|
||||||
for fs in fieldstats:
|
|
||||||
fields, stats = fs[0], fs[1:]
|
|
||||||
for field, fieldval in fields.items():
|
|
||||||
for group in stats:
|
|
||||||
for stat, statval in group.items():
|
|
||||||
if stat in ["fields", "percent"] or \
|
|
||||||
("fields" in group and field not in group["fields"]):
|
|
||||||
continue
|
|
||||||
colname = field + stat
|
|
||||||
coldesc = fieldval[1] + " " + statval[1]
|
|
||||||
cols[colname] = [len(colname), 1024, coldesc]
|
|
||||||
if "percent" in group:
|
|
||||||
cols[colname + "%"] = [len(colname) + 1, 100, \
|
|
||||||
coldesc + " percentage"]
|
|
||||||
|
|
||||||
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"]
|
|
||||||
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
|
|
||||||
l2exist = False
|
|
||||||
cmd = ("Usage: zarcstat [-havxp] [-f fields] [-o file] [-s string] [interval "
|
|
||||||
"[count]]\n")
|
|
||||||
cur = {}
|
|
||||||
d = {}
|
|
||||||
out = None
|
|
||||||
kstat = None
|
|
||||||
pretty_print = True
|
|
||||||
|
|
||||||
|
|
||||||
if sys.platform.startswith('freebsd'):
|
|
||||||
# Requires py-sysctl on FreeBSD
|
|
||||||
import sysctl
|
|
||||||
|
|
||||||
def kstat_update():
|
|
||||||
global kstat
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
kstat = {}
|
|
||||||
|
|
||||||
for s in k:
|
|
||||||
if not s:
|
|
||||||
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)
|
|
||||||
|
|
||||||
elif sys.platform.startswith('linux'):
|
|
||||||
def kstat_update():
|
|
||||||
global kstat
|
|
||||||
|
|
||||||
k1 = [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:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
del k1[0:2]
|
|
||||||
del k2[0:2]
|
|
||||||
k = k1 + k2
|
|
||||||
kstat = {}
|
|
||||||
|
|
||||||
for s in k:
|
|
||||||
if not s:
|
|
||||||
continue
|
|
||||||
|
|
||||||
name, unused, value = s.split()
|
|
||||||
kstat[name] = int(value)
|
|
||||||
|
|
||||||
|
|
||||||
def detailed_usage():
|
|
||||||
sys.stderr.write("%s\n" % cmd)
|
|
||||||
sys.stderr.write("Field definitions are as follows:\n")
|
|
||||||
for key in cols:
|
|
||||||
sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
|
|
||||||
sys.stderr.write("\n")
|
|
||||||
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
def usage():
|
|
||||||
sys.stderr.write("%s\n" % cmd)
|
|
||||||
sys.stderr.write("\t -h : Print this help message\n")
|
|
||||||
sys.stderr.write("\t -a : Print all possible stats\n")
|
|
||||||
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 "
|
|
||||||
"character or string\n")
|
|
||||||
sys.stderr.write("\t -p : Disable auto-scaling of numerical fields\n")
|
|
||||||
sys.stderr.write("\nExamples:\n")
|
|
||||||
sys.stderr.write("\tzarcstat -o /tmp/a.log 2 10\n")
|
|
||||||
sys.stderr.write("\tzarcstat -s \",\" -o /tmp/a.log 2 10\n")
|
|
||||||
sys.stderr.write("\tzarcstat -v\n")
|
|
||||||
sys.stderr.write("\tzarcstat -f time,hit%,dh%,ph%,mh% 1\n")
|
|
||||||
sys.stderr.write("\n")
|
|
||||||
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def snap_stats():
|
|
||||||
global cur
|
|
||||||
global kstat
|
|
||||||
|
|
||||||
prev = copy.deepcopy(cur)
|
|
||||||
kstat_update()
|
|
||||||
|
|
||||||
cur = kstat
|
|
||||||
|
|
||||||
# fill in additional values from zarcsummary
|
|
||||||
cur["caches_size"] = caches_size = cur["anon_data"]+cur["anon_metadata"]+\
|
|
||||||
cur["mfu_data"]+cur["mfu_metadata"]+cur["mru_data"]+cur["mru_metadata"]+\
|
|
||||||
cur["uncached_data"]+cur["uncached_metadata"]
|
|
||||||
s = 4294967296
|
|
||||||
pd = cur["pd"]
|
|
||||||
pm = cur["pm"]
|
|
||||||
meta = cur["meta"]
|
|
||||||
v = (s-int(pd))*(s-int(meta))/s
|
|
||||||
cur["mfu_data_target"] = v / 65536 * caches_size / 65536
|
|
||||||
v = (s-int(pm))*int(meta)/s
|
|
||||||
cur["mfu_metadata_target"] = v / 65536 * caches_size / 65536
|
|
||||||
v = int(pd)*(s-int(meta))/s
|
|
||||||
cur["mru_data_target"] = v / 65536 * caches_size / 65536
|
|
||||||
v = int(pm)*int(meta)/s
|
|
||||||
cur["mru_metadata_target"] = v / 65536 * caches_size / 65536
|
|
||||||
|
|
||||||
cur["data_target"] = cur["mfu_data_target"] + cur["mru_data_target"]
|
|
||||||
cur["metadata_target"] = cur["mfu_metadata_target"] + cur["mru_metadata_target"]
|
|
||||||
cur["mfu_target"] = cur["mfu_data_target"] + cur["mfu_metadata_target"]
|
|
||||||
cur["mru_target"] = cur["mru_data_target"] + cur["mru_metadata_target"]
|
|
||||||
|
|
||||||
for key in cur:
|
|
||||||
if re.match(key, "class"):
|
|
||||||
continue
|
|
||||||
if key in prev:
|
|
||||||
d[key] = cur[key] - prev[key]
|
|
||||||
else:
|
|
||||||
d[key] = cur[key]
|
|
||||||
|
|
||||||
|
|
||||||
def isint(num):
|
|
||||||
if isinstance(num, float):
|
|
||||||
return num.is_integer()
|
|
||||||
if isinstance(num, int):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def prettynum(sz, scale, num=0):
|
|
||||||
suffix = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
|
|
||||||
index = 0
|
|
||||||
|
|
||||||
# Special case for date field
|
|
||||||
if scale == -1:
|
|
||||||
return "%s" % num
|
|
||||||
|
|
||||||
if scale != 100:
|
|
||||||
while abs(num) > scale and index < 5:
|
|
||||||
num = num / scale
|
|
||||||
index += 1
|
|
||||||
|
|
||||||
width = sz - (0 if index == 0 else 1)
|
|
||||||
intlen = len("%.0f" % num) # %.0f rounds to nearest int
|
|
||||||
if sint == 1 and isint(num) or width < intlen + 2:
|
|
||||||
decimal = 0
|
|
||||||
else:
|
|
||||||
decimal = 1
|
|
||||||
return "%*.*f%s" % (width, decimal, num, suffix[index])
|
|
||||||
|
|
||||||
|
|
||||||
def print_values():
|
|
||||||
global hdr
|
|
||||||
global sep
|
|
||||||
global v
|
|
||||||
global pretty_print
|
|
||||||
|
|
||||||
if pretty_print:
|
|
||||||
fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col])
|
|
||||||
else:
|
|
||||||
fmt = lambda col: str(v[col])
|
|
||||||
|
|
||||||
sys.stdout.write(sep.join(fmt(col) for col in hdr))
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def print_header():
|
|
||||||
global hdr
|
|
||||||
global sep
|
|
||||||
global pretty_print
|
|
||||||
|
|
||||||
if pretty_print:
|
|
||||||
fmt = lambda col: "%*s" % (cols[col][0], col)
|
|
||||||
else:
|
|
||||||
fmt = lambda col: col
|
|
||||||
|
|
||||||
sys.stdout.write(sep.join(fmt(col) for col in hdr))
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
|
|
||||||
|
|
||||||
def get_terminal_lines():
|
|
||||||
try:
|
|
||||||
import fcntl
|
|
||||||
import termios
|
|
||||||
import struct
|
|
||||||
data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
|
|
||||||
sz = struct.unpack('hh', data)
|
|
||||||
return sz[0]
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def update_hdr_intr():
|
|
||||||
global hdr_intr
|
|
||||||
|
|
||||||
lines = get_terminal_lines()
|
|
||||||
if lines and lines > 3:
|
|
||||||
hdr_intr = lines - 3
|
|
||||||
|
|
||||||
|
|
||||||
def resize_handler(signum, frame):
|
|
||||||
update_hdr_intr()
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
|
||||||
global sint
|
|
||||||
global count
|
|
||||||
global hdr
|
|
||||||
global xhdr
|
|
||||||
global zhdr
|
|
||||||
global opfile
|
|
||||||
global sep
|
|
||||||
global out
|
|
||||||
global l2exist
|
|
||||||
global pretty_print
|
|
||||||
|
|
||||||
desired_cols = None
|
|
||||||
aflag = False
|
|
||||||
xflag = False
|
|
||||||
hflag = False
|
|
||||||
vflag = False
|
|
||||||
zflag = False
|
|
||||||
i = 1
|
|
||||||
|
|
||||||
try:
|
|
||||||
opts, args = getopt.getopt(
|
|
||||||
sys.argv[1:],
|
|
||||||
"axzo:hvs:f:p",
|
|
||||||
[
|
|
||||||
"all",
|
|
||||||
"extended",
|
|
||||||
"zfetch",
|
|
||||||
"outfile",
|
|
||||||
"help",
|
|
||||||
"verbose",
|
|
||||||
"separator",
|
|
||||||
"columns",
|
|
||||||
"parsable"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
except getopt.error as msg:
|
|
||||||
sys.stderr.write("Error: %s\n" % str(msg))
|
|
||||||
usage()
|
|
||||||
opts = None
|
|
||||||
|
|
||||||
for opt, arg in opts:
|
|
||||||
if opt in ('-a', '--all'):
|
|
||||||
aflag = True
|
|
||||||
if opt in ('-x', '--extended'):
|
|
||||||
xflag = True
|
|
||||||
if opt in ('-o', '--outfile'):
|
|
||||||
opfile = arg
|
|
||||||
i += 1
|
|
||||||
if opt in ('-h', '--help'):
|
|
||||||
hflag = True
|
|
||||||
if opt in ('-v', '--verbose'):
|
|
||||||
vflag = True
|
|
||||||
if opt in ('-s', '--separator'):
|
|
||||||
sep = arg
|
|
||||||
i += 1
|
|
||||||
if opt in ('-f', '--columns'):
|
|
||||||
desired_cols = arg
|
|
||||||
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):
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if vflag:
|
|
||||||
detailed_usage()
|
|
||||||
|
|
||||||
if xflag:
|
|
||||||
hdr = xhdr
|
|
||||||
|
|
||||||
if zflag:
|
|
||||||
hdr = zhdr
|
|
||||||
|
|
||||||
update_hdr_intr()
|
|
||||||
|
|
||||||
# check if L2ARC exists
|
|
||||||
snap_stats()
|
|
||||||
l2_size = cur.get("l2_size")
|
|
||||||
if l2_size:
|
|
||||||
l2exist = True
|
|
||||||
|
|
||||||
if desired_cols:
|
|
||||||
hdr = desired_cols.split(",")
|
|
||||||
|
|
||||||
invalid = []
|
|
||||||
incompat = []
|
|
||||||
for ele in hdr:
|
|
||||||
if ele not in cols:
|
|
||||||
invalid.append(ele)
|
|
||||||
elif not l2exist and ele.startswith("l2"):
|
|
||||||
sys.stdout.write("No L2ARC Here\n%s\n" % ele)
|
|
||||||
incompat.append(ele)
|
|
||||||
|
|
||||||
if len(invalid) > 0:
|
|
||||||
sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if len(incompat) > 0:
|
|
||||||
sys.stderr.write("Incompatible field specified! -- %s\n" %
|
|
||||||
incompat)
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if aflag:
|
|
||||||
if l2exist:
|
|
||||||
hdr = cols.keys()
|
|
||||||
else:
|
|
||||||
hdr = [col for col in cols.keys() if not col.startswith("l2")]
|
|
||||||
|
|
||||||
if opfile:
|
|
||||||
try:
|
|
||||||
out = open(opfile, "w")
|
|
||||||
sys.stdout = out
|
|
||||||
|
|
||||||
except IOError:
|
|
||||||
sys.stderr.write("Cannot open %s for writing\n" % opfile)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def calculate():
|
|
||||||
global d
|
|
||||||
global v
|
|
||||||
global l2exist
|
|
||||||
|
|
||||||
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["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["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["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["pmis"] = (d["prefetch_data_misses"] +
|
|
||||||
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["mhit"] = (d["prefetch_metadata_hits"] +
|
|
||||||
d["demand_metadata_hits"]) / sint
|
|
||||||
v["mioh"] = (d["prefetch_metadata_iohits"] +
|
|
||||||
d["demand_metadata_iohits"]) / sint
|
|
||||||
v["mmis"] = (d["prefetch_metadata_misses"] +
|
|
||||||
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["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
|
|
||||||
|
|
||||||
# ARC structural breakdown, ARC types breakdown, ARC states breakdown
|
|
||||||
v["cachessz"] = cur["caches_size"]
|
|
||||||
for fs in fieldstats:
|
|
||||||
fields, stats = fs[0], fs[1:]
|
|
||||||
for field, fieldval in fields.items():
|
|
||||||
for group in stats:
|
|
||||||
for stat, statval in group.items():
|
|
||||||
if stat in ["fields", "percent"] or \
|
|
||||||
("fields" in group and field not in group["fields"]):
|
|
||||||
continue
|
|
||||||
colname = field + stat
|
|
||||||
v[colname] = cur[fieldval[0] + statval[0]]
|
|
||||||
if "percent" in group:
|
|
||||||
v[colname + "%"] = 100 * v[colname] / \
|
|
||||||
v[group["percent"]] if v[group["percent"]] > 0 else 0
|
|
||||||
|
|
||||||
if l2exist:
|
|
||||||
l2asize = cur["l2_asize"]
|
|
||||||
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["l2miss%"] = 100 - v["l2hit%"] if v["l2read"] > 0 else 0
|
|
||||||
v["l2asize"] = l2asize
|
|
||||||
v["l2size"] = cur["l2_size"]
|
|
||||||
v["l2bytes"] = d["l2_read_bytes"] / sint
|
|
||||||
v["l2wbytes"] = d["l2_write_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"] / l2asize if l2asize > 0 else 0
|
|
||||||
v["l2mfu%"] = 100 * v["l2mfu"] / l2asize if l2asize > 0 else 0
|
|
||||||
v["l2mru%"] = 100 * v["l2mru"] / l2asize if l2asize > 0 else 0
|
|
||||||
v["l2data%"] = 100 * v["l2data"] / l2asize if l2asize > 0 else 0
|
|
||||||
v["l2meta%"] = 100 * v["l2meta"] / l2asize if l2asize > 0 else 0
|
|
||||||
|
|
||||||
v["grow"] = 0 if cur["arc_no_grow"] else 1
|
|
||||||
v["need"] = cur["arc_need_free"]
|
|
||||||
v["free"] = cur["memory_free_bytes"]
|
|
||||||
v["avail"] = cur["memory_available_bytes"]
|
|
||||||
v["waste"] = cur["abd_chunk_waste_size"]
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
global sint
|
|
||||||
global count
|
|
||||||
global hdr_intr
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
count_flag = 0
|
|
||||||
|
|
||||||
init()
|
|
||||||
if count > 0:
|
|
||||||
count_flag = 1
|
|
||||||
|
|
||||||
signal(SIGINT, SIG_DFL)
|
|
||||||
signal(SIGWINCH, resize_handler)
|
|
||||||
while True:
|
|
||||||
if i == 0:
|
|
||||||
print_header()
|
|
||||||
|
|
||||||
snap_stats()
|
|
||||||
calculate()
|
|
||||||
print_values()
|
|
||||||
|
|
||||||
if count_flag == 1:
|
|
||||||
if count <= 1:
|
|
||||||
break
|
|
||||||
count -= 1
|
|
||||||
|
|
||||||
i = 0 if i >= hdr_intr else i + 1
|
|
||||||
time.sleep(sint)
|
|
||||||
|
|
||||||
if out:
|
|
||||||
out.close()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
-1073
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
|||||||
|
/zdb
|
||||||
+15
-14
@@ -1,19 +1,20 @@
|
|||||||
# SPDX-License-Identifier: CDDL-1.0
|
include $(top_srcdir)/config/Rules.am
|
||||||
zdb_CPPFLAGS = $(AM_CPPFLAGS) $(LIBZPOOL_CPPFLAGS)
|
|
||||||
zdb_CFLAGS = $(AM_CFLAGS) $(LIBCRYPTO_CFLAGS)
|
|
||||||
|
|
||||||
sbin_PROGRAMS += zdb
|
AM_CPPFLAGS += -DDEBUG
|
||||||
CPPCHECKTARGETS += zdb
|
|
||||||
|
DEFAULT_INCLUDES += \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
|
-I$(top_srcdir)/lib/libspl/include
|
||||||
|
|
||||||
|
sbin_PROGRAMS = zdb
|
||||||
|
|
||||||
zdb_SOURCES = \
|
zdb_SOURCES = \
|
||||||
%D%/zdb.c \
|
zdb.c \
|
||||||
%D%/zdb.h \
|
zdb_il.c
|
||||||
%D%/zdb_il.c
|
|
||||||
|
|
||||||
zdb_LDADD = \
|
zdb_LDADD = \
|
||||||
libzdb.la \
|
$(top_builddir)/lib/libnvpair/libnvpair.la \
|
||||||
libzpool.la \
|
$(top_builddir)/lib/libuutil/libuutil.la \
|
||||||
libzfs_core.la \
|
$(top_builddir)/lib/libzpool/libzpool.la \
|
||||||
libnvpair.la
|
$(top_builddir)/lib/libzfs/libzfs.la \
|
||||||
|
$(top_builddir)/lib/libzfs_core/libzfs_core.la
|
||||||
zdb_LDADD += $(LIBCRYPTO_LIBS)
|
|
||||||
|
|||||||
+984
-6661
File diff suppressed because it is too large
Load Diff
@@ -1,34 +0,0 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
|
||||||
* CDDL HEADER START
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the terms of the
|
|
||||||
* Common Development and Distribution License (the "License").
|
|
||||||
* 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.
|
|
||||||
* See the License for the specific language governing permissions
|
|
||||||
* and limitations under the License.
|
|
||||||
*
|
|
||||||
* When distributing Covered Code, include this CDDL HEADER in each
|
|
||||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
||||||
* If applicable, add the following below this CDDL HEADER, with the
|
|
||||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
||||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
||||||
*
|
|
||||||
* CDDL HEADER END
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Copyright 2017 Spectra Logic Corp Inc. All rights reserved.
|
|
||||||
* Use is subject to license terms.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _ZDB_H
|
|
||||||
#define _ZDB_H
|
|
||||||
|
|
||||||
void dump_intent_log(zilog_t *);
|
|
||||||
extern uint8_t dump_opt[512];
|
|
||||||
|
|
||||||
#endif /* _ZDB_H */
|
|
||||||
+96
-233
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -7,7 +6,7 @@
|
|||||||
* You may not use this file except in compliance with the License.
|
* 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
|
* 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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -26,7 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013, 2017 by Delphix. All rights reserved.
|
* Copyright (c) 2013, 2016 by Delphix. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -43,12 +42,11 @@
|
|||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/zil.h>
|
#include <sys/zil.h>
|
||||||
#include <sys/zil_impl.h>
|
#include <sys/zil_impl.h>
|
||||||
#include <sys/spa_impl.h>
|
|
||||||
#include <sys/abd.h>
|
#include <sys/abd.h>
|
||||||
|
|
||||||
#include "zdb.h"
|
extern uint8_t dump_opt[256];
|
||||||
|
|
||||||
static char tab_prefix[4] = "\t\t\t";
|
static char prefix[4] = "\t\t\t";
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_log_bp(const blkptr_t *bp, const char *prefix)
|
print_log_bp(const blkptr_t *bp, const char *prefix)
|
||||||
@@ -59,93 +57,77 @@ print_log_bp(const blkptr_t *bp, const char *prefix)
|
|||||||
(void) printf("%s%s\n", prefix, blkbuf);
|
(void) printf("%s%s\n", prefix, blkbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
static void
|
static void
|
||||||
zil_prt_rec_create(zilog_t *zilog, int txtype, const void *arg)
|
zil_prt_rec_create(zilog_t *zilog, int txtype, lr_create_t *lr)
|
||||||
{
|
{
|
||||||
(void) zilog;
|
|
||||||
const lr_create_t *lrc = arg;
|
|
||||||
const _lr_create_t *lr = &lrc->lr_create;
|
|
||||||
time_t crtime = lr->lr_crtime[0];
|
time_t crtime = lr->lr_crtime[0];
|
||||||
const char *name, *link;
|
char *name, *link;
|
||||||
lr_attr_t *lrattr;
|
lr_attr_t *lrattr;
|
||||||
|
|
||||||
name = (const char *)&lrc->lr_data[0];
|
name = (char *)(lr + 1);
|
||||||
|
|
||||||
if (lr->lr_common.lrc_txtype == TX_CREATE_ATTR ||
|
if (lr->lr_common.lrc_txtype == TX_CREATE_ATTR ||
|
||||||
lr->lr_common.lrc_txtype == TX_MKDIR_ATTR) {
|
lr->lr_common.lrc_txtype == TX_MKDIR_ATTR) {
|
||||||
lrattr = (lr_attr_t *)&lrc->lr_data[0];
|
lrattr = (lr_attr_t *)(lr + 1);
|
||||||
name += ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
|
name += ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (txtype == TX_SYMLINK) {
|
if (txtype == TX_SYMLINK) {
|
||||||
link = (const char *)&lrc->lr_data[strlen(name) + 1];
|
link = name + strlen(name) + 1;
|
||||||
(void) printf("%s%s -> %s\n", tab_prefix, name, link);
|
(void) printf("%s%s -> %s\n", prefix, name, link);
|
||||||
} else if (txtype != TX_MKXATTR) {
|
} else if (txtype != TX_MKXATTR) {
|
||||||
(void) printf("%s%s\n", tab_prefix, name);
|
(void) printf("%s%s\n", prefix, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) printf("%s%s", tab_prefix, ctime(&crtime));
|
(void) printf("%s%s", prefix, ctime(&crtime));
|
||||||
(void) printf("%sdoid %llu, foid %llu, slots %llu, mode %llo\n",
|
(void) printf("%sdoid %llu, foid %llu, slots %llu, mode %llo\n", prefix,
|
||||||
tab_prefix, (u_longlong_t)lr->lr_doid,
|
(u_longlong_t)lr->lr_doid,
|
||||||
(u_longlong_t)LR_FOID_GET_OBJ(lr->lr_foid),
|
(u_longlong_t)LR_FOID_GET_OBJ(lr->lr_foid),
|
||||||
(u_longlong_t)LR_FOID_GET_SLOTS(lr->lr_foid),
|
(u_longlong_t)LR_FOID_GET_SLOTS(lr->lr_foid),
|
||||||
(longlong_t)lr->lr_mode);
|
(longlong_t)lr->lr_mode);
|
||||||
(void) printf("%suid %llu, gid %llu, gen %llu, rdev 0x%llx\n",
|
(void) printf("%suid %llu, gid %llu, gen %llu, rdev 0x%llx\n", prefix,
|
||||||
tab_prefix,
|
|
||||||
(u_longlong_t)lr->lr_uid, (u_longlong_t)lr->lr_gid,
|
(u_longlong_t)lr->lr_uid, (u_longlong_t)lr->lr_gid,
|
||||||
(u_longlong_t)lr->lr_gen, (u_longlong_t)lr->lr_rdev);
|
(u_longlong_t)lr->lr_gen, (u_longlong_t)lr->lr_rdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
static void
|
static void
|
||||||
zil_prt_rec_remove(zilog_t *zilog, int txtype, const void *arg)
|
zil_prt_rec_remove(zilog_t *zilog, int txtype, lr_remove_t *lr)
|
||||||
{
|
{
|
||||||
(void) zilog, (void) txtype;
|
(void) printf("%sdoid %llu, name %s\n", prefix,
|
||||||
const lr_remove_t *lr = arg;
|
(u_longlong_t)lr->lr_doid, (char *)(lr + 1));
|
||||||
|
|
||||||
(void) printf("%sdoid %llu, name %s\n", tab_prefix,
|
|
||||||
(u_longlong_t)lr->lr_doid, (const char *)&lr->lr_data[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
static void
|
static void
|
||||||
zil_prt_rec_link(zilog_t *zilog, int txtype, const void *arg)
|
zil_prt_rec_link(zilog_t *zilog, int txtype, lr_link_t *lr)
|
||||||
{
|
{
|
||||||
(void) zilog, (void) txtype;
|
(void) printf("%sdoid %llu, link_obj %llu, name %s\n", prefix,
|
||||||
const lr_link_t *lr = arg;
|
|
||||||
|
|
||||||
(void) printf("%sdoid %llu, link_obj %llu, name %s\n", tab_prefix,
|
|
||||||
(u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_link_obj,
|
(u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_link_obj,
|
||||||
(const char *)&lr->lr_data[0]);
|
(char *)(lr + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
static void
|
static void
|
||||||
zil_prt_rec_rename(zilog_t *zilog, int txtype, const void *arg)
|
zil_prt_rec_rename(zilog_t *zilog, int txtype, lr_rename_t *lr)
|
||||||
{
|
{
|
||||||
(void) zilog, (void) txtype;
|
char *snm = (char *)(lr + 1);
|
||||||
const lr_rename_t *lrr = arg;
|
char *tnm = snm + strlen(snm) + 1;
|
||||||
const _lr_rename_t *lr = &lrr->lr_rename;
|
|
||||||
const char *snm = (const char *)&lrr->lr_data[0];
|
|
||||||
const char *tnm = (const char *)&lrr->lr_data[strlen(snm) + 1];
|
|
||||||
|
|
||||||
(void) printf("%ssdoid %llu, tdoid %llu\n", tab_prefix,
|
(void) printf("%ssdoid %llu, tdoid %llu\n", prefix,
|
||||||
(u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid);
|
(u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid);
|
||||||
(void) printf("%ssrc %s tgt %s\n", tab_prefix, snm, tnm);
|
(void) printf("%ssrc %s tgt %s\n", 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
|
static int
|
||||||
zil_prt_rec_write_cb(void *data, size_t len, void *unused)
|
zil_prt_rec_write_cb(void *data, size_t len, void *unused)
|
||||||
{
|
{
|
||||||
(void) unused;
|
|
||||||
char *cdata = data;
|
char *cdata = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
if (isprint(*cdata))
|
if (isprint(*cdata))
|
||||||
(void) printf("%c ", *cdata);
|
(void) printf("%c ", *cdata);
|
||||||
else
|
else
|
||||||
@@ -155,45 +137,41 @@ zil_prt_rec_write_cb(void *data, size_t len, void *unused)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
static void
|
static void
|
||||||
zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
|
zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
|
||||||
{
|
{
|
||||||
const lr_write_t *lr = arg;
|
|
||||||
abd_t *data;
|
abd_t *data;
|
||||||
const blkptr_t *bp = &lr->lr_blkptr;
|
blkptr_t *bp = &lr->lr_blkptr;
|
||||||
zbookmark_phys_t zb;
|
zbookmark_phys_t zb;
|
||||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
(void) printf("%sfoid %llu, offset %llx, length %llx\n", tab_prefix,
|
(void) printf("%sfoid %llu, offset %llx, length %llx\n", prefix,
|
||||||
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset,
|
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset,
|
||||||
(u_longlong_t)lr->lr_length);
|
(u_longlong_t)lr->lr_length);
|
||||||
|
|
||||||
if (txtype == TX_WRITE2 || verbose < 4)
|
if (txtype == TX_WRITE2 || verbose < 5)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
|
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
|
||||||
(void) printf("%shas blkptr, %s\n", tab_prefix,
|
(void) printf("%shas blkptr, %s\n", prefix,
|
||||||
!BP_IS_HOLE(bp) && BP_GET_BIRTH(bp) >=
|
!BP_IS_HOLE(bp) &&
|
||||||
spa_min_claim_txg(zilog->zl_spa) ?
|
bp->blk_birth >= spa_first_txg(zilog->zl_spa) ?
|
||||||
"will claim" : "won't claim");
|
"will claim" : "won't claim");
|
||||||
print_log_bp(bp, tab_prefix);
|
print_log_bp(bp, prefix);
|
||||||
|
|
||||||
if (verbose < 5)
|
|
||||||
return;
|
|
||||||
if (BP_IS_HOLE(bp)) {
|
if (BP_IS_HOLE(bp)) {
|
||||||
(void) printf("\t\t\tLSIZE 0x%llx\n",
|
(void) printf("\t\t\tLSIZE 0x%llx\n",
|
||||||
(u_longlong_t)BP_GET_LSIZE(bp));
|
(u_longlong_t)BP_GET_LSIZE(bp));
|
||||||
(void) printf("%s<hole>\n", tab_prefix);
|
(void) printf("%s<hole>\n", prefix);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (BP_GET_BIRTH(bp) < zilog->zl_header->zh_claim_txg) {
|
if (bp->blk_birth < zilog->zl_header->zh_claim_txg) {
|
||||||
(void) printf("%s<block already committed>\n",
|
(void) printf("%s<block already committed>\n", prefix);
|
||||||
tab_prefix);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT3U(BP_GET_LSIZE(bp), !=, 0);
|
|
||||||
SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os),
|
SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os),
|
||||||
lr->lr_foid, ZB_ZIL_LEVEL,
|
lr->lr_foid, ZB_ZIL_LEVEL,
|
||||||
lr->lr_offset / BP_GET_LSIZE(bp));
|
lr->lr_offset / BP_GET_LSIZE(bp));
|
||||||
@@ -205,15 +183,12 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
|
|||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
if (verbose < 5)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* data is stored after the end of the lr_write record */
|
/* data is stored after the end of the lr_write record */
|
||||||
data = abd_alloc(lr->lr_length, B_FALSE);
|
data = abd_alloc(lr->lr_length, B_FALSE);
|
||||||
abd_copy_from_buf(data, &lr->lr_data[0], lr->lr_length);
|
abd_copy_from_buf(data, lr + 1, lr->lr_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) printf("%s", tab_prefix);
|
(void) printf("%s", prefix);
|
||||||
(void) abd_iterate_func(data,
|
(void) abd_iterate_func(data,
|
||||||
0, MIN(lr->lr_length, (verbose < 6 ? 20 : SPA_MAXBLOCKSIZE)),
|
0, MIN(lr->lr_length, (verbose < 6 ? 20 : SPA_MAXBLOCKSIZE)),
|
||||||
zil_prt_rec_write_cb, NULL);
|
zil_prt_rec_write_cb, NULL);
|
||||||
@@ -223,203 +198,103 @@ out:
|
|||||||
abd_free(data);
|
abd_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
static void
|
static void
|
||||||
zil_prt_rec_write_enc(zilog_t *zilog, int txtype, const void *arg)
|
zil_prt_rec_truncate(zilog_t *zilog, int txtype, lr_truncate_t *lr)
|
||||||
{
|
{
|
||||||
(void) txtype;
|
(void) printf("%sfoid %llu, offset 0x%llx, length 0x%llx\n", prefix,
|
||||||
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_GET_BIRTH(bp) >=
|
|
||||||
spa_min_claim_txg(zilog->zl_spa) ?
|
|
||||||
"will claim" : "won't claim");
|
|
||||||
print_log_bp(bp, tab_prefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
(u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
|
(u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
|
||||||
(u_longlong_t)lr->lr_length);
|
(u_longlong_t)lr->lr_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
static void
|
static void
|
||||||
zil_prt_rec_setattr(zilog_t *zilog, int txtype, const void *arg)
|
zil_prt_rec_setattr(zilog_t *zilog, int txtype, lr_setattr_t *lr)
|
||||||
{
|
{
|
||||||
(void) zilog, (void) txtype;
|
|
||||||
const lr_setattr_t *lr = arg;
|
|
||||||
time_t atime = (time_t)lr->lr_atime[0];
|
time_t atime = (time_t)lr->lr_atime[0];
|
||||||
time_t mtime = (time_t)lr->lr_mtime[0];
|
time_t mtime = (time_t)lr->lr_mtime[0];
|
||||||
|
|
||||||
(void) printf("%sfoid %llu, mask 0x%llx\n", tab_prefix,
|
(void) printf("%sfoid %llu, mask 0x%llx\n", prefix,
|
||||||
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_mask);
|
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_mask);
|
||||||
|
|
||||||
if (lr->lr_mask & AT_MODE) {
|
if (lr->lr_mask & AT_MODE) {
|
||||||
(void) printf("%sAT_MODE %llo\n", tab_prefix,
|
(void) printf("%sAT_MODE %llo\n", prefix,
|
||||||
(longlong_t)lr->lr_mode);
|
(longlong_t)lr->lr_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lr->lr_mask & AT_UID) {
|
if (lr->lr_mask & AT_UID) {
|
||||||
(void) printf("%sAT_UID %llu\n", tab_prefix,
|
(void) printf("%sAT_UID %llu\n", prefix,
|
||||||
(u_longlong_t)lr->lr_uid);
|
(u_longlong_t)lr->lr_uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lr->lr_mask & AT_GID) {
|
if (lr->lr_mask & AT_GID) {
|
||||||
(void) printf("%sAT_GID %llu\n", tab_prefix,
|
(void) printf("%sAT_GID %llu\n", prefix,
|
||||||
(u_longlong_t)lr->lr_gid);
|
(u_longlong_t)lr->lr_gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lr->lr_mask & AT_SIZE) {
|
if (lr->lr_mask & AT_SIZE) {
|
||||||
(void) printf("%sAT_SIZE %llu\n", tab_prefix,
|
(void) printf("%sAT_SIZE %llu\n", prefix,
|
||||||
(u_longlong_t)lr->lr_size);
|
(u_longlong_t)lr->lr_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lr->lr_mask & AT_ATIME) {
|
if (lr->lr_mask & AT_ATIME) {
|
||||||
(void) printf("%sAT_ATIME %llu.%09llu %s", tab_prefix,
|
(void) printf("%sAT_ATIME %llu.%09llu %s", prefix,
|
||||||
(u_longlong_t)lr->lr_atime[0],
|
(u_longlong_t)lr->lr_atime[0],
|
||||||
(u_longlong_t)lr->lr_atime[1],
|
(u_longlong_t)lr->lr_atime[1],
|
||||||
ctime(&atime));
|
ctime(&atime));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lr->lr_mask & AT_MTIME) {
|
if (lr->lr_mask & AT_MTIME) {
|
||||||
(void) printf("%sAT_MTIME %llu.%09llu %s", tab_prefix,
|
(void) printf("%sAT_MTIME %llu.%09llu %s", prefix,
|
||||||
(u_longlong_t)lr->lr_mtime[0],
|
(u_longlong_t)lr->lr_mtime[0],
|
||||||
(u_longlong_t)lr->lr_mtime[1],
|
(u_longlong_t)lr->lr_mtime[1],
|
||||||
ctime(&mtime));
|
ctime(&mtime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
static void
|
static void
|
||||||
zil_prt_rec_setsaxattr(zilog_t *zilog, int txtype, const void *arg)
|
zil_prt_rec_acl(zilog_t *zilog, int txtype, lr_acl_t *lr)
|
||||||
{
|
{
|
||||||
(void) zilog, (void) txtype;
|
(void) printf("%sfoid %llu, aclcnt %llu\n", prefix,
|
||||||
const lr_setsaxattr_t *lr = arg;
|
|
||||||
|
|
||||||
const char *name = (const char *)&lr->lr_data[0];
|
|
||||||
(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);
|
|
||||||
const char *val = (const char *)&lr->lr_data[strlen(name) + 1];
|
|
||||||
for (int i = 0; i < lr->lr_size; i++) {
|
|
||||||
(void) printf("%c", *val);
|
|
||||||
val++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_aclcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
typedef void (*zil_prt_rec_func_t)(zilog_t *, int, 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 {
|
typedef struct zil_rec_info {
|
||||||
zil_prt_rec_func_t zri_print;
|
zil_prt_rec_func_t zri_print;
|
||||||
zil_prt_rec_func_t zri_print_enc;
|
char *zri_name;
|
||||||
const char *zri_name;
|
|
||||||
uint64_t zri_count;
|
uint64_t zri_count;
|
||||||
} zil_rec_info_t;
|
} zil_rec_info_t;
|
||||||
|
|
||||||
static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
|
static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
|
||||||
{.zri_print = NULL, .zri_name = "Total "},
|
{ NULL, "Total " },
|
||||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_CREATE " },
|
||||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_MKDIR " },
|
||||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_MKXATTR "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_MKXATTR " },
|
||||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_SYMLINK "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_SYMLINK " },
|
||||||
{.zri_print = zil_prt_rec_remove, .zri_name = "TX_REMOVE "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_remove, "TX_REMOVE " },
|
||||||
{.zri_print = zil_prt_rec_remove, .zri_name = "TX_RMDIR "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_remove, "TX_RMDIR " },
|
||||||
{.zri_print = zil_prt_rec_link, .zri_name = "TX_LINK "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_link, "TX_LINK " },
|
||||||
{.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_rename, "TX_RENAME " },
|
||||||
{.zri_print = zil_prt_rec_write,
|
{ (zil_prt_rec_func_t)zil_prt_rec_write, "TX_WRITE " },
|
||||||
.zri_print_enc = zil_prt_rec_write_enc,
|
{ (zil_prt_rec_func_t)zil_prt_rec_truncate, "TX_TRUNCATE " },
|
||||||
.zri_name = "TX_WRITE "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_setattr, "TX_SETATTR " },
|
||||||
{.zri_print = zil_prt_rec_truncate, .zri_name = "TX_TRUNCATE "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_acl, "TX_ACL_V0 " },
|
||||||
{.zri_print = zil_prt_rec_setattr, .zri_name = "TX_SETATTR "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_acl, "TX_ACL_ACL " },
|
||||||
{.zri_print = zil_prt_rec_acl, .zri_name = "TX_ACL_V0 "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_CREATE_ACL " },
|
||||||
{.zri_print = zil_prt_rec_acl, .zri_name = "TX_ACL_ACL "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_CREATE_ATTR " },
|
||||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE_ACL "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_CREATE_ACL_ATTR " },
|
||||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE_ATTR "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_MKDIR_ACL " },
|
||||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_CREATE_ACL_ATTR "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_MKDIR_ATTR " },
|
||||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ACL "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_create, "TX_MKDIR_ACL_ATTR " },
|
||||||
{.zri_print = zil_prt_rec_create, .zri_name = "TX_MKDIR_ATTR "},
|
{ (zil_prt_rec_func_t)zil_prt_rec_write, "TX_WRITE2 " },
|
||||||
{.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
|
static int
|
||||||
print_log_record(zilog_t *zilog, const lr_t *lr, void *arg, uint64_t claim_txg)
|
print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
|
||||||
{
|
{
|
||||||
(void) arg, (void) claim_txg;
|
|
||||||
int txtype;
|
int txtype;
|
||||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||||
|
|
||||||
@@ -436,15 +311,8 @@ print_log_record(zilog_t *zilog, const lr_t *lr, void *arg, uint64_t claim_txg)
|
|||||||
(u_longlong_t)lr->lrc_txg,
|
(u_longlong_t)lr->lrc_txg,
|
||||||
(u_longlong_t)lr->lrc_seq);
|
(u_longlong_t)lr->lrc_seq);
|
||||||
|
|
||||||
if (txtype && verbose >= 3) {
|
if (txtype && verbose >= 3)
|
||||||
if (!zilog->zl_os->os_encrypted) {
|
zil_rec_info[txtype].zri_print(zilog, txtype, lr);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zil_rec_info[txtype].zri_count++;
|
zil_rec_info[txtype].zri_count++;
|
||||||
zil_rec_info[0].zri_count++;
|
zil_rec_info[0].zri_count++;
|
||||||
@@ -452,14 +320,13 @@ print_log_record(zilog_t *zilog, const lr_t *lr, void *arg, uint64_t claim_txg)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
static int
|
static int
|
||||||
print_log_block(zilog_t *zilog, const blkptr_t *bp, void *arg,
|
print_log_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
|
||||||
uint64_t claim_txg)
|
|
||||||
{
|
{
|
||||||
(void) arg;
|
|
||||||
char blkbuf[BP_SPRINTF_LEN + 10];
|
char blkbuf[BP_SPRINTF_LEN + 10];
|
||||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||||
const char *claim;
|
char *claim;
|
||||||
|
|
||||||
if (verbose <= 3)
|
if (verbose <= 3)
|
||||||
return (0);
|
return (0);
|
||||||
@@ -474,7 +341,7 @@ print_log_block(zilog_t *zilog, const blkptr_t *bp, void *arg,
|
|||||||
|
|
||||||
if (claim_txg != 0)
|
if (claim_txg != 0)
|
||||||
claim = "already claimed";
|
claim = "already claimed";
|
||||||
else if (BP_GET_BIRTH(bp) >= spa_min_claim_txg(zilog->zl_spa))
|
else if (bp->blk_birth >= spa_first_txg(zilog->zl_spa))
|
||||||
claim = "will claim";
|
claim = "will claim";
|
||||||
else
|
else
|
||||||
claim = "won't claim";
|
claim = "won't claim";
|
||||||
@@ -488,7 +355,7 @@ print_log_block(zilog_t *zilog, const blkptr_t *bp, void *arg,
|
|||||||
static void
|
static void
|
||||||
print_log_stats(int verbose)
|
print_log_stats(int verbose)
|
||||||
{
|
{
|
||||||
unsigned i, w, p10;
|
int i, w, p10;
|
||||||
|
|
||||||
if (verbose > 3)
|
if (verbose > 3)
|
||||||
(void) printf("\n");
|
(void) printf("\n");
|
||||||
@@ -507,6 +374,7 @@ print_log_stats(int verbose)
|
|||||||
(void) printf("\n");
|
(void) printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
void
|
void
|
||||||
dump_intent_log(zilog_t *zilog)
|
dump_intent_log(zilog_t *zilog)
|
||||||
{
|
{
|
||||||
@@ -528,15 +396,10 @@ dump_intent_log(zilog_t *zilog)
|
|||||||
for (i = 0; i < TX_MAX_TYPE; i++)
|
for (i = 0; i < TX_MAX_TYPE; i++)
|
||||||
zil_rec_info[i].zri_count = 0;
|
zil_rec_info[i].zri_count = 0;
|
||||||
|
|
||||||
/* see comment in zil_claim() or zil_check_log_chain() */
|
|
||||||
if (zilog->zl_spa->spa_uberblock.ub_checkpoint_txg != 0 &&
|
|
||||||
zh->zh_claim_txg == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (verbose >= 2) {
|
if (verbose >= 2) {
|
||||||
(void) printf("\n");
|
(void) printf("\n");
|
||||||
(void) zil_parse(zilog, print_log_block, print_log_record, NULL,
|
(void) zil_parse(zilog, print_log_block, print_log_record, NULL,
|
||||||
zh->zh_claim_txg, B_FALSE);
|
zh->zh_claim_txg);
|
||||||
print_log_stats(verbose);
|
print_log_stats(verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+87
-40
@@ -1,47 +1,94 @@
|
|||||||
# SPDX-License-Identifier: CDDL-1.0
|
include $(top_srcdir)/config/Rules.am
|
||||||
include $(srcdir)/%D%/zed.d/Makefile.am
|
|
||||||
|
|
||||||
zed_CFLAGS = $(AM_CFLAGS)
|
DEFAULT_INCLUDES += \
|
||||||
zed_CFLAGS += $(LIBUDEV_CFLAGS) $(LIBUUID_CFLAGS)
|
-I$(top_srcdir)/include \
|
||||||
|
-I$(top_srcdir)/lib/libspl/include
|
||||||
|
|
||||||
sbin_PROGRAMS += zed
|
EXTRA_DIST = zed.d/README
|
||||||
CPPCHECKTARGETS += zed
|
|
||||||
|
|
||||||
zed_SOURCES = \
|
sbin_PROGRAMS = zed
|
||||||
%D%/zed.c \
|
|
||||||
%D%/zed.h \
|
ZED_SRC = \
|
||||||
%D%/zed_conf.c \
|
zed.c \
|
||||||
%D%/zed_conf.h \
|
zed.h \
|
||||||
%D%/zed_disk_event.c \
|
zed_conf.c \
|
||||||
%D%/zed_disk_event.h \
|
zed_conf.h \
|
||||||
%D%/zed_event.c \
|
zed_disk_event.c \
|
||||||
%D%/zed_event.h \
|
zed_disk_event.h \
|
||||||
%D%/zed_exec.c \
|
zed_event.c \
|
||||||
%D%/zed_exec.h \
|
zed_event.h \
|
||||||
%D%/zed_file.c \
|
zed_exec.c \
|
||||||
%D%/zed_file.h \
|
zed_exec.h \
|
||||||
%D%/zed_log.c \
|
zed_file.c \
|
||||||
%D%/zed_log.h \
|
zed_file.h \
|
||||||
%D%/zed_strings.c \
|
zed_log.c \
|
||||||
%D%/zed_strings.h \
|
zed_log.h \
|
||||||
\
|
zed_strings.c \
|
||||||
%D%/agents/fmd_api.c \
|
zed_strings.h
|
||||||
%D%/agents/fmd_api.h \
|
|
||||||
%D%/agents/fmd_serd.c \
|
FMA_SRC = \
|
||||||
%D%/agents/fmd_serd.h \
|
agents/zfs_agents.c \
|
||||||
%D%/agents/zfs_agents.c \
|
agents/zfs_agents.h \
|
||||||
%D%/agents/zfs_agents.h \
|
agents/zfs_diagnosis.c \
|
||||||
%D%/agents/zfs_diagnosis.c \
|
agents/zfs_mod.c \
|
||||||
%D%/agents/zfs_mod.c \
|
agents/zfs_retire.c \
|
||||||
%D%/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 = \
|
zed_LDADD = \
|
||||||
libzfs.la \
|
$(top_builddir)/lib/libavl/libavl.la \
|
||||||
libzfs_core.la \
|
$(top_builddir)/lib/libnvpair/libnvpair.la \
|
||||||
libnvpair.la \
|
$(top_builddir)/lib/libspl/libspl.la \
|
||||||
libuutil.la
|
$(top_builddir)/lib/libuutil/libuutil.la \
|
||||||
|
$(top_builddir)/lib/libzpool/libzpool.la \
|
||||||
|
$(top_builddir)/lib/libzfs/libzfs.la \
|
||||||
|
$(top_builddir)/lib/libzfs_core/libzfs_core.la
|
||||||
|
|
||||||
zed_LDADD += -lrt $(LIBATOMIC_LIBS) $(LIBUDEV_LIBS) $(LIBUUID_LIBS)
|
zed_LDFLAGS = -lrt -pthread
|
||||||
zed_LDFLAGS = -pthread
|
|
||||||
|
|
||||||
dist_noinst_DATA += %D%/agents/README.md
|
zedconfdir = $(sysconfdir)/zfs/zed.d
|
||||||
|
|
||||||
|
dist_zedconf_DATA = \
|
||||||
|
zed.d/zed-functions.sh \
|
||||||
|
zed.d/zed.rc
|
||||||
|
|
||||||
|
zedexecdir = $(libexecdir)/zfs/zed.d
|
||||||
|
|
||||||
|
dist_zedexec_SCRIPTS = \
|
||||||
|
zed.d/all-debug.sh \
|
||||||
|
zed.d/all-syslog.sh \
|
||||||
|
zed.d/data-notify.sh \
|
||||||
|
zed.d/generic-notify.sh \
|
||||||
|
zed.d/resilver_finish-notify.sh \
|
||||||
|
zed.d/scrub_finish-notify.sh \
|
||||||
|
zed.d/statechange-led.sh \
|
||||||
|
zed.d/statechange-notify.sh \
|
||||||
|
zed.d/vdev_clear-led.sh \
|
||||||
|
zed.d/vdev_attach-led.sh \
|
||||||
|
zed.d/pool_import-led.sh \
|
||||||
|
zed.d/resilver_finish-start-scrub.sh
|
||||||
|
|
||||||
|
zedconfdefaults = \
|
||||||
|
all-syslog.sh \
|
||||||
|
data-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
|
||||||
|
|
||||||
|
install-data-hook:
|
||||||
|
$(MKDIR_P) "$(DESTDIR)$(zedconfdir)"
|
||||||
|
for f in $(zedconfdefaults); do \
|
||||||
|
test -f "$(DESTDIR)$(zedconfdir)/$${f}" -o \
|
||||||
|
-L "$(DESTDIR)$(zedconfdir)/$${f}" || \
|
||||||
|
ln -s "$(zedexecdir)/$${f}" "$(DESTDIR)$(zedconfdir)"; \
|
||||||
|
done
|
||||||
|
chmod 0600 "$(DESTDIR)$(zedconfdir)/zed.rc"
|
||||||
|
|||||||
+46
-63
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -7,7 +6,7 @@
|
|||||||
* You may not use this file except in compliance with the License.
|
* 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
|
* 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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -23,11 +22,10 @@
|
|||||||
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016, Intel Corporation.
|
* Copyright (c) 2016, Intel Corporation.
|
||||||
* Copyright (c) 2023, Klara Inc.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file implements the minimal FMD module API required to support the
|
* This file imlements the minimal FMD module API required to support the
|
||||||
* fault logic modules in ZED. This support includes module registration,
|
* fault logic modules in ZED. This support includes module registration,
|
||||||
* memory allocation, module property accessors, basic case management,
|
* memory allocation, module property accessors, basic case management,
|
||||||
* one-shot timers and SERD engines.
|
* one-shot timers and SERD engines.
|
||||||
@@ -40,7 +38,7 @@
|
|||||||
#include <sys/fm/protocol.h>
|
#include <sys/fm/protocol.h>
|
||||||
#include <uuid/uuid.h>
|
#include <uuid/uuid.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <string.h>
|
#include <strings.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "fmd_api.h"
|
#include "fmd_api.h"
|
||||||
@@ -99,7 +97,6 @@ _umem_logging_init(void)
|
|||||||
int
|
int
|
||||||
fmd_hdl_register(fmd_hdl_t *hdl, int version, const fmd_hdl_info_t *mip)
|
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;
|
fmd_module_t *mp = (fmd_module_t *)hdl;
|
||||||
|
|
||||||
mp->mod_info = mip;
|
mp->mod_info = mip;
|
||||||
@@ -182,21 +179,18 @@ fmd_hdl_getspecific(fmd_hdl_t *hdl)
|
|||||||
void *
|
void *
|
||||||
fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags)
|
fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
|
||||||
return (umem_alloc(size, flags));
|
return (umem_alloc(size, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags)
|
fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
|
||||||
return (umem_zalloc(size, flags));
|
return (umem_zalloc(size, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size)
|
fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
|
||||||
umem_free(data, size);
|
umem_free(data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,8 +217,6 @@ fmd_hdl_debug(fmd_hdl_t *hdl, const char *format, ...)
|
|||||||
int32_t
|
int32_t
|
||||||
fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name)
|
fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These can be looked up in mp->modinfo->fmdi_props
|
* These can be looked up in mp->modinfo->fmdi_props
|
||||||
* For now we just hard code for phase 2. In the
|
* For now we just hard code for phase 2. In the
|
||||||
@@ -233,6 +225,26 @@ fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name)
|
|||||||
if (strcmp(name, "spare_on_remove") == 0)
|
if (strcmp(name, "spare_on_remove") == 0)
|
||||||
return (1);
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,24 +334,22 @@ fmd_case_uuresolved(fmd_hdl_t *hdl, const char *uuid)
|
|||||||
fmd_hdl_debug(hdl, "case resolved by uuid (%s)", 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)
|
fmd_case_solved(fmd_hdl_t *hdl, fmd_case_t *cp)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
return ((cp->ci_state >= FMD_CASE_SOLVED) ? FMD_B_TRUE : FMD_B_FALSE);
|
||||||
return (cp->ci_state >= FMD_CASE_SOLVED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep)
|
fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep)
|
||||||
{
|
{
|
||||||
(void) hdl, (void) cp, (void) ep;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
|
zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
|
||||||
{
|
{
|
||||||
nvlist_t *rsrc;
|
nvlist_t *rsrc;
|
||||||
const char *strval;
|
char *strval;
|
||||||
uint64_t guid;
|
uint64_t guid;
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
|
|
||||||
@@ -352,7 +362,7 @@ zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
|
|||||||
if (code != NULL)
|
if (code != NULL)
|
||||||
zed_log_msg(LOG_INFO, "\t%s: %s", FM_SUSPECT_DIAG_CODE, code);
|
zed_log_msg(LOG_INFO, "\t%s: %s", FM_SUSPECT_DIAG_CODE, code);
|
||||||
if (nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &byte) == 0)
|
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_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
|
||||||
if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &strval) == 0)
|
if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &strval) == 0)
|
||||||
zed_log_msg(LOG_INFO, "\t%s: %s", FM_FMRI_SCHEME,
|
zed_log_msg(LOG_INFO, "\t%s: %s", FM_FMRI_SCHEME,
|
||||||
@@ -369,8 +379,7 @@ zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
|
|||||||
static const char *
|
static const char *
|
||||||
fmd_fault_mkcode(nvlist_t *fault)
|
fmd_fault_mkcode(nvlist_t *fault)
|
||||||
{
|
{
|
||||||
const char *class;
|
char *class, *code = "-";
|
||||||
const char *code = "-";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: message codes come from: openzfs/usr/src/cmd/fm/dicts/ZFS.po
|
* Note: message codes come from: openzfs/usr/src/cmd/fm/dicts/ZFS.po
|
||||||
@@ -419,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_string(nvl, FM_SUSPECT_DIAG_CODE, code);
|
||||||
err |= nvlist_add_int64_array(nvl, FM_SUSPECT_DIAG_TIME, tod, 2);
|
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_uint32(nvl, FM_SUSPECT_FAULT_SZ, 1);
|
||||||
err |= nvlist_add_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
|
err |= nvlist_add_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &fault, 1);
|
||||||
(const nvlist_t **)&fault, 1);
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
zed_log_die("failed to populate nvlist");
|
zed_log_die("failed to populate nvlist");
|
||||||
@@ -435,21 +443,19 @@ fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *fault)
|
|||||||
void
|
void
|
||||||
fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data)
|
fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
|
||||||
cp->ci_data = data;
|
cp->ci_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp)
|
fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
|
||||||
return (cp->ci_data);
|
return (cp->ci_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fmd_buf_create(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name, size_t size)
|
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(cp->ci_bufptr == NULL);
|
||||||
assert(size < (1024 * 1024));
|
assert(size < (1024 * 1024));
|
||||||
|
|
||||||
@@ -461,24 +467,22 @@ void
|
|||||||
fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp,
|
fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp,
|
||||||
const char *name, void *buf, size_t size)
|
const char *name, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
assert(strcmp(name, "data") == 0);
|
||||||
assert(strcmp(name, "data") == 0), (void) name;
|
|
||||||
assert(cp->ci_bufptr != NULL);
|
assert(cp->ci_bufptr != NULL);
|
||||||
assert(size <= cp->ci_bufsiz);
|
assert(size <= cp->ci_bufsiz);
|
||||||
|
|
||||||
memcpy(buf, cp->ci_bufptr, size);
|
bcopy(cp->ci_bufptr, buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp,
|
fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp,
|
||||||
const char *name, const void *buf, size_t size)
|
const char *name, const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
assert(strcmp(name, "data") == 0);
|
||||||
assert(strcmp(name, "data") == 0), (void) name;
|
|
||||||
assert(cp->ci_bufptr != NULL);
|
assert(cp->ci_bufptr != NULL);
|
||||||
assert(cp->ci_bufsiz >= size);
|
assert(cp->ci_bufsiz >= size);
|
||||||
|
|
||||||
memcpy(cp->ci_bufptr, buf, size);
|
bcopy(buf, cp->ci_bufptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SERD Engines */
|
/* SERD Engines */
|
||||||
@@ -515,19 +519,6 @@ fmd_serd_exists(fmd_hdl_t *hdl, const char *name)
|
|||||||
return (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL);
|
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
|
void
|
||||||
fmd_serd_reset(fmd_hdl_t *hdl, const char *name)
|
fmd_serd_reset(fmd_hdl_t *hdl, const char *name)
|
||||||
{
|
{
|
||||||
@@ -536,10 +527,12 @@ fmd_serd_reset(fmd_hdl_t *hdl, const char *name)
|
|||||||
|
|
||||||
if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
|
if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
|
||||||
zed_log_msg(LOG_ERR, "serd engine '%s' does not exist", name);
|
zed_log_msg(LOG_ERR, "serd engine '%s' does not exist", name);
|
||||||
} else {
|
return;
|
||||||
fmd_serd_eng_reset(sgp);
|
|
||||||
fmd_hdl_debug(hdl, "serd_reset %s", name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmd_serd_eng_reset(sgp);
|
||||||
|
|
||||||
|
fmd_hdl_debug(hdl, "serd_reset %s", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -547,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_module_t *mp = (fmd_module_t *)hdl;
|
||||||
fmd_serd_eng_t *sgp;
|
fmd_serd_eng_t *sgp;
|
||||||
|
int err;
|
||||||
|
|
||||||
if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
|
if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
|
||||||
zed_log_msg(LOG_ERR, "failed to add record to SERD engine '%s'",
|
zed_log_msg(LOG_ERR, "failed to add record to SERD engine '%s'",
|
||||||
name);
|
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
|
return (err);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FMD Timers */
|
/* FMD Timers */
|
||||||
@@ -575,10 +563,10 @@ _timer_notify(union sigval sv)
|
|||||||
const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
|
const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
|
||||||
struct itimerspec its;
|
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 */
|
/* disarm the timer */
|
||||||
memset(&its, 0, sizeof (struct itimerspec));
|
bzero(&its, sizeof (struct itimerspec));
|
||||||
timer_settime(ftp->ft_tid, 0, &its, NULL);
|
timer_settime(ftp->ft_tid, 0, &its, NULL);
|
||||||
|
|
||||||
/* Note that the fmdo_timeout can remove this timer */
|
/* Note that the fmdo_timeout can remove this timer */
|
||||||
@@ -594,7 +582,6 @@ _timer_notify(union sigval sv)
|
|||||||
fmd_timer_t *
|
fmd_timer_t *
|
||||||
fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
|
fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
|
||||||
{
|
{
|
||||||
(void) ep;
|
|
||||||
struct sigevent sev;
|
struct sigevent sev;
|
||||||
struct itimerspec its;
|
struct itimerspec its;
|
||||||
fmd_timer_t *ftp;
|
fmd_timer_t *ftp;
|
||||||
@@ -612,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_function = _timer_notify;
|
||||||
sev.sigev_notify_attributes = NULL;
|
sev.sigev_notify_attributes = NULL;
|
||||||
sev.sigev_value.sival_ptr = ftp;
|
sev.sigev_value.sival_ptr = ftp;
|
||||||
sev.sigev_signo = 0;
|
|
||||||
|
|
||||||
timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid);
|
timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid);
|
||||||
timer_settime(ftp->ft_tid, 0, &its, NULL);
|
timer_settime(ftp->ft_tid, 0, &its, NULL);
|
||||||
@@ -639,7 +625,6 @@ nvlist_t *
|
|||||||
fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t certainty,
|
fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t certainty,
|
||||||
nvlist_t *asru, nvlist_t *fru, nvlist_t *resource)
|
nvlist_t *asru, nvlist_t *fru, nvlist_t *resource)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
|
||||||
nvlist_t *nvl;
|
nvlist_t *nvl;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
@@ -703,8 +688,7 @@ fmd_strmatch(const char *s, const char *p)
|
|||||||
int
|
int
|
||||||
fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern)
|
fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
char *class;
|
||||||
const char *class;
|
|
||||||
|
|
||||||
return (nvl != NULL &&
|
return (nvl != NULL &&
|
||||||
nvlist_lookup_string(nvl, FM_CLASS, &class) == 0 &&
|
nvlist_lookup_string(nvl, FM_CLASS, &class) == 0 &&
|
||||||
@@ -714,7 +698,6 @@ fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern)
|
|||||||
nvlist_t *
|
nvlist_t *
|
||||||
fmd_nvl_alloc(fmd_hdl_t *hdl, int flags)
|
fmd_nvl_alloc(fmd_hdl_t *hdl, int flags)
|
||||||
{
|
{
|
||||||
(void) hdl, (void) flags;
|
|
||||||
nvlist_t *nvl = NULL;
|
nvlist_t *nvl = NULL;
|
||||||
|
|
||||||
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
|
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -7,7 +6,7 @@
|
|||||||
* You may not use this file except in compliance with the License.
|
* 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
|
* 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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -73,6 +72,10 @@ typedef struct fmd_case {
|
|||||||
} fmd_case_t;
|
} 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_UNSOLVED 0 /* case is not yet solved (waiting) */
|
||||||
#define FMD_CASE_SOLVED 1 /* case is solved (suspects added) */
|
#define FMD_CASE_SOLVED 1 /* case is solved (suspects added) */
|
||||||
#define FMD_CASE_CLOSE_WAIT 2 /* case is executing fmdo_close() */
|
#define FMD_CASE_CLOSE_WAIT 2 /* case is executing fmdo_close() */
|
||||||
@@ -152,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 void fmd_hdl_debug(fmd_hdl_t *, const char *, ...);
|
||||||
|
|
||||||
extern int32_t fmd_prop_get_int32(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_NOALLOC 0x0 /* fmd should use caller's memory */
|
||||||
#define FMD_STAT_ALLOC 0x1 /* fmd should allocate stats memory */
|
#define FMD_STAT_ALLOC 0x1 /* fmd should allocate stats memory */
|
||||||
@@ -172,7 +176,8 @@ extern int fmd_case_uuclosed(fmd_hdl_t *, const char *);
|
|||||||
extern int fmd_case_uuisresolved(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 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_ereport(fmd_hdl_t *, fmd_case_t *, fmd_event_t *);
|
||||||
extern void fmd_case_add_serd(fmd_hdl_t *, fmd_case_t *, const char *);
|
extern void fmd_case_add_serd(fmd_hdl_t *, fmd_case_t *, const char *);
|
||||||
@@ -195,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_create(fmd_hdl_t *, const char *, uint_t, hrtime_t);
|
||||||
extern void fmd_serd_destroy(fmd_hdl_t *, const char *);
|
extern void fmd_serd_destroy(fmd_hdl_t *, const char *);
|
||||||
extern int fmd_serd_exists(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 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_record(fmd_hdl_t *, const char *, fmd_event_t *);
|
||||||
extern int fmd_serd_fired(fmd_hdl_t *, const char *);
|
extern int fmd_serd_fired(fmd_hdl_t *, const char *);
|
||||||
extern int fmd_serd_empty(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 id_t fmd_timer_install(fmd_hdl_t *, void *, fmd_event_t *, hrtime_t);
|
||||||
extern void fmd_timer_remove(fmd_hdl_t *, id_t);
|
extern void fmd_timer_remove(fmd_hdl_t *, id_t);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -8,7 +7,7 @@
|
|||||||
* with the License.
|
* with the License.
|
||||||
*
|
*
|
||||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -30,7 +29,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <strings.h>
|
||||||
#include <sys/list.h>
|
#include <sys/list.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
@@ -75,18 +74,9 @@ fmd_serd_eng_alloc(const char *name, uint64_t n, hrtime_t t)
|
|||||||
fmd_serd_eng_t *sgp;
|
fmd_serd_eng_t *sgp;
|
||||||
|
|
||||||
sgp = malloc(sizeof (fmd_serd_eng_t));
|
sgp = malloc(sizeof (fmd_serd_eng_t));
|
||||||
if (sgp == NULL) {
|
bzero(sgp, sizeof (fmd_serd_eng_t));
|
||||||
perror("malloc");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
memset(sgp, 0, sizeof (fmd_serd_eng_t));
|
|
||||||
|
|
||||||
sgp->sg_name = strdup(name);
|
sgp->sg_name = strdup(name);
|
||||||
if (sgp->sg_name == NULL) {
|
|
||||||
perror("strdup");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
sgp->sg_flags = FMD_SERD_DIRTY;
|
sgp->sg_flags = FMD_SERD_DIRTY;
|
||||||
sgp->sg_n = n;
|
sgp->sg_n = n;
|
||||||
sgp->sg_t = t;
|
sgp->sg_t = t;
|
||||||
@@ -133,12 +123,6 @@ fmd_serd_hash_create(fmd_serd_hash_t *shp)
|
|||||||
shp->sh_hashlen = FMD_STR_BUCKETS;
|
shp->sh_hashlen = FMD_STR_BUCKETS;
|
||||||
shp->sh_hash = calloc(shp->sh_hashlen, sizeof (void *));
|
shp->sh_hash = calloc(shp->sh_hashlen, sizeof (void *));
|
||||||
shp->sh_count = 0;
|
shp->sh_count = 0;
|
||||||
|
|
||||||
if (shp->sh_hash == NULL) {
|
|
||||||
perror("calloc");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -155,7 +139,7 @@ fmd_serd_hash_destroy(fmd_serd_hash_t *shp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
free(shp->sh_hash);
|
free(shp->sh_hash);
|
||||||
memset(shp, 0, sizeof (fmd_serd_hash_t));
|
bzero(shp, sizeof (fmd_serd_hash_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -250,17 +234,13 @@ fmd_serd_eng_record(fmd_serd_eng_t *sgp, hrtime_t hrt)
|
|||||||
if (sgp->sg_flags & FMD_SERD_FIRED) {
|
if (sgp->sg_flags & FMD_SERD_FIRED) {
|
||||||
serd_log_msg(" SERD Engine: record %s already fired!",
|
serd_log_msg(" SERD Engine: record %s already fired!",
|
||||||
sgp->sg_name);
|
sgp->sg_name);
|
||||||
return (B_FALSE);
|
return (FMD_B_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (sgp->sg_count >= sgp->sg_n)
|
while (sgp->sg_count >= sgp->sg_n)
|
||||||
fmd_serd_eng_discard(sgp, list_tail(&sgp->sg_list));
|
fmd_serd_eng_discard(sgp, list_tail(&sgp->sg_list));
|
||||||
|
|
||||||
sep = malloc(sizeof (fmd_serd_elem_t));
|
sep = malloc(sizeof (fmd_serd_elem_t));
|
||||||
if (sep == NULL) {
|
|
||||||
perror("malloc");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
sep->se_hrt = hrt;
|
sep->se_hrt = hrt;
|
||||||
|
|
||||||
list_insert_head(&sgp->sg_list, sep);
|
list_insert_head(&sgp->sg_list, sep);
|
||||||
@@ -279,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) {
|
fmd_event_delta(oep->se_hrt, sep->se_hrt) <= sgp->sg_t) {
|
||||||
sgp->sg_flags |= FMD_SERD_FIRED | FMD_SERD_DIRTY;
|
sgp->sg_flags |= FMD_SERD_FIRED | FMD_SERD_DIRTY;
|
||||||
serd_log_msg(" SERD Engine: fired %s", sgp->sg_name);
|
serd_log_msg(" SERD Engine: fired %s", sgp->sg_name);
|
||||||
return (B_TRUE);
|
return (FMD_B_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
sgp->sg_flags |= FMD_SERD_DIRTY;
|
sgp->sg_flags |= FMD_SERD_DIRTY;
|
||||||
return (B_FALSE);
|
return (FMD_B_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -301,7 +281,7 @@ fmd_serd_eng_empty(fmd_serd_eng_t *sgp)
|
|||||||
void
|
void
|
||||||
fmd_serd_eng_reset(fmd_serd_eng_t *sgp)
|
fmd_serd_eng_reset(fmd_serd_eng_t *sgp)
|
||||||
{
|
{
|
||||||
serd_log_msg(" SERD Engine: resetting %s", sgp->sg_name);
|
serd_log_msg(" SERD Engine: reseting %s", sgp->sg_name);
|
||||||
|
|
||||||
while (sgp->sg_count != 0)
|
while (sgp->sg_count != 0)
|
||||||
fmd_serd_eng_discard(sgp, list_head(&sgp->sg_list));
|
fmd_serd_eng_discard(sgp, list_head(&sgp->sg_list));
|
||||||
@@ -311,9 +291,8 @@ fmd_serd_eng_reset(fmd_serd_eng_t *sgp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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;
|
fmd_serd_elem_t *sep, *nep;
|
||||||
hrtime_t hrt;
|
hrtime_t hrt;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -8,7 +7,7 @@
|
|||||||
* with the License.
|
* with the License.
|
||||||
*
|
*
|
||||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -78,7 +77,7 @@ extern int fmd_serd_eng_fired(fmd_serd_eng_t *);
|
|||||||
extern int fmd_serd_eng_empty(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_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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
+60
-153
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -13,8 +12,6 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Intel Corporation.
|
* Copyright (c) 2016, Intel Corporation.
|
||||||
* Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>
|
|
||||||
* Copyright (c) 2021 Hewlett Packard Enterprise Development LP
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libnvpair.h>
|
#include <libnvpair.h>
|
||||||
@@ -56,97 +53,38 @@ pthread_t g_agents_tid;
|
|||||||
libzfs_handle_t *g_zfs_hdl;
|
libzfs_handle_t *g_zfs_hdl;
|
||||||
|
|
||||||
/* guid search data */
|
/* guid search data */
|
||||||
typedef enum device_type {
|
|
||||||
DEVICE_TYPE_L2ARC, /* l2arc device */
|
|
||||||
DEVICE_TYPE_SPARE, /* spare device */
|
|
||||||
DEVICE_TYPE_PRIMARY /* any primary pool storage device */
|
|
||||||
} device_type_t;
|
|
||||||
|
|
||||||
typedef struct guid_search {
|
typedef struct guid_search {
|
||||||
uint64_t gs_pool_guid;
|
uint64_t gs_pool_guid;
|
||||||
uint64_t gs_vdev_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;
|
} guid_search_t;
|
||||||
|
|
||||||
/*
|
static void
|
||||||
* Walks the vdev tree recursively looking for a matching devid.
|
|
||||||
* Returns B_TRUE as soon as a matching device is found, B_FALSE otherwise.
|
|
||||||
*/
|
|
||||||
static boolean_t
|
|
||||||
zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
|
zfs_agent_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *arg)
|
||||||
{
|
{
|
||||||
guid_search_t *gsp = arg;
|
guid_search_t *gsp = arg;
|
||||||
const char *path = NULL;
|
char *path = NULL;
|
||||||
uint_t c, children;
|
uint_t c, children;
|
||||||
nvlist_t **child;
|
nvlist_t **child;
|
||||||
uint64_t vdev_guid;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First iterate over any children.
|
* First iterate over any children.
|
||||||
*/
|
*/
|
||||||
if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
|
if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
|
||||||
&child, &children) == 0) {
|
&child, &children) == 0) {
|
||||||
for (c = 0; c < children; c++) {
|
for (c = 0; c < children; c++)
|
||||||
if (zfs_agent_iter_vdev(zhp, child[c], gsp)) {
|
zfs_agent_iter_vdev(zhp, child[c], gsp);
|
||||||
gsp->gs_vdev_type = DEVICE_TYPE_PRIMARY;
|
return;
|
||||||
return (B_TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Iterate over any spares and cache devices
|
* On a devid match, grab the vdev guid
|
||||||
*/
|
*/
|
||||||
if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_SPARES,
|
if ((gsp->gs_vdev_guid == 0) &&
|
||||||
&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;
|
|
||||||
return (B_TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_L2CACHE,
|
|
||||||
&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;
|
|
||||||
return (B_TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* On a devid match, grab the vdev guid and expansion time, if any.
|
|
||||||
*/
|
|
||||||
if (gsp->gs_devid != NULL &&
|
|
||||||
(nvlist_lookup_string(nvl, ZPOOL_CONFIG_DEVID, &path) == 0) &&
|
(nvlist_lookup_string(nvl, ZPOOL_CONFIG_DEVID, &path) == 0) &&
|
||||||
(strcmp(gsp->gs_devid, path) == 0)) {
|
(strcmp(gsp->gs_devid, path) == 0)) {
|
||||||
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID,
|
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID,
|
||||||
&gsp->gs_vdev_guid);
|
&gsp->gs_vdev_guid);
|
||||||
(void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_EXPANSION_TIME,
|
|
||||||
&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 &&
|
|
||||||
nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, &vdev_guid) == 0 &&
|
|
||||||
gsp->gs_vdev_guid == vdev_guid) {
|
|
||||||
if (gsp->gs_devid == NULL) {
|
|
||||||
(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -158,28 +96,22 @@ zfs_agent_iter_pool(zpool_handle_t *zhp, void *arg)
|
|||||||
/*
|
/*
|
||||||
* For each vdev in this pool, look for a match by devid
|
* For each vdev in this pool, look for a match by devid
|
||||||
*/
|
*/
|
||||||
boolean_t found = B_FALSE;
|
if ((config = zpool_get_config(zhp, NULL)) != NULL) {
|
||||||
uint64_t pool_guid;
|
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||||
|
&nvl) == 0) {
|
||||||
|
zfs_agent_iter_vdev(zhp, nvl, gsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* if a match was found then grab the pool guid
|
||||||
|
*/
|
||||||
|
if (gsp->gs_vdev_guid) {
|
||||||
|
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
|
||||||
|
&gsp->gs_pool_guid);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get pool configuration and extract pool GUID */
|
|
||||||
if ((config = zpool_get_config(zhp, NULL)) == NULL ||
|
|
||||||
nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
|
|
||||||
&pool_guid) != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Skip this pool if we're looking for a specific pool */
|
|
||||||
if (gsp->gs_pool_guid != 0 && pool_guid != gsp->gs_pool_guid)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvl) == 0)
|
|
||||||
found = zfs_agent_iter_vdev(zhp, nvl, gsp);
|
|
||||||
|
|
||||||
if (found && gsp->gs_pool_guid == 0)
|
|
||||||
gsp->gs_pool_guid = pool_guid;
|
|
||||||
|
|
||||||
out:
|
|
||||||
zpool_close(zhp);
|
zpool_close(zhp);
|
||||||
return (found);
|
return (gsp->gs_vdev_guid != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -203,12 +135,10 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On Linux, we don't get the expected FM_RESOURCE_REMOVED ereport
|
* On ZFS on Linux, we don't get the expected FM_RESOURCE_REMOVED
|
||||||
* from the vdev_disk layer after a hot unplug. Fortunately we do
|
* ereport from vdev_disk layer after a hot unplug. Fortunately we
|
||||||
* get an EC_DEV_REMOVE from our disk monitor and it is a suitable
|
* get a EC_DEV_REMOVE from our disk monitor and it is a suitable
|
||||||
* proxy so we remap it here for the benefit of the diagnosis engine.
|
* proxy so we remap it here for the benefit of the diagnosis engine.
|
||||||
* Starting in OpenZFS 2.0, we do get FM_RESOURCE_REMOVED from the spa
|
|
||||||
* layer. Processing multiple FM_RESOURCE_REMOVED events is not harmful.
|
|
||||||
*/
|
*/
|
||||||
if ((strcmp(class, EC_DEV_REMOVE) == 0) &&
|
if ((strcmp(class, EC_DEV_REMOVE) == 0) &&
|
||||||
(strcmp(subclass, ESC_DISK) == 0) &&
|
(strcmp(subclass, ESC_DISK) == 0) &&
|
||||||
@@ -218,76 +148,38 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
|
|||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
int64_t tod[2];
|
int64_t tod[2];
|
||||||
uint64_t pool_guid = 0, vdev_guid = 0;
|
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";
|
class = "resource.fs.zfs.removed";
|
||||||
subclass = "";
|
subclass = "";
|
||||||
|
|
||||||
(void) nvlist_add_string(payload, FM_CLASS, class);
|
(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_POOL_GUID, &pool_guid);
|
||||||
(void) nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &vdev_guid);
|
(void) nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &vdev_guid);
|
||||||
|
|
||||||
(void) gettimeofday(&tv, NULL);
|
|
||||||
tod[0] = tv.tv_sec;
|
|
||||||
tod[1] = tv.tv_usec;
|
|
||||||
(void) nvlist_add_int64_array(payload, FM_EREPORT_TIME, tod, 2);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If devid is missing but vdev_guid is available, find devid
|
* For multipath, ZFS_EV_VDEV_GUID is missing so find it.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
search.gs_devid = devid;
|
if (vdev_guid == 0) {
|
||||||
search.gs_vdev_guid = vdev_guid;
|
guid_search_t search = { 0 };
|
||||||
search.gs_pool_guid = pool_guid;
|
|
||||||
zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search);
|
(void) nvlist_lookup_string(nvl, DEV_IDENTIFIER,
|
||||||
if (devid == NULL)
|
&search.gs_devid);
|
||||||
devid = search.gs_devid;
|
|
||||||
if (pool_guid == 0)
|
(void) zpool_iter(g_zfs_hdl, zfs_agent_iter_pool,
|
||||||
|
&search);
|
||||||
pool_guid = search.gs_pool_guid;
|
pool_guid = search.gs_pool_guid;
|
||||||
if (vdev_guid == 0)
|
|
||||||
vdev_guid = search.gs_vdev_guid;
|
vdev_guid = search.gs_vdev_guid;
|
||||||
devtype = search.gs_vdev_type;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We want to avoid reporting "remove" events coming from
|
|
||||||
* libudev for VDEVs which were expanded recently (10s) and
|
|
||||||
* avoid activating spares in response to partitions being
|
|
||||||
* deleted and created in rapid succession.
|
|
||||||
*/
|
|
||||||
if (search.gs_vdev_expandtime != 0 &&
|
|
||||||
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);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) nvlist_add_uint64(payload,
|
(void) nvlist_add_uint64(payload,
|
||||||
FM_EREPORT_PAYLOAD_ZFS_POOL_GUID, pool_guid);
|
FM_EREPORT_PAYLOAD_ZFS_POOL_GUID, pool_guid);
|
||||||
(void) nvlist_add_uint64(payload,
|
(void) nvlist_add_uint64(payload,
|
||||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, vdev_guid);
|
FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, vdev_guid);
|
||||||
switch (devtype) {
|
|
||||||
case DEVICE_TYPE_L2ARC:
|
(void) gettimeofday(&tv, NULL);
|
||||||
(void) nvlist_add_string(payload,
|
tod[0] = tv.tv_sec;
|
||||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE,
|
tod[1] = tv.tv_usec;
|
||||||
VDEV_TYPE_L2CACHE);
|
(void) nvlist_add_int64_array(payload, FM_EREPORT_TIME, tod, 2);
|
||||||
break;
|
|
||||||
case DEVICE_TYPE_SPARE:
|
|
||||||
(void) nvlist_add_string(payload,
|
|
||||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE, VDEV_TYPE_SPARE);
|
|
||||||
break;
|
|
||||||
case DEVICE_TYPE_PRIMARY:
|
|
||||||
(void) nvlist_add_string(payload,
|
|
||||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE, VDEV_TYPE_DISK);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
zed_log_msg(LOG_INFO, "agent post event: mapping '%s' to '%s'",
|
zed_log_msg(LOG_INFO, "agent post event: mapping '%s' to '%s'",
|
||||||
EC_DEV_REMOVE, class);
|
EC_DEV_REMOVE, class);
|
||||||
@@ -301,7 +193,6 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
|
|||||||
list_insert_tail(&agent_events, event);
|
list_insert_tail(&agent_events, event);
|
||||||
(void) pthread_mutex_unlock(&agent_lock);
|
(void) pthread_mutex_unlock(&agent_lock);
|
||||||
|
|
||||||
out:
|
|
||||||
(void) pthread_cond_signal(&agent_cond);
|
(void) pthread_cond_signal(&agent_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,8 +248,6 @@ zfs_agent_dispatch(const char *class, const char *subclass, nvlist_t *nvl)
|
|||||||
static void *
|
static void *
|
||||||
zfs_agent_consumer_thread(void *arg)
|
zfs_agent_consumer_thread(void *arg)
|
||||||
{
|
{
|
||||||
(void) arg;
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
agent_event_t *event;
|
agent_event_t *event;
|
||||||
|
|
||||||
@@ -375,7 +264,9 @@ zfs_agent_consumer_thread(void *arg)
|
|||||||
return (NULL);
|
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);
|
(void) pthread_mutex_unlock(&agent_lock);
|
||||||
|
|
||||||
/* dispatch to all event subscribers */
|
/* dispatch to all event subscribers */
|
||||||
@@ -422,7 +313,6 @@ zfs_agent_init(libzfs_handle_t *zfs_hdl)
|
|||||||
list_destroy(&agent_events);
|
list_destroy(&agent_events);
|
||||||
zed_log_die("Failed to initialize agents");
|
zed_log_die("Failed to initialize agents");
|
||||||
}
|
}
|
||||||
pthread_setname_np(g_agents_tid, "agents");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -438,7 +328,8 @@ zfs_agent_fini(void)
|
|||||||
(void) pthread_join(g_agents_tid, NULL);
|
(void) pthread_join(g_agents_tid, NULL);
|
||||||
|
|
||||||
/* drain any pending events */
|
/* 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);
|
nvlist_free(event->ae_nvl);
|
||||||
free(event);
|
free(event);
|
||||||
}
|
}
|
||||||
@@ -459,3 +350,19 @@ zfs_agent_fini(void)
|
|||||||
|
|
||||||
g_zfs_hdl = NULL;
|
g_zfs_hdl = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In ZED context, all the FMA agents run in the same thread
|
||||||
|
* and do not require a unique libzfs instance. Modules should
|
||||||
|
* use these stubs.
|
||||||
|
*/
|
||||||
|
libzfs_handle_t *
|
||||||
|
__libzfs_init(void)
|
||||||
|
{
|
||||||
|
return (g_zfs_hdl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__libzfs_fini(libzfs_handle_t *hdl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -40,6 +39,13 @@ extern int zfs_slm_init(void);
|
|||||||
extern void zfs_slm_fini(void);
|
extern void zfs_slm_fini(void);
|
||||||
extern void zfs_slm_event(const char *, const char *, nvlist_t *);
|
extern void zfs_slm_event(const char *, const char *, nvlist_t *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In ZED context, all the FMA agents run in the same thread
|
||||||
|
* and do not require a unique libzfs instance.
|
||||||
|
*/
|
||||||
|
extern libzfs_handle_t *__libzfs_init(void);
|
||||||
|
extern void __libzfs_fini(libzfs_handle_t *);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+131
-261
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -7,7 +6,7 @@
|
|||||||
* You may not use this file except in compliance with the License.
|
* 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
|
* 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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -24,11 +23,10 @@
|
|||||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
|
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
|
||||||
* Copyright (c) 2016, Intel Corporation.
|
* Copyright (c) 2016, Intel Corporation.
|
||||||
* Copyright (c) 2023, Klara Inc.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <strings.h>
|
||||||
#include <libuutil.h>
|
#include <libuutil.h>
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@@ -36,29 +34,14 @@
|
|||||||
#include <sys/fs/zfs.h>
|
#include <sys/fs/zfs.h>
|
||||||
#include <sys/fm/protocol.h>
|
#include <sys/fm/protocol.h>
|
||||||
#include <sys/fm/fs/zfs.h>
|
#include <sys/fm/fs/zfs.h>
|
||||||
#include <sys/zio.h>
|
|
||||||
|
|
||||||
#include "zfs_agents.h"
|
#include "zfs_agents.h"
|
||||||
#include "fmd_api.h"
|
#include "fmd_api.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default values for the serd engine when processing checksum or io errors. The
|
* Our serd engines are named 'zfs_<pool_guid>_<vdev_guid>_{checksum,io}'. This
|
||||||
* semantics are N <events> in T <seconds>.
|
* #define reserves enough space for two 64-bit hex values plus the length of
|
||||||
*/
|
* the longest string.
|
||||||
#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.
|
|
||||||
*/
|
*/
|
||||||
#define MAX_SERDLEN (16 * 2 + sizeof ("zfs___checksum"))
|
#define MAX_SERDLEN (16 * 2 + sizeof ("zfs___checksum"))
|
||||||
|
|
||||||
@@ -72,11 +55,9 @@ typedef struct zfs_case_data {
|
|||||||
uint64_t zc_ena;
|
uint64_t zc_ena;
|
||||||
uint64_t zc_pool_guid;
|
uint64_t zc_pool_guid;
|
||||||
uint64_t zc_vdev_guid;
|
uint64_t zc_vdev_guid;
|
||||||
uint64_t zc_parent_guid;
|
|
||||||
int zc_pool_state;
|
int zc_pool_state;
|
||||||
char zc_serd_checksum[MAX_SERDLEN];
|
char zc_serd_checksum[MAX_SERDLEN];
|
||||||
char zc_serd_io[MAX_SERDLEN];
|
char zc_serd_io[MAX_SERDLEN];
|
||||||
char zc_serd_slow_io[MAX_SERDLEN];
|
|
||||||
int zc_has_remove_timer;
|
int zc_has_remove_timer;
|
||||||
} zfs_case_data_t;
|
} zfs_case_data_t;
|
||||||
|
|
||||||
@@ -123,8 +104,7 @@ zfs_de_stats_t zfs_stats = {
|
|||||||
{ "resource_drops", FMD_TYPE_UINT64, "resource related ereports" }
|
{ "resource_drops", FMD_TYPE_UINT64, "resource related ereports" }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* wait 15 seconds after a removal */
|
static hrtime_t zfs_remove_timeout;
|
||||||
static hrtime_t zfs_remove_timeout = SEC2NSEC(15);
|
|
||||||
|
|
||||||
uu_list_pool_t *zfs_case_pool;
|
uu_list_pool_t *zfs_case_pool;
|
||||||
uu_list_t *zfs_cases;
|
uu_list_t *zfs_cases;
|
||||||
@@ -134,13 +114,11 @@ uu_list_t *zfs_cases;
|
|||||||
#define ZFS_MAKE_EREPORT(type) \
|
#define ZFS_MAKE_EREPORT(type) \
|
||||||
FM_EREPORT_CLASS "." ZFS_ERROR_CLASS "." 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.
|
* Write out the persistent representation of an active case.
|
||||||
*/
|
*/
|
||||||
static void
|
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;
|
zcp->zc_data.zc_version = CASE_DATA_VERSION_SERD;
|
||||||
}
|
}
|
||||||
@@ -182,64 +160,6 @@ zfs_case_unserialize(fmd_hdl_t *hdl, fmd_case_t *cp)
|
|||||||
return (zcp);
|
return (zcp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Return count of other unique SERD cases under same vdev parent
|
|
||||||
*/
|
|
||||||
static uint_t
|
|
||||||
zfs_other_serd_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)) {
|
|
||||||
zfs_case_data_t *zcd = &zcp->zc_data;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* must be same pool and parent vdev but different leaf vdev
|
|
||||||
*/
|
|
||||||
if (zcd->zc_pool_guid != zfs_case->zc_pool_guid ||
|
|
||||||
zcd->zc_parent_guid != zfs_case->zc_parent_guid ||
|
|
||||||
zcd->zc_vdev_guid == zfs_case->zc_vdev_guid) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if there is another active serd case besides zfs_case
|
|
||||||
*
|
|
||||||
* Only one serd engine will be assigned to the case
|
|
||||||
*/
|
|
||||||
if (zcd->zc_serd_checksum[0] == zfs_case->zc_serd_checksum[0] &&
|
|
||||||
fmd_serd_active(hdl, zcd->zc_serd_checksum)) {
|
|
||||||
cases++;
|
|
||||||
}
|
|
||||||
if (zcd->zc_serd_io[0] == zfs_case->zc_serd_io[0] &&
|
|
||||||
fmd_serd_active(hdl, zcd->zc_serd_io)) {
|
|
||||||
cases++;
|
|
||||||
}
|
|
||||||
if (zcd->zc_serd_slow_io[0] == zfs_case->zc_serd_slow_io[0] &&
|
|
||||||
fmd_serd_active(hdl, zcd->zc_serd_slow_io)) {
|
|
||||||
cases++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (cases);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterate over any active cases. If any cases are associated with a pool or
|
* 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.
|
* vdev which is no longer present on the system, close the associated case.
|
||||||
@@ -247,12 +167,14 @@ zfs_other_serd_cases(fmd_hdl_t *hdl, const zfs_case_data_t *zfs_case)
|
|||||||
static void
|
static void
|
||||||
zfs_mark_vdev(uint64_t pool_guid, nvlist_t *vd, er_timeval_t *loaded)
|
zfs_mark_vdev(uint64_t pool_guid, nvlist_t *vd, er_timeval_t *loaded)
|
||||||
{
|
{
|
||||||
uint64_t vdev_guid = 0;
|
uint64_t vdev_guid;
|
||||||
uint_t c, children;
|
uint_t c, children;
|
||||||
nvlist_t **child;
|
nvlist_t **child;
|
||||||
zfs_case_t *zcp;
|
zfs_case_t *zcp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
(void) nvlist_lookup_uint64(vd, ZPOOL_CONFIG_GUID, &vdev_guid);
|
ret = nvlist_lookup_uint64(vd, ZPOOL_CONFIG_GUID, &vdev_guid);
|
||||||
|
assert(ret == 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark any cases associated with this (pool, vdev) pair.
|
* Mark any cases associated with this (pool, vdev) pair.
|
||||||
@@ -288,10 +210,10 @@ zfs_mark_vdev(uint64_t pool_guid, nvlist_t *vd, er_timeval_t *loaded)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
static int
|
static int
|
||||||
zfs_mark_pool(zpool_handle_t *zhp, void *unused)
|
zfs_mark_pool(zpool_handle_t *zhp, void *unused)
|
||||||
{
|
{
|
||||||
(void) unused;
|
|
||||||
zfs_case_t *zcp;
|
zfs_case_t *zcp;
|
||||||
uint64_t pool_guid;
|
uint64_t pool_guid;
|
||||||
uint64_t *tod;
|
uint64_t *tod;
|
||||||
@@ -331,10 +253,7 @@ zfs_mark_pool(zpool_handle_t *zhp, void *unused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &vd);
|
ret = nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &vd);
|
||||||
if (ret) {
|
assert(ret == 0);
|
||||||
zpool_close(zhp);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
zfs_mark_vdev(pool_guid, vd, &loaded);
|
zfs_mark_vdev(pool_guid, vd, &loaded);
|
||||||
|
|
||||||
@@ -446,25 +365,23 @@ zfs_serd_name(char *buf, uint64_t pool_guid, uint64_t vdev_guid,
|
|||||||
(long long unsigned int)vdev_guid, type);
|
(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
|
* 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
|
* still valid, as well as cleaning up any pending timer associated with the
|
||||||
* case.
|
* case.
|
||||||
*/
|
*/
|
||||||
static void
|
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;
|
nvlist_t *detector, *fault;
|
||||||
boolean_t serialize;
|
boolean_t serialize;
|
||||||
nvlist_t *fru = NULL;
|
nvlist_t *fru = NULL;
|
||||||
|
#ifdef HAVE_LIBTOPO
|
||||||
|
nvlist_t *fmri;
|
||||||
|
topo_hdl_t *thp;
|
||||||
|
int err;
|
||||||
|
#endif
|
||||||
fmd_hdl_debug(hdl, "solving fault '%s'", faultname);
|
fmd_hdl_debug(hdl, "solving fault '%s'", faultname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -483,6 +400,64 @@ zfs_case_solve(fmd_hdl_t *hdl, zfs_case_t *zcp, const char *faultname)
|
|||||||
zcp->zc_data.zc_vdev_guid);
|
zcp->zc_data.zc_vdev_guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBTOPO
|
||||||
|
/*
|
||||||
|
* We also want to make sure that the detector (pool or vdev) properly
|
||||||
|
* reflects the diagnosed state, when the fault corresponds to internal
|
||||||
|
* ZFS state (i.e. not checksum or I/O error-induced). Otherwise, a
|
||||||
|
* device which was unavailable early in boot (because the driver/file
|
||||||
|
* wasn't available) and is now healthy will be mis-diagnosed.
|
||||||
|
*/
|
||||||
|
if (!fmd_nvl_fmri_present(hdl, detector) ||
|
||||||
|
(checkunusable && !fmd_nvl_fmri_unusable(hdl, detector))) {
|
||||||
|
fmd_case_close(hdl, zcp->zc_case);
|
||||||
|
nvlist_free(detector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fru = NULL;
|
||||||
|
if (zcp->zc_fru != NULL &&
|
||||||
|
(thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) != NULL) {
|
||||||
|
/*
|
||||||
|
* If the vdev had an associated FRU, then get the FRU nvlist
|
||||||
|
* from the topo handle and use that in the suspect list. We
|
||||||
|
* explicitly lookup the FRU because the fmri reported from the
|
||||||
|
* kernel may not have up to date details about the disk itself
|
||||||
|
* (serial, part, etc).
|
||||||
|
*/
|
||||||
|
if (topo_fmri_str2nvl(thp, zcp->zc_fru, &fmri, &err) == 0) {
|
||||||
|
libzfs_handle_t *zhdl = fmd_hdl_getspecific(hdl);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the disk is part of the system chassis, but the
|
||||||
|
* FRU indicates a different chassis ID than our
|
||||||
|
* current system, then ignore the error. This
|
||||||
|
* indicates that the device was part of another
|
||||||
|
* cluster head, and for obvious reasons cannot be
|
||||||
|
* imported on this system.
|
||||||
|
*/
|
||||||
|
if (libzfs_fru_notself(zhdl, zcp->zc_fru)) {
|
||||||
|
fmd_case_close(hdl, zcp->zc_case);
|
||||||
|
nvlist_free(fmri);
|
||||||
|
fmd_hdl_topo_rele(hdl, thp);
|
||||||
|
nvlist_free(detector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the device is no longer present on the system, or
|
||||||
|
* topo_fmri_fru() fails for other reasons, then fall
|
||||||
|
* back to the fmri specified in the vdev.
|
||||||
|
*/
|
||||||
|
if (topo_fmri_fru(thp, fmri, &fru, &err) != 0)
|
||||||
|
fru = fmd_nvl_dup(hdl, fmri, FMD_SLEEP);
|
||||||
|
nvlist_free(fmri);
|
||||||
|
}
|
||||||
|
|
||||||
|
fmd_hdl_topo_rele(hdl, thp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
fault = fmd_nvl_create_fault(hdl, faultname, 100, detector,
|
fault = fmd_nvl_create_fault(hdl, faultname, 100, detector,
|
||||||
fru, detector);
|
fru, detector);
|
||||||
fmd_case_add_suspect(hdl, zcp->zc_case, fault);
|
fmd_case_add_suspect(hdl, zcp->zc_case, fault);
|
||||||
@@ -498,7 +473,7 @@ zfs_case_solve(fmd_hdl_t *hdl, zfs_case_t *zcp, const char *faultname)
|
|||||||
serialize = B_TRUE;
|
serialize = B_TRUE;
|
||||||
}
|
}
|
||||||
if (serialize)
|
if (serialize)
|
||||||
zfs_case_serialize(zcp);
|
zfs_case_serialize(hdl, zcp);
|
||||||
|
|
||||||
nvlist_free(detector);
|
nvlist_free(detector);
|
||||||
}
|
}
|
||||||
@@ -510,10 +485,10 @@ timeval_earlier(er_timeval_t *a, er_timeval_t *b)
|
|||||||
(a->ertv_sec == b->ertv_sec && a->ertv_nsec < b->ertv_nsec));
|
(a->ertv_sec == b->ertv_sec && a->ertv_nsec < b->ertv_nsec));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
static void
|
static void
|
||||||
zfs_ereport_when(fmd_hdl_t *hdl, nvlist_t *nvl, er_timeval_t *when)
|
zfs_ereport_when(fmd_hdl_t *hdl, nvlist_t *nvl, er_timeval_t *when)
|
||||||
{
|
{
|
||||||
(void) hdl;
|
|
||||||
int64_t *tod;
|
int64_t *tod;
|
||||||
uint_t nelem;
|
uint_t nelem;
|
||||||
|
|
||||||
@@ -526,51 +501,22 @@ zfs_ereport_when(fmd_hdl_t *hdl, nvlist_t *nvl, er_timeval_t *when)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Record the specified event in the SERD engine and return a
|
|
||||||
* boolean value indicating whether or not the engine fired as
|
|
||||||
* the result of inserting this event.
|
|
||||||
*
|
|
||||||
* When the pool has similar active cases on other vdevs, then
|
|
||||||
* the fired state is disregarded and the case is retired.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
zfs_fm_serd_record(fmd_hdl_t *hdl, const char *name, fmd_event_t *ep,
|
|
||||||
zfs_case_t *zcp, const char *err_type)
|
|
||||||
{
|
|
||||||
int fired = fmd_serd_record(hdl, name, ep);
|
|
||||||
int peers = 0;
|
|
||||||
|
|
||||||
if (fired && (peers = zfs_other_serd_cases(hdl, &zcp->zc_data)) > 0) {
|
|
||||||
fmd_hdl_debug(hdl, "pool %llu is tracking %d other %s cases "
|
|
||||||
"-- skip faulting the vdev %llu",
|
|
||||||
(u_longlong_t)zcp->zc_data.zc_pool_guid,
|
|
||||||
peers, err_type,
|
|
||||||
(u_longlong_t)zcp->zc_data.zc_vdev_guid);
|
|
||||||
zfs_case_retire(hdl, zcp);
|
|
||||||
fired = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (fired);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main fmd entry point.
|
* Main fmd entry point.
|
||||||
*/
|
*/
|
||||||
|
/*ARGSUSED*/
|
||||||
static void
|
static void
|
||||||
zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
||||||
{
|
{
|
||||||
zfs_case_t *zcp, *dcp;
|
zfs_case_t *zcp, *dcp;
|
||||||
int32_t pool_state;
|
int32_t pool_state;
|
||||||
uint64_t ena, pool_guid, vdev_guid, parent_guid;
|
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 pool_load;
|
||||||
er_timeval_t er_when;
|
er_timeval_t er_when;
|
||||||
nvlist_t *detector;
|
nvlist_t *detector;
|
||||||
boolean_t pool_found = B_FALSE;
|
boolean_t pool_found = B_FALSE;
|
||||||
boolean_t isresource;
|
boolean_t isresource;
|
||||||
const char *type;
|
char *type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We subscribe to notifications for vdev or pool removal. In these
|
* We subscribe to notifications for vdev or pool removal. In these
|
||||||
@@ -652,9 +598,6 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
|||||||
if (nvlist_lookup_uint64(nvl,
|
if (nvlist_lookup_uint64(nvl,
|
||||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, &vdev_guid) != 0)
|
FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, &vdev_guid) != 0)
|
||||||
vdev_guid = 0;
|
vdev_guid = 0;
|
||||||
if (nvlist_lookup_uint64(nvl,
|
|
||||||
FM_EREPORT_PAYLOAD_ZFS_PARENT_GUID, &parent_guid) != 0)
|
|
||||||
parent_guid = 0;
|
|
||||||
if (nvlist_lookup_uint64(nvl, FM_EREPORT_ENA, &ena) != 0)
|
if (nvlist_lookup_uint64(nvl, FM_EREPORT_ENA, &ena) != 0)
|
||||||
ena = 0;
|
ena = 0;
|
||||||
|
|
||||||
@@ -741,7 +684,9 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
|||||||
if (strcmp(class,
|
if (strcmp(class,
|
||||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_DATA)) == 0 ||
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_DATA)) == 0 ||
|
||||||
strcmp(class,
|
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++;
|
zfs_stats.resource_drops.fmds_value.ui64++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -765,7 +710,6 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
|||||||
data.zc_ena = ena;
|
data.zc_ena = ena;
|
||||||
data.zc_pool_guid = pool_guid;
|
data.zc_pool_guid = pool_guid;
|
||||||
data.zc_vdev_guid = vdev_guid;
|
data.zc_vdev_guid = vdev_guid;
|
||||||
data.zc_parent_guid = parent_guid;
|
|
||||||
data.zc_pool_state = (int)pool_state;
|
data.zc_pool_state = (int)pool_state;
|
||||||
|
|
||||||
fmd_buf_write(hdl, cs, CASE_DATA, &data, sizeof (data));
|
fmd_buf_write(hdl, cs, CASE_DATA, &data, sizeof (data));
|
||||||
@@ -803,16 +747,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) {
|
if (zcp->zc_data.zc_has_remove_timer) {
|
||||||
fmd_timer_remove(hdl, zcp->zc_remove_timer);
|
fmd_timer_remove(hdl, zcp->zc_remove_timer);
|
||||||
zcp->zc_data.zc_has_remove_timer = 0;
|
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')
|
if (zcp->zc_data.zc_serd_io[0] != '\0')
|
||||||
fmd_serd_reset(hdl, zcp->zc_data.zc_serd_io);
|
fmd_serd_reset(hdl, zcp->zc_data.zc_serd_io);
|
||||||
if (zcp->zc_data.zc_serd_checksum[0] != '\0')
|
if (zcp->zc_data.zc_serd_checksum[0] != '\0')
|
||||||
fmd_serd_reset(hdl,
|
fmd_serd_reset(hdl,
|
||||||
zcp->zc_data.zc_serd_checksum);
|
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,
|
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||||
ZFS_MAKE_RSRC(FM_RESOURCE_STATECHANGE))) {
|
ZFS_MAKE_RSRC(FM_RESOURCE_STATECHANGE))) {
|
||||||
uint64_t state = 0;
|
uint64_t state = 0;
|
||||||
@@ -841,11 +782,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))
|
if (fmd_case_solved(hdl, zcp->zc_case))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (vdev_guid)
|
fmd_hdl_debug(hdl, "error event '%s'", class);
|
||||||
fmd_hdl_debug(hdl, "error event '%s', vdev %llu", class,
|
|
||||||
vdev_guid);
|
|
||||||
else
|
|
||||||
fmd_hdl_debug(hdl, "error event '%s'", class);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine if we should solve the case and generate a fault. We solve
|
* Determine if we should solve the case and generate a fault. We solve
|
||||||
@@ -875,18 +812,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);
|
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,
|
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_LOG_REPLAY))) {
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_LOG_REPLAY))) {
|
||||||
/*
|
/*
|
||||||
* Pool level fault for reading the intent logs.
|
* 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.*")) {
|
} else if (fmd_nvl_class_match(hdl, nvl, "ereport.fs.zfs.vdev.*")) {
|
||||||
/*
|
/*
|
||||||
* Device fault.
|
* 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,
|
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO)) ||
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO)) ||
|
||||||
fmd_nvl_class_match(hdl, nvl,
|
fmd_nvl_class_match(hdl, nvl,
|
||||||
@@ -894,12 +831,9 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
|||||||
fmd_nvl_class_match(hdl, nvl,
|
fmd_nvl_class_match(hdl, nvl,
|
||||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO_FAILURE)) ||
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO_FAILURE)) ||
|
||||||
fmd_nvl_class_match(hdl, nvl,
|
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))) {
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) {
|
||||||
const char *failmode = NULL;
|
char *failmode = NULL;
|
||||||
boolean_t checkremove = B_FALSE;
|
boolean_t checkremove = B_FALSE;
|
||||||
uint32_t pri = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a checksum or I/O error, then toss it into the
|
* If this is a checksum or I/O error, then toss it into the
|
||||||
@@ -911,111 +845,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,
|
if (fmd_nvl_class_match(hdl, nvl,
|
||||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO))) {
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO))) {
|
||||||
if (zcp->zc_data.zc_serd_io[0] == '\0') {
|
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,
|
zfs_serd_name(zcp->zc_data.zc_serd_io,
|
||||||
pool_guid, vdev_guid, "io");
|
pool_guid, vdev_guid, "io");
|
||||||
fmd_serd_create(hdl, zcp->zc_data.zc_serd_io,
|
fmd_serd_create(hdl, zcp->zc_data.zc_serd_io,
|
||||||
io_n,
|
fmd_prop_get_int32(hdl, "io_N"),
|
||||||
SEC2NSEC(io_t));
|
fmd_prop_get_int64(hdl, "io_T"));
|
||||||
zfs_case_serialize(zcp);
|
zfs_case_serialize(hdl, zcp);
|
||||||
}
|
}
|
||||||
if (zfs_fm_serd_record(hdl, zcp->zc_data.zc_serd_io,
|
if (fmd_serd_record(hdl, zcp->zc_data.zc_serd_io, ep))
|
||||||
ep, zcp, "io error")) {
|
|
||||||
checkremove = B_TRUE;
|
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' &&
|
|
||||||
zfs_fm_serd_record(hdl,
|
|
||||||
zcp->zc_data.zc_serd_slow_io, ep, zcp, "slow io")) {
|
|
||||||
zfs_case_solve(hdl, zcp,
|
|
||||||
"fault.fs.zfs.vdev.slow_io");
|
|
||||||
}
|
|
||||||
} else if (fmd_nvl_class_match(hdl, nvl,
|
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_CHECKSUM))) {
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_CHECKSUM))) {
|
||||||
uint64_t flags = 0;
|
|
||||||
int32_t flags32 = 0;
|
|
||||||
/*
|
|
||||||
* We ignore ereports for checksum errors generated by
|
|
||||||
* scrub/resilver I/O to avoid potentially further
|
|
||||||
* degrading the pool while it's being repaired.
|
|
||||||
*
|
|
||||||
* Note that FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS used to
|
|
||||||
* be int32. To allow newer zed to work on older
|
|
||||||
* kernels, if we don't find the flags, we look for
|
|
||||||
* the older ones too.
|
|
||||||
*/
|
|
||||||
if (((nvlist_lookup_uint32(nvl,
|
|
||||||
FM_EREPORT_PAYLOAD_ZFS_ZIO_PRIORITY, &pri) == 0) &&
|
|
||||||
(pri == ZIO_PRIORITY_SCRUB ||
|
|
||||||
pri == ZIO_PRIORITY_REBUILD)) ||
|
|
||||||
((nvlist_lookup_uint64(nvl,
|
|
||||||
FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS, &flags) == 0) &&
|
|
||||||
(flags & (ZIO_FLAG_SCRUB | ZIO_FLAG_RESILVER))) ||
|
|
||||||
((nvlist_lookup_int32(nvl,
|
|
||||||
FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS, &flags32) == 0) &&
|
|
||||||
(flags32 & (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 (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,
|
zfs_serd_name(zcp->zc_data.zc_serd_checksum,
|
||||||
pool_guid, vdev_guid, "checksum");
|
pool_guid, vdev_guid, "checksum");
|
||||||
fmd_serd_create(hdl,
|
fmd_serd_create(hdl,
|
||||||
zcp->zc_data.zc_serd_checksum,
|
zcp->zc_data.zc_serd_checksum,
|
||||||
checksum_n,
|
fmd_prop_get_int32(hdl, "checksum_N"),
|
||||||
SEC2NSEC(checksum_t));
|
fmd_prop_get_int64(hdl, "checksum_T"));
|
||||||
zfs_case_serialize(zcp);
|
zfs_case_serialize(hdl, zcp);
|
||||||
}
|
}
|
||||||
if (zfs_fm_serd_record(hdl,
|
if (fmd_serd_record(hdl,
|
||||||
zcp->zc_data.zc_serd_checksum, ep, zcp,
|
zcp->zc_data.zc_serd_checksum, ep)) {
|
||||||
"checksum")) {
|
|
||||||
zfs_case_solve(hdl, zcp,
|
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,
|
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO_FAILURE)) &&
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_IO_FAILURE)) &&
|
||||||
@@ -1025,11 +878,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,
|
if (strncmp(failmode, FM_EREPORT_FAILMODE_CONTINUE,
|
||||||
strlen(FM_EREPORT_FAILMODE_CONTINUE)) == 0) {
|
strlen(FM_EREPORT_FAILMODE_CONTINUE)) == 0) {
|
||||||
zfs_case_solve(hdl, zcp,
|
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,
|
} else if (strncmp(failmode, FM_EREPORT_FAILMODE_WAIT,
|
||||||
strlen(FM_EREPORT_FAILMODE_WAIT)) == 0) {
|
strlen(FM_EREPORT_FAILMODE_WAIT)) == 0) {
|
||||||
zfs_case_solve(hdl, zcp,
|
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,
|
} else if (fmd_nvl_class_match(hdl, nvl,
|
||||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) {
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) {
|
||||||
@@ -1051,7 +905,7 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
|||||||
zfs_remove_timeout);
|
zfs_remove_timeout);
|
||||||
if (!zcp->zc_data.zc_has_remove_timer) {
|
if (!zcp->zc_data.zc_has_remove_timer) {
|
||||||
zcp->zc_data.zc_has_remove_timer = 1;
|
zcp->zc_data.zc_has_remove_timer = 1;
|
||||||
zfs_case_serialize(zcp);
|
zfs_case_serialize(hdl, zcp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1061,13 +915,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
|
* 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).
|
* device removal (which would cause the timeout to be cancelled).
|
||||||
*/
|
*/
|
||||||
|
/* ARGSUSED */
|
||||||
static void
|
static void
|
||||||
zfs_fm_timeout(fmd_hdl_t *hdl, id_t id, void *data)
|
zfs_fm_timeout(fmd_hdl_t *hdl, id_t id, void *data)
|
||||||
{
|
{
|
||||||
zfs_case_t *zcp = data;
|
zfs_case_t *zcp = data;
|
||||||
|
|
||||||
if (id == zcp->zc_remove_timer)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1083,8 +938,6 @@ zfs_fm_close(fmd_hdl_t *hdl, fmd_case_t *cs)
|
|||||||
fmd_serd_destroy(hdl, zcp->zc_data.zc_serd_checksum);
|
fmd_serd_destroy(hdl, zcp->zc_data.zc_serd_checksum);
|
||||||
if (zcp->zc_data.zc_serd_io[0] != '\0')
|
if (zcp->zc_data.zc_serd_io[0] != '\0')
|
||||||
fmd_serd_destroy(hdl, zcp->zc_data.zc_serd_io);
|
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)
|
if (zcp->zc_data.zc_has_remove_timer)
|
||||||
fmd_timer_remove(hdl, zcp->zc_remove_timer);
|
fmd_timer_remove(hdl, zcp->zc_remove_timer);
|
||||||
|
|
||||||
@@ -1093,15 +946,30 @@ zfs_fm_close(fmd_hdl_t *hdl, fmd_case_t *cs)
|
|||||||
fmd_hdl_free(hdl, zcp, sizeof (zfs_case_t));
|
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 = {
|
static const fmd_hdl_ops_t fmd_ops = {
|
||||||
zfs_fm_recv, /* fmdo_recv */
|
zfs_fm_recv, /* fmdo_recv */
|
||||||
zfs_fm_timeout, /* fmdo_timeout */
|
zfs_fm_timeout, /* fmdo_timeout */
|
||||||
zfs_fm_close, /* fmdo_close */
|
zfs_fm_close, /* fmdo_close */
|
||||||
NULL, /* fmdo_stats */
|
NULL, /* fmdo_stats */
|
||||||
NULL, /* fmdo_gc */
|
zfs_fm_gc, /* fmdo_gc */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const fmd_prop_t fmd_props[] = {
|
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 }
|
{ NULL, 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1114,27 +982,27 @@ _zfs_diagnosis_init(fmd_hdl_t *hdl)
|
|||||||
{
|
{
|
||||||
libzfs_handle_t *zhdl;
|
libzfs_handle_t *zhdl;
|
||||||
|
|
||||||
if ((zhdl = libzfs_init()) == NULL)
|
if ((zhdl = __libzfs_init()) == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((zfs_case_pool = uu_list_pool_create("zfs_case_pool",
|
if ((zfs_case_pool = uu_list_pool_create("zfs_case_pool",
|
||||||
sizeof (zfs_case_t), offsetof(zfs_case_t, zc_node),
|
sizeof (zfs_case_t), offsetof(zfs_case_t, zc_node),
|
||||||
NULL, UU_LIST_POOL_DEBUG)) == NULL) {
|
NULL, UU_LIST_POOL_DEBUG)) == NULL) {
|
||||||
libzfs_fini(zhdl);
|
__libzfs_fini(zhdl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((zfs_cases = uu_list_create(zfs_case_pool, NULL,
|
if ((zfs_cases = uu_list_create(zfs_case_pool, NULL,
|
||||||
UU_LIST_DEBUG)) == NULL) {
|
UU_LIST_DEBUG)) == NULL) {
|
||||||
uu_list_pool_destroy(zfs_case_pool);
|
uu_list_pool_destroy(zfs_case_pool);
|
||||||
libzfs_fini(zhdl);
|
__libzfs_fini(zhdl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) {
|
if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) {
|
||||||
uu_list_destroy(zfs_cases);
|
uu_list_destroy(zfs_cases);
|
||||||
uu_list_pool_destroy(zfs_case_pool);
|
uu_list_pool_destroy(zfs_case_pool);
|
||||||
libzfs_fini(zhdl);
|
__libzfs_fini(zhdl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1142,6 +1010,8 @@ _zfs_diagnosis_init(fmd_hdl_t *hdl)
|
|||||||
|
|
||||||
(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (zfs_stats) /
|
(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (zfs_stats) /
|
||||||
sizeof (fmd_stat_t), (fmd_stat_t *)&zfs_stats);
|
sizeof (fmd_stat_t), (fmd_stat_t *)&zfs_stats);
|
||||||
|
|
||||||
|
zfs_remove_timeout = fmd_prop_get_int64(hdl, "remove_timeout");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1168,5 +1038,5 @@ _zfs_diagnosis_fini(fmd_hdl_t *hdl)
|
|||||||
uu_list_pool_destroy(zfs_case_pool);
|
uu_list_pool_destroy(zfs_case_pool);
|
||||||
|
|
||||||
zhdl = fmd_hdl_getspecific(hdl);
|
zhdl = fmd_hdl_getspecific(hdl);
|
||||||
libzfs_fini(zhdl);
|
__libzfs_fini(zhdl);
|
||||||
}
|
}
|
||||||
|
|||||||
+145
-600
File diff suppressed because it is too large
Load Diff
+169
-210
@@ -1,4 +1,3 @@
|
|||||||
// SPDX-License-Identifier: CDDL-1.0
|
|
||||||
/*
|
/*
|
||||||
* CDDL HEADER START
|
* CDDL HEADER START
|
||||||
*
|
*
|
||||||
@@ -7,7 +6,7 @@
|
|||||||
* You may not use this file except in compliance with the License.
|
* 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
|
* 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
|
* See the License for the specific language governing permissions
|
||||||
* and limitations under the License.
|
* and limitations under the License.
|
||||||
*
|
*
|
||||||
@@ -23,7 +22,6 @@
|
|||||||
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016, Intel Corporation.
|
* Copyright (c) 2016, Intel Corporation.
|
||||||
* Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -39,10 +37,8 @@
|
|||||||
#include <sys/fs/zfs.h>
|
#include <sys/fs/zfs.h>
|
||||||
#include <sys/fm/protocol.h>
|
#include <sys/fm/protocol.h>
|
||||||
#include <sys/fm/fs/zfs.h>
|
#include <sys/fm/fs/zfs.h>
|
||||||
#include <libzutil.h>
|
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <libgen.h>
|
|
||||||
|
|
||||||
#include "zfs_agents.h"
|
#include "zfs_agents.h"
|
||||||
#include "fmd_api.h"
|
#include "fmd_api.h"
|
||||||
@@ -75,10 +71,9 @@ zfs_retire_clear_data(fmd_hdl_t *hdl, zfs_retire_data_t *zdp)
|
|||||||
*/
|
*/
|
||||||
typedef struct find_cbdata {
|
typedef struct find_cbdata {
|
||||||
uint64_t cb_guid;
|
uint64_t cb_guid;
|
||||||
|
const char *cb_fru;
|
||||||
zpool_handle_t *cb_zhp;
|
zpool_handle_t *cb_zhp;
|
||||||
nvlist_t *cb_vdev;
|
nvlist_t *cb_vdev;
|
||||||
uint64_t cb_vdev_guid;
|
|
||||||
uint64_t cb_num_spares;
|
|
||||||
} find_cbdata_t;
|
} find_cbdata_t;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -100,18 +95,26 @@ find_pool(zpool_handle_t *zhp, void *data)
|
|||||||
* Find a vdev within a tree with a matching GUID.
|
* Find a vdev within a tree with a matching GUID.
|
||||||
*/
|
*/
|
||||||
static nvlist_t *
|
static nvlist_t *
|
||||||
find_vdev(libzfs_handle_t *zhdl, nvlist_t *nv, uint64_t search_guid)
|
find_vdev(libzfs_handle_t *zhdl, nvlist_t *nv, const char *search_fru,
|
||||||
|
uint64_t search_guid)
|
||||||
{
|
{
|
||||||
uint64_t guid;
|
uint64_t guid;
|
||||||
nvlist_t **child;
|
nvlist_t **child;
|
||||||
uint_t c, children;
|
uint_t c, children;
|
||||||
nvlist_t *ret;
|
nvlist_t *ret;
|
||||||
|
char *fru;
|
||||||
|
|
||||||
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
|
if (search_fru != NULL) {
|
||||||
guid == search_guid) {
|
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_FRU, &fru) == 0 &&
|
||||||
fmd_hdl_debug(fmd_module_hdl("zfs-retire"),
|
libzfs_fru_compare(zhdl, fru, search_fru))
|
||||||
"matched vdev %llu", guid);
|
return (nv);
|
||||||
return (nv);
|
} else {
|
||||||
|
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
|
||||||
|
guid == search_guid) {
|
||||||
|
fmd_hdl_debug(fmd_module_hdl("zfs-retire"),
|
||||||
|
"matched vdev %llu", guid);
|
||||||
|
return (nv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
|
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
|
||||||
@@ -119,7 +122,8 @@ find_vdev(libzfs_handle_t *zhdl, nvlist_t *nv, uint64_t search_guid)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
for (c = 0; c < children; c++) {
|
for (c = 0; c < children; c++) {
|
||||||
if ((ret = find_vdev(zhdl, child[c], search_guid)) != NULL)
|
if ((ret = find_vdev(zhdl, child[c], search_fru,
|
||||||
|
search_guid)) != NULL)
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,80 +132,14 @@ find_vdev(libzfs_handle_t *zhdl, nvlist_t *nv, uint64_t search_guid)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
for (c = 0; c < children; c++) {
|
for (c = 0; c < children; c++) {
|
||||||
if ((ret = find_vdev(zhdl, child[c], search_guid)) != NULL)
|
if ((ret = find_vdev(zhdl, child[c], search_fru,
|
||||||
return (ret);
|
search_guid)) != NULL)
|
||||||
}
|
|
||||||
|
|
||||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
|
|
||||||
&child, &children) != 0)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
for (c = 0; c < children; c++) {
|
|
||||||
if ((ret = find_vdev(zhdl, child[c], search_guid)) != NULL)
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (NULL);
|
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.
|
* Given a (pool, vdev) GUID pair, find the matching pool and vdev.
|
||||||
*/
|
*/
|
||||||
@@ -229,7 +167,8 @@ find_by_guid(libzfs_handle_t *zhdl, uint64_t pool_guid, uint64_t vdev_guid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vdev_guid != 0) {
|
if (vdev_guid != 0) {
|
||||||
if ((*vdevp = find_vdev(zhdl, nvroot, vdev_guid)) == NULL) {
|
if ((*vdevp = find_vdev(zhdl, nvroot, NULL,
|
||||||
|
vdev_guid)) == NULL) {
|
||||||
zpool_close(zhp);
|
zpool_close(zhp);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
@@ -238,37 +177,72 @@ find_by_guid(libzfs_handle_t *zhdl, uint64_t pool_guid, uint64_t vdev_guid,
|
|||||||
return (zhp);
|
return (zhp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBTOPO
|
||||||
|
static int
|
||||||
|
search_pool(zpool_handle_t *zhp, void *data)
|
||||||
|
{
|
||||||
|
find_cbdata_t *cbp = data;
|
||||||
|
nvlist_t *config;
|
||||||
|
nvlist_t *nvroot;
|
||||||
|
|
||||||
|
config = zpool_get_config(zhp, NULL);
|
||||||
|
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||||
|
&nvroot) != 0) {
|
||||||
|
zpool_close(zhp);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cbp->cb_vdev = find_vdev(zpool_get_handle(zhp), nvroot,
|
||||||
|
cbp->cb_fru, 0)) != NULL) {
|
||||||
|
cbp->cb_zhp = zhp;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
zpool_close(zhp);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a FRU FMRI, find the matching pool and vdev.
|
||||||
|
*/
|
||||||
|
static zpool_handle_t *
|
||||||
|
find_by_fru(libzfs_handle_t *zhdl, const char *fru, nvlist_t **vdevp)
|
||||||
|
{
|
||||||
|
find_cbdata_t cb;
|
||||||
|
|
||||||
|
cb.cb_fru = fru;
|
||||||
|
cb.cb_zhp = NULL;
|
||||||
|
if (zpool_iter(zhdl, search_pool, &cb) != 1)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
*vdevp = cb.cb_vdev;
|
||||||
|
return (cb.cb_zhp);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_LIBTOPO */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a vdev, attempt to replace it with every known spare until one
|
* Given a vdev, attempt to replace it with every known spare until one
|
||||||
* succeeds or we run out of devices to try.
|
* succeeds.
|
||||||
* Return whether we were successful or not in replacing the device.
|
|
||||||
*/
|
*/
|
||||||
static boolean_t
|
static void
|
||||||
replace_with_spare(fmd_hdl_t *hdl, zpool_handle_t *zhp, nvlist_t *vdev)
|
replace_with_spare(fmd_hdl_t *hdl, zpool_handle_t *zhp, nvlist_t *vdev)
|
||||||
{
|
{
|
||||||
nvlist_t *config, *nvroot, *replacement;
|
nvlist_t *config, *nvroot, *replacement;
|
||||||
nvlist_t **spares;
|
nvlist_t **spares;
|
||||||
uint_t s, nspares;
|
uint_t s, nspares;
|
||||||
char *dev_name;
|
char *dev_name;
|
||||||
zprop_source_t source;
|
|
||||||
int ashift;
|
|
||||||
|
|
||||||
config = zpool_get_config(zhp, NULL);
|
config = zpool_get_config(zhp, NULL);
|
||||||
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||||
&nvroot) != 0)
|
&nvroot) != 0)
|
||||||
return (B_FALSE);
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find out if there are any hot spares available in the pool.
|
* Find out if there are any hot spares available in the pool.
|
||||||
*/
|
*/
|
||||||
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
|
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
|
||||||
&spares, &nspares) != 0)
|
&spares, &nspares) != 0)
|
||||||
return (B_FALSE);
|
return;
|
||||||
|
|
||||||
/*
|
|
||||||
* lookup "ashift" pool property, we may need it for the replacement
|
|
||||||
*/
|
|
||||||
ashift = zpool_get_prop_int(zhp, ZPOOL_PROP_ASHIFT, &source);
|
|
||||||
|
|
||||||
replacement = fmd_nvl_alloc(hdl, FMD_SLEEP);
|
replacement = fmd_nvl_alloc(hdl, FMD_SLEEP);
|
||||||
|
|
||||||
@@ -282,41 +256,25 @@ replace_with_spare(fmd_hdl_t *hdl, zpool_handle_t *zhp, nvlist_t *vdev)
|
|||||||
* replace it.
|
* replace it.
|
||||||
*/
|
*/
|
||||||
for (s = 0; s < nspares; s++) {
|
for (s = 0; s < nspares; s++) {
|
||||||
boolean_t rebuild = B_FALSE;
|
char *spare_name;
|
||||||
const char *spare_name, *type;
|
|
||||||
|
|
||||||
if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
|
if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
|
||||||
&spare_name) != 0)
|
&spare_name) != 0)
|
||||||
continue;
|
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,
|
(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'",
|
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,
|
if (zpool_vdev_attach(zhp, dev_name, spare_name,
|
||||||
replacement, B_TRUE, rebuild) == 0) {
|
replacement, B_TRUE) == 0)
|
||||||
free(dev_name);
|
break;
|
||||||
nvlist_free(replacement);
|
|
||||||
return (B_TRUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(dev_name);
|
free(dev_name);
|
||||||
nvlist_free(replacement);
|
nvlist_free(replacement);
|
||||||
|
|
||||||
return (B_FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -324,12 +282,17 @@ 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
|
* ASRU is now usable. ZFS has found the device to be present and
|
||||||
* functioning.
|
* functioning.
|
||||||
*/
|
*/
|
||||||
|
/*ARGSUSED*/
|
||||||
static void
|
static void
|
||||||
zfs_vdev_repair(fmd_hdl_t *hdl, nvlist_t *nvl)
|
zfs_vdev_repair(fmd_hdl_t *hdl, nvlist_t *nvl)
|
||||||
{
|
{
|
||||||
zfs_retire_data_t *zdp = fmd_hdl_getspecific(hdl);
|
zfs_retire_data_t *zdp = fmd_hdl_getspecific(hdl);
|
||||||
zfs_retire_repaired_t *zrp;
|
zfs_retire_repaired_t *zrp;
|
||||||
uint64_t pool_guid, vdev_guid;
|
uint64_t pool_guid, vdev_guid;
|
||||||
|
#ifdef HAVE_LIBTOPO
|
||||||
|
nvlist_t *asru;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_POOL_GUID,
|
if (nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_POOL_GUID,
|
||||||
&pool_guid) != 0 || nvlist_lookup_uint64(nvl,
|
&pool_guid) != 0 || nvlist_lookup_uint64(nvl,
|
||||||
FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, &vdev_guid) != 0)
|
FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, &vdev_guid) != 0)
|
||||||
@@ -352,6 +315,47 @@ zfs_vdev_repair(fmd_hdl_t *hdl, nvlist_t *nvl)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBTOPO
|
||||||
|
asru = fmd_nvl_alloc(hdl, FMD_SLEEP);
|
||||||
|
|
||||||
|
(void) nvlist_add_uint8(asru, FM_VERSION, ZFS_SCHEME_VERSION0);
|
||||||
|
(void) nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS);
|
||||||
|
(void) nvlist_add_uint64(asru, FM_FMRI_ZFS_POOL, pool_guid);
|
||||||
|
(void) nvlist_add_uint64(asru, FM_FMRI_ZFS_VDEV, vdev_guid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We explicitly check for the unusable state here to make sure we
|
||||||
|
* aren't responding to a transient state change. As part of opening a
|
||||||
|
* vdev, it's possible to see the 'statechange' event, only to be
|
||||||
|
* followed by a vdev failure later. If we don't check the current
|
||||||
|
* state of the vdev (or pool) before marking it repaired, then we risk
|
||||||
|
* generating spurious repair events followed immediately by the same
|
||||||
|
* diagnosis.
|
||||||
|
*
|
||||||
|
* This assumes that the ZFS scheme code associated unusable (i.e.
|
||||||
|
* isolated) with its own definition of faulty state. In the case of a
|
||||||
|
* DEGRADED leaf vdev (due to checksum errors), this is not the case.
|
||||||
|
* This works, however, because the transient state change is not
|
||||||
|
* posted in this case. This could be made more explicit by not
|
||||||
|
* relying on the scheme's unusable callback and instead directly
|
||||||
|
* checking the vdev state, where we could correctly account for
|
||||||
|
* DEGRADED state.
|
||||||
|
*/
|
||||||
|
if (!fmd_nvl_fmri_unusable(hdl, asru) && fmd_nvl_fmri_has_fault(hdl,
|
||||||
|
asru, FMD_HAS_FAULT_ASRU, NULL)) {
|
||||||
|
topo_hdl_t *thp;
|
||||||
|
char *fmri = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
|
||||||
|
if (topo_fmri_nvl2str(thp, asru, &fmri, &err) == 0)
|
||||||
|
(void) fmd_repair_asru(hdl, fmri);
|
||||||
|
fmd_hdl_topo_rele(hdl, thp);
|
||||||
|
|
||||||
|
topo_hdl_strfree(thp, fmri);
|
||||||
|
}
|
||||||
|
nvlist_free(asru);
|
||||||
|
#endif
|
||||||
zrp = fmd_hdl_alloc(hdl, sizeof (zfs_retire_repaired_t), FMD_SLEEP);
|
zrp = fmd_hdl_alloc(hdl, sizeof (zfs_retire_repaired_t), FMD_SLEEP);
|
||||||
zrp->zrr_next = zdp->zrd_repaired;
|
zrp->zrr_next = zdp->zrd_repaired;
|
||||||
zrp->zrr_pool = pool_guid;
|
zrp->zrr_pool = pool_guid;
|
||||||
@@ -362,11 +366,11 @@ zfs_vdev_repair(fmd_hdl_t *hdl, nvlist_t *nvl)
|
|||||||
vdev_guid, pool_guid);
|
vdev_guid, pool_guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
static void
|
static void
|
||||||
zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
||||||
const char *class)
|
const char *class)
|
||||||
{
|
{
|
||||||
(void) ep;
|
|
||||||
uint64_t pool_guid, vdev_guid;
|
uint64_t pool_guid, vdev_guid;
|
||||||
zpool_handle_t *zhp;
|
zpool_handle_t *zhp;
|
||||||
nvlist_t *resource, *fault;
|
nvlist_t *resource, *fault;
|
||||||
@@ -376,108 +380,34 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
|||||||
libzfs_handle_t *zhdl = zdp->zrd_hdl;
|
libzfs_handle_t *zhdl = zdp->zrd_hdl;
|
||||||
boolean_t fault_device, degrade_device;
|
boolean_t fault_device, degrade_device;
|
||||||
boolean_t is_repair;
|
boolean_t is_repair;
|
||||||
boolean_t l2arc = B_FALSE;
|
char *scheme;
|
||||||
boolean_t spare = B_FALSE;
|
|
||||||
const char *scheme;
|
|
||||||
nvlist_t *vdev = NULL;
|
nvlist_t *vdev = NULL;
|
||||||
const char *uuid;
|
char *uuid;
|
||||||
int repair_done = 0;
|
int repair_done = 0;
|
||||||
boolean_t retire;
|
boolean_t retire;
|
||||||
boolean_t is_disk;
|
boolean_t is_disk;
|
||||||
vdev_aux_t aux;
|
vdev_aux_t aux;
|
||||||
uint64_t state = 0;
|
uint64_t state = 0;
|
||||||
vdev_stat_t *vs;
|
|
||||||
unsigned int c;
|
|
||||||
|
|
||||||
fmd_hdl_debug(hdl, "zfs_retire_recv: '%s'", class);
|
fmd_hdl_debug(hdl, "zfs_retire_recv: '%s'", class);
|
||||||
|
|
||||||
(void) nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE,
|
|
||||||
&state);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a resource notifying us of device removal then simply
|
* If this is a resource notifying us of device removal, then simply
|
||||||
* check for an available spare and continue unless the device is a
|
* check for an available spare and continue.
|
||||||
* l2arc vdev, in which case we just offline it.
|
|
||||||
*/
|
*/
|
||||||
if (strcmp(class, "resource.fs.zfs.removed") == 0 ||
|
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;
|
|
||||||
char *devname;
|
|
||||||
boolean_t skip_removal = B_FALSE;
|
|
||||||
|
|
||||||
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,
|
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;
|
return;
|
||||||
|
|
||||||
if ((zhp = find_by_guid(zhdl, pool_guid, vdev_guid,
|
if ((zhp = find_by_guid(zhdl, pool_guid, vdev_guid,
|
||||||
&vdev)) == NULL)
|
&vdev)) == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
devname = zpool_vdev_name(NULL, zhp, vdev, B_FALSE);
|
if (fmd_prop_get_int32(hdl, "spare_on_remove"))
|
||||||
|
replace_with_spare(hdl, zhp, vdev);
|
||||||
nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
|
|
||||||
(uint64_t **)&vs, &c);
|
|
||||||
|
|
||||||
if (vs->vs_state == VDEV_STATE_OFFLINE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)) {
|
|
||||||
if (strcmp(class, "resource.fs.zfs.removed") == 0 &&
|
|
||||||
nvlist_exists(nvl, "by_kernel")) {
|
|
||||||
skip_removal = B_TRUE;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove the vdev since device is unplugged */
|
|
||||||
int remove_status = 0;
|
|
||||||
if (!skip_removal && (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)) {
|
|
||||||
/* Could not handle with spare */
|
|
||||||
fmd_hdl_debug(hdl, "no spare for '%s'", devname);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(devname);
|
|
||||||
zpool_close(zhp);
|
zpool_close(zhp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -486,11 +416,12 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: on Linux statechange events are more than just
|
* Note: on zfsonlinux statechange events are more than just
|
||||||
* healthy ones so we need to confirm the actual state value.
|
* healthy ones so we need to confirm the actual state value.
|
||||||
*/
|
*/
|
||||||
if (strcmp(class, "resource.fs.zfs.statechange") == 0 &&
|
if (strcmp(class, "resource.fs.zfs.statechange") == 0 &&
|
||||||
state == VDEV_STATE_HEALTHY) {
|
nvlist_lookup_uint64(nvl, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE,
|
||||||
|
&state) == 0 && state == VDEV_STATE_HEALTHY) {
|
||||||
zfs_vdev_repair(hdl, nvl);
|
zfs_vdev_repair(hdl, nvl);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -535,9 +466,6 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
|||||||
} else if (fmd_nvl_class_match(hdl, fault,
|
} else if (fmd_nvl_class_match(hdl, fault,
|
||||||
"fault.fs.zfs.vdev.checksum")) {
|
"fault.fs.zfs.vdev.checksum")) {
|
||||||
degrade_device = B_TRUE;
|
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,
|
} else if (fmd_nvl_class_match(hdl, fault,
|
||||||
"fault.fs.zfs.device")) {
|
"fault.fs.zfs.device")) {
|
||||||
fault_device = B_FALSE;
|
fault_device = B_FALSE;
|
||||||
@@ -549,7 +477,39 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_disk) {
|
if (is_disk) {
|
||||||
|
#ifdef HAVE_LIBTOPO
|
||||||
|
/*
|
||||||
|
* This is a disk fault. Lookup the FRU, convert it to
|
||||||
|
* an FMRI string, and attempt to find a matching vdev.
|
||||||
|
*/
|
||||||
|
if (nvlist_lookup_nvlist(fault, FM_FAULT_FRU,
|
||||||
|
&fru) != 0 ||
|
||||||
|
nvlist_lookup_string(fru, FM_FMRI_SCHEME,
|
||||||
|
&scheme) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strcmp(scheme, FM_FMRI_SCHEME_HC) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
|
||||||
|
if (topo_fmri_nvl2str(thp, fru, &fmri, &err) != 0) {
|
||||||
|
fmd_hdl_topo_rele(hdl, thp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
zhp = find_by_fru(zhdl, fmri, &vdev);
|
||||||
|
topo_hdl_strfree(thp, fmri);
|
||||||
|
fmd_hdl_topo_rele(hdl, thp);
|
||||||
|
|
||||||
|
if (zhp == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
(void) nvlist_lookup_uint64(vdev,
|
||||||
|
ZPOOL_CONFIG_GUID, &vdev_guid);
|
||||||
|
aux = VDEV_AUX_EXTERNAL;
|
||||||
|
#else
|
||||||
continue;
|
continue;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* This is a ZFS fault. Lookup the resource, and
|
* This is a ZFS fault. Lookup the resource, and
|
||||||
@@ -623,8 +583,7 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
|||||||
/*
|
/*
|
||||||
* Attempt to substitute a hot spare.
|
* Attempt to substitute a hot spare.
|
||||||
*/
|
*/
|
||||||
(void) replace_with_spare(hdl, zhp, vdev);
|
replace_with_spare(hdl, zhp, vdev);
|
||||||
|
|
||||||
zpool_close(zhp);
|
zpool_close(zhp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,7 +615,7 @@ _zfs_retire_init(fmd_hdl_t *hdl)
|
|||||||
zfs_retire_data_t *zdp;
|
zfs_retire_data_t *zdp;
|
||||||
libzfs_handle_t *zhdl;
|
libzfs_handle_t *zhdl;
|
||||||
|
|
||||||
if ((zhdl = libzfs_init()) == NULL)
|
if ((zhdl = __libzfs_init()) == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) {
|
if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) {
|
||||||
@@ -677,7 +636,7 @@ _zfs_retire_fini(fmd_hdl_t *hdl)
|
|||||||
|
|
||||||
if (zdp != NULL) {
|
if (zdp != NULL) {
|
||||||
zfs_retire_clear_data(hdl, zdp);
|
zfs_retire_clear_data(hdl, zdp);
|
||||||
libzfs_fini(zdp->zrd_hdl);
|
__libzfs_fini(zdp->zrd_hdl);
|
||||||
fmd_hdl_free(hdl, zdp, sizeof (zfs_retire_data_t));
|
fmd_hdl_free(hdl, zdp, sizeof (zfs_retire_data_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user