mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-24 11:18:52 +03:00
Compare commits
443 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef686e96ec | |||
| 7a41ef240a | |||
| 72d16a9b49 | |||
| 54c358c3f2 | |||
| 560e9fc817 | |||
| d642efe83c | |||
| 51e313f610 | |||
| 327f12c291 | |||
| 5d4f7e7566 | |||
| abd0b59e48 | |||
| 6b9d0eda75 | |||
| 744cdfd93b | |||
| 36d50b60d8 | |||
| 0c4f86be74 | |||
| 88be308b2f | |||
| d6dc79eabc | |||
| 900a444107 | |||
| 1885e5ebab | |||
| 1ad8fcc054 | |||
| 05c96b438a | |||
| ccf6d0a59b | |||
| 61ae6c99f7 | |||
| e9353bc2ef | |||
| 87d93731e7 | |||
| bd197378e7 | |||
| cd2bb9ca44 | |||
| 52d9bc7174 | |||
| 6905f6b2c1 | |||
| cfc82609a2 | |||
| e26776f14c | |||
| e68e938f54 | |||
| ab2110e3e2 | |||
| a909190683 | |||
| 073f3c7826 | |||
| 5072f37419 | |||
| 332cd2e313 | |||
| ac6f332154 | |||
| f14b6f2302 | |||
| bfb2928490 | |||
| ecb1b1a31d | |||
| 412b69dfab | |||
| d014da0032 | |||
| 8f93ab53d4 | |||
| 88891b804b | |||
| 87b5e7fb1d | |||
| 5722dce473 | |||
| 91d5ac85c0 | |||
| fd8ccce07b | |||
| c2a3bcc91d | |||
| d1277e2a13 | |||
| a59bf29606 | |||
| 28fdc5f811 | |||
| a78a93e67e | |||
| 9a68ceba10 | |||
| 3c7ad493a6 | |||
| faad85637b | |||
| 501da8d433 | |||
| 30620ad8e1 | |||
| 1d65d1a597 | |||
| edf3d7aa43 | |||
| 9755cdfd89 | |||
| f36e8118fd | |||
| e69f73c5cf | |||
| 3430eced80 | |||
| 0839934d84 | |||
| f831d1377f | |||
| a559c3d0f4 | |||
| 95e29a7275 | |||
| 85890d54d9 | |||
| 12e25a6ec3 | |||
| 57490d5e13 | |||
| 214196e9f5 | |||
| 932d471bec | |||
| 77cba40b85 | |||
| 18d069a20f | |||
| dfc25ea91c | |||
| 7428adc6b7 | |||
| 30782f2ff5 | |||
| 43efd5625b | |||
| 87a520c4e7 | |||
| d02bcae0c4 | |||
| d9bcadc6ba | |||
| 67819ea28d | |||
| 79430bf34b | |||
| cabc605aa7 | |||
| 0740d41e9b | |||
| 16e8e24f9c | |||
| bc5afff351 | |||
| 825d8e1b0f | |||
| f7797f3f5e | |||
| 2439e95f36 | |||
| de722e55ca | |||
| acb4e7b0e1 | |||
| 5a397fda09 | |||
| 525a7037c7 | |||
| 789f3d0e56 | |||
| 5d946dfa1c | |||
| cd80d6d355 | |||
| 140584bfff | |||
| 8773e29c23 | |||
| bb21c0aa3b | |||
| 455ea5bb1f | |||
| 7126b0e5ed | |||
| 7ca0ef36e1 | |||
| 0d6186cff3 | |||
| 6f349d33a5 | |||
| 226d362b12 | |||
| 497fc5fb06 | |||
| abb485a34a | |||
| 0ccffb2634 | |||
| 26cb87d22d | |||
| 43dbfa3921 | |||
| 395583e38e | |||
| 818bc70c32 | |||
| 6150fbe67f | |||
| 458bb8c8a1 | |||
| cda6fdd500 | |||
| df8271301e | |||
| e219935f10 | |||
| bb9104f1e8 | |||
| 94b240bae0 | |||
| e93203e004 | |||
| ccb453acd0 | |||
| 6c1989923e | |||
| a0eb5a77a0 | |||
| fe77c48320 | |||
| db9b29895e | |||
| 4d4dd76f0f | |||
| 286c7f75bb | |||
| 403703d57a | |||
| f17c843eff | |||
| f6440fa094 | |||
| 62f9691e10 | |||
| 73e26fdc09 | |||
| 65a89d9f49 | |||
| 8829ba19b7 | |||
| 642d86af0d | |||
| 07ca7592ad | |||
| fb0d807477 | |||
| 858ea8861c | |||
| 549841ef9a | |||
| 96f322e7e2 | |||
| d022406a14 | |||
| a1a1386965 | |||
| 43eaef6de8 | |||
| 5bc4c39d70 | |||
| 756e28be51 | |||
| 039a810491 | |||
| bfb7b9613a | |||
| 3e33897bec | |||
| 0f3b928e85 | |||
| 12fec4a147 | |||
| 7930a5ee65 | |||
| be94a3de0f | |||
| db83b3abe9 | |||
| 55fd8ceab6 | |||
| e269e1c07a | |||
| 81f981cd82 | |||
| 3790aa8176 | |||
| 4e1d1b4b92 | |||
| c32c475363 | |||
| dd487640b2 | |||
| acb39fc9a4 | |||
| 6539bf71fe | |||
| 32a78e579d | |||
| fb7aa3c9b2 | |||
| 4016ad705b | |||
| 59570a05d8 | |||
| 88ae76a4e0 | |||
| 88d7da62b5 | |||
| 6410ee4a94 | |||
| a296875da0 | |||
| 921ec61b77 | |||
| fcd9966ed9 | |||
| a2621753b2 | |||
| e888f28988 | |||
| 305510fd33 | |||
| 67cff6e4c1 | |||
| 944180ab50 | |||
| 3075b29ca8 | |||
| e1d9228b08 | |||
| afaf9414ff | |||
| cee725c9bd | |||
| 03ad94a3b2 | |||
| 7a7e101437 | |||
| 401ba57ccd | |||
| 188950df9e | |||
| 58bc86c5cb | |||
| 7cf4cd8246 | |||
| 783be694f1 | |||
| af5626ac27 | |||
| cc1f85be8b | |||
| 9585538d0e | |||
| 86e74dc162 | |||
| b3d723fb0e | |||
| 3d40b65540 | |||
| fa7b558bef | |||
| a103ae446e | |||
| 2ab24dfded | |||
| 489633d99a | |||
| ee49d9e02b | |||
| 1fbda9caee | |||
| 42bdfd3b36 | |||
| 900480bd96 | |||
| 058b6fd069 | |||
| 8847b06bf6 | |||
| 21adfb031c | |||
| ae2cfdf8a7 | |||
| 20e4513c56 | |||
| f217a2b902 | |||
| aa5b9e1d7c | |||
| fb3ad5d24e | |||
| de2ac3f700 | |||
| f9688b21d7 | |||
| fad85e52e5 | |||
| 038aaec1cd | |||
| 94ca328fb3 | |||
| 65c4c9a233 | |||
| 07ca433973 | |||
| f21d1f8fad | |||
| ee8794195b | |||
| 0ef4def852 | |||
| aa51adf0a2 | |||
| 1d02bdee6c | |||
| 2080c4f27e | |||
| 49ba502f99 | |||
| 7735c9addf | |||
| ed02d603a1 | |||
| 529469769f | |||
| 3b854534f0 | |||
| dcbf847493 | |||
| 2757204434 | |||
| 24a6f83847 | |||
| 2c36eb763f | |||
| a4ab0c607e | |||
| a3a4b8def7 | |||
| 14bdf57a99 | |||
| 45061cc797 | |||
| cb01817f22 | |||
| 1c4ccfb34e | |||
| 056287e3f7 | |||
| ccfa35c6f9 | |||
| 8471f71132 | |||
| 813185d141 | |||
| be12087783 | |||
| 4f9014b70b | |||
| 043ef5c25e | |||
| c06118e0b1 | |||
| 5f24bd11ee | |||
| f6f3089cf6 | |||
| a09aeb9fc4 | |||
| e4257ed76d | |||
| c4a5e3b90f | |||
| d02fc15ba1 | |||
| 435dc4baab | |||
| 04177b9c3f | |||
| 4a87c280dc | |||
| d237d9a918 | |||
| 2132ae465d | |||
| 87f01fc158 | |||
| 995b80fa3a | |||
| d842f99c6b | |||
| 8cad25a39c | |||
| c00bb5f4ea | |||
| d33cbbbf93 | |||
| a4efa59a94 | |||
| cb4d3fb737 | |||
| 4a2e9811e9 | |||
| 050dfc5045 | |||
| b49118220c | |||
| 806dda56ce | |||
| 97f5cfea77 | |||
| 5ecbea67eb | |||
| 957b4e9fbd | |||
| ef648fec0e | |||
| e518548e17 | |||
| 1f442afa41 | |||
| 62d549d757 | |||
| ab9011e79b | |||
| b42f36f0b0 | |||
| a30fed54f4 | |||
| e767b1cacc | |||
| d2090becab | |||
| 54f10674f3 | |||
| f8460e7e62 | |||
| 45479eb1de | |||
| aaeffd09bf | |||
| 0c270bb6c4 | |||
| c2c643256c | |||
| 896d0f0906 | |||
| ef525e0841 | |||
| 00a27515f0 | |||
| 52f1ef3b2d | |||
| c6b0680d9b | |||
| 2c37e1416b | |||
| 6e4845aee3 | |||
| 48cf7d674a | |||
| ca54e52122 | |||
| c3ae9321bf | |||
| 2dd2e49cc7 | |||
| 8a1b26eb54 | |||
| 7e76d21bc8 | |||
| e579a4ed0f | |||
| 6867d00403 | |||
| 0dc6fb730f | |||
| f5bffd3748 | |||
| 07c7899a37 | |||
| 79bfba2fa8 | |||
| 73511e3dde | |||
| 3b79394bc9 | |||
| 4df31aa98c | |||
| aeeada355c | |||
| 0905a4fe9b | |||
| 3ba6774e58 | |||
| 26e9c479b5 | |||
| db75854cbb | |||
| bd565f3e24 | |||
| 3c4e580e9a | |||
| b3f4436d37 | |||
| 05f8be3b49 | |||
| d8091c9294 | |||
| 05613fa7a3 | |||
| 725c9e22ca | |||
| fbfc7e843a | |||
| faa62966b1 | |||
| be28cdd1c3 | |||
| 7f0b3fa042 | |||
| f40a1ad9e0 | |||
| 9cf33c99fc | |||
| a51019f4ec | |||
| c71847b77b | |||
| 5c6d3c21b1 | |||
| 5e7198b873 | |||
| 46c71074ca | |||
| 35ba2ca5b7 | |||
| cbcb88dff8 | |||
| 0df5b5737c | |||
| 102a1db6b2 | |||
| 25e44a17ff | |||
| 718d20ed93 | |||
| 18fea82b89 | |||
| cfb602125e | |||
| 106627caa7 | |||
| d6bee967ed | |||
| 47e3dba972 | |||
| a09e3a8594 | |||
| 5573cbea9a | |||
| fc5966589b | |||
| 5d61d6e8dd | |||
| 775afc4dcd | |||
| 7ce9da0bea | |||
| e58dee8cae | |||
| 83b5a22d86 | |||
| 13c38c4c45 | |||
| fdbec0423b | |||
| 9f29a4d972 | |||
| ced5f71eec | |||
| e5a4f9cfc4 | |||
| 1579483a86 | |||
| edd23dba81 | |||
| 7b353d2c8c | |||
| b37efb872b | |||
| d8a81c3d3c | |||
| 875307b6a1 | |||
| 626abe164d | |||
| ba28919168 | |||
| c70c6e004e | |||
| 227273efa4 | |||
| b199e62d17 | |||
| b9d18bdbdc | |||
| e651a5b233 | |||
| 723726ae7d | |||
| aba5b019cb | |||
| f664153078 | |||
| 4ce06f940e | |||
| 5899ea5a77 | |||
| 56e69c1e9c | |||
| dacb4f6a61 | |||
| 66ccc9b75f | |||
| 7b86ad215e | |||
| aa7817c151 | |||
| 3902eaf9ed | |||
| 2cec08a1f0 | |||
| 0968d689a2 | |||
| 1ce90aa441 | |||
| c9eab8257d | |||
| df39626fdd | |||
| 083ddb7714 | |||
| 7bc2d04398 | |||
| 84d9492e52 | |||
| c8bbb0c93d | |||
| ae93e46716 | |||
| 645ca45a13 | |||
| 29bc31f62f | |||
| 17e2fd3bfd | |||
| 55de40fe47 | |||
| 9cea5f0d69 | |||
| 78d84f56d1 | |||
| 127daad223 | |||
| b155a243a6 | |||
| ac71835706 | |||
| 3625a0131a | |||
| 0b5a4c4d6b | |||
| ee73a8ff3d | |||
| c0234eab65 | |||
| dd34e6cdd9 | |||
| e9c1fa0cc1 | |||
| 18524b936d | |||
| 8afac5dc55 | |||
| bd724261d2 | |||
| a1e03186fd | |||
| e28635396a | |||
| 36f36610c3 | |||
| fd20a81b9a | |||
| ef8a6fe9fe | |||
| 7c36a9e24a | |||
| da81d91d48 | |||
| ecd3976f5b | |||
| 76a157f004 | |||
| 6512c18fe1 | |||
| f5ddb3b481 | |||
| d6a779a278 | |||
| bbba0b7f93 | |||
| 8a06356e24 | |||
| b73a8b1dc2 | |||
| baed4fbacb | |||
| f4c8e9c69b | |||
| 8639ca86da | |||
| c6ee83893e | |||
| 0fba4d138c | |||
| 6bf3f4dfe5 | |||
| fa0cd2d16f | |||
| a00c61db44 | |||
| c2068750d7 | |||
| af424d8a1a | |||
| 1ac6248312 | |||
| 77b01f53e7 | |||
| 57fc3987a0 | |||
| 4f6167deb5 | |||
| 79d6a1b1da | |||
| 510179f086 | |||
| cb16a5e043 | |||
| 3ca31bd0c6 |
@@ -25,16 +25,14 @@ Type | Version/Name
|
|||||||
--- | ---
|
--- | ---
|
||||||
Distribution Name |
|
Distribution Name |
|
||||||
Distribution Version |
|
Distribution Version |
|
||||||
Kernel Version |
|
Linux Kernel |
|
||||||
Architecture |
|
Architecture |
|
||||||
OpenZFS Version |
|
ZFS Version |
|
||||||
|
SPL Version |
|
||||||
<!--
|
<!--
|
||||||
Command to find OpenZFS version:
|
Commands to find ZFS/SPL versions:
|
||||||
zfs version
|
modinfo zfs | grep -iw version
|
||||||
|
modinfo spl | grep -iw version
|
||||||
Commands to find kernel version:
|
|
||||||
uname -r # Linux
|
|
||||||
freebsd-version -r # FreeBSD
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
### Describe the problem you're observing
|
### Describe the problem you're observing
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
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)
|
- name: OpenZFS Community Support Mailing list (Linux)
|
||||||
url: https://zfsonlinux.topicbox.com/groups/zfs-discuss
|
url: https://zfsonlinux.topicbox.com/groups/zfs-discuss
|
||||||
about: Get community support for OpenZFS on Linux
|
about: Get community support for OpenZFS on Linux
|
||||||
@@ -10,5 +7,5 @@ contact_links:
|
|||||||
url: https://lists.freebsd.org/mailman/listinfo/freebsd-fs
|
url: https://lists.freebsd.org/mailman/listinfo/freebsd-fs
|
||||||
about: Get community support for OpenZFS on FreeBSD
|
about: Get community support for OpenZFS on FreeBSD
|
||||||
- name: OpenZFS on IRC
|
- name: OpenZFS on IRC
|
||||||
url: https://web.libera.chat/#openzfs
|
url: https://webchat.freenode.net/#openzfs
|
||||||
about: Use IRC to get community support for OpenZFS
|
about: Use IRC to get community support for OpenZFS
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
name: Code Question
|
||||||
|
about: Ask a question about the code
|
||||||
|
title: ''
|
||||||
|
labels: 'Type: Question'
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Thank you for taking an interest in the OpenZFS codebase.
|
||||||
|
|
||||||
|
Please be aware that most questions are preferably asked in the mailing list first.
|
||||||
|
This form is primarily meant for asking questions about the code itself.
|
||||||
|
|
||||||
|
Please also check our issue tracker before opening a new question.
|
||||||
|
Filling out the following template will help other contributors better understand your question.
|
||||||
|
-->
|
||||||
|
|
||||||
|
### Ask your question!
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please provide a clear and concise question.
|
||||||
|
-->
|
||||||
|
|
||||||
|
### Which portion of the codebase does your question involve?
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Optional: Please describe what portion of the codebase your issue involved.
|
||||||
|
Example: "Testsuite", "Buildbots", "CLI", a code snippet etc.
|
||||||
|
-->
|
||||||
|
|
||||||
|
### Additional context
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Any additional information you want to add?
|
||||||
|
-->
|
||||||
@@ -28,15 +28,14 @@ https://openzfs.github.io/openzfs-docs/Developer%20Resources/Buildbot%20Options.
|
|||||||
- [ ] 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)
|
||||||
- [ ] 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](https://github.com/zfsonlinux/zfs/blob/master/.github/CONTRIBUTING.md#coding-conventions).
|
||||||
- [ ] 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](https://github.com/zfsonlinux/zfs/blob/master/.github/CONTRIBUTING.md).
|
||||||
- [ ] I have added [tests](https://github.com/openzfs/zfs/tree/master/tests) to cover my changes.
|
- [ ] I have added [tests](https://github.com/zfsonlinux/zfs/tree/master/tests) to cover my changes.
|
||||||
- [ ] I have run the ZFS Test Suite with this change applied.
|
- [ ] I have run the ZFS Test Suite with this change applied.
|
||||||
- [ ] All commit messages are properly formatted and contain [`Signed-off-by`](https://github.com/openzfs/zfs/blob/master/.github/CONTRIBUTING.md#signed-off-by).
|
- [ ] All commit messages are properly formatted and contain [`Signed-off-by`](https://github.com/zfsonlinux/zfs/blob/master/.github/CONTRIBUTING.md#signed-off-by).
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# Configuration for probot-no-response - https://github.com/probot/no-response
|
|
||||||
|
|
||||||
# Number of days of inactivity before an Issue is closed for lack of response
|
|
||||||
daysUntilClose: 31
|
|
||||||
# Label requiring a response
|
|
||||||
responseRequiredLabel: "Status: Feedback requested"
|
|
||||||
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
|
|
||||||
closeComment: >
|
|
||||||
This issue has been automatically closed because there has been no response
|
|
||||||
to our request for more information from the original author. With only the
|
|
||||||
information that is currently in the issue, we don't have enough information
|
|
||||||
to take action. Please reach out if you have or find the answers we need so
|
|
||||||
that we can investigate further.
|
|
||||||
+1
-10
@@ -7,14 +7,7 @@ only: issues
|
|||||||
# Issues with these labels will never be considered stale
|
# Issues with these labels will never be considered stale
|
||||||
exemptLabels:
|
exemptLabels:
|
||||||
- "Type: Feature"
|
- "Type: Feature"
|
||||||
- "Bot: Not Stale"
|
- "Type: Understood"
|
||||||
- "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
|
# Label to use when marking an issue as stale
|
||||||
staleLabel: "Status: Stale"
|
staleLabel: "Status: Stale"
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
@@ -22,5 +15,3 @@ markComment: >
|
|||||||
This issue has been automatically marked as "stale" because it has not had
|
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.
|
any activity for a while. It will be closed in 90 days if no further activity occurs.
|
||||||
Thank you for your contributions.
|
Thank you for your contributions.
|
||||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
|
||||||
limitPerRun: 6
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
checkstyle:
|
checkstyle:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
@@ -18,13 +18,12 @@ jobs:
|
|||||||
sudo apt-get install --yes -qq zlib1g-dev uuid-dev libattr1-dev libblkid-dev libselinux-dev libudev-dev libssl-dev python-dev python-setuptools python-cffi python3 python3-dev python3-setuptools python3-cffi
|
sudo apt-get install --yes -qq zlib1g-dev uuid-dev libattr1-dev libblkid-dev libselinux-dev libudev-dev libssl-dev python-dev python-setuptools python-cffi python3 python3-dev python3-setuptools python3-cffi
|
||||||
# packages for tests
|
# packages for tests
|
||||||
sudo apt-get install --yes -qq parted lsscsi ksh attr acl nfs-kernel-server fio
|
sudo apt-get install --yes -qq parted lsscsi ksh attr acl nfs-kernel-server fio
|
||||||
sudo apt-get install --yes -qq mandoc cppcheck pax-utils devscripts
|
sudo apt-get install --yes -qq mandoc cppcheck pax-utils abigail-tools # devscripts - enable then bashisms fixed
|
||||||
sudo -E pip --quiet install flake8
|
sudo -E pip --quiet install flake8
|
||||||
- name: Prepare
|
- name: Prepare
|
||||||
run: |
|
run: |
|
||||||
sh ./autogen.sh
|
sh ./autogen.sh
|
||||||
./configure
|
./configure
|
||||||
make -j$(nproc)
|
|
||||||
- name: Checkstyle
|
- name: Checkstyle
|
||||||
run: |
|
run: |
|
||||||
make checkstyle
|
make checkstyle
|
||||||
@@ -32,19 +31,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make lint
|
make lint
|
||||||
- name: CheckABI
|
- name: CheckABI
|
||||||
id: CheckABI
|
|
||||||
run: |
|
run: |
|
||||||
sudo docker run -v $(pwd):/source ghcr.io/openzfs/libabigail make checkabi
|
make -j$(nproc)
|
||||||
- name: StoreABI
|
make checkabi
|
||||||
if: failure() && steps.CheckABI.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
sudo docker run -v $(pwd):/source ghcr.io/openzfs/libabigail make storeabi
|
|
||||||
- name: Prepare artifacts
|
|
||||||
if: failure() && steps.CheckABI.outcome == 'failure'
|
|
||||||
run: |
|
|
||||||
find -name *.abi | tar -cf abi_files.tar -T -
|
|
||||||
- uses: actions/upload-artifact@v2
|
|
||||||
if: failure() && steps.CheckABI.outcome == 'failure'
|
|
||||||
with:
|
|
||||||
name: New ABI files (use only if you're sure about interface changes)
|
|
||||||
path: abi_files.tar
|
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ jobs:
|
|||||||
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
||||||
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
||||||
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
|
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
|
||||||
python3 python3-dev python3-setuptools python3-cffi python3-packaging \
|
python3 python3-dev python3-setuptools python3-cffi
|
||||||
libcurl4-openssl-dev
|
|
||||||
- name: Autogen.sh
|
- name: Autogen.sh
|
||||||
run: |
|
run: |
|
||||||
sh autogen.sh
|
sh autogen.sh
|
||||||
@@ -45,17 +44,6 @@ jobs:
|
|||||||
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
|
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
|
||||||
sudo depmod
|
sudo depmod
|
||||||
sudo modprobe zfs
|
sudo modprobe zfs
|
||||||
# Workaround for cloud-init bug
|
|
||||||
# see https://github.com/openzfs/zfs/issues/12644
|
|
||||||
FILE=/lib/udev/rules.d/10-cloud-init-hook-hotplug.rules
|
|
||||||
if [ -r "${FILE}" ]; then
|
|
||||||
HASH=$(md5sum "${FILE}" | awk '{ print $1 }')
|
|
||||||
if [ "${HASH}" = "121ff0ef1936cd2ef65aec0458a35772" ]; then
|
|
||||||
# Just shove a zd* exclusion right above the hotplug hook...
|
|
||||||
sudo sed -i -e s/'LABEL="cloudinit_hook"'/'KERNEL=="zd*", GOTO="cloudinit_end"\n&'/ "${FILE}"
|
|
||||||
sudo udevadm control --reload-rules
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# Workaround to provide additional free space for testing.
|
# Workaround to provide additional free space for testing.
|
||||||
# https://github.com/actions/virtual-environments/issues/2840
|
# https://github.com/actions/virtual-environments/issues/2840
|
||||||
sudo rm -rf /usr/share/dotnet
|
sudo rm -rf /usr/share/dotnet
|
||||||
@@ -64,8 +52,7 @@ jobs:
|
|||||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: |
|
run: |
|
||||||
/usr/share/zfs/zfs-tests.sh -vR -s 3G
|
/usr/share/zfs/zfs-tests.sh -v -s 3G
|
||||||
timeout-minutes: 330
|
|
||||||
- name: Prepare artifacts
|
- name: Prepare artifacts
|
||||||
if: failure()
|
if: failure()
|
||||||
run: |
|
run: |
|
||||||
@@ -74,7 +61,7 @@ jobs:
|
|||||||
sudo cp /var/log/syslog $RESULTS_PATH/
|
sudo cp /var/log/syslog $RESULTS_PATH/
|
||||||
sudo chmod +r $RESULTS_PATH/*
|
sudo chmod +r $RESULTS_PATH/*
|
||||||
# Replace ':' in dir names, actions/upload-artifact doesn't support it
|
# Replace ':' in dir names, actions/upload-artifact doesn't support it
|
||||||
for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done
|
for f in $(find $RESULTS_PATH -name '*:*'); do mv "$f" "${f//:/__}"; done
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ jobs:
|
|||||||
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
||||||
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
||||||
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
|
libpam0g-dev pamtester python-dev python-setuptools python-cffi \
|
||||||
python3 python3-dev python3-setuptools python3-cffi python3-packaging \
|
python3 python3-dev python3-setuptools python3-cffi
|
||||||
libcurl4-openssl-dev
|
|
||||||
- name: Autogen.sh
|
- name: Autogen.sh
|
||||||
run: |
|
run: |
|
||||||
sh autogen.sh
|
sh autogen.sh
|
||||||
@@ -41,17 +40,6 @@ jobs:
|
|||||||
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
|
sudo sed -i.bak 's/updates/extra updates/' /etc/depmod.d/ubuntu.conf
|
||||||
sudo depmod
|
sudo depmod
|
||||||
sudo modprobe zfs
|
sudo modprobe zfs
|
||||||
# Workaround for cloud-init bug
|
|
||||||
# see https://github.com/openzfs/zfs/issues/12644
|
|
||||||
FILE=/lib/udev/rules.d/10-cloud-init-hook-hotplug.rules
|
|
||||||
if [ -r "${FILE}" ]; then
|
|
||||||
HASH=$(md5sum "${FILE}" | awk '{ print $1 }')
|
|
||||||
if [ "${HASH}" = "121ff0ef1936cd2ef65aec0458a35772" ]; then
|
|
||||||
# Just shove a zd* exclusion right above the hotplug hook...
|
|
||||||
sudo sed -i -e s/'LABEL="cloudinit_hook"'/'KERNEL=="zd*", GOTO="cloudinit_end"\n&'/ "${FILE}"
|
|
||||||
sudo udevadm control --reload-rules
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# Workaround to provide additional free space for testing.
|
# Workaround to provide additional free space for testing.
|
||||||
# https://github.com/actions/virtual-environments/issues/2840
|
# https://github.com/actions/virtual-environments/issues/2840
|
||||||
sudo rm -rf /usr/share/dotnet
|
sudo rm -rf /usr/share/dotnet
|
||||||
@@ -60,8 +48,7 @@ jobs:
|
|||||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: |
|
run: |
|
||||||
/usr/share/zfs/zfs-tests.sh -vR -s 3G -r sanity
|
/usr/share/zfs/zfs-tests.sh -v -s 3G -r sanity
|
||||||
timeout-minutes: 330
|
|
||||||
- name: Prepare artifacts
|
- name: Prepare artifacts
|
||||||
if: failure()
|
if: failure()
|
||||||
run: |
|
run: |
|
||||||
@@ -70,7 +57,7 @@ jobs:
|
|||||||
sudo cp /var/log/syslog $RESULTS_PATH/
|
sudo cp /var/log/syslog $RESULTS_PATH/
|
||||||
sudo chmod +r $RESULTS_PATH/*
|
sudo chmod +r $RESULTS_PATH/*
|
||||||
# Replace ':' in dir names, actions/upload-artifact doesn't support it
|
# Replace ':' in dir names, actions/upload-artifact doesn't support it
|
||||||
for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done
|
for f in $(find $RESULTS_PATH -name '*:*'); do mv "$f" "${f//:/__}"; done
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ jobs:
|
|||||||
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \
|
||||||
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \
|
||||||
libpam0g-dev \
|
libpam0g-dev \
|
||||||
python-dev python-setuptools python-cffi python-packaging \
|
python-dev python-setuptools python-cffi \
|
||||||
python3 python3-dev python3-setuptools python3-cffi python3-packaging
|
python3 python3-dev python3-setuptools python3-cffi
|
||||||
- name: Autogen.sh
|
- name: Autogen.sh
|
||||||
run: |
|
run: |
|
||||||
sh autogen.sh
|
sh autogen.sh
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo mkdir -p $TEST_DIR
|
sudo mkdir -p $TEST_DIR
|
||||||
# run for 20 minutes to have a total runner time of 30 minutes
|
# run for 20 minutes to have a total runner time of 30 minutes
|
||||||
sudo /usr/share/zfs/zloop.sh -t 1200 -l -m1 -- -T 120 -P 60
|
sudo /usr/share/zfs/zloop.sh -t 1200 -l -m1
|
||||||
- name: Prepare artifacts
|
- name: Prepare artifacts
|
||||||
if: failure()
|
if: failure()
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+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,10 +1,10 @@
|
|||||||
Meta: 1
|
Meta: 1
|
||||||
Name: zfs
|
Name: zfs
|
||||||
Branch: 1.0
|
Branch: 1.0
|
||||||
Version: 2.1.5
|
Version: 2.0.6
|
||||||
Release: 1
|
Release: 1
|
||||||
Release-Tags: relext
|
Release-Tags: relext
|
||||||
License: CDDL
|
License: CDDL
|
||||||
Author: OpenZFS
|
Author: OpenZFS
|
||||||
Linux-Maximum: 5.18
|
Linux-Maximum: 5.14
|
||||||
Linux-Minimum: 3.10
|
Linux-Minimum: 3.10
|
||||||
|
|||||||
+49
-27
@@ -1,5 +1,3 @@
|
|||||||
include $(top_srcdir)/config/Shellcheck.am
|
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I config
|
ACLOCAL_AMFLAGS = -I config
|
||||||
|
|
||||||
SUBDIRS = include
|
SUBDIRS = include
|
||||||
@@ -8,7 +6,7 @@ SUBDIRS += rpm
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
if CONFIG_USER
|
if CONFIG_USER
|
||||||
SUBDIRS += man scripts lib tests cmd etc contrib
|
SUBDIRS += etc man scripts lib tests cmd contrib
|
||||||
if BUILD_LINUX
|
if BUILD_LINUX
|
||||||
SUBDIRS += udev
|
SUBDIRS += udev
|
||||||
endif
|
endif
|
||||||
@@ -28,8 +26,8 @@ endif
|
|||||||
AUTOMAKE_OPTIONS = foreign
|
AUTOMAKE_OPTIONS = foreign
|
||||||
EXTRA_DIST = autogen.sh copy-builtin
|
EXTRA_DIST = autogen.sh copy-builtin
|
||||||
EXTRA_DIST += config/config.awk config/rpm.am config/deb.am config/tgz.am
|
EXTRA_DIST += config/config.awk config/rpm.am config/deb.am config/tgz.am
|
||||||
EXTRA_DIST += AUTHORS CODE_OF_CONDUCT.md COPYRIGHT LICENSE META NEWS NOTICE
|
EXTRA_DIST += META AUTHORS COPYRIGHT LICENSE NEWS NOTICE README.md
|
||||||
EXTRA_DIST += README.md RELEASES.md
|
EXTRA_DIST += CODE_OF_CONDUCT.md
|
||||||
EXTRA_DIST += module/lua/README.zfs module/os/linux/spl/README.md
|
EXTRA_DIST += module/lua/README.zfs module/os/linux/spl/README.md
|
||||||
|
|
||||||
# Include all the extra licensing information for modules
|
# Include all the extra licensing information for modules
|
||||||
@@ -103,7 +101,7 @@ endif
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
PHONY += codecheck
|
PHONY += codecheck
|
||||||
codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck zstdcheck
|
codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck
|
||||||
|
|
||||||
PHONY += checkstyle
|
PHONY += checkstyle
|
||||||
checkstyle: codecheck commitcheck
|
checkstyle: codecheck commitcheck
|
||||||
@@ -120,36 +118,64 @@ cstyle:
|
|||||||
-o -type f -name '*.[hc]' \
|
-o -type f -name '*.[hc]' \
|
||||||
! -name 'zfs_config.*' ! -name '*.mod.c' \
|
! -name 'zfs_config.*' ! -name '*.mod.c' \
|
||||||
! -name 'opt_global.h' ! -name '*_if*.h' \
|
! -name 'opt_global.h' ! -name '*_if*.h' \
|
||||||
! -name 'zstd_compat_wrapper.h' \
|
|
||||||
! -path './module/zstd/lib/*' \
|
! -path './module/zstd/lib/*' \
|
||||||
-exec ${top_srcdir}/scripts/cstyle.pl -cpP {} \+
|
-exec ${top_srcdir}/scripts/cstyle.pl -cpP {} \+
|
||||||
|
|
||||||
filter_executable = -exec test -x '{}' \; -print
|
filter_executable = -exec test -x '{}' \; -print
|
||||||
|
|
||||||
SHELLCHECKDIRS = cmd contrib etc scripts tests
|
PHONY += shellcheck
|
||||||
SHELLCHECKSCRIPTS = autogen.sh
|
shellcheck:
|
||||||
|
@if type shellcheck > /dev/null 2>&1; then \
|
||||||
|
shellcheck --exclude=SC1090 --exclude=SC1117 --format=gcc \
|
||||||
|
$$(find ${top_srcdir}/scripts/*.sh -type f) \
|
||||||
|
$$(find ${top_srcdir}/cmd/zed/zed.d/*.sh -type f) \
|
||||||
|
$$(find ${top_srcdir}/cmd/zpool/zpool.d/* \
|
||||||
|
-type f ${filter_executable}); \
|
||||||
|
else \
|
||||||
|
echo "skipping shellcheck because shellcheck is not installed"; \
|
||||||
|
fi
|
||||||
|
|
||||||
PHONY += checkabi storeabi
|
PHONY += checkabi storeabi
|
||||||
|
checkabi: lib
|
||||||
checklibabiversion:
|
|
||||||
libabiversion=`abidw -v | $(SED) 's/[^0-9]//g'`; \
|
|
||||||
if test $$libabiversion -lt "200"; then \
|
|
||||||
/bin/echo -e "\n" \
|
|
||||||
"*** Please use libabigail 2.0.0 version or newer;\n" \
|
|
||||||
"*** otherwise results are not consistent!\n" \
|
|
||||||
"(or see https://github.com/openzfs/libabigail-docker )\n"; \
|
|
||||||
exit 1; \
|
|
||||||
fi;
|
|
||||||
|
|
||||||
checkabi: checklibabiversion lib
|
|
||||||
$(MAKE) -C lib checkabi
|
$(MAKE) -C lib checkabi
|
||||||
|
|
||||||
storeabi: checklibabiversion lib
|
storeabi: lib
|
||||||
$(MAKE) -C lib storeabi
|
$(MAKE) -C lib storeabi
|
||||||
|
|
||||||
|
PHONY += checkbashisms
|
||||||
|
checkbashisms:
|
||||||
|
@if type checkbashisms > /dev/null 2>&1; then \
|
||||||
|
checkbashisms -n -p -x \
|
||||||
|
$$(find ${top_srcdir} \
|
||||||
|
-name '.git' -prune \
|
||||||
|
-o -name 'build' -prune \
|
||||||
|
-o -name 'tests' -prune \
|
||||||
|
-o -name 'config' -prune \
|
||||||
|
-o -name 'zed-functions.sh*' -prune \
|
||||||
|
-o -name 'zfs-import*' -prune \
|
||||||
|
-o -name 'zfs-mount*' -prune \
|
||||||
|
-o -name 'zfs-zed*' -prune \
|
||||||
|
-o -name 'smart' -prune \
|
||||||
|
-o -name 'paxcheck.sh' -prune \
|
||||||
|
-o -name 'make_gitrev.sh' -prune \
|
||||||
|
-o -name '90zfs' -prune \
|
||||||
|
-o -type f ! -name 'config*' \
|
||||||
|
! -name 'libtool' \
|
||||||
|
-exec sh -c 'awk "NR==1 && /#!.*bin\/sh.*/ {print FILENAME;}" "{}"' \;); \
|
||||||
|
else \
|
||||||
|
echo "skipping checkbashisms because checkbashisms is not installed"; \
|
||||||
|
fi
|
||||||
|
|
||||||
PHONY += mancheck
|
PHONY += mancheck
|
||||||
mancheck:
|
mancheck:
|
||||||
${top_srcdir}/scripts/mancheck.sh ${top_srcdir}/man ${top_srcdir}/tests/test-runner/man
|
@if type mandoc > /dev/null 2>&1; then \
|
||||||
|
find ${top_srcdir}/man/man8 -type f -name 'zfs.8' \
|
||||||
|
-o -name 'zpool.8' -o -name 'zdb.8' \
|
||||||
|
-o -name 'zgenhostid.8' | \
|
||||||
|
xargs mandoc -Tlint -Werror; \
|
||||||
|
else \
|
||||||
|
echo "skipping mancheck because mandoc is not installed"; \
|
||||||
|
fi
|
||||||
|
|
||||||
if BUILD_LINUX
|
if BUILD_LINUX
|
||||||
stat_fmt = -c '%A %n'
|
stat_fmt = -c '%A %n'
|
||||||
@@ -174,10 +200,6 @@ vcscheck:
|
|||||||
awk '{c++; print} END {if(c>0) exit 1}' ; \
|
awk '{c++; print} END {if(c>0) exit 1}' ; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PHONY += zstdcheck
|
|
||||||
zstdcheck:
|
|
||||||
@$(MAKE) -C module/zstd checksymbols
|
|
||||||
|
|
||||||
PHONY += lint
|
PHONY += lint
|
||||||
lint: cppcheck paxcheck
|
lint: cppcheck paxcheck
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ This repository contains the code for running OpenZFS on Linux and FreeBSD.
|
|||||||
* [Documentation](https://openzfs.github.io/openzfs-docs/) - for using and developing this repo
|
* [Documentation](https://openzfs.github.io/openzfs-docs/) - for using and developing this repo
|
||||||
* [ZoL Site](https://zfsonlinux.org) - Linux release info & links
|
* [ZoL Site](https://zfsonlinux.org) - Linux release info & links
|
||||||
* [Mailing lists](https://openzfs.github.io/openzfs-docs/Project%20and%20Community/Mailing%20Lists.html)
|
* [Mailing lists](https://openzfs.github.io/openzfs-docs/Project%20and%20Community/Mailing%20Lists.html)
|
||||||
* [OpenZFS site](https://openzfs.org/) - for conference videos and info on other platforms (illumos, OSX, Windows, etc)
|
* [OpenZFS site](http://open-zfs.org/) - for conference videos and info on other platforms (illumos, OSX, Windows, etc)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
@@ -32,4 +32,4 @@ For more details see the NOTICE, LICENSE and COPYRIGHT files; `UCRL-CODE-235197`
|
|||||||
|
|
||||||
# Supported Kernels
|
# Supported Kernels
|
||||||
* The `META` file contains the officially recognized supported Linux kernel versions.
|
* The `META` file contains the officially recognized supported Linux kernel versions.
|
||||||
* Supported FreeBSD versions are any supported branches and releases starting from 12.2-RELEASE.
|
* Supported FreeBSD versions are 12-STABLE and 13-CURRENT.
|
||||||
|
|||||||
-37
@@ -1,37 +0,0 @@
|
|||||||
OpenZFS uses the MAJOR.MINOR.PATCH versioning scheme described here:
|
|
||||||
|
|
||||||
* MAJOR - Incremented at the discretion of the OpenZFS developers to indicate
|
|
||||||
a particularly noteworthy feature or change. An increase in MAJOR number
|
|
||||||
does not indicate any incompatible on-disk format change. The ability
|
|
||||||
to import a ZFS pool is controlled by the feature flags enabled on the
|
|
||||||
pool and the feature flags supported by the installed OpenZFS version.
|
|
||||||
Increasing the MAJOR version is expected to be an infrequent occurrence.
|
|
||||||
|
|
||||||
* MINOR - Incremented to indicate new functionality such as a new feature
|
|
||||||
flag, pool/dataset property, zfs/zpool sub-command, new user/kernel
|
|
||||||
interface, etc. MINOR releases may introduce incompatible changes to the
|
|
||||||
user space library APIs (libzfs.so). Existing user/kernel interfaces are
|
|
||||||
considered to be stable to maximize compatibility between OpenZFS releases.
|
|
||||||
Additions to the user/kernel interface are backwards compatible.
|
|
||||||
|
|
||||||
* PATCH - Incremented when applying documentation updates, important bug
|
|
||||||
fixes, minor performance improvements, and kernel compatibility patches.
|
|
||||||
The user space library APIs and user/kernel interface are considered to
|
|
||||||
be stable. PATCH releases for a MAJOR.MINOR are published as needed.
|
|
||||||
|
|
||||||
Two release branches are maintained for OpenZFS, they are:
|
|
||||||
|
|
||||||
* OpenZFS LTS - A designated MAJOR.MINOR release with periodic PATCH
|
|
||||||
releases that incorporate important changes backported from newer OpenZFS
|
|
||||||
releases. This branch is intended for use in environments using an
|
|
||||||
LTS, enterprise, or similarly managed kernel (RHEL, Ubuntu LTS, Debian).
|
|
||||||
Minor changes to support these distribution kernels will be applied as
|
|
||||||
needed. New kernel versions released after the OpenZFS LTS release are
|
|
||||||
not supported. LTS releases will receive patches for at least 2 years.
|
|
||||||
The current LTS release is OpenZFS 2.1.
|
|
||||||
|
|
||||||
* OpenZFS current - Tracks the newest MAJOR.MINOR release. This branch
|
|
||||||
includes support for the latest OpenZFS features and recently releases
|
|
||||||
kernels. When a new MINOR release is tagged the previous MINOR release
|
|
||||||
will no longer be maintained (unless it is an LTS release). New MINOR
|
|
||||||
releases are planned to occur roughly annually.
|
|
||||||
+2
-9
@@ -1,14 +1,8 @@
|
|||||||
include $(top_srcdir)/config/Shellcheck.am
|
SUBDIRS = zfs zpool zdb zhack zinject zstream zstreamdump ztest
|
||||||
|
|
||||||
SUBDIRS = zfs zpool zdb zhack zinject zstream ztest
|
|
||||||
SUBDIRS += fsck_zfs vdev_id raidz_test zfs_ids_to_path
|
SUBDIRS += fsck_zfs vdev_id raidz_test zfs_ids_to_path
|
||||||
SUBDIRS += zpool_influxdb
|
|
||||||
|
|
||||||
CPPCHECKDIRS = zfs zpool zdb zhack zinject zstream ztest
|
CPPCHECKDIRS = zfs zpool zdb zhack zinject zstream ztest
|
||||||
CPPCHECKDIRS += raidz_test zfs_ids_to_path zpool_influxdb
|
CPPCHECKDIRS += raidz_test zfs_ids_to_path
|
||||||
|
|
||||||
# TODO: #12084: SHELLCHECKDIRS = fsck_zfs vdev_id zpool
|
|
||||||
SHELLCHECKDIRS = fsck_zfs zpool
|
|
||||||
|
|
||||||
if USING_PYTHON
|
if USING_PYTHON
|
||||||
SUBDIRS += arcstat arc_summary dbufstat
|
SUBDIRS += arcstat arc_summary dbufstat
|
||||||
@@ -17,7 +11,6 @@ endif
|
|||||||
if BUILD_LINUX
|
if BUILD_LINUX
|
||||||
SUBDIRS += mount_zfs zed zgenhostid zvol_id zvol_wait
|
SUBDIRS += mount_zfs zed zgenhostid zvol_id zvol_wait
|
||||||
CPPCHECKDIRS += mount_zfs zed zgenhostid zvol_id
|
CPPCHECKDIRS += mount_zfs zed zgenhostid zvol_id
|
||||||
SHELLCHECKDIRS += zed
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
PHONY = cppcheck
|
PHONY = cppcheck
|
||||||
|
|||||||
+58
-139
@@ -102,6 +102,18 @@ show_tunable_descriptions = False
|
|||||||
alternate_tunable_layout = False
|
alternate_tunable_layout = False
|
||||||
|
|
||||||
|
|
||||||
|
def handle_Exception(ex_cls, ex, tb):
|
||||||
|
if ex is IOError:
|
||||||
|
if ex.errno == errno.EPIPE:
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if ex is KeyboardInterrupt:
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
|
sys.excepthook = handle_Exception
|
||||||
|
|
||||||
|
|
||||||
def get_Kstat():
|
def get_Kstat():
|
||||||
"""Collect information on the ZFS subsystem from the /proc virtual
|
"""Collect information on the ZFS subsystem from the /proc virtual
|
||||||
file system. The name "kstat" is a holdover from the Solaris utility
|
file system. The name "kstat" is a holdover from the Solaris utility
|
||||||
@@ -213,30 +225,12 @@ def get_arc_summary(Kstat):
|
|||||||
deleted = Kstat["kstat.zfs.misc.arcstats.deleted"]
|
deleted = Kstat["kstat.zfs.misc.arcstats.deleted"]
|
||||||
mutex_miss = Kstat["kstat.zfs.misc.arcstats.mutex_miss"]
|
mutex_miss = Kstat["kstat.zfs.misc.arcstats.mutex_miss"]
|
||||||
evict_skip = Kstat["kstat.zfs.misc.arcstats.evict_skip"]
|
evict_skip = Kstat["kstat.zfs.misc.arcstats.evict_skip"]
|
||||||
evict_l2_cached = Kstat["kstat.zfs.misc.arcstats.evict_l2_cached"]
|
|
||||||
evict_l2_eligible = Kstat["kstat.zfs.misc.arcstats.evict_l2_eligible"]
|
|
||||||
evict_l2_eligible_mfu = Kstat["kstat.zfs.misc.arcstats.evict_l2_eligible_mfu"]
|
|
||||||
evict_l2_eligible_mru = Kstat["kstat.zfs.misc.arcstats.evict_l2_eligible_mru"]
|
|
||||||
evict_l2_ineligible = Kstat["kstat.zfs.misc.arcstats.evict_l2_ineligible"]
|
|
||||||
evict_l2_skip = Kstat["kstat.zfs.misc.arcstats.evict_l2_skip"]
|
|
||||||
|
|
||||||
# ARC Misc.
|
# ARC Misc.
|
||||||
output["arc_misc"] = {}
|
output["arc_misc"] = {}
|
||||||
output["arc_misc"]["deleted"] = fHits(deleted)
|
output["arc_misc"]["deleted"] = fHits(deleted)
|
||||||
output["arc_misc"]["mutex_miss"] = fHits(mutex_miss)
|
output["arc_misc"]['mutex_miss'] = fHits(mutex_miss)
|
||||||
output["arc_misc"]["evict_skips"] = fHits(evict_skip)
|
output["arc_misc"]['evict_skips'] = fHits(evict_skip)
|
||||||
output["arc_misc"]["evict_l2_skip"] = fHits(evict_l2_skip)
|
|
||||||
output["arc_misc"]["evict_l2_cached"] = fBytes(evict_l2_cached)
|
|
||||||
output["arc_misc"]["evict_l2_eligible"] = fBytes(evict_l2_eligible)
|
|
||||||
output["arc_misc"]["evict_l2_eligible_mfu"] = {
|
|
||||||
'per': fPerc(evict_l2_eligible_mfu, evict_l2_eligible),
|
|
||||||
'num': fBytes(evict_l2_eligible_mfu),
|
|
||||||
}
|
|
||||||
output["arc_misc"]["evict_l2_eligible_mru"] = {
|
|
||||||
'per': fPerc(evict_l2_eligible_mru, evict_l2_eligible),
|
|
||||||
'num': fBytes(evict_l2_eligible_mru),
|
|
||||||
}
|
|
||||||
output["arc_misc"]["evict_l2_ineligible"] = fBytes(evict_l2_ineligible)
|
|
||||||
|
|
||||||
# ARC Sizing
|
# ARC Sizing
|
||||||
arc_size = Kstat["kstat.zfs.misc.arcstats.size"]
|
arc_size = Kstat["kstat.zfs.misc.arcstats.size"]
|
||||||
@@ -352,26 +346,8 @@ def _arc_summary(Kstat):
|
|||||||
sys.stdout.write("\tDeleted:\t\t\t\t%s\n" % arc['arc_misc']['deleted'])
|
sys.stdout.write("\tDeleted:\t\t\t\t%s\n" % arc['arc_misc']['deleted'])
|
||||||
sys.stdout.write("\tMutex Misses:\t\t\t\t%s\n" %
|
sys.stdout.write("\tMutex Misses:\t\t\t\t%s\n" %
|
||||||
arc['arc_misc']['mutex_miss'])
|
arc['arc_misc']['mutex_miss'])
|
||||||
sys.stdout.write("\tEviction Skips:\t\t\t\t%s\n" %
|
sys.stdout.write("\tEvict Skips:\t\t\t\t%s\n" %
|
||||||
arc['arc_misc']['evict_skips'])
|
arc['arc_misc']['evict_skips'])
|
||||||
sys.stdout.write("\tEviction Skips Due to L2 Writes:\t%s\n" %
|
|
||||||
arc['arc_misc']['evict_l2_skip'])
|
|
||||||
sys.stdout.write("\tL2 Cached Evictions:\t\t\t%s\n" %
|
|
||||||
arc['arc_misc']['evict_l2_cached'])
|
|
||||||
sys.stdout.write("\tL2 Eligible Evictions:\t\t\t%s\n" %
|
|
||||||
arc['arc_misc']['evict_l2_eligible'])
|
|
||||||
sys.stdout.write("\tL2 Eligible MFU Evictions:\t%s\t%s\n" % (
|
|
||||||
arc['arc_misc']['evict_l2_eligible_mfu']['per'],
|
|
||||||
arc['arc_misc']['evict_l2_eligible_mfu']['num'],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
sys.stdout.write("\tL2 Eligible MRU Evictions:\t%s\t%s\n" % (
|
|
||||||
arc['arc_misc']['evict_l2_eligible_mru']['per'],
|
|
||||||
arc['arc_misc']['evict_l2_eligible_mru']['num'],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
sys.stdout.write("\tL2 Ineligible Evictions:\t\t%s\n" %
|
|
||||||
arc['arc_misc']['evict_l2_ineligible'])
|
|
||||||
sys.stdout.write("\n")
|
sys.stdout.write("\n")
|
||||||
|
|
||||||
# ARC Sizing
|
# ARC Sizing
|
||||||
@@ -707,11 +683,6 @@ def get_l2arc_summary(Kstat):
|
|||||||
l2_writes_done = Kstat["kstat.zfs.misc.arcstats.l2_writes_done"]
|
l2_writes_done = Kstat["kstat.zfs.misc.arcstats.l2_writes_done"]
|
||||||
l2_writes_error = Kstat["kstat.zfs.misc.arcstats.l2_writes_error"]
|
l2_writes_error = Kstat["kstat.zfs.misc.arcstats.l2_writes_error"]
|
||||||
l2_writes_sent = Kstat["kstat.zfs.misc.arcstats.l2_writes_sent"]
|
l2_writes_sent = Kstat["kstat.zfs.misc.arcstats.l2_writes_sent"]
|
||||||
l2_mfu_asize = Kstat["kstat.zfs.misc.arcstats.l2_mfu_asize"]
|
|
||||||
l2_mru_asize = Kstat["kstat.zfs.misc.arcstats.l2_mru_asize"]
|
|
||||||
l2_prefetch_asize = Kstat["kstat.zfs.misc.arcstats.l2_prefetch_asize"]
|
|
||||||
l2_bufc_data_asize = Kstat["kstat.zfs.misc.arcstats.l2_bufc_data_asize"]
|
|
||||||
l2_bufc_metadata_asize = Kstat["kstat.zfs.misc.arcstats.l2_bufc_metadata_asize"]
|
|
||||||
|
|
||||||
l2_access_total = (l2_hits + l2_misses)
|
l2_access_total = (l2_hits + l2_misses)
|
||||||
output['l2_health_count'] = (l2_writes_error + l2_cksum_bad + l2_io_error)
|
output['l2_health_count'] = (l2_writes_error + l2_cksum_bad + l2_io_error)
|
||||||
@@ -734,7 +705,7 @@ def get_l2arc_summary(Kstat):
|
|||||||
output["io_errors"] = fHits(l2_io_error)
|
output["io_errors"] = fHits(l2_io_error)
|
||||||
|
|
||||||
output["l2_arc_size"] = {}
|
output["l2_arc_size"] = {}
|
||||||
output["l2_arc_size"]["adaptive"] = fBytes(l2_size)
|
output["l2_arc_size"]["adative"] = fBytes(l2_size)
|
||||||
output["l2_arc_size"]["actual"] = {
|
output["l2_arc_size"]["actual"] = {
|
||||||
'per': fPerc(l2_asize, l2_size),
|
'per': fPerc(l2_asize, l2_size),
|
||||||
'num': fBytes(l2_asize)
|
'num': fBytes(l2_asize)
|
||||||
@@ -743,26 +714,6 @@ def get_l2arc_summary(Kstat):
|
|||||||
'per': fPerc(l2_hdr_size, l2_size),
|
'per': fPerc(l2_hdr_size, l2_size),
|
||||||
'num': fBytes(l2_hdr_size),
|
'num': fBytes(l2_hdr_size),
|
||||||
}
|
}
|
||||||
output["l2_arc_size"]["mfu_asize"] = {
|
|
||||||
'per': fPerc(l2_mfu_asize, l2_asize),
|
|
||||||
'num': fBytes(l2_mfu_asize),
|
|
||||||
}
|
|
||||||
output["l2_arc_size"]["mru_asize"] = {
|
|
||||||
'per': fPerc(l2_mru_asize, l2_asize),
|
|
||||||
'num': fBytes(l2_mru_asize),
|
|
||||||
}
|
|
||||||
output["l2_arc_size"]["prefetch_asize"] = {
|
|
||||||
'per': fPerc(l2_prefetch_asize, l2_asize),
|
|
||||||
'num': fBytes(l2_prefetch_asize),
|
|
||||||
}
|
|
||||||
output["l2_arc_size"]["bufc_data_asize"] = {
|
|
||||||
'per': fPerc(l2_bufc_data_asize, l2_asize),
|
|
||||||
'num': fBytes(l2_bufc_data_asize),
|
|
||||||
}
|
|
||||||
output["l2_arc_size"]["bufc_metadata_asize"] = {
|
|
||||||
'per': fPerc(l2_bufc_metadata_asize, l2_asize),
|
|
||||||
'num': fBytes(l2_bufc_metadata_asize),
|
|
||||||
}
|
|
||||||
|
|
||||||
output["l2_arc_evicts"] = {}
|
output["l2_arc_evicts"] = {}
|
||||||
output["l2_arc_evicts"]['lock_retries'] = fHits(l2_evict_lock_retry)
|
output["l2_arc_evicts"]['lock_retries'] = fHits(l2_evict_lock_retry)
|
||||||
@@ -827,7 +778,7 @@ def _l2arc_summary(Kstat):
|
|||||||
sys.stdout.write("\n")
|
sys.stdout.write("\n")
|
||||||
|
|
||||||
sys.stdout.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" %
|
sys.stdout.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" %
|
||||||
arc["l2_arc_size"]["adaptive"])
|
arc["l2_arc_size"]["adative"])
|
||||||
sys.stdout.write("\tCompressed:\t\t\t%s\t%s\n" % (
|
sys.stdout.write("\tCompressed:\t\t\t%s\t%s\n" % (
|
||||||
arc["l2_arc_size"]["actual"]["per"],
|
arc["l2_arc_size"]["actual"]["per"],
|
||||||
arc["l2_arc_size"]["actual"]["num"],
|
arc["l2_arc_size"]["actual"]["num"],
|
||||||
@@ -838,36 +789,11 @@ def _l2arc_summary(Kstat):
|
|||||||
arc["l2_arc_size"]["head_size"]["num"],
|
arc["l2_arc_size"]["head_size"]["num"],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
sys.stdout.write("\tMFU Alloc. Size:\t\t%s\t%s\n" % (
|
|
||||||
arc["l2_arc_size"]["mfu_asize"]["per"],
|
|
||||||
arc["l2_arc_size"]["mfu_asize"]["num"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
sys.stdout.write("\tMRU Alloc. Size:\t\t%s\t%s\n" % (
|
|
||||||
arc["l2_arc_size"]["mru_asize"]["per"],
|
|
||||||
arc["l2_arc_size"]["mru_asize"]["num"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
sys.stdout.write("\tPrefetch Alloc. Size:\t\t%s\t%s\n" % (
|
|
||||||
arc["l2_arc_size"]["prefetch_asize"]["per"],
|
|
||||||
arc["l2_arc_size"]["prefetch_asize"]["num"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
sys.stdout.write("\tData (buf content) Alloc. Size:\t%s\t%s\n" % (
|
|
||||||
arc["l2_arc_size"]["bufc_data_asize"]["per"],
|
|
||||||
arc["l2_arc_size"]["bufc_data_asize"]["num"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
sys.stdout.write("\tMetadata (buf content) Size:\t%s\t%s\n" % (
|
|
||||||
arc["l2_arc_size"]["bufc_metadata_asize"]["per"],
|
|
||||||
arc["l2_arc_size"]["bufc_metadata_asize"]["num"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
sys.stdout.write("\n")
|
sys.stdout.write("\n")
|
||||||
|
|
||||||
if arc["l2_arc_evicts"]['lock_retries'] != '0' or \
|
if arc["l2_arc_evicts"]['lock_retries'] != '0' or \
|
||||||
arc["l2_arc_evicts"]["reading"] != '0':
|
arc["l2_arc_evicts"]["reading"] != '0':
|
||||||
sys.stdout.write("L2 ARC Evictions:\n")
|
sys.stdout.write("L2 ARC Evicts:\n")
|
||||||
sys.stdout.write("\tLock Retries:\t\t\t\t%s\n" %
|
sys.stdout.write("\tLock Retries:\t\t\t\t%s\n" %
|
||||||
arc["l2_arc_evicts"]['lock_retries'])
|
arc["l2_arc_evicts"]['lock_retries'])
|
||||||
sys.stdout.write("\tUpon Reading:\t\t\t\t%s\n" %
|
sys.stdout.write("\tUpon Reading:\t\t\t\t%s\n" %
|
||||||
@@ -1125,55 +1051,48 @@ def main():
|
|||||||
global alternate_tunable_layout
|
global alternate_tunable_layout
|
||||||
|
|
||||||
try:
|
try:
|
||||||
try:
|
opts, args = getopt.getopt(
|
||||||
opts, args = getopt.getopt(
|
sys.argv[1:],
|
||||||
sys.argv[1:],
|
"adp:h", ["alternate", "description", "page=", "help"]
|
||||||
"adp:h", ["alternate", "description", "page=", "help"]
|
)
|
||||||
)
|
except getopt.error as e:
|
||||||
except getopt.error as e:
|
sys.stderr.write("Error: %s\n" % e.msg)
|
||||||
sys.stderr.write("Error: %s\n" % e.msg)
|
usage()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
args = {}
|
||||||
|
for opt, arg in opts:
|
||||||
|
if opt in ('-a', '--alternate'):
|
||||||
|
args['a'] = True
|
||||||
|
if opt in ('-d', '--description'):
|
||||||
|
args['d'] = True
|
||||||
|
if opt in ('-p', '--page'):
|
||||||
|
args['p'] = arg
|
||||||
|
if opt in ('-h', '--help'):
|
||||||
usage()
|
usage()
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
args = {}
|
|
||||||
for opt, arg in opts:
|
|
||||||
if opt in ('-a', '--alternate'):
|
|
||||||
args['a'] = True
|
|
||||||
if opt in ('-d', '--description'):
|
|
||||||
args['d'] = True
|
|
||||||
if opt in ('-p', '--page'):
|
|
||||||
args['p'] = arg
|
|
||||||
if opt in ('-h', '--help'):
|
|
||||||
usage()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
Kstat = get_Kstat()
|
|
||||||
|
|
||||||
alternate_tunable_layout = 'a' in args
|
|
||||||
show_tunable_descriptions = 'd' in args
|
|
||||||
|
|
||||||
pages = []
|
|
||||||
|
|
||||||
if 'p' in args:
|
|
||||||
try:
|
|
||||||
pages.append(unSub[int(args['p']) - 1])
|
|
||||||
except IndexError:
|
|
||||||
sys.stderr.write('the argument to -p must be between 1 and ' +
|
|
||||||
str(len(unSub)) + '\n')
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
pages = unSub
|
|
||||||
|
|
||||||
zfs_header()
|
|
||||||
for page in pages:
|
|
||||||
page(Kstat)
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
except IOError as ex:
|
|
||||||
if (ex.errno == errno.EPIPE):
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
raise
|
|
||||||
except KeyboardInterrupt:
|
Kstat = get_Kstat()
|
||||||
sys.exit(0)
|
|
||||||
|
alternate_tunable_layout = 'a' in args
|
||||||
|
show_tunable_descriptions = 'd' in args
|
||||||
|
|
||||||
|
pages = []
|
||||||
|
|
||||||
|
if 'p' in args:
|
||||||
|
try:
|
||||||
|
pages.append(unSub[int(args['p']) - 1])
|
||||||
|
except IndexError:
|
||||||
|
sys.stderr.write('the argument to -p must be between 1 and ' +
|
||||||
|
str(len(unSub)) + '\n')
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
pages = unSub
|
||||||
|
|
||||||
|
zfs_header()
|
||||||
|
for page in pages:
|
||||||
|
page(Kstat)
|
||||||
|
sys.stdout.write("\n")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -42,13 +42,6 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import errno
|
|
||||||
|
|
||||||
# We can't use env -S portably, and we need python3 -u to handle pipes in
|
|
||||||
# the shell abruptly closing the way we want to, so...
|
|
||||||
import io
|
|
||||||
if isinstance(sys.__stderr__.buffer, io.BufferedWriter):
|
|
||||||
os.execv(sys.executable, [sys.executable, "-u"] + sys.argv)
|
|
||||||
|
|
||||||
DESCRIPTION = 'Print ARC and other statistics for OpenZFS'
|
DESCRIPTION = 'Print ARC and other statistics for OpenZFS'
|
||||||
INDENT = ' '*8
|
INDENT = ' '*8
|
||||||
@@ -65,6 +58,7 @@ SECTION_PATHS = {'arc': 'arcstats',
|
|||||||
'dmu': 'dmu_tx',
|
'dmu': 'dmu_tx',
|
||||||
'l2arc': 'arcstats', # L2ARC stuff lives in arcstats
|
'l2arc': 'arcstats', # L2ARC stuff lives in arcstats
|
||||||
'vdev': 'vdev_cache_stats',
|
'vdev': 'vdev_cache_stats',
|
||||||
|
'xuio': 'xuio_stats',
|
||||||
'zfetch': 'zfetchstats',
|
'zfetch': 'zfetchstats',
|
||||||
'zil': 'zil'}
|
'zil': 'zil'}
|
||||||
|
|
||||||
@@ -168,11 +162,21 @@ elif sys.platform.startswith('linux'):
|
|||||||
# The original arc_summary called /sbin/modinfo/{spl,zfs} to get
|
# The original arc_summary called /sbin/modinfo/{spl,zfs} to get
|
||||||
# the version information. We switch to /sys/module/{spl,zfs}/version
|
# the version information. We switch to /sys/module/{spl,zfs}/version
|
||||||
# to make sure we get what is really loaded in the kernel
|
# to make sure we get what is really loaded in the kernel
|
||||||
try:
|
command = ["cat", "/sys/module/{0}/version".format(request)]
|
||||||
with open("/sys/module/{}/version".format(request)) as f:
|
req = request.upper()
|
||||||
return f.read().strip()
|
|
||||||
except:
|
# The recommended way to do this is with subprocess.run(). However,
|
||||||
return "(unknown)"
|
# some installed versions of Python are < 3.5, so we offer them
|
||||||
|
# the option of doing it the old way (for now)
|
||||||
|
if 'run' in dir(subprocess):
|
||||||
|
info = subprocess.run(command, stdout=subprocess.PIPE,
|
||||||
|
universal_newlines=True)
|
||||||
|
version = info.stdout.strip()
|
||||||
|
else:
|
||||||
|
info = subprocess.check_output(command, universal_newlines=True)
|
||||||
|
version = info.strip()
|
||||||
|
|
||||||
|
return version
|
||||||
|
|
||||||
def get_descriptions(request):
|
def get_descriptions(request):
|
||||||
"""Get the descriptions of the Solaris Porting Layer (SPL) or the
|
"""Get the descriptions of the Solaris Porting Layer (SPL) or the
|
||||||
@@ -228,29 +232,6 @@ elif sys.platform.startswith('linux'):
|
|||||||
|
|
||||||
return descs
|
return descs
|
||||||
|
|
||||||
def handle_unraisableException(exc_type, exc_value=None, exc_traceback=None,
|
|
||||||
err_msg=None, object=None):
|
|
||||||
handle_Exception(exc_type, object, exc_traceback)
|
|
||||||
|
|
||||||
def handle_Exception(ex_cls, ex, tb):
|
|
||||||
if ex_cls is KeyboardInterrupt:
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
if ex_cls is BrokenPipeError:
|
|
||||||
# It turns out that while sys.exit() triggers an exception
|
|
||||||
# not handled message on Python 3.8+, os._exit() does not.
|
|
||||||
os._exit(0)
|
|
||||||
|
|
||||||
if ex_cls is OSError:
|
|
||||||
if ex.errno == errno.ENOTCONN:
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
raise ex
|
|
||||||
|
|
||||||
if hasattr(sys,'unraisablehook'): # Python 3.8+
|
|
||||||
sys.unraisablehook = handle_unraisableException
|
|
||||||
sys.excepthook = handle_Exception
|
|
||||||
|
|
||||||
|
|
||||||
def cleanup_line(single_line):
|
def cleanup_line(single_line):
|
||||||
"""Format a raw line of data from /proc and isolate the name value
|
"""Format a raw line of data from /proc and isolate the name value
|
||||||
@@ -612,20 +593,6 @@ def section_arc(kstats_dict):
|
|||||||
prt_i1('Deleted:', f_hits(arc_stats['deleted']))
|
prt_i1('Deleted:', f_hits(arc_stats['deleted']))
|
||||||
prt_i1('Mutex misses:', f_hits(arc_stats['mutex_miss']))
|
prt_i1('Mutex misses:', f_hits(arc_stats['mutex_miss']))
|
||||||
prt_i1('Eviction skips:', f_hits(arc_stats['evict_skip']))
|
prt_i1('Eviction skips:', f_hits(arc_stats['evict_skip']))
|
||||||
prt_i1('Eviction skips due to L2 writes:',
|
|
||||||
f_hits(arc_stats['evict_l2_skip']))
|
|
||||||
prt_i1('L2 cached evictions:', f_bytes(arc_stats['evict_l2_cached']))
|
|
||||||
prt_i1('L2 eligible evictions:', f_bytes(arc_stats['evict_l2_eligible']))
|
|
||||||
prt_i2('L2 eligible MFU evictions:',
|
|
||||||
f_perc(arc_stats['evict_l2_eligible_mfu'],
|
|
||||||
arc_stats['evict_l2_eligible']),
|
|
||||||
f_bytes(arc_stats['evict_l2_eligible_mfu']))
|
|
||||||
prt_i2('L2 eligible MRU evictions:',
|
|
||||||
f_perc(arc_stats['evict_l2_eligible_mru'],
|
|
||||||
arc_stats['evict_l2_eligible']),
|
|
||||||
f_bytes(arc_stats['evict_l2_eligible_mru']))
|
|
||||||
prt_i1('L2 ineligible evictions:',
|
|
||||||
f_bytes(arc_stats['evict_l2_ineligible']))
|
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
|
||||||
@@ -764,21 +731,6 @@ def section_l2arc(kstats_dict):
|
|||||||
prt_i2('Header size:',
|
prt_i2('Header size:',
|
||||||
f_perc(arc_stats['l2_hdr_size'], arc_stats['l2_size']),
|
f_perc(arc_stats['l2_hdr_size'], arc_stats['l2_size']),
|
||||||
f_bytes(arc_stats['l2_hdr_size']))
|
f_bytes(arc_stats['l2_hdr_size']))
|
||||||
prt_i2('MFU allocated size:',
|
|
||||||
f_perc(arc_stats['l2_mfu_asize'], arc_stats['l2_asize']),
|
|
||||||
f_bytes(arc_stats['l2_mfu_asize']))
|
|
||||||
prt_i2('MRU allocated size:',
|
|
||||||
f_perc(arc_stats['l2_mru_asize'], arc_stats['l2_asize']),
|
|
||||||
f_bytes(arc_stats['l2_mru_asize']))
|
|
||||||
prt_i2('Prefetch allocated size:',
|
|
||||||
f_perc(arc_stats['l2_prefetch_asize'], arc_stats['l2_asize']),
|
|
||||||
f_bytes(arc_stats['l2_prefetch_asize']))
|
|
||||||
prt_i2('Data (buffer content) allocated size:',
|
|
||||||
f_perc(arc_stats['l2_bufc_data_asize'], arc_stats['l2_asize']),
|
|
||||||
f_bytes(arc_stats['l2_bufc_data_asize']))
|
|
||||||
prt_i2('Metadata (buffer content) allocated size:',
|
|
||||||
f_perc(arc_stats['l2_bufc_metadata_asize'], arc_stats['l2_asize']),
|
|
||||||
f_bytes(arc_stats['l2_bufc_metadata_asize']))
|
|
||||||
|
|
||||||
print()
|
print()
|
||||||
prt_1('L2ARC breakdown:', f_hits(l2_access_total))
|
prt_1('L2ARC breakdown:', f_hits(l2_access_total))
|
||||||
|
|||||||
@@ -88,12 +88,6 @@ cols = {
|
|||||||
"mfug": [4, 1000, "MFU ghost list hits per second"],
|
"mfug": [4, 1000, "MFU ghost list hits per second"],
|
||||||
"mrug": [4, 1000, "MRU ghost list hits per second"],
|
"mrug": [4, 1000, "MRU ghost list hits per second"],
|
||||||
"eskip": [5, 1000, "evict_skip 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"],
|
"mtxmis": [6, 1000, "mutex_miss per second"],
|
||||||
"dread": [5, 1000, "Demand accesses per second"],
|
"dread": [5, 1000, "Demand accesses per second"],
|
||||||
"pread": [5, 1000, "Prefetch accesses per second"],
|
"pread": [5, 1000, "Prefetch accesses per second"],
|
||||||
@@ -102,16 +96,6 @@ cols = {
|
|||||||
"l2read": [6, 1000, "Total L2ARC accesses per second"],
|
"l2read": [6, 1000, "Total L2ARC accesses per second"],
|
||||||
"l2hit%": [6, 100, "L2ARC access hit percentage"],
|
"l2hit%": [6, 100, "L2ARC access hit percentage"],
|
||||||
"l2miss%": [7, 100, "L2ARC access miss 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"],
|
"l2asize": [7, 1024, "Actual (compressed) size of the L2ARC"],
|
||||||
"l2size": [6, 1024, "Size of the L2ARC"],
|
"l2size": [6, 1024, "Size of the L2ARC"],
|
||||||
"l2bytes": [7, 1024, "Bytes read per second from the L2ARC"],
|
"l2bytes": [7, 1024, "Bytes read per second from the L2ARC"],
|
||||||
@@ -479,12 +463,6 @@ def calculate():
|
|||||||
v["mrug"] = d["mru_ghost_hits"] / sint
|
v["mrug"] = d["mru_ghost_hits"] / sint
|
||||||
v["mfug"] = d["mfu_ghost_hits"] / sint
|
v["mfug"] = d["mfu_ghost_hits"] / sint
|
||||||
v["eskip"] = d["evict_skip"] / 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["mtxmis"] = d["mutex_miss"] / sint
|
||||||
|
|
||||||
if l2exist:
|
if l2exist:
|
||||||
@@ -498,17 +476,6 @@ def calculate():
|
|||||||
v["l2size"] = cur["l2_size"]
|
v["l2size"] = cur["l2_size"]
|
||||||
v["l2bytes"] = d["l2_read_bytes"] / sint
|
v["l2bytes"] = d["l2_read_bytes"] / sint
|
||||||
|
|
||||||
v["l2pref"] = cur["l2_prefetch_asize"]
|
|
||||||
v["l2mfu"] = cur["l2_mfu_asize"]
|
|
||||||
v["l2mru"] = cur["l2_mru_asize"]
|
|
||||||
v["l2data"] = cur["l2_bufc_data_asize"]
|
|
||||||
v["l2meta"] = cur["l2_bufc_metadata_asize"]
|
|
||||||
v["l2pref%"] = 100 * v["l2pref"] / v["l2asize"]
|
|
||||||
v["l2mfu%"] = 100 * v["l2mfu"] / v["l2asize"]
|
|
||||||
v["l2mru%"] = 100 * v["l2mru"] / v["l2asize"]
|
|
||||||
v["l2data%"] = 100 * v["l2data"] / v["l2asize"]
|
|
||||||
v["l2meta%"] = 100 * v["l2meta"] / v["l2asize"]
|
|
||||||
|
|
||||||
v["grow"] = 0 if cur["arc_no_grow"] else 1
|
v["grow"] = 0 if cur["arc_no_grow"] else 1
|
||||||
v["need"] = cur["arc_need_free"]
|
v["need"] = cur["arc_need_free"]
|
||||||
v["free"] = cur["memory_free_bytes"]
|
v["free"] = cur["memory_free_bytes"]
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
/fsck.zfs
|
|
||||||
@@ -1,6 +1 @@
|
|||||||
include $(top_srcdir)/config/Substfiles.am
|
|
||||||
include $(top_srcdir)/config/Shellcheck.am
|
|
||||||
|
|
||||||
dist_sbin_SCRIPTS = fsck.zfs
|
dist_sbin_SCRIPTS = fsck.zfs
|
||||||
|
|
||||||
SUBSTFILES += $(dist_sbin_SCRIPTS)
|
|
||||||
|
|||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# fsck.zfs: A fsck helper to accommodate distributions that expect
|
||||||
|
# to be able to execute a fsck on all filesystem types. Currently
|
||||||
|
# this script does nothing but it could be extended to act as a
|
||||||
|
# compatibility wrapper for 'zpool scrub'.
|
||||||
|
#
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -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 [ "$#" = "0" ]; then
|
|
||||||
echo "Usage: $0 [options] dataset…" >&2
|
|
||||||
exit 16
|
|
||||||
fi
|
|
||||||
|
|
||||||
ret=0
|
|
||||||
for dataset in "$@"; 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"
|
|
||||||
+17
-39
@@ -185,11 +185,10 @@ main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
if (optopt)
|
(void) fprintf(stderr, gettext("Invalid option '%c'\n"),
|
||||||
(void) fprintf(stderr,
|
optopt);
|
||||||
gettext("Invalid option '%c'\n"), optopt);
|
|
||||||
(void) fprintf(stderr, gettext("Usage: mount.zfs "
|
(void) fprintf(stderr, gettext("Usage: mount.zfs "
|
||||||
"[-sfnvh] [-o options] <dataset> <mountpoint>\n"));
|
"[-sfnv] [-o options] <dataset> <mountpoint>\n"));
|
||||||
return (MOUNT_USAGE);
|
return (MOUNT_USAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,6 +245,13 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
(void) fprintf(stdout, gettext("mount.zfs:\n"
|
||||||
|
" dataset: \"%s\"\n mountpoint: \"%s\"\n"
|
||||||
|
" mountflags: 0x%lx\n zfsflags: 0x%lx\n"
|
||||||
|
" mountopts: \"%s\"\n mtabopts: \"%s\"\n"),
|
||||||
|
dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
|
||||||
|
|
||||||
if (mntflags & MS_REMOUNT) {
|
if (mntflags & MS_REMOUNT) {
|
||||||
nomtab = 1;
|
nomtab = 1;
|
||||||
remount = 1;
|
remount = 1;
|
||||||
@@ -268,10 +274,7 @@ main(int argc, char **argv)
|
|||||||
return (MOUNT_USAGE);
|
return (MOUNT_USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!zfsutil || sloppy ||
|
zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt);
|
||||||
libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
|
|
||||||
zfs_adjust_mount_options(zhp, mntpoint, mntopts, mtabopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* treat all snapshots as legacy mount points */
|
/* treat all snapshots as legacy mount points */
|
||||||
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
|
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
|
||||||
@@ -289,11 +292,12 @@ main(int argc, char **argv)
|
|||||||
if (zfs_version == 0) {
|
if (zfs_version == 0) {
|
||||||
fprintf(stderr, gettext("unable to fetch "
|
fprintf(stderr, gettext("unable to fetch "
|
||||||
"ZFS version for filesystem '%s'\n"), dataset);
|
"ZFS version for filesystem '%s'\n"), dataset);
|
||||||
zfs_close(zhp);
|
|
||||||
libzfs_fini(g_zfs);
|
|
||||||
return (MOUNT_SYSERR);
|
return (MOUNT_SYSERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zfs_close(zhp);
|
||||||
|
libzfs_fini(g_zfs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Legacy mount points may only be mounted using 'mount', never using
|
* Legacy mount points may only be mounted using 'mount', never using
|
||||||
* 'zfs mount'. However, since 'zfs mount' actually invokes 'mount'
|
* 'zfs mount'. However, since 'zfs mount' actually invokes 'mount'
|
||||||
@@ -311,8 +315,6 @@ main(int argc, char **argv)
|
|||||||
"Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n"
|
"Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n"
|
||||||
"See zfs(8) for more information.\n"),
|
"See zfs(8) for more information.\n"),
|
||||||
dataset, mntpoint, dataset, mntpoint);
|
dataset, mntpoint, dataset, mntpoint);
|
||||||
zfs_close(zhp);
|
|
||||||
libzfs_fini(g_zfs);
|
|
||||||
return (MOUNT_USAGE);
|
return (MOUNT_USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,38 +325,14 @@ main(int argc, char **argv)
|
|||||||
"Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n"
|
"Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n"
|
||||||
"See zfs(8) for more information.\n"),
|
"See zfs(8) for more information.\n"),
|
||||||
dataset, "legacy", dataset);
|
dataset, "legacy", dataset);
|
||||||
zfs_close(zhp);
|
|
||||||
libzfs_fini(g_zfs);
|
|
||||||
return (MOUNT_USAGE);
|
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 (!fake) {
|
||||||
if (zfsutil && !sloppy &&
|
error = mount(dataset, mntpoint, MNTTYPE_ZFS,
|
||||||
!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
|
mntflags, mntopts);
|
||||||
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) {
|
if (error) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
@@ -389,7 +367,7 @@ main(int argc, char **argv)
|
|||||||
"mount the filesystem again.\n"), dataset);
|
"mount the filesystem again.\n"), dataset);
|
||||||
return (MOUNT_SYSERR);
|
return (MOUNT_SYSERR);
|
||||||
}
|
}
|
||||||
fallthrough;
|
/* fallthru */
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
(void) fprintf(stderr, gettext("filesystem "
|
(void) fprintf(stderr, gettext("filesystem "
|
||||||
|
|||||||
@@ -31,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)
|
||||||
@@ -81,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.io_abd,
|
|
||||||
zio_bench.io_size, zio_bench.io_offset,
|
|
||||||
rto_opts.rto_ashift, ncols+1, ncols,
|
|
||||||
fn+1, rto_opts.rto_expand_offset);
|
|
||||||
} else {
|
|
||||||
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
|
||||||
BENCH_ASHIFT, ncols, fn+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* estimate iteration count */
|
/* estimate iteration count */
|
||||||
iter_cnt = GEN_BENCH_MEMORY;
|
iter_cnt = GEN_BENCH_MEMORY;
|
||||||
@@ -170,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.io_abd,
|
|
||||||
zio_bench.io_size, zio_bench.io_offset,
|
|
||||||
BENCH_ASHIFT, ncols+1, ncols,
|
|
||||||
PARITY_PQR, rto_opts.rto_expand_offset);
|
|
||||||
} else {
|
|
||||||
rm_bench = vdev_raidz_map_alloc(&zio_bench,
|
|
||||||
BENCH_ASHIFT, ncols, PARITY_PQR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* estimate iteration count */
|
/* estimate iteration count */
|
||||||
iter_cnt = (REC_BENCH_MEMORY);
|
iter_cnt = (REC_BENCH_MEMORY);
|
||||||
|
|||||||
+45
-284
@@ -77,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 */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,8 +104,6 @@ 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[-r expanded raidz map reflow offset (default: %llx)]\n"
|
|
||||||
"\t[-v increase verbosity (default: %zu)]\n"
|
"\t[-v increase verbosity (default: %zu)]\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"
|
||||||
@@ -120,8 +114,6 @@ 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 */
|
|
||||||
(u_longlong_t)o->rto_expand_offset, /* -r */
|
|
||||||
o->rto_v); /* -d */
|
o->rto_v); /* -d */
|
||||||
|
|
||||||
exit(requested ? 0 : 1);
|
exit(requested ? 0 : 1);
|
||||||
@@ -136,7 +128,7 @@ static void process_options(int argc, char **argv)
|
|||||||
|
|
||||||
bcopy(&rto_opts_defaults, o, sizeof (*o));
|
bcopy(&rto_opts_defaults, o, sizeof (*o));
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "TDBSvha:er:o:d:s:t:")) != -1) {
|
while ((opt = getopt(argc, argv, "TDBSvha:o:d:s:t:")) != -1) {
|
||||||
value = 0;
|
value = 0;
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
@@ -144,12 +136,6 @@ static void process_options(int argc, char **argv)
|
|||||||
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;
|
||||||
@@ -193,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);
|
||||||
@@ -229,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);
|
||||||
@@ -269,13 +236,12 @@ init_rand(void *data, size_t size, void *private)
|
|||||||
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]];
|
||||||
init_rand, NULL);
|
abd_iterate_func(col->rc_abd, 0, col->rc_size, init_rand, NULL);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,22 +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->io_abd,
|
rm_test = vdev_raidz_map_alloc(zio_test,
|
||||||
opts->zio_golden->io_size, opts->zio_golden->io_offset,
|
opts->rto_ashift, total_ncols, parity);
|
||||||
opts->rto_ashift, total_ncols+1, total_ncols,
|
|
||||||
parity, opts->rto_expand_offset);
|
|
||||||
rm_test = vdev_raidz_map_alloc_expanded(zio_test->io_abd,
|
|
||||||
zio_test->io_size, zio_test->io_offset,
|
|
||||||
opts->rto_ashift, total_ncols+1, total_ncols,
|
|
||||||
parity, opts->rto_expand_offset);
|
|
||||||
} else {
|
|
||||||
opts->rm_golden = vdev_raidz_map_alloc(opts->zio_golden,
|
|
||||||
opts->rto_ashift, total_ncols, parity);
|
|
||||||
rm_test = vdev_raidz_map_alloc(zio_test,
|
|
||||||
opts->rto_ashift, total_ncols, parity);
|
|
||||||
}
|
|
||||||
|
|
||||||
VERIFY(opts->zio_golden);
|
VERIFY(opts->zio_golden);
|
||||||
VERIFY(opts->rm_golden);
|
VERIFY(opts->rm_golden);
|
||||||
@@ -358,187 +312,6 @@ init_raidz_golden_map(raidz_test_opts_t *opts, const int parity)
|
|||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If reflow is not in progress, reflow_offset should be UINT64_MAX.
|
|
||||||
* For each row, if the row is entirely before reflow_offset, it will
|
|
||||||
* come from the new location. Otherwise this row will come from the
|
|
||||||
* old location. Therefore, rows that straddle the reflow_offset will
|
|
||||||
* come from the old location.
|
|
||||||
*
|
|
||||||
* NOTE: Until raidz expansion is implemented this function is only
|
|
||||||
* needed by raidz_test.c to the multi-row raid_map_t functionality.
|
|
||||||
*/
|
|
||||||
raidz_map_t *
|
|
||||||
vdev_raidz_map_alloc_expanded(abd_t *abd, uint64_t size, uint64_t offset,
|
|
||||||
uint64_t ashift, uint64_t physical_cols, uint64_t logical_cols,
|
|
||||||
uint64_t nparity, uint64_t reflow_offset)
|
|
||||||
{
|
|
||||||
/* The zio's size in units of the vdev's minimum sector size. */
|
|
||||||
uint64_t s = size >> ashift;
|
|
||||||
uint64_t q, r, bc, devidx, asize = 0, tot;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* "Quotient": The number of data sectors for this stripe on all but
|
|
||||||
* the "big column" child vdevs that also contain "remainder" data.
|
|
||||||
* AKA "full rows"
|
|
||||||
*/
|
|
||||||
q = s / (logical_cols - nparity);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* "Remainder": The number of partial stripe data sectors in this I/O.
|
|
||||||
* This will add a sector to some, but not all, child vdevs.
|
|
||||||
*/
|
|
||||||
r = s - q * (logical_cols - nparity);
|
|
||||||
|
|
||||||
/* The number of "big columns" - those which contain remainder data. */
|
|
||||||
bc = (r == 0 ? 0 : r + nparity);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The total number of data and parity sectors associated with
|
|
||||||
* this I/O.
|
|
||||||
*/
|
|
||||||
tot = s + nparity * (q + (r == 0 ? 0 : 1));
|
|
||||||
|
|
||||||
/* How many rows contain data (not skip) */
|
|
||||||
uint64_t rows = howmany(tot, logical_cols);
|
|
||||||
int cols = MIN(tot, logical_cols);
|
|
||||||
|
|
||||||
raidz_map_t *rm = kmem_zalloc(offsetof(raidz_map_t, rm_row[rows]),
|
|
||||||
KM_SLEEP);
|
|
||||||
rm->rm_nrows = rows;
|
|
||||||
|
|
||||||
for (uint64_t row = 0; row < rows; row++) {
|
|
||||||
raidz_row_t *rr = kmem_alloc(offsetof(raidz_row_t,
|
|
||||||
rr_col[cols]), KM_SLEEP);
|
|
||||||
rm->rm_row[row] = rr;
|
|
||||||
|
|
||||||
/* The starting RAIDZ (parent) vdev sector of the row. */
|
|
||||||
uint64_t b = (offset >> ashift) + row * logical_cols;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we are in the middle of a reflow, and any part of this
|
|
||||||
* row has not been copied, then use the old location of
|
|
||||||
* this row.
|
|
||||||
*/
|
|
||||||
int row_phys_cols = physical_cols;
|
|
||||||
if (b + (logical_cols - nparity) > reflow_offset >> ashift)
|
|
||||||
row_phys_cols--;
|
|
||||||
|
|
||||||
/* starting child of this row */
|
|
||||||
uint64_t child_id = b % row_phys_cols;
|
|
||||||
/* The starting byte offset on each child vdev. */
|
|
||||||
uint64_t child_offset = (b / row_phys_cols) << ashift;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We set cols to the entire width of the block, even
|
|
||||||
* if this row is shorter. This is needed because parity
|
|
||||||
* generation (for Q and R) needs to know the entire width,
|
|
||||||
* because it treats the short row as though it was
|
|
||||||
* full-width (and the "phantom" sectors were zero-filled).
|
|
||||||
*
|
|
||||||
* Another approach to this would be to set cols shorter
|
|
||||||
* (to just the number of columns that we might do i/o to)
|
|
||||||
* and have another mechanism to tell the parity generation
|
|
||||||
* about the "entire width". Reconstruction (at least
|
|
||||||
* vdev_raidz_reconstruct_general()) would also need to
|
|
||||||
* know about the "entire width".
|
|
||||||
*/
|
|
||||||
rr->rr_cols = cols;
|
|
||||||
rr->rr_bigcols = bc;
|
|
||||||
rr->rr_missingdata = 0;
|
|
||||||
rr->rr_missingparity = 0;
|
|
||||||
rr->rr_firstdatacol = nparity;
|
|
||||||
rr->rr_abd_empty = NULL;
|
|
||||||
rr->rr_nempty = 0;
|
|
||||||
|
|
||||||
for (int c = 0; c < rr->rr_cols; c++, child_id++) {
|
|
||||||
if (child_id >= row_phys_cols) {
|
|
||||||
child_id -= row_phys_cols;
|
|
||||||
child_offset += 1ULL << ashift;
|
|
||||||
}
|
|
||||||
rr->rr_col[c].rc_devidx = child_id;
|
|
||||||
rr->rr_col[c].rc_offset = child_offset;
|
|
||||||
rr->rr_col[c].rc_orig_data = NULL;
|
|
||||||
rr->rr_col[c].rc_error = 0;
|
|
||||||
rr->rr_col[c].rc_tried = 0;
|
|
||||||
rr->rr_col[c].rc_skipped = 0;
|
|
||||||
rr->rr_col[c].rc_need_orig_restore = B_FALSE;
|
|
||||||
|
|
||||||
uint64_t dc = c - rr->rr_firstdatacol;
|
|
||||||
if (c < rr->rr_firstdatacol) {
|
|
||||||
rr->rr_col[c].rc_size = 1ULL << ashift;
|
|
||||||
rr->rr_col[c].rc_abd =
|
|
||||||
abd_alloc_linear(rr->rr_col[c].rc_size,
|
|
||||||
B_TRUE);
|
|
||||||
} else if (row == rows - 1 && bc != 0 && c >= bc) {
|
|
||||||
/*
|
|
||||||
* Past the end, this for parity generation.
|
|
||||||
*/
|
|
||||||
rr->rr_col[c].rc_size = 0;
|
|
||||||
rr->rr_col[c].rc_abd = NULL;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* "data column" (col excluding parity)
|
|
||||||
* Add an ASCII art diagram here
|
|
||||||
*/
|
|
||||||
uint64_t off;
|
|
||||||
|
|
||||||
if (c < bc || r == 0) {
|
|
||||||
off = dc * rows + row;
|
|
||||||
} else {
|
|
||||||
off = r * rows +
|
|
||||||
(dc - r) * (rows - 1) + row;
|
|
||||||
}
|
|
||||||
rr->rr_col[c].rc_size = 1ULL << ashift;
|
|
||||||
rr->rr_col[c].rc_abd = abd_get_offset_struct(
|
|
||||||
&rr->rr_col[c].rc_abdstruct,
|
|
||||||
abd, off << ashift, 1 << ashift);
|
|
||||||
}
|
|
||||||
|
|
||||||
asize += rr->rr_col[c].rc_size;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* If all data stored spans all columns, there's a danger that
|
|
||||||
* parity will always be on the same device and, since parity
|
|
||||||
* isn't read during normal operation, that that device's I/O
|
|
||||||
* bandwidth won't be used effectively. We therefore switch
|
|
||||||
* the parity every 1MB.
|
|
||||||
*
|
|
||||||
* ...at least that was, ostensibly, the theory. As a practical
|
|
||||||
* matter unless we juggle the parity between all devices
|
|
||||||
* evenly, we won't see any benefit. Further, occasional writes
|
|
||||||
* that aren't a multiple of the LCM of the number of children
|
|
||||||
* and the minimum stripe width are sufficient to avoid pessimal
|
|
||||||
* behavior. Unfortunately, this decision created an implicit
|
|
||||||
* on-disk format requirement that we need to support for all
|
|
||||||
* eternity, but only for single-parity RAID-Z.
|
|
||||||
*
|
|
||||||
* If we intend to skip a sector in the zeroth column for
|
|
||||||
* padding we must make sure to note this swap. We will never
|
|
||||||
* intend to skip the first column since at least one data and
|
|
||||||
* one parity column must appear in each row.
|
|
||||||
*/
|
|
||||||
if (rr->rr_firstdatacol == 1 && rr->rr_cols > 1 &&
|
|
||||||
(offset & (1ULL << 20))) {
|
|
||||||
ASSERT(rr->rr_cols >= 2);
|
|
||||||
ASSERT(rr->rr_col[0].rc_size == rr->rr_col[1].rc_size);
|
|
||||||
devidx = rr->rr_col[0].rc_devidx;
|
|
||||||
uint64_t o = rr->rr_col[0].rc_offset;
|
|
||||||
rr->rr_col[0].rc_devidx = rr->rr_col[1].rc_devidx;
|
|
||||||
rr->rr_col[0].rc_offset = rr->rr_col[1].rc_offset;
|
|
||||||
rr->rr_col[1].rc_devidx = devidx;
|
|
||||||
rr->rr_col[1].rc_offset = o;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
ASSERT3U(asize, ==, tot << ashift);
|
|
||||||
|
|
||||||
/* init RAIDZ parity ops */
|
|
||||||
rm->rm_ops = vdev_raidz_math_get_ops();
|
|
||||||
|
|
||||||
return (rm);
|
|
||||||
}
|
|
||||||
|
|
||||||
static raidz_map_t *
|
static raidz_map_t *
|
||||||
init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)
|
init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)
|
||||||
{
|
{
|
||||||
@@ -557,15 +330,8 @@ init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)
|
|||||||
(*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)->io_abd,
|
total_ncols, parity);
|
||||||
(*zio)->io_size, (*zio)->io_offset,
|
|
||||||
opts->rto_ashift, total_ncols+1, total_ncols,
|
|
||||||
parity, opts->rto_expand_offset);
|
|
||||||
} else {
|
|
||||||
rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,
|
|
||||||
total_ncols, parity);
|
|
||||||
}
|
|
||||||
VERIFY(rm);
|
VERIFY(rm);
|
||||||
|
|
||||||
/* Make sure code columns are destroyed */
|
/* Make sure code columns are destroyed */
|
||||||
@@ -654,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 */
|
||||||
@@ -679,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 */
|
||||||
@@ -710,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 */
|
||||||
@@ -936,8 +700,6 @@ run_sweep(void)
|
|||||||
opts->rto_dcols = dcols_v[d];
|
opts->rto_dcols = dcols_v[d];
|
||||||
opts->rto_offset = (1 << 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(thread_create(NULL, 0, sweep_thread, (void *) opts,
|
||||||
@@ -970,7 +732,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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,15 +44,13 @@ static const char *raidz_impl_names[] = {
|
|||||||
|
|
||||||
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;
|
||||||
size_t 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;
|
||||||
|
|
||||||
@@ -71,8 +69,6 @@ static const raidz_test_opts_t rto_opts_defaults = {
|
|||||||
.rto_v = 0,
|
.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
|
||||||
@@ -117,7 +113,4 @@ void init_zio_abd(zio_t *zio);
|
|||||||
|
|
||||||
void run_raidz_benchmark(void);
|
void run_raidz_benchmark(void);
|
||||||
|
|
||||||
struct raidz_map *vdev_raidz_map_alloc_expanded(abd_t *, uint64_t, uint64_t,
|
|
||||||
uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
|
||||||
|
|
||||||
#endif /* RAIDZ_TEST_H */
|
#endif /* RAIDZ_TEST_H */
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
include $(top_srcdir)/config/Shellcheck.am
|
|
||||||
|
|
||||||
dist_udev_SCRIPTS = vdev_id
|
dist_udev_SCRIPTS = vdev_id
|
||||||
|
|||||||
+119
-305
@@ -79,34 +79,6 @@
|
|||||||
# channel 86:00.0 1 A
|
# channel 86:00.0 1 A
|
||||||
# channel 86:00.0 0 B
|
# channel 86:00.0 0 B
|
||||||
|
|
||||||
# #
|
|
||||||
# # Example vdev_id.conf - multipath / multijbod-daisychaining
|
|
||||||
# #
|
|
||||||
#
|
|
||||||
# multipath yes
|
|
||||||
# multijbod yes
|
|
||||||
#
|
|
||||||
# # PCI_ID HBA PORT CHANNEL NAME
|
|
||||||
# channel 85:00.0 1 A
|
|
||||||
# channel 85:00.0 0 B
|
|
||||||
# channel 86:00.0 1 A
|
|
||||||
# channel 86:00.0 0 B
|
|
||||||
|
|
||||||
# #
|
|
||||||
# # Example vdev_id.conf - multipath / mixed
|
|
||||||
# #
|
|
||||||
#
|
|
||||||
# multipath yes
|
|
||||||
# slot mix
|
|
||||||
#
|
|
||||||
# # PCI_ID HBA PORT CHANNEL NAME
|
|
||||||
# channel 85:00.0 3 A
|
|
||||||
# channel 85:00.0 2 B
|
|
||||||
# channel 86:00.0 3 A
|
|
||||||
# channel 86:00.0 2 B
|
|
||||||
# channel af:00.0 0 C
|
|
||||||
# channel af:00.0 1 C
|
|
||||||
|
|
||||||
# #
|
# #
|
||||||
# # Example vdev_id.conf - alias
|
# # Example vdev_id.conf - alias
|
||||||
# #
|
# #
|
||||||
@@ -120,10 +92,9 @@ PATH=/bin:/sbin:/usr/bin:/usr/sbin
|
|||||||
CONFIG=/etc/zfs/vdev_id.conf
|
CONFIG=/etc/zfs/vdev_id.conf
|
||||||
PHYS_PER_PORT=
|
PHYS_PER_PORT=
|
||||||
DEV=
|
DEV=
|
||||||
|
MULTIPATH=
|
||||||
TOPOLOGY=
|
TOPOLOGY=
|
||||||
BAY=
|
BAY=
|
||||||
ENCL_ID=""
|
|
||||||
UNIQ_ENCL_ID=""
|
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat << EOF
|
cat << EOF
|
||||||
@@ -136,25 +107,22 @@ Usage: vdev_id [-h]
|
|||||||
-e Create enclose device symlinks only (/dev/by-enclosure)
|
-e Create enclose device symlinks only (/dev/by-enclosure)
|
||||||
-g Storage network topology [default="$TOPOLOGY"]
|
-g Storage network topology [default="$TOPOLOGY"]
|
||||||
-m Run in multipath mode
|
-m Run in multipath mode
|
||||||
-j Run in multijbod mode
|
|
||||||
-p number of phy's per switch port [default=$PHYS_PER_PORT]
|
-p number of phy's per switch port [default=$PHYS_PER_PORT]
|
||||||
-h show this summary
|
-h show this summary
|
||||||
EOF
|
EOF
|
||||||
exit 1
|
exit 0
|
||||||
# exit with error to avoid processing usage message by a udev rule
|
|
||||||
}
|
}
|
||||||
|
|
||||||
map_slot() {
|
map_slot() {
|
||||||
LINUX_SLOT=$1
|
LINUX_SLOT=$1
|
||||||
CHANNEL=$2
|
CHANNEL=$2
|
||||||
|
|
||||||
MAPPED_SLOT=$(awk -v linux_slot="$LINUX_SLOT" -v channel="$CHANNEL" \
|
MAPPED_SLOT=`awk "\\$1 == \"slot\" && \\$2 == ${LINUX_SLOT} && \
|
||||||
'$1 == "slot" && $2 == linux_slot && \
|
\\$4 ~ /^${CHANNEL}$|^$/ { print \\$3; exit }" $CONFIG`
|
||||||
($4 ~ "^"channel"$" || $4 ~ /^$/) { print $3; exit}' $CONFIG)
|
|
||||||
if [ -z "$MAPPED_SLOT" ] ; then
|
if [ -z "$MAPPED_SLOT" ] ; then
|
||||||
MAPPED_SLOT=$LINUX_SLOT
|
MAPPED_SLOT=$LINUX_SLOT
|
||||||
fi
|
fi
|
||||||
printf "%d" "${MAPPED_SLOT}"
|
printf "%d" ${MAPPED_SLOT}
|
||||||
}
|
}
|
||||||
|
|
||||||
map_channel() {
|
map_channel() {
|
||||||
@@ -164,120 +132,40 @@ map_channel() {
|
|||||||
|
|
||||||
case $TOPOLOGY in
|
case $TOPOLOGY in
|
||||||
"sas_switch")
|
"sas_switch")
|
||||||
MAPPED_CHAN=$(awk -v port="$PORT" \
|
MAPPED_CHAN=`awk "\\$1 == \"channel\" && \\$2 == ${PORT} \
|
||||||
'$1 == "channel" && $2 == port \
|
{ print \\$3; exit }" $CONFIG`
|
||||||
{ print $3; exit }' $CONFIG)
|
|
||||||
;;
|
;;
|
||||||
"sas_direct"|"scsi")
|
"sas_direct"|"scsi")
|
||||||
MAPPED_CHAN=$(awk -v pciID="$PCI_ID" -v port="$PORT" \
|
MAPPED_CHAN=`awk "\\$1 == \"channel\" && \
|
||||||
'$1 == "channel" && $2 == pciID && $3 == port \
|
\\$2 == \"${PCI_ID}\" && \\$3 == ${PORT} \
|
||||||
{print $4}' $CONFIG)
|
{ print \\$4; exit }" $CONFIG`
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
printf "%s" "${MAPPED_CHAN}"
|
printf "%s" ${MAPPED_CHAN}
|
||||||
}
|
|
||||||
|
|
||||||
get_encl_id() {
|
|
||||||
set -- $(echo $1)
|
|
||||||
count=$#
|
|
||||||
|
|
||||||
i=1
|
|
||||||
while [ $i -le $count ] ; do
|
|
||||||
d=$(eval echo '$'{$i})
|
|
||||||
id=$(cat "/sys/class/enclosure/${d}/id")
|
|
||||||
ENCL_ID="${ENCL_ID} $id"
|
|
||||||
i=$((i + 1))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
get_uniq_encl_id() {
|
|
||||||
for uuid in ${ENCL_ID}; do
|
|
||||||
found=0
|
|
||||||
|
|
||||||
for count in ${UNIQ_ENCL_ID}; do
|
|
||||||
if [ $count = $uuid ]; then
|
|
||||||
found=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $found -eq 0 ]; then
|
|
||||||
UNIQ_ENCL_ID="${UNIQ_ENCL_ID} $uuid"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# map_jbod explainer: The bsg driver knows the difference between a SAS
|
|
||||||
# expander and fanout expander. Use hostX instance along with top-level
|
|
||||||
# (whole enclosure) expander instances in /sys/class/enclosure and
|
|
||||||
# matching a field in an array of expanders, using the index of the
|
|
||||||
# matched array field as the enclosure instance, thereby making jbod IDs
|
|
||||||
# dynamic. Avoids reliance on high overhead userspace commands like
|
|
||||||
# multipath and lsscsi and instead uses existing sysfs data. $HOSTCHAN
|
|
||||||
# variable derived from devpath gymnastics in sas_handler() function.
|
|
||||||
map_jbod() {
|
|
||||||
DEVEXP=$(ls -l "/sys/block/$DEV/device/" | grep enclos | awk -F/ '{print $(NF-1) }')
|
|
||||||
DEV=$1
|
|
||||||
|
|
||||||
# Use "set --" to create index values (Arrays)
|
|
||||||
set -- $(ls -l /sys/class/enclosure | grep -v "^total" | awk '{print $9}')
|
|
||||||
# Get count of total elements
|
|
||||||
JBOD_COUNT=$#
|
|
||||||
JBOD_ITEM=$*
|
|
||||||
|
|
||||||
# Build JBODs (enclosure) id from sys/class/enclosure/<dev>/id
|
|
||||||
get_encl_id "$JBOD_ITEM"
|
|
||||||
# Different expander instances for each paths.
|
|
||||||
# Filter out and keep only unique id.
|
|
||||||
get_uniq_encl_id
|
|
||||||
|
|
||||||
# Identify final 'mapped jbod'
|
|
||||||
j=0
|
|
||||||
for count in ${UNIQ_ENCL_ID}; do
|
|
||||||
i=1
|
|
||||||
j=$((j + 1))
|
|
||||||
while [ $i -le $JBOD_COUNT ] ; do
|
|
||||||
d=$(eval echo '$'{$i})
|
|
||||||
id=$(cat "/sys/class/enclosure/${d}/id")
|
|
||||||
if [ "$d" = "$DEVEXP" ] && [ $id = $count ] ; then
|
|
||||||
MAPPED_JBOD=$j
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
i=$((i + 1))
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
printf "%d" "${MAPPED_JBOD}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sas_handler() {
|
sas_handler() {
|
||||||
if [ -z "$PHYS_PER_PORT" ] ; then
|
if [ -z "$PHYS_PER_PORT" ] ; then
|
||||||
PHYS_PER_PORT=$(awk '$1 == "phys_per_port" \
|
PHYS_PER_PORT=`awk "\\$1 == \"phys_per_port\" \
|
||||||
{print $2; exit}' $CONFIG)
|
{print \\$2; exit}" $CONFIG`
|
||||||
fi
|
fi
|
||||||
PHYS_PER_PORT=${PHYS_PER_PORT:-4}
|
PHYS_PER_PORT=${PHYS_PER_PORT:-4}
|
||||||
|
if ! echo $PHYS_PER_PORT | grep -q -E '^[0-9]+$' ; then
|
||||||
if ! echo "$PHYS_PER_PORT" | grep -q -E '^[0-9]+$' ; then
|
|
||||||
echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
|
echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$MULTIPATH_MODE" ] ; then
|
if [ -z "$MULTIPATH_MODE" ] ; then
|
||||||
MULTIPATH_MODE=$(awk '$1 == "multipath" \
|
MULTIPATH_MODE=`awk "\\$1 == \"multipath\" \
|
||||||
{print $2; exit}' $CONFIG)
|
{print \\$2; exit}" $CONFIG`
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$MULTIJBOD_MODE" ] ; then
|
|
||||||
MULTIJBOD_MODE=$(awk '$1 == "multijbod" \
|
|
||||||
{print $2; exit}' $CONFIG)
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use first running component device if we're handling a dm-mpath device
|
# Use first running component device if we're handling a dm-mpath device
|
||||||
if [ "$MULTIPATH_MODE" = "yes" ] ; then
|
if [ "$MULTIPATH_MODE" = "yes" ] ; then
|
||||||
# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
|
# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
|
||||||
if [ -z "$DM_NAME" ] ; then
|
if [ -z "$DM_NAME" ] ; then
|
||||||
DM_NAME=$(ls -l --full-time /dev/mapper |
|
DM_NAME=`ls -l --full-time /dev/mapper |
|
||||||
grep "$DEV"$ | awk '{print $9}')
|
awk "/\/$DEV$/{print \\$9}"`
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For raw disks udev exports DEVTYPE=partition when
|
# For raw disks udev exports DEVTYPE=partition when
|
||||||
@@ -287,50 +175,28 @@ sas_handler() {
|
|||||||
# we have to append the -part suffix directly in the
|
# we have to append the -part suffix directly in the
|
||||||
# helper.
|
# helper.
|
||||||
if [ "$DEVTYPE" != "partition" ] ; then
|
if [ "$DEVTYPE" != "partition" ] ; then
|
||||||
# Match p[number], remove the 'p' and prepend "-part"
|
PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
|
||||||
PART=$(echo "$DM_NAME" |
|
|
||||||
awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Strip off partition information.
|
# Strip off partition information.
|
||||||
DM_NAME=$(echo "$DM_NAME" | sed 's/p[0-9][0-9]*$//')
|
DM_NAME=`echo $DM_NAME | sed 's/p[0-9][0-9]*$//'`
|
||||||
if [ -z "$DM_NAME" ] ; then
|
if [ -z "$DM_NAME" ] ; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Utilize DM device name to gather subordinate block devices
|
# Get the raw scsi device name from multipath -ll. Strip off
|
||||||
# using sysfs to avoid userspace utilities
|
# leading pipe symbols to make field numbering consistent.
|
||||||
|
DEV=`multipath -ll $DM_NAME |
|
||||||
# If our DEVNAME is something like /dev/dm-177, then we may be
|
awk '/running/{gsub("^[|]"," "); print $3 ; exit}'`
|
||||||
# able to get our DMDEV from it.
|
|
||||||
DMDEV=$(echo $DEVNAME | sed 's;/dev/;;g')
|
|
||||||
if [ ! -e /sys/block/$DMDEV/slaves/* ] ; then
|
|
||||||
# It's not there, try looking in /dev/mapper
|
|
||||||
DMDEV=$(ls -l --full-time /dev/mapper | grep $DM_NAME |
|
|
||||||
awk '{gsub("../", " "); print $NF}')
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use sysfs pointers in /sys/block/dm-X/slaves because using
|
|
||||||
# userspace tools creates lots of overhead and should be avoided
|
|
||||||
# whenever possible. Use awk to isolate lowest instance of
|
|
||||||
# sd device member in dm device group regardless of string
|
|
||||||
# length.
|
|
||||||
DEV=$(ls "/sys/block/$DMDEV/slaves" | awk '
|
|
||||||
{ len=sprintf ("%20s",length($0)); gsub(/ /,0,str); a[NR]=len "_" $0; }
|
|
||||||
END {
|
|
||||||
asort(a)
|
|
||||||
print substr(a[1],22)
|
|
||||||
}')
|
|
||||||
|
|
||||||
if [ -z "$DEV" ] ; then
|
if [ -z "$DEV" ] ; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if echo "$DEV" | grep -q ^/devices/ ; then
|
if echo $DEV | grep -q ^/devices/ ; then
|
||||||
sys_path=$DEV
|
sys_path=$DEV
|
||||||
else
|
else
|
||||||
sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
|
sys_path=`udevadm info -q path -p /sys/block/$DEV 2>/dev/null`
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use positional parameters as an ad-hoc array
|
# Use positional parameters as an ad-hoc array
|
||||||
@@ -340,104 +206,84 @@ sas_handler() {
|
|||||||
|
|
||||||
# Get path up to /sys/.../hostX
|
# Get path up to /sys/.../hostX
|
||||||
i=1
|
i=1
|
||||||
|
while [ $i -le $num_dirs ] ; do
|
||||||
while [ $i -le "$num_dirs" ] ; do
|
d=$(eval echo \${$i})
|
||||||
d=$(eval echo '$'{$i})
|
|
||||||
scsi_host_dir="$scsi_host_dir/$d"
|
scsi_host_dir="$scsi_host_dir/$d"
|
||||||
echo "$d" | grep -q -E '^host[0-9]+$' && break
|
echo $d | grep -q -E '^host[0-9]+$' && break
|
||||||
i=$((i + 1))
|
i=$(($i + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
# Lets grab the SAS host channel number and save it for JBOD sorting later
|
if [ $i = $num_dirs ] ; then
|
||||||
HOSTCHAN=$(echo "$d" | awk -F/ '{ gsub("host","",$NF); print $NF}')
|
|
||||||
|
|
||||||
if [ $i = "$num_dirs" ] ; then
|
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
|
PCI_ID=$(eval echo \${$(($i -1))} | awk -F: '{print $2":"$3}')
|
||||||
|
|
||||||
# In sas_switch mode, the directory four levels beneath
|
# In sas_switch mode, the directory four levels beneath
|
||||||
# /sys/.../hostX contains symlinks to phy devices that reveal
|
# /sys/.../hostX contains symlinks to phy devices that reveal
|
||||||
# the switch port number. In sas_direct mode, the phy links one
|
# the switch port number. In sas_direct mode, the phy links one
|
||||||
# directory down reveal the HBA port.
|
# directory down reveal the HBA port.
|
||||||
port_dir=$scsi_host_dir
|
port_dir=$scsi_host_dir
|
||||||
|
|
||||||
case $TOPOLOGY in
|
case $TOPOLOGY in
|
||||||
"sas_switch") j=$((i + 4)) ;;
|
"sas_switch") j=$(($i + 4)) ;;
|
||||||
"sas_direct") j=$((i + 1)) ;;
|
"sas_direct") j=$(($i + 1)) ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
i=$((i + 1))
|
i=$(($i + 1))
|
||||||
|
|
||||||
while [ $i -le $j ] ; do
|
while [ $i -le $j ] ; do
|
||||||
port_dir="$port_dir/$(eval echo '$'{$i})"
|
port_dir="$port_dir/$(eval echo \${$i})"
|
||||||
i=$((i + 1))
|
i=$(($i + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
PHY=$(ls -vd "$port_dir"/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}')
|
PHY=`ls -d $port_dir/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}'`
|
||||||
if [ -z "$PHY" ] ; then
|
if [ -z "$PHY" ] ; then
|
||||||
PHY=0
|
PHY=0
|
||||||
fi
|
fi
|
||||||
PORT=$((PHY / PHYS_PER_PORT))
|
PORT=$(( $PHY / $PHYS_PER_PORT ))
|
||||||
|
|
||||||
# Look in /sys/.../sas_device/end_device-X for the bay_identifier
|
# Look in /sys/.../sas_device/end_device-X for the bay_identifier
|
||||||
# attribute.
|
# attribute.
|
||||||
end_device_dir=$port_dir
|
end_device_dir=$port_dir
|
||||||
|
while [ $i -lt $num_dirs ] ; do
|
||||||
while [ $i -lt "$num_dirs" ] ; do
|
d=$(eval echo \${$i})
|
||||||
d=$(eval echo '$'{$i})
|
|
||||||
end_device_dir="$end_device_dir/$d"
|
end_device_dir="$end_device_dir/$d"
|
||||||
if echo "$d" | grep -q '^end_device' ; then
|
if echo $d | grep -q '^end_device' ; then
|
||||||
end_device_dir="$end_device_dir/sas_device/$d"
|
end_device_dir="$end_device_dir/sas_device/$d"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
i=$((i + 1))
|
i=$(($i + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
# Add 'mix' slot type for environments where dm-multipath devices
|
|
||||||
# include end-devices connected via SAS expanders or direct connection
|
|
||||||
# to SAS HBA. A mixed connectivity environment such as pool devices
|
|
||||||
# contained in a SAS JBOD and spare drives or log devices directly
|
|
||||||
# connected in a server backplane without expanders in the I/O path.
|
|
||||||
SLOT=
|
SLOT=
|
||||||
|
|
||||||
case $BAY in
|
case $BAY in
|
||||||
"bay")
|
"bay")
|
||||||
SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
|
SLOT=`cat $end_device_dir/bay_identifier 2>/dev/null`
|
||||||
;;
|
|
||||||
"mix")
|
|
||||||
if [ $(cat "$end_device_dir/bay_identifier" 2>/dev/null) ] ; then
|
|
||||||
SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
|
|
||||||
else
|
|
||||||
SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
"phy")
|
"phy")
|
||||||
SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
|
SLOT=`cat $end_device_dir/phy_identifier 2>/dev/null`
|
||||||
;;
|
;;
|
||||||
"port")
|
"port")
|
||||||
d=$(eval echo '$'{$i})
|
d=$(eval echo \${$i})
|
||||||
SLOT=$(echo "$d" | sed -e 's/^.*://')
|
SLOT=`echo $d | sed -e 's/^.*://'`
|
||||||
;;
|
;;
|
||||||
"id")
|
"id")
|
||||||
i=$((i + 1))
|
i=$(($i + 1))
|
||||||
d=$(eval echo '$'{$i})
|
d=$(eval echo \${$i})
|
||||||
SLOT=$(echo "$d" | sed -e 's/^.*://')
|
SLOT=`echo $d | sed -e 's/^.*://'`
|
||||||
;;
|
;;
|
||||||
"lun")
|
"lun")
|
||||||
i=$((i + 2))
|
i=$(($i + 2))
|
||||||
d=$(eval echo '$'{$i})
|
d=$(eval echo \${$i})
|
||||||
SLOT=$(echo "$d" | sed -e 's/^.*://')
|
SLOT=`echo $d | sed -e 's/^.*://'`
|
||||||
;;
|
;;
|
||||||
"ses")
|
"ses")
|
||||||
# look for this SAS path in all SCSI Enclosure Services
|
# look for this SAS path in all SCSI Enclosure Services
|
||||||
# (SES) enclosures
|
# (SES) enclosures
|
||||||
sas_address=$(cat "$end_device_dir/sas_address" 2>/dev/null)
|
sas_address=`cat $end_device_dir/sas_address 2>/dev/null`
|
||||||
enclosures=$(lsscsi -g | \
|
enclosures=`lsscsi -g | \
|
||||||
sed -n -e '/enclosu/s/^.* \([^ ][^ ]*\) *$/\1/p')
|
sed -n -e '/enclosu/s/^.* \([^ ][^ ]*\) *$/\1/p'`
|
||||||
for enclosure in $enclosures; do
|
for enclosure in $enclosures; do
|
||||||
set -- $(sg_ses -p aes "$enclosure" | \
|
set -- $(sg_ses -p aes $enclosure | \
|
||||||
awk "/device slot number:/{slot=\$12} \
|
awk "/device slot number:/{slot=\$12} \
|
||||||
/SAS address: $sas_address/\
|
/SAS address: $sas_address/\
|
||||||
{print slot}")
|
{print slot}")
|
||||||
@@ -452,55 +298,42 @@ sas_handler() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$MULTIJBOD_MODE" = "yes" ] ; then
|
CHAN=`map_channel $PCI_ID $PORT`
|
||||||
CHAN=$(map_channel "$PCI_ID" "$PORT")
|
SLOT=`map_slot $SLOT $CHAN`
|
||||||
SLOT=$(map_slot "$SLOT" "$CHAN")
|
if [ -z "$CHAN" ] ; then
|
||||||
JBOD=$(map_jbod "$DEV")
|
return
|
||||||
|
|
||||||
if [ -z "$CHAN" ] ; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
echo "${CHAN}"-"${JBOD}"-"${SLOT}${PART}"
|
|
||||||
else
|
|
||||||
CHAN=$(map_channel "$PCI_ID" "$PORT")
|
|
||||||
SLOT=$(map_slot "$SLOT" "$CHAN")
|
|
||||||
|
|
||||||
if [ -z "$CHAN" ] ; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
echo "${CHAN}${SLOT}${PART}"
|
|
||||||
fi
|
fi
|
||||||
|
echo ${CHAN}${SLOT}${PART}
|
||||||
}
|
}
|
||||||
|
|
||||||
scsi_handler() {
|
scsi_handler() {
|
||||||
if [ -z "$FIRST_BAY_NUMBER" ] ; then
|
if [ -z "$FIRST_BAY_NUMBER" ] ; then
|
||||||
FIRST_BAY_NUMBER=$(awk '$1 == "first_bay_number" \
|
FIRST_BAY_NUMBER=`awk "\\$1 == \"first_bay_number\" \
|
||||||
{print $2; exit}' $CONFIG)
|
{print \\$2; exit}" $CONFIG`
|
||||||
fi
|
fi
|
||||||
FIRST_BAY_NUMBER=${FIRST_BAY_NUMBER:-0}
|
FIRST_BAY_NUMBER=${FIRST_BAY_NUMBER:-0}
|
||||||
|
|
||||||
if [ -z "$PHYS_PER_PORT" ] ; then
|
if [ -z "$PHYS_PER_PORT" ] ; then
|
||||||
PHYS_PER_PORT=$(awk '$1 == "phys_per_port" \
|
PHYS_PER_PORT=`awk "\\$1 == \"phys_per_port\" \
|
||||||
{print $2; exit}' $CONFIG)
|
{print \\$2; exit}" $CONFIG`
|
||||||
fi
|
fi
|
||||||
PHYS_PER_PORT=${PHYS_PER_PORT:-4}
|
PHYS_PER_PORT=${PHYS_PER_PORT:-4}
|
||||||
|
if ! echo $PHYS_PER_PORT | grep -q -E '^[0-9]+$' ; then
|
||||||
if ! echo "$PHYS_PER_PORT" | grep -q -E '^[0-9]+$' ; then
|
|
||||||
echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
|
echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$MULTIPATH_MODE" ] ; then
|
if [ -z "$MULTIPATH_MODE" ] ; then
|
||||||
MULTIPATH_MODE=$(awk '$1 == "multipath" \
|
MULTIPATH_MODE=`awk "\\$1 == \"multipath\" \
|
||||||
{print $2; exit}' $CONFIG)
|
{print \\$2; exit}" $CONFIG`
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use first running component device if we're handling a dm-mpath device
|
# Use first running component device if we're handling a dm-mpath device
|
||||||
if [ "$MULTIPATH_MODE" = "yes" ] ; then
|
if [ "$MULTIPATH_MODE" = "yes" ] ; then
|
||||||
# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
|
# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
|
||||||
if [ -z "$DM_NAME" ] ; then
|
if [ -z "$DM_NAME" ] ; then
|
||||||
DM_NAME=$(ls -l --full-time /dev/mapper |
|
DM_NAME=`ls -l --full-time /dev/mapper |
|
||||||
grep "$DEV"$ | awk '{print $9}')
|
awk "/\/$DEV$/{print \\$9}"`
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For raw disks udev exports DEVTYPE=partition when
|
# For raw disks udev exports DEVTYPE=partition when
|
||||||
@@ -510,30 +343,28 @@ scsi_handler() {
|
|||||||
# we have to append the -part suffix directly in the
|
# we have to append the -part suffix directly in the
|
||||||
# helper.
|
# helper.
|
||||||
if [ "$DEVTYPE" != "partition" ] ; then
|
if [ "$DEVTYPE" != "partition" ] ; then
|
||||||
# Match p[number], remove the 'p' and prepend "-part"
|
PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
|
||||||
PART=$(echo "$DM_NAME" |
|
|
||||||
awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Strip off partition information.
|
# Strip off partition information.
|
||||||
DM_NAME=$(echo "$DM_NAME" | sed 's/p[0-9][0-9]*$//')
|
DM_NAME=`echo $DM_NAME | sed 's/p[0-9][0-9]*$//'`
|
||||||
if [ -z "$DM_NAME" ] ; then
|
if [ -z "$DM_NAME" ] ; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get the raw scsi device name from multipath -ll. Strip off
|
# Get the raw scsi device name from multipath -ll. Strip off
|
||||||
# leading pipe symbols to make field numbering consistent.
|
# leading pipe symbols to make field numbering consistent.
|
||||||
DEV=$(multipath -ll "$DM_NAME" |
|
DEV=`multipath -ll $DM_NAME |
|
||||||
awk '/running/{gsub("^[|]"," "); print $3 ; exit}')
|
awk '/running/{gsub("^[|]"," "); print $3 ; exit}'`
|
||||||
if [ -z "$DEV" ] ; then
|
if [ -z "$DEV" ] ; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if echo "$DEV" | grep -q ^/devices/ ; then
|
if echo $DEV | grep -q ^/devices/ ; then
|
||||||
sys_path=$DEV
|
sys_path=$DEV
|
||||||
else
|
else
|
||||||
sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
|
sys_path=`udevadm info -q path -p /sys/block/$DEV 2>/dev/null`
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# expect sys_path like this, for example:
|
# expect sys_path like this, for example:
|
||||||
@@ -546,47 +377,44 @@ scsi_handler() {
|
|||||||
|
|
||||||
# Get path up to /sys/.../hostX
|
# Get path up to /sys/.../hostX
|
||||||
i=1
|
i=1
|
||||||
|
while [ $i -le $num_dirs ] ; do
|
||||||
while [ $i -le "$num_dirs" ] ; do
|
d=$(eval echo \${$i})
|
||||||
d=$(eval echo '$'{$i})
|
|
||||||
scsi_host_dir="$scsi_host_dir/$d"
|
scsi_host_dir="$scsi_host_dir/$d"
|
||||||
|
echo $d | grep -q -E '^host[0-9]+$' && break
|
||||||
echo "$d" | grep -q -E '^host[0-9]+$' && break
|
i=$(($i + 1))
|
||||||
i=$((i + 1))
|
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ $i = "$num_dirs" ] ; then
|
if [ $i = $num_dirs ] ; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
|
PCI_ID=$(eval echo \${$(($i -1))} | awk -F: '{print $2":"$3}')
|
||||||
|
|
||||||
# In scsi mode, the directory two levels beneath
|
# In scsi mode, the directory two levels beneath
|
||||||
# /sys/.../hostX reveals the port and slot.
|
# /sys/.../hostX reveals the port and slot.
|
||||||
port_dir=$scsi_host_dir
|
port_dir=$scsi_host_dir
|
||||||
j=$((i + 2))
|
j=$(($i + 2))
|
||||||
|
|
||||||
i=$((i + 1))
|
i=$(($i + 1))
|
||||||
while [ $i -le $j ] ; do
|
while [ $i -le $j ] ; do
|
||||||
port_dir="$port_dir/$(eval echo '$'{$i})"
|
port_dir="$port_dir/$(eval echo \${$i})"
|
||||||
i=$((i + 1))
|
i=$(($i + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
set -- $(echo "$port_dir" | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/')
|
set -- $(echo $port_dir | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/')
|
||||||
PORT=$1
|
PORT=$1
|
||||||
SLOT=$(($2 + FIRST_BAY_NUMBER))
|
SLOT=$(($2 + $FIRST_BAY_NUMBER))
|
||||||
|
|
||||||
if [ -z "$SLOT" ] ; then
|
if [ -z "$SLOT" ] ; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CHAN=$(map_channel "$PCI_ID" "$PORT")
|
CHAN=`map_channel $PCI_ID $PORT`
|
||||||
SLOT=$(map_slot "$SLOT" "$CHAN")
|
SLOT=`map_slot $SLOT $CHAN`
|
||||||
|
|
||||||
if [ -z "$CHAN" ] ; then
|
if [ -z "$CHAN" ] ; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
echo "${CHAN}${SLOT}${PART}"
|
echo ${CHAN}${SLOT}${PART}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Figure out the name for the enclosure symlink
|
# Figure out the name for the enclosure symlink
|
||||||
@@ -596,10 +424,8 @@ enclosure_handler () {
|
|||||||
# DEVPATH=/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/subsystem/devices/0:0:0:0/scsi_generic/sg0
|
# 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")
|
# Get the enclosure ID ("0:0:0:0")
|
||||||
ENC="${DEVPATH%/*}"
|
ENC=$(basename $(readlink -m "/sys/$DEVPATH/../.."))
|
||||||
ENC="${ENC%/*}"
|
if [ ! -d /sys/class/enclosure/$ENC ] ; then
|
||||||
ENC="${ENC##*/}"
|
|
||||||
if [ ! -d "/sys/class/enclosure/$ENC" ] ; then
|
|
||||||
# Not an enclosure, bail out
|
# Not an enclosure, bail out
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@@ -607,26 +433,25 @@ enclosure_handler () {
|
|||||||
# Get the long sysfs device path to our enclosure. Looks like:
|
# 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
|
# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0/ ... /enclosure/0:0:0:0
|
||||||
|
|
||||||
ENC_DEVICE=$(readlink "/sys/class/enclosure/$ENC")
|
ENC_DEVICE=$(readlink /sys/class/enclosure/$ENC)
|
||||||
|
|
||||||
# Grab the full path to the hosts port dir:
|
# Grab the full path to the hosts port dir:
|
||||||
# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0
|
# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0
|
||||||
PORT_DIR=$(echo "$ENC_DEVICE" | grep -Eo '.+host[0-9]+/port-[0-9]+:[0-9]+')
|
PORT_DIR=$(echo $ENC_DEVICE | grep -Eo '.+host[0-9]+/port-[0-9]+:[0-9]+')
|
||||||
|
|
||||||
# Get the port number
|
# Get the port number
|
||||||
PORT_ID=$(echo "$PORT_DIR" | grep -Eo "[0-9]+$")
|
PORT_ID=$(echo $PORT_DIR | grep -Eo "[0-9]+$")
|
||||||
|
|
||||||
# The PCI directory is two directories up from the port directory
|
# The PCI directory is two directories up from the port directory
|
||||||
# /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0
|
# /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0
|
||||||
PCI_ID_LONG="$(readlink -m "/sys/$PORT_DIR/../..")"
|
PCI_ID_LONG=$(basename $(readlink -m "/sys/$PORT_DIR/../.."))
|
||||||
PCI_ID_LONG="${PCI_ID_LONG##*/}"
|
|
||||||
|
|
||||||
# Strip down the PCI address from 0000:05:00.0 to 05:00.0
|
# Strip down the PCI address from 0000:05:00.0 to 05:00.0
|
||||||
PCI_ID="${PCI_ID_LONG#[0-9]*:}"
|
PCI_ID=$(echo "$PCI_ID_LONG" | sed -r 's/^[0-9]+://g')
|
||||||
|
|
||||||
# Name our device according to vdev_id.conf (like "L0" or "U1").
|
# Name our device according to vdev_id.conf (like "L0" or "U1").
|
||||||
NAME=$(awk "/channel/{if (\$1 == \"channel\" && \$2 == \"$PCI_ID\" && \
|
NAME=$(awk "/channel/{if (\$1 == \"channel\" && \$2 == \"$PCI_ID\" && \
|
||||||
\$3 == \"$PORT_ID\") {print \$4\$3}}" $CONFIG)
|
\$3 == \"$PORT_ID\") {print \$4int(count[\$4])}; count[\$4]++}" $CONFIG)
|
||||||
|
|
||||||
echo "${NAME}"
|
echo "${NAME}"
|
||||||
}
|
}
|
||||||
@@ -662,11 +487,9 @@ alias_handler () {
|
|||||||
# ambiguity seems unavoidable, so devices using this facility
|
# ambiguity seems unavoidable, so devices using this facility
|
||||||
# must not use such names.
|
# must not use such names.
|
||||||
DM_PART=
|
DM_PART=
|
||||||
if echo "$DM_NAME" | grep -q -E 'p[0-9][0-9]*$' ; then
|
if echo $DM_NAME | grep -q -E 'p[0-9][0-9]*$' ; then
|
||||||
if [ "$DEVTYPE" != "partition" ] ; then
|
if [ "$DEVTYPE" != "partition" ] ; then
|
||||||
# Match p[number], remove the 'p' and prepend "-part"
|
DM_PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
|
||||||
DM_PART=$(echo "$DM_NAME" |
|
|
||||||
awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -674,25 +497,21 @@ alias_handler () {
|
|||||||
for link in $DEVLINKS ; do
|
for link in $DEVLINKS ; do
|
||||||
# Remove partition information to match key of top-level device.
|
# Remove partition information to match key of top-level device.
|
||||||
if [ -n "$DM_PART" ] ; then
|
if [ -n "$DM_PART" ] ; then
|
||||||
link=$(echo "$link" | sed 's/p[0-9][0-9]*$//')
|
link=`echo $link | sed 's/p[0-9][0-9]*$//'`
|
||||||
fi
|
fi
|
||||||
# Check both the fully qualified and the base name of link.
|
# Check both the fully qualified and the base name of link.
|
||||||
for l in $link ${link##*/} ; do
|
for l in $link `basename $link` ; do
|
||||||
if [ ! -z "$l" ]; then
|
alias=`awk "\\$1 == \"alias\" && \\$3 == \"${l}\" \
|
||||||
alias=$(awk -v var="$l" '($1 == "alias") && \
|
{ print \\$2; exit }" $CONFIG`
|
||||||
($3 == var) \
|
if [ -n "$alias" ] ; then
|
||||||
{ print $2; exit }' $CONFIG)
|
echo ${alias}${DM_PART}
|
||||||
if [ -n "$alias" ] ; then
|
return
|
||||||
echo "${alias}${DM_PART}"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# main
|
while getopts 'c:d:eg:mp:h' OPTION; do
|
||||||
while getopts 'c:d:eg:jmp:h' OPTION; do
|
|
||||||
case ${OPTION} in
|
case ${OPTION} in
|
||||||
c)
|
c)
|
||||||
CONFIG=${OPTARG}
|
CONFIG=${OPTARG}
|
||||||
@@ -705,9 +524,7 @@ while getopts 'c:d:eg:jmp:h' OPTION; do
|
|||||||
# create the enclosure device symlinks only. We also need
|
# create the enclosure device symlinks only. We also need
|
||||||
# "enclosure_symlinks yes" set in vdev_id.config to actually create the
|
# "enclosure_symlinks yes" set in vdev_id.config to actually create the
|
||||||
# symlink.
|
# symlink.
|
||||||
ENCLOSURE_MODE=$(awk '{if ($1 == "enclosure_symlinks") \
|
ENCLOSURE_MODE=$(awk '{if ($1 == "enclosure_symlinks") print $2}' $CONFIG)
|
||||||
print $2}' "$CONFIG")
|
|
||||||
|
|
||||||
if [ "$ENCLOSURE_MODE" != "yes" ] ; then
|
if [ "$ENCLOSURE_MODE" != "yes" ] ; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -718,9 +535,6 @@ while getopts 'c:d:eg:jmp:h' OPTION; do
|
|||||||
p)
|
p)
|
||||||
PHYS_PER_PORT=${OPTARG}
|
PHYS_PER_PORT=${OPTARG}
|
||||||
;;
|
;;
|
||||||
j)
|
|
||||||
MULTIJBOD_MODE=yes
|
|
||||||
;;
|
|
||||||
m)
|
m)
|
||||||
MULTIPATH_MODE=yes
|
MULTIPATH_MODE=yes
|
||||||
;;
|
;;
|
||||||
@@ -730,9 +544,9 @@ while getopts 'c:d:eg:jmp:h' OPTION; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ ! -r "$CONFIG" ] ; then
|
if [ ! -r $CONFIG ] ; then
|
||||||
echo "Error: Config file \"$CONFIG\" not found"
|
echo "Error: Config file \"$CONFIG\" not found"
|
||||||
exit 1
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then
|
if [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then
|
||||||
@@ -741,11 +555,11 @@ if [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$TOPOLOGY" ] ; then
|
if [ -z "$TOPOLOGY" ] ; then
|
||||||
TOPOLOGY=$(awk '($1 == "topology") {print $2; exit}' "$CONFIG")
|
TOPOLOGY=`awk "\\$1 == \"topology\" {print \\$2; exit}" $CONFIG`
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$BAY" ] ; then
|
if [ -z "$BAY" ] ; then
|
||||||
BAY=$(awk '($1 == "slot") {print $2; exit}' "$CONFIG")
|
BAY=`awk "\\$1 == \"slot\" {print \\$2; exit}" $CONFIG`
|
||||||
fi
|
fi
|
||||||
|
|
||||||
TOPOLOGY=${TOPOLOGY:-sas_direct}
|
TOPOLOGY=${TOPOLOGY:-sas_direct}
|
||||||
@@ -758,7 +572,7 @@ if [ "$ENCLOSURE_MODE" = "yes" ] && [ "$TOPOLOGY" = "sas_direct" ] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Just create the symlinks to the enclosure devices and then exit.
|
# Just create the symlinks to the enclosure devices and then exit.
|
||||||
ENCLOSURE_PREFIX=$(awk '/enclosure_symlinks_prefix/{print $2}' "$CONFIG")
|
ENCLOSURE_PREFIX=$(awk '/enclosure_symlinks_prefix/{print $2}' $CONFIG)
|
||||||
if [ -z "$ENCLOSURE_PREFIX" ] ; then
|
if [ -z "$ENCLOSURE_PREFIX" ] ; then
|
||||||
ENCLOSURE_PREFIX="enc"
|
ENCLOSURE_PREFIX="enc"
|
||||||
fi
|
fi
|
||||||
@@ -768,16 +582,16 @@ if [ "$ENCLOSURE_MODE" = "yes" ] && [ "$TOPOLOGY" = "sas_direct" ] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# First check if an alias was defined for this device.
|
# First check if an alias was defined for this device.
|
||||||
ID_VDEV=$(alias_handler)
|
ID_VDEV=`alias_handler`
|
||||||
|
|
||||||
if [ -z "$ID_VDEV" ] ; then
|
if [ -z "$ID_VDEV" ] ; then
|
||||||
BAY=${BAY:-bay}
|
BAY=${BAY:-bay}
|
||||||
case $TOPOLOGY in
|
case $TOPOLOGY in
|
||||||
sas_direct|sas_switch)
|
sas_direct|sas_switch)
|
||||||
ID_VDEV=$(sas_handler)
|
ID_VDEV=`sas_handler`
|
||||||
;;
|
;;
|
||||||
scsi)
|
scsi)
|
||||||
ID_VDEV=$(scsi_handler)
|
ID_VDEV=`scsi_handler`
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Error: unknown topology $TOPOLOGY"
|
echo "Error: unknown topology $TOPOLOGY"
|
||||||
|
|||||||
+23
-154
@@ -31,7 +31,6 @@
|
|||||||
*
|
*
|
||||||
* [1] Portions of this software were developed by Allan Jude
|
* [1] Portions of this software were developed by Allan Jude
|
||||||
* under sponsorship from the FreeBSD Foundation.
|
* under sponsorship from the FreeBSD Foundation.
|
||||||
* Copyright (c) 2021 Allan Jude
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -110,7 +109,6 @@ extern int zfs_recover;
|
|||||||
extern unsigned long zfs_arc_meta_min, zfs_arc_meta_limit;
|
extern unsigned long zfs_arc_meta_min, zfs_arc_meta_limit;
|
||||||
extern int zfs_vdev_async_read_max_active;
|
extern int zfs_vdev_async_read_max_active;
|
||||||
extern boolean_t spa_load_verify_dryrun;
|
extern boolean_t spa_load_verify_dryrun;
|
||||||
extern boolean_t spa_mode_readable_spacemaps;
|
|
||||||
extern int zfs_reconstruct_indirect_combinations_max;
|
extern int zfs_reconstruct_indirect_combinations_max;
|
||||||
extern int zfs_btree_verify_intensity;
|
extern int zfs_btree_verify_intensity;
|
||||||
|
|
||||||
@@ -784,14 +782,13 @@ usage(void)
|
|||||||
"\t%s -m [-AFLPX] [-e [-V] [-p <path> ...]] [-t <txg>] "
|
"\t%s -m [-AFLPX] [-e [-V] [-p <path> ...]] [-t <txg>] "
|
||||||
"[-U <cache>]\n\t\t<poolname> [<vdev> [<metaslab> ...]]\n"
|
"[-U <cache>]\n\t\t<poolname> [<vdev> [<metaslab> ...]]\n"
|
||||||
"\t%s -O <dataset> <path>\n"
|
"\t%s -O <dataset> <path>\n"
|
||||||
"\t%s -r <dataset> <path> <destination>\n"
|
|
||||||
"\t%s -R [-A] [-e [-V] [-p <path> ...]] [-U <cache>]\n"
|
"\t%s -R [-A] [-e [-V] [-p <path> ...]] [-U <cache>]\n"
|
||||||
"\t\t<poolname> <vdev>:<offset>:<size>[:<flags>]\n"
|
"\t\t<poolname> <vdev>:<offset>:<size>[:<flags>]\n"
|
||||||
"\t%s -E [-A] word0:word1:...:word15\n"
|
"\t%s -E [-A] word0:word1:...:word15\n"
|
||||||
"\t%s -S [-AP] [-e [-V] [-p <path> ...]] [-U <cache>] "
|
"\t%s -S [-AP] [-e [-V] [-p <path> ...]] [-U <cache>] "
|
||||||
"<poolname>\n\n",
|
"<poolname>\n\n",
|
||||||
cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname,
|
cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname,
|
||||||
cmdname, cmdname, cmdname, cmdname);
|
cmdname, cmdname, cmdname);
|
||||||
|
|
||||||
(void) fprintf(stderr, " Dataset name must include at least one "
|
(void) fprintf(stderr, " Dataset name must include at least one "
|
||||||
"separator character '/' or '@'\n");
|
"separator character '/' or '@'\n");
|
||||||
@@ -830,7 +827,6 @@ usage(void)
|
|||||||
(void) fprintf(stderr, " -m metaslabs\n");
|
(void) fprintf(stderr, " -m metaslabs\n");
|
||||||
(void) fprintf(stderr, " -M metaslab groups\n");
|
(void) fprintf(stderr, " -M metaslab groups\n");
|
||||||
(void) fprintf(stderr, " -O perform object lookups by path\n");
|
(void) fprintf(stderr, " -O perform object lookups by path\n");
|
||||||
(void) fprintf(stderr, " -r copy an object by path to file\n");
|
|
||||||
(void) fprintf(stderr, " -R read and display block from a "
|
(void) fprintf(stderr, " -R read and display block from a "
|
||||||
"device\n");
|
"device\n");
|
||||||
(void) fprintf(stderr, " -s report stats on zdb's I/O\n");
|
(void) fprintf(stderr, " -s report stats on zdb's I/O\n");
|
||||||
@@ -1673,11 +1669,7 @@ dump_metaslab(metaslab_t *msp)
|
|||||||
SPACE_MAP_HISTOGRAM_SIZE, sm->sm_shift);
|
SPACE_MAP_HISTOGRAM_SIZE, sm->sm_shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vd->vdev_ops == &vdev_draid_ops)
|
ASSERT(msp->ms_size == (1ULL << vd->vdev_ms_shift));
|
||||||
ASSERT3U(msp->ms_size, <=, 1ULL << vd->vdev_ms_shift);
|
|
||||||
else
|
|
||||||
ASSERT3U(msp->ms_size, ==, 1ULL << vd->vdev_ms_shift);
|
|
||||||
|
|
||||||
dump_spacemap(spa->spa_meta_objset, msp->ms_sm);
|
dump_spacemap(spa->spa_meta_objset, msp->ms_sm);
|
||||||
|
|
||||||
if (spa_feature_is_active(spa, SPA_FEATURE_LOG_SPACEMAP)) {
|
if (spa_feature_is_active(spa, SPA_FEATURE_LOG_SPACEMAP)) {
|
||||||
@@ -2219,8 +2211,7 @@ snprintf_zstd_header(spa_t *spa, char *blkbuf, size_t buflen,
|
|||||||
(void) snprintf(blkbuf + strlen(blkbuf),
|
(void) snprintf(blkbuf + strlen(blkbuf),
|
||||||
buflen - strlen(blkbuf),
|
buflen - strlen(blkbuf),
|
||||||
" ZSTD:size=%u:version=%u:level=%u:EMBEDDED",
|
" ZSTD:size=%u:version=%u:level=%u:EMBEDDED",
|
||||||
zstd_hdr.c_len, zfs_get_hdrversion(&zstd_hdr),
|
zstd_hdr.c_len, zstd_hdr.version, zstd_hdr.level);
|
||||||
zfs_get_hdrlevel(&zstd_hdr));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2244,8 +2235,7 @@ snprintf_zstd_header(spa_t *spa, char *blkbuf, size_t buflen,
|
|||||||
(void) snprintf(blkbuf + strlen(blkbuf),
|
(void) snprintf(blkbuf + strlen(blkbuf),
|
||||||
buflen - strlen(blkbuf),
|
buflen - strlen(blkbuf),
|
||||||
" ZSTD:size=%u:version=%u:level=%u:NORMAL",
|
" ZSTD:size=%u:version=%u:level=%u:NORMAL",
|
||||||
zstd_hdr.c_len, zfs_get_hdrversion(&zstd_hdr),
|
zstd_hdr.c_len, zstd_hdr.version, zstd_hdr.level);
|
||||||
zfs_get_hdrlevel(&zstd_hdr));
|
|
||||||
|
|
||||||
abd_return_buf_copy(pabd, buf, BP_GET_LSIZE(bp));
|
abd_return_buf_copy(pabd, buf, BP_GET_LSIZE(bp));
|
||||||
}
|
}
|
||||||
@@ -3125,18 +3115,13 @@ dump_znode_symlink(sa_handle_t *hdl)
|
|||||||
{
|
{
|
||||||
int sa_symlink_size = 0;
|
int sa_symlink_size = 0;
|
||||||
char linktarget[MAXPATHLEN];
|
char linktarget[MAXPATHLEN];
|
||||||
|
linktarget[0] = '\0';
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = sa_size(hdl, sa_attr_table[ZPL_SYMLINK], &sa_symlink_size);
|
error = sa_size(hdl, sa_attr_table[ZPL_SYMLINK], &sa_symlink_size);
|
||||||
if (error || sa_symlink_size == 0) {
|
if (error || sa_symlink_size == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sa_symlink_size >= sizeof (linktarget)) {
|
|
||||||
(void) printf("symlink size %d is too large\n",
|
|
||||||
sa_symlink_size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
linktarget[sa_symlink_size] = '\0';
|
|
||||||
if (sa_lookup(hdl, sa_attr_table[ZPL_SYMLINK],
|
if (sa_lookup(hdl, sa_attr_table[ZPL_SYMLINK],
|
||||||
&linktarget, sa_symlink_size) == 0)
|
&linktarget, sa_symlink_size) == 0)
|
||||||
(void) printf("\ttarget %s\n", linktarget);
|
(void) printf("\ttarget %s\n", linktarget);
|
||||||
@@ -4102,7 +4087,7 @@ cksum_record_compare(const void *x1, const void *x2)
|
|||||||
const cksum_record_t *l = (cksum_record_t *)x1;
|
const cksum_record_t *l = (cksum_record_t *)x1;
|
||||||
const cksum_record_t *r = (cksum_record_t *)x2;
|
const cksum_record_t *r = (cksum_record_t *)x2;
|
||||||
int arraysize = ARRAY_SIZE(l->cksum.zc_word);
|
int arraysize = ARRAY_SIZE(l->cksum.zc_word);
|
||||||
int difference = 0;
|
int difference;
|
||||||
|
|
||||||
for (int i = 0; i < arraysize; i++) {
|
for (int i = 0; i < arraysize; i++) {
|
||||||
difference = TREE_CMP(l->cksum.zc_word[i], r->cksum.zc_word[i]);
|
difference = TREE_CMP(l->cksum.zc_word[i], r->cksum.zc_word[i]);
|
||||||
@@ -4244,8 +4229,6 @@ dump_l2arc_log_entries(uint64_t log_entries,
|
|||||||
(u_longlong_t)L2BLK_GET_PREFETCH((&le[j])->le_prop));
|
(u_longlong_t)L2BLK_GET_PREFETCH((&le[j])->le_prop));
|
||||||
(void) printf("|\t\t\t\taddress: %llu\n",
|
(void) printf("|\t\t\t\taddress: %llu\n",
|
||||||
(u_longlong_t)le[j].le_daddr);
|
(u_longlong_t)le[j].le_daddr);
|
||||||
(void) printf("|\t\t\t\tARC state: %llu\n",
|
|
||||||
(u_longlong_t)L2BLK_GET_STATE((&le[j])->le_prop));
|
|
||||||
(void) printf("|\n");
|
(void) printf("|\n");
|
||||||
}
|
}
|
||||||
(void) printf("\n");
|
(void) printf("\n");
|
||||||
@@ -4528,7 +4511,7 @@ static char curpath[PATH_MAX];
|
|||||||
* for the last one.
|
* for the last one.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
dump_path_impl(objset_t *os, uint64_t obj, char *name, uint64_t *retobj)
|
dump_path_impl(objset_t *os, uint64_t obj, char *name)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
boolean_t header = B_TRUE;
|
boolean_t header = B_TRUE;
|
||||||
@@ -4578,15 +4561,10 @@ dump_path_impl(objset_t *os, uint64_t obj, char *name, uint64_t *retobj)
|
|||||||
switch (doi.doi_type) {
|
switch (doi.doi_type) {
|
||||||
case DMU_OT_DIRECTORY_CONTENTS:
|
case DMU_OT_DIRECTORY_CONTENTS:
|
||||||
if (s != NULL && *(s + 1) != '\0')
|
if (s != NULL && *(s + 1) != '\0')
|
||||||
return (dump_path_impl(os, child_obj, s + 1, retobj));
|
return (dump_path_impl(os, child_obj, s + 1));
|
||||||
fallthrough;
|
/*FALLTHROUGH*/
|
||||||
case DMU_OT_PLAIN_FILE_CONTENTS:
|
case DMU_OT_PLAIN_FILE_CONTENTS:
|
||||||
if (retobj != NULL) {
|
dump_object(os, child_obj, dump_opt['v'], &header, NULL, 0);
|
||||||
*retobj = child_obj;
|
|
||||||
} else {
|
|
||||||
dump_object(os, child_obj, dump_opt['v'], &header,
|
|
||||||
NULL, 0);
|
|
||||||
}
|
|
||||||
return (0);
|
return (0);
|
||||||
default:
|
default:
|
||||||
(void) fprintf(stderr, "object %llu has non-file/directory "
|
(void) fprintf(stderr, "object %llu has non-file/directory "
|
||||||
@@ -4601,7 +4579,7 @@ dump_path_impl(objset_t *os, uint64_t obj, char *name, uint64_t *retobj)
|
|||||||
* Dump the blocks for the object specified by path inside the dataset.
|
* Dump the blocks for the object specified by path inside the dataset.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
dump_path(char *ds, char *path, uint64_t *retobj)
|
dump_path(char *ds, char *path)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
objset_t *os;
|
objset_t *os;
|
||||||
@@ -4621,89 +4599,12 @@ dump_path(char *ds, char *path, uint64_t *retobj)
|
|||||||
|
|
||||||
(void) snprintf(curpath, sizeof (curpath), "dataset=%s path=/", ds);
|
(void) snprintf(curpath, sizeof (curpath), "dataset=%s path=/", ds);
|
||||||
|
|
||||||
err = dump_path_impl(os, root_obj, path, retobj);
|
err = dump_path_impl(os, root_obj, path);
|
||||||
|
|
||||||
close_objset(os, FTAG);
|
close_objset(os, FTAG);
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
zdb_copy_object(objset_t *os, uint64_t srcobj, char *destfile)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
uint64_t size, readsize, oursize, offset;
|
|
||||||
ssize_t writesize;
|
|
||||||
sa_handle_t *hdl;
|
|
||||||
|
|
||||||
(void) printf("Copying object %" PRIu64 " to file %s\n", srcobj,
|
|
||||||
destfile);
|
|
||||||
|
|
||||||
VERIFY3P(os, ==, sa_os);
|
|
||||||
if ((err = sa_handle_get(os, srcobj, NULL, SA_HDL_PRIVATE, &hdl))) {
|
|
||||||
(void) printf("Failed to get handle for SA znode\n");
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
if ((err = sa_lookup(hdl, sa_attr_table[ZPL_SIZE], &size, 8))) {
|
|
||||||
(void) sa_handle_destroy(hdl);
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
(void) sa_handle_destroy(hdl);
|
|
||||||
|
|
||||||
(void) printf("Object %" PRIu64 " is %" PRIu64 " bytes\n", srcobj,
|
|
||||||
size);
|
|
||||||
if (size == 0) {
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fd = open(destfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
||||||
/*
|
|
||||||
* We cap the size at 1 mebibyte here to prevent
|
|
||||||
* allocation failures and nigh-infinite printing if the
|
|
||||||
* object is extremely large.
|
|
||||||
*/
|
|
||||||
oursize = MIN(size, 1 << 20);
|
|
||||||
offset = 0;
|
|
||||||
char *buf = kmem_alloc(oursize, KM_NOSLEEP);
|
|
||||||
if (buf == NULL) {
|
|
||||||
return (ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (offset < size) {
|
|
||||||
readsize = MIN(size - offset, 1 << 20);
|
|
||||||
err = dmu_read(os, srcobj, offset, readsize, buf, 0);
|
|
||||||
if (err != 0) {
|
|
||||||
(void) printf("got error %u from dmu_read\n", err);
|
|
||||||
kmem_free(buf, oursize);
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
if (dump_opt['v'] > 3) {
|
|
||||||
(void) printf("Read offset=%" PRIu64 " size=%" PRIu64
|
|
||||||
" error=%d\n", offset, readsize, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
writesize = write(fd, buf, readsize);
|
|
||||||
if (writesize < 0) {
|
|
||||||
err = errno;
|
|
||||||
break;
|
|
||||||
} else if (writesize != readsize) {
|
|
||||||
/* Incomplete write */
|
|
||||||
(void) fprintf(stderr, "Short write, only wrote %llu of"
|
|
||||||
" %" PRIu64 " bytes, exiting...\n",
|
|
||||||
(u_longlong_t)writesize, readsize);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += readsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) close(fd);
|
|
||||||
|
|
||||||
if (buf != NULL)
|
|
||||||
kmem_free(buf, oursize);
|
|
||||||
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dump_label(const char *dev)
|
dump_label(const char *dev)
|
||||||
{
|
{
|
||||||
@@ -5327,6 +5228,8 @@ zdb_blkptr_done(zio_t *zio)
|
|||||||
zdb_cb_t *zcb = zio->io_private;
|
zdb_cb_t *zcb = zio->io_private;
|
||||||
zbookmark_phys_t *zb = &zio->io_bookmark;
|
zbookmark_phys_t *zb = &zio->io_bookmark;
|
||||||
|
|
||||||
|
abd_free(zio->io_abd);
|
||||||
|
|
||||||
mutex_enter(&spa->spa_scrub_lock);
|
mutex_enter(&spa->spa_scrub_lock);
|
||||||
spa->spa_load_verify_bytes -= BP_GET_PSIZE(bp);
|
spa->spa_load_verify_bytes -= BP_GET_PSIZE(bp);
|
||||||
cv_broadcast(&spa->spa_scrub_io_cv);
|
cv_broadcast(&spa->spa_scrub_io_cv);
|
||||||
@@ -5353,8 +5256,6 @@ zdb_blkptr_done(zio_t *zio)
|
|||||||
blkbuf);
|
blkbuf);
|
||||||
}
|
}
|
||||||
mutex_exit(&spa->spa_scrub_lock);
|
mutex_exit(&spa->spa_scrub_lock);
|
||||||
|
|
||||||
abd_free(zio->io_abd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -5964,7 +5865,6 @@ zdb_leak_init_prepare_indirect_vdevs(spa_t *spa, zdb_cb_t *zcb)
|
|||||||
* metaslabs. We want to set them up for
|
* metaslabs. We want to set them up for
|
||||||
* zio_claim().
|
* zio_claim().
|
||||||
*/
|
*/
|
||||||
vdev_metaslab_group_create(vd);
|
|
||||||
VERIFY0(vdev_metaslab_init(vd, 0));
|
VERIFY0(vdev_metaslab_init(vd, 0));
|
||||||
|
|
||||||
vdev_indirect_mapping_t *vim __maybe_unused =
|
vdev_indirect_mapping_t *vim __maybe_unused =
|
||||||
@@ -6004,7 +5904,6 @@ zdb_leak_init(spa_t *spa, zdb_cb_t *zcb)
|
|||||||
*/
|
*/
|
||||||
spa->spa_normal_class->mc_ops = &zdb_metaslab_ops;
|
spa->spa_normal_class->mc_ops = &zdb_metaslab_ops;
|
||||||
spa->spa_log_class->mc_ops = &zdb_metaslab_ops;
|
spa->spa_log_class->mc_ops = &zdb_metaslab_ops;
|
||||||
spa->spa_embedded_log_class->mc_ops = &zdb_metaslab_ops;
|
|
||||||
|
|
||||||
zcb->zcb_vd_obsolete_counts =
|
zcb->zcb_vd_obsolete_counts =
|
||||||
umem_zalloc(rvd->vdev_children * sizeof (uint32_t *),
|
umem_zalloc(rvd->vdev_children * sizeof (uint32_t *),
|
||||||
@@ -6138,6 +6037,7 @@ zdb_leak_fini(spa_t *spa, zdb_cb_t *zcb)
|
|||||||
vdev_t *rvd = spa->spa_root_vdev;
|
vdev_t *rvd = spa->spa_root_vdev;
|
||||||
for (unsigned c = 0; c < rvd->vdev_children; c++) {
|
for (unsigned c = 0; c < rvd->vdev_children; c++) {
|
||||||
vdev_t *vd = rvd->vdev_child[c];
|
vdev_t *vd = rvd->vdev_child[c];
|
||||||
|
metaslab_group_t *mg __maybe_unused = vd->vdev_mg;
|
||||||
|
|
||||||
if (zcb->zcb_vd_obsolete_counts[c] != NULL) {
|
if (zcb->zcb_vd_obsolete_counts[c] != NULL) {
|
||||||
leaks |= zdb_check_for_obsolete_leaks(vd, zcb);
|
leaks |= zdb_check_for_obsolete_leaks(vd, zcb);
|
||||||
@@ -6145,9 +6045,7 @@ zdb_leak_fini(spa_t *spa, zdb_cb_t *zcb)
|
|||||||
|
|
||||||
for (uint64_t m = 0; m < vd->vdev_ms_count; m++) {
|
for (uint64_t m = 0; m < vd->vdev_ms_count; m++) {
|
||||||
metaslab_t *msp = vd->vdev_ms[m];
|
metaslab_t *msp = vd->vdev_ms[m];
|
||||||
ASSERT3P(msp->ms_group, ==, (msp->ms_group->mg_class ==
|
ASSERT3P(mg, ==, msp->ms_group);
|
||||||
spa_embedded_log_class(spa)) ?
|
|
||||||
vd->vdev_log_mg : vd->vdev_mg);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ms_allocatable has been overloaded
|
* ms_allocatable has been overloaded
|
||||||
@@ -6354,8 +6252,6 @@ dump_block_stats(spa_t *spa)
|
|||||||
zcb.zcb_totalasize = metaslab_class_get_alloc(spa_normal_class(spa));
|
zcb.zcb_totalasize = metaslab_class_get_alloc(spa_normal_class(spa));
|
||||||
zcb.zcb_totalasize += metaslab_class_get_alloc(spa_special_class(spa));
|
zcb.zcb_totalasize += metaslab_class_get_alloc(spa_special_class(spa));
|
||||||
zcb.zcb_totalasize += metaslab_class_get_alloc(spa_dedup_class(spa));
|
zcb.zcb_totalasize += metaslab_class_get_alloc(spa_dedup_class(spa));
|
||||||
zcb.zcb_totalasize +=
|
|
||||||
metaslab_class_get_alloc(spa_embedded_log_class(spa));
|
|
||||||
zcb.zcb_start = zcb.zcb_lastprint = gethrtime();
|
zcb.zcb_start = zcb.zcb_lastprint = gethrtime();
|
||||||
err = traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
|
err = traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
|
||||||
|
|
||||||
@@ -6403,7 +6299,6 @@ dump_block_stats(spa_t *spa)
|
|||||||
|
|
||||||
total_alloc = norm_alloc +
|
total_alloc = norm_alloc +
|
||||||
metaslab_class_get_alloc(spa_log_class(spa)) +
|
metaslab_class_get_alloc(spa_log_class(spa)) +
|
||||||
metaslab_class_get_alloc(spa_embedded_log_class(spa)) +
|
|
||||||
metaslab_class_get_alloc(spa_special_class(spa)) +
|
metaslab_class_get_alloc(spa_special_class(spa)) +
|
||||||
metaslab_class_get_alloc(spa_dedup_class(spa)) +
|
metaslab_class_get_alloc(spa_dedup_class(spa)) +
|
||||||
get_unflushed_alloc_space(spa);
|
get_unflushed_alloc_space(spa);
|
||||||
@@ -6449,7 +6344,7 @@ dump_block_stats(spa_t *spa)
|
|||||||
(void) printf("\t%-16s %14llu used: %5.2f%%\n", "Normal class:",
|
(void) printf("\t%-16s %14llu used: %5.2f%%\n", "Normal class:",
|
||||||
(u_longlong_t)norm_alloc, 100.0 * norm_alloc / norm_space);
|
(u_longlong_t)norm_alloc, 100.0 * norm_alloc / norm_space);
|
||||||
|
|
||||||
if (spa_special_class(spa)->mc_allocator[0].mca_rotor != NULL) {
|
if (spa_special_class(spa)->mc_rotor != NULL) {
|
||||||
uint64_t alloc = metaslab_class_get_alloc(
|
uint64_t alloc = metaslab_class_get_alloc(
|
||||||
spa_special_class(spa));
|
spa_special_class(spa));
|
||||||
uint64_t space = metaslab_class_get_space(
|
uint64_t space = metaslab_class_get_space(
|
||||||
@@ -6460,7 +6355,7 @@ dump_block_stats(spa_t *spa)
|
|||||||
100.0 * alloc / space);
|
100.0 * alloc / space);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spa_dedup_class(spa)->mc_allocator[0].mca_rotor != NULL) {
|
if (spa_dedup_class(spa)->mc_rotor != NULL) {
|
||||||
uint64_t alloc = metaslab_class_get_alloc(
|
uint64_t alloc = metaslab_class_get_alloc(
|
||||||
spa_dedup_class(spa));
|
spa_dedup_class(spa));
|
||||||
uint64_t space = metaslab_class_get_space(
|
uint64_t space = metaslab_class_get_space(
|
||||||
@@ -6471,17 +6366,6 @@ dump_block_stats(spa_t *spa)
|
|||||||
100.0 * alloc / space);
|
100.0 * alloc / space);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spa_embedded_log_class(spa)->mc_allocator[0].mca_rotor != NULL) {
|
|
||||||
uint64_t alloc = metaslab_class_get_alloc(
|
|
||||||
spa_embedded_log_class(spa));
|
|
||||||
uint64_t space = metaslab_class_get_space(
|
|
||||||
spa_embedded_log_class(spa));
|
|
||||||
|
|
||||||
(void) printf("\t%-16s %14llu used: %5.2f%%\n",
|
|
||||||
"Embedded log class", (u_longlong_t)alloc,
|
|
||||||
100.0 * alloc / space);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < NUM_BP_EMBEDDED_TYPES; i++) {
|
for (i = 0; i < NUM_BP_EMBEDDED_TYPES; i++) {
|
||||||
if (zcb.zcb_embedded_blocks[i] == 0)
|
if (zcb.zcb_embedded_blocks[i] == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -8288,7 +8172,6 @@ main(int argc, char **argv)
|
|||||||
nvlist_t *policy = NULL;
|
nvlist_t *policy = NULL;
|
||||||
uint64_t max_txg = UINT64_MAX;
|
uint64_t max_txg = UINT64_MAX;
|
||||||
int64_t objset_id = -1;
|
int64_t objset_id = -1;
|
||||||
uint64_t object;
|
|
||||||
int flags = ZFS_IMPORT_MISSING_LOG;
|
int flags = ZFS_IMPORT_MISSING_LOG;
|
||||||
int rewind = ZPOOL_NEVER_REWIND;
|
int rewind = ZPOOL_NEVER_REWIND;
|
||||||
char *spa_config_path_env, *objset_str;
|
char *spa_config_path_env, *objset_str;
|
||||||
@@ -8317,7 +8200,7 @@ main(int argc, char **argv)
|
|||||||
zfs_btree_verify_intensity = 3;
|
zfs_btree_verify_intensity = 3;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv,
|
while ((c = getopt(argc, argv,
|
||||||
"AbcCdDeEFGhiI:klLmMo:Op:PqrRsSt:uU:vVx:XYyZ")) != -1) {
|
"AbcCdDeEFGhiI:klLmMo:Op:PqRsSt:uU:vVx:XYyZ")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'c':
|
case 'c':
|
||||||
@@ -8332,7 +8215,6 @@ main(int argc, char **argv)
|
|||||||
case 'm':
|
case 'm':
|
||||||
case 'M':
|
case 'M':
|
||||||
case 'O':
|
case 'O':
|
||||||
case 'r':
|
|
||||||
case 'R':
|
case 'R':
|
||||||
case 's':
|
case 's':
|
||||||
case 'S':
|
case 'S':
|
||||||
@@ -8422,7 +8304,7 @@ main(int argc, char **argv)
|
|||||||
(void) fprintf(stderr, "-p option requires use of -e\n");
|
(void) fprintf(stderr, "-p option requires use of -e\n");
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
if (dump_opt['d'] || dump_opt['r']) {
|
if (dump_opt['d']) {
|
||||||
/* <pool>[/<dataset | objset id> is accepted */
|
/* <pool>[/<dataset | objset id> is accepted */
|
||||||
if (argv[2] && (objset_str = strchr(argv[2], '/')) != NULL &&
|
if (argv[2] && (objset_str = strchr(argv[2], '/')) != NULL &&
|
||||||
objset_str++ != NULL) {
|
objset_str++ != NULL) {
|
||||||
@@ -8475,18 +8357,13 @@ main(int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
spa_load_verify_dryrun = B_TRUE;
|
spa_load_verify_dryrun = B_TRUE;
|
||||||
|
|
||||||
/*
|
|
||||||
* ZDB should have ability to read spacemaps.
|
|
||||||
*/
|
|
||||||
spa_mode_readable_spacemaps = B_TRUE;
|
|
||||||
|
|
||||||
kernel_init(SPA_MODE_READ);
|
kernel_init(SPA_MODE_READ);
|
||||||
|
|
||||||
if (dump_all)
|
if (dump_all)
|
||||||
verbose = MAX(verbose, 1);
|
verbose = MAX(verbose, 1);
|
||||||
|
|
||||||
for (c = 0; c < 256; c++) {
|
for (c = 0; c < 256; c++) {
|
||||||
if (dump_all && strchr("AeEFklLOPrRSXy", c) == NULL)
|
if (dump_all && strchr("AeEFklLOPRSXy", c) == NULL)
|
||||||
dump_opt[c] = 1;
|
dump_opt[c] = 1;
|
||||||
if (dump_opt[c])
|
if (dump_opt[c])
|
||||||
dump_opt[c] += verbose;
|
dump_opt[c] += verbose;
|
||||||
@@ -8522,13 +8399,7 @@ main(int argc, char **argv)
|
|||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
usage();
|
usage();
|
||||||
dump_opt['v'] = verbose + 3;
|
dump_opt['v'] = verbose + 3;
|
||||||
return (dump_path(argv[0], argv[1], NULL));
|
return (dump_path(argv[0], argv[1]));
|
||||||
}
|
|
||||||
if (dump_opt['r']) {
|
|
||||||
if (argc != 3)
|
|
||||||
usage();
|
|
||||||
dump_opt['v'] = verbose;
|
|
||||||
error = dump_path(argv[0], argv[1], &object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dump_opt['X'] || dump_opt['F'])
|
if (dump_opt['X'] || dump_opt['F'])
|
||||||
@@ -8706,9 +8577,7 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
argv++;
|
argv++;
|
||||||
argc--;
|
argc--;
|
||||||
if (dump_opt['r']) {
|
if (!dump_opt['R']) {
|
||||||
error = zdb_copy_object(os, object, argv[1]);
|
|
||||||
} else if (!dump_opt['R']) {
|
|
||||||
flagbits['d'] = ZOR_FLAG_DIRECTORY;
|
flagbits['d'] = ZOR_FLAG_DIRECTORY;
|
||||||
flagbits['f'] = ZOR_FLAG_PLAIN_FILE;
|
flagbits['f'] = ZOR_FLAG_PLAIN_FILE;
|
||||||
flagbits['m'] = ZOR_FLAG_SPACE_MAP;
|
flagbits['m'] = ZOR_FLAG_SPACE_MAP;
|
||||||
|
|||||||
+1
-3
@@ -1,10 +1,8 @@
|
|||||||
include $(top_srcdir)/config/Rules.am
|
include $(top_srcdir)/config/Rules.am
|
||||||
include $(top_srcdir)/config/Shellcheck.am
|
|
||||||
|
|
||||||
AM_CFLAGS += $(LIBUDEV_CFLAGS) $(LIBUUID_CFLAGS)
|
AM_CFLAGS += $(LIBUDEV_CFLAGS) $(LIBUUID_CFLAGS)
|
||||||
|
|
||||||
SUBDIRS = zed.d
|
SUBDIRS = zed.d
|
||||||
SHELLCHECKDIRS = $(SUBDIRS)
|
|
||||||
|
|
||||||
sbin_PROGRAMS = zed
|
sbin_PROGRAMS = zed
|
||||||
|
|
||||||
@@ -45,7 +43,7 @@ zed_LDADD = \
|
|||||||
$(abs_top_builddir)/lib/libnvpair/libnvpair.la \
|
$(abs_top_builddir)/lib/libnvpair/libnvpair.la \
|
||||||
$(abs_top_builddir)/lib/libuutil/libuutil.la
|
$(abs_top_builddir)/lib/libuutil/libuutil.la
|
||||||
|
|
||||||
zed_LDADD += -lrt $(LIBATOMIC_LIBS) $(LIBUDEV_LIBS) $(LIBUUID_LIBS)
|
zed_LDADD += -lrt $(LIBUDEV_LIBS) $(LIBUUID_LIBS)
|
||||||
zed_LDFLAGS = -pthread
|
zed_LDFLAGS = -pthread
|
||||||
|
|
||||||
EXTRA_DIST = agents/README.md
|
EXTRA_DIST = agents/README.md
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Intel Corporation.
|
* Copyright (c) 2016, Intel Corporation.
|
||||||
* Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>
|
* Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>
|
||||||
* Copyright (c) 2021 Hewlett Packard Enterprise Development LP
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libnvpair.h>
|
#include <libnvpair.h>
|
||||||
@@ -212,18 +211,12 @@ zfs_agent_post_event(const char *class, const char *subclass, nvlist_t *nvl)
|
|||||||
* For multipath, spare and l2arc devices ZFS_EV_VDEV_GUID or
|
* For multipath, spare and l2arc devices ZFS_EV_VDEV_GUID or
|
||||||
* ZFS_EV_POOL_GUID may be missing so find them.
|
* ZFS_EV_POOL_GUID may be missing so find them.
|
||||||
*/
|
*/
|
||||||
if (pool_guid == 0 || vdev_guid == 0) {
|
(void) nvlist_lookup_string(nvl, DEV_IDENTIFIER,
|
||||||
if ((nvlist_lookup_string(nvl, DEV_IDENTIFIER,
|
&search.gs_devid);
|
||||||
&search.gs_devid) == 0) &&
|
(void) zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search);
|
||||||
(zpool_iter(g_zfs_hdl, zfs_agent_iter_pool, &search)
|
pool_guid = search.gs_pool_guid;
|
||||||
== 1)) {
|
vdev_guid = search.gs_vdev_guid;
|
||||||
if (pool_guid == 0)
|
devtype = search.gs_vdev_type;
|
||||||
pool_guid = search.gs_pool_guid;
|
|
||||||
if (vdev_guid == 0)
|
|
||||||
vdev_guid = search.gs_vdev_guid;
|
|
||||||
devtype = search.gs_vdev_type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want to avoid reporting "remove" events coming from
|
* We want to avoid reporting "remove" events coming from
|
||||||
@@ -392,7 +385,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
|
||||||
|
|||||||
@@ -35,7 +35,6 @@
|
|||||||
#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"
|
||||||
@@ -774,8 +773,6 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
|||||||
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) {
|
ZFS_MAKE_EREPORT(FM_EREPORT_ZFS_PROBE_FAILURE))) {
|
||||||
char *failmode = NULL;
|
char *failmode = NULL;
|
||||||
boolean_t checkremove = B_FALSE;
|
boolean_t checkremove = B_FALSE;
|
||||||
uint32_t pri = 0;
|
|
||||||
int32_t flags = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a checksum or I/O error, then toss it into the
|
* If this is a checksum or I/O error, then toss it into the
|
||||||
@@ -798,23 +795,6 @@ zfs_fm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
|
|||||||
checkremove = B_TRUE;
|
checkremove = B_TRUE;
|
||||||
} 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))) {
|
||||||
/*
|
|
||||||
* We ignore ereports for checksum errors generated by
|
|
||||||
* scrub/resilver I/O to avoid potentially further
|
|
||||||
* degrading the pool while it's being repaired.
|
|
||||||
*/
|
|
||||||
if (((nvlist_lookup_uint32(nvl,
|
|
||||||
FM_EREPORT_PAYLOAD_ZFS_ZIO_PRIORITY, &pri) == 0) &&
|
|
||||||
(pri == ZIO_PRIORITY_SCRUB ||
|
|
||||||
pri == ZIO_PRIORITY_REBUILD)) ||
|
|
||||||
((nvlist_lookup_int32(nvl,
|
|
||||||
FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS, &flags) == 0) &&
|
|
||||||
(flags & (ZIO_FLAG_SCRUB | ZIO_FLAG_RESILVER)))) {
|
|
||||||
fmd_hdl_debug(hdl, "ignoring '%s' for "
|
|
||||||
"scrub/resilver I/O", class);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zcp->zc_data.zc_serd_checksum[0] == '\0') {
|
if (zcp->zc_data.zc_serd_checksum[0] == '\0') {
|
||||||
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");
|
||||||
|
|||||||
+23
-207
@@ -183,14 +183,14 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
|||||||
nvlist_t *nvroot, *newvd;
|
nvlist_t *nvroot, *newvd;
|
||||||
pendingdev_t *device;
|
pendingdev_t *device;
|
||||||
uint64_t wholedisk = 0ULL;
|
uint64_t wholedisk = 0ULL;
|
||||||
uint64_t offline = 0ULL, faulted = 0ULL;
|
uint64_t offline = 0ULL;
|
||||||
uint64_t guid = 0ULL;
|
uint64_t guid = 0ULL;
|
||||||
char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL;
|
char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL;
|
||||||
char rawpath[PATH_MAX], fullpath[PATH_MAX];
|
char rawpath[PATH_MAX], fullpath[PATH_MAX];
|
||||||
char devpath[PATH_MAX];
|
char devpath[PATH_MAX];
|
||||||
int ret;
|
int ret;
|
||||||
|
boolean_t is_dm = B_FALSE;
|
||||||
boolean_t is_sd = B_FALSE;
|
boolean_t is_sd = B_FALSE;
|
||||||
boolean_t is_mpath_wholedisk = B_FALSE;
|
|
||||||
uint_t c;
|
uint_t c;
|
||||||
vdev_stat_t *vs;
|
vdev_stat_t *vs;
|
||||||
|
|
||||||
@@ -211,73 +211,15 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
|||||||
&enc_sysfs_path);
|
&enc_sysfs_path);
|
||||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
|
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
|
||||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline);
|
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline);
|
||||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_FAULTED, &faulted);
|
|
||||||
|
|
||||||
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid);
|
(void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid);
|
||||||
|
|
||||||
/*
|
if (offline)
|
||||||
* Special case:
|
return; /* don't intervene if it was taken offline */
|
||||||
*
|
|
||||||
* We've seen times where a disk won't have a ZPOOL_CONFIG_PHYS_PATH
|
|
||||||
* entry in their config. For example, on this force-faulted disk:
|
|
||||||
*
|
|
||||||
* children[0]:
|
|
||||||
* type: 'disk'
|
|
||||||
* id: 0
|
|
||||||
* guid: 14309659774640089719
|
|
||||||
* path: '/dev/disk/by-vdev/L28'
|
|
||||||
* whole_disk: 0
|
|
||||||
* DTL: 654
|
|
||||||
* create_txg: 4
|
|
||||||
* com.delphix:vdev_zap_leaf: 1161
|
|
||||||
* faulted: 1
|
|
||||||
* aux_state: 'external'
|
|
||||||
* children[1]:
|
|
||||||
* type: 'disk'
|
|
||||||
* id: 1
|
|
||||||
* guid: 16002508084177980912
|
|
||||||
* path: '/dev/disk/by-vdev/L29'
|
|
||||||
* devid: 'dm-uuid-mpath-35000c500a61d68a3'
|
|
||||||
* phys_path: 'L29'
|
|
||||||
* vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32'
|
|
||||||
* whole_disk: 0
|
|
||||||
* DTL: 1028
|
|
||||||
* create_txg: 4
|
|
||||||
* com.delphix:vdev_zap_leaf: 131
|
|
||||||
*
|
|
||||||
* If the disk's path is a /dev/disk/by-vdev/ path, then we can infer
|
|
||||||
* the ZPOOL_CONFIG_PHYS_PATH from the by-vdev disk name.
|
|
||||||
*/
|
|
||||||
if (physpath == NULL && path != NULL) {
|
|
||||||
/* If path begins with "/dev/disk/by-vdev/" ... */
|
|
||||||
if (strncmp(path, DEV_BYVDEV_PATH,
|
|
||||||
strlen(DEV_BYVDEV_PATH)) == 0) {
|
|
||||||
/* Set physpath to the char after "/dev/disk/by-vdev" */
|
|
||||||
physpath = &path[strlen(DEV_BYVDEV_PATH)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
is_dm = zfs_dev_is_dm(path);
|
||||||
* We don't want to autoreplace offlined disks. However, we do want to
|
|
||||||
* replace force-faulted disks (`zpool offline -f`). Force-faulted
|
|
||||||
* disks have both offline=1 and faulted=1 in the nvlist.
|
|
||||||
*/
|
|
||||||
if (offline && !faulted) {
|
|
||||||
zed_log_msg(LOG_INFO, "%s: %s is offline, skip autoreplace",
|
|
||||||
__func__, path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
is_mpath_wholedisk = is_mpath_whole_disk(path);
|
|
||||||
zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s', phys '%s'"
|
zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s', phys '%s'"
|
||||||
" %s blank disk, %s mpath blank disk, %s labeled, enc sysfs '%s', "
|
" wholedisk %d, %s dm (guid %llu)", zpool_get_name(zhp), path,
|
||||||
"(guid %llu)",
|
physpath ? physpath : "NULL", wholedisk, is_dm ? "is" : "not",
|
||||||
zpool_get_name(zhp), path,
|
|
||||||
physpath ? physpath : "NULL",
|
|
||||||
wholedisk ? "is" : "not",
|
|
||||||
is_mpath_wholedisk? "is" : "not",
|
|
||||||
labeled ? "is" : "not",
|
|
||||||
enc_sysfs_path,
|
|
||||||
(long long unsigned int)guid);
|
(long long unsigned int)guid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -311,9 +253,8 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
|||||||
ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, &newstate) == 0 &&
|
ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, &newstate) == 0 &&
|
||||||
(newstate == VDEV_STATE_HEALTHY ||
|
(newstate == VDEV_STATE_HEALTHY ||
|
||||||
newstate == VDEV_STATE_DEGRADED)) {
|
newstate == VDEV_STATE_DEGRADED)) {
|
||||||
zed_log_msg(LOG_INFO,
|
zed_log_msg(LOG_INFO, " zpool_vdev_online: vdev %s is %s",
|
||||||
" zpool_vdev_online: vdev '%s' ('%s') is "
|
fullpath, (newstate == VDEV_STATE_HEALTHY) ?
|
||||||
"%s", fullpath, physpath, (newstate == VDEV_STATE_HEALTHY) ?
|
|
||||||
"HEALTHY" : "DEGRADED");
|
"HEALTHY" : "DEGRADED");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -330,12 +271,11 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
|||||||
* vdev online to trigger a FMA fault by posting an ereport.
|
* vdev online to trigger a FMA fault by posting an ereport.
|
||||||
*/
|
*/
|
||||||
if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) ||
|
if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) ||
|
||||||
!(wholedisk || is_mpath_wholedisk) || (physpath == NULL)) {
|
!(wholedisk || is_dm) || (physpath == NULL)) {
|
||||||
(void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
|
(void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
|
||||||
&newstate);
|
&newstate);
|
||||||
zed_log_msg(LOG_INFO, "Pool's autoreplace is not enabled or "
|
zed_log_msg(LOG_INFO, "Pool's autoreplace is not enabled or "
|
||||||
"not a blank disk for '%s' ('%s')", fullpath,
|
"not a whole disk for '%s'", fullpath);
|
||||||
physpath);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +287,7 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
|||||||
(void) snprintf(rawpath, sizeof (rawpath), "%s%s",
|
(void) snprintf(rawpath, sizeof (rawpath), "%s%s",
|
||||||
is_sd ? DEV_BYVDEV_PATH : DEV_BYPATH_PATH, physpath);
|
is_sd ? DEV_BYVDEV_PATH : DEV_BYPATH_PATH, physpath);
|
||||||
|
|
||||||
if (realpath(rawpath, devpath) == NULL && !is_mpath_wholedisk) {
|
if (realpath(rawpath, devpath) == NULL && !is_dm) {
|
||||||
zed_log_msg(LOG_INFO, " realpath: %s failed (%s)",
|
zed_log_msg(LOG_INFO, " realpath: %s failed (%s)",
|
||||||
rawpath, strerror(errno));
|
rawpath, strerror(errno));
|
||||||
|
|
||||||
@@ -363,14 +303,12 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
|||||||
if ((vs->vs_state != VDEV_STATE_DEGRADED) &&
|
if ((vs->vs_state != VDEV_STATE_DEGRADED) &&
|
||||||
(vs->vs_state != VDEV_STATE_FAULTED) &&
|
(vs->vs_state != VDEV_STATE_FAULTED) &&
|
||||||
(vs->vs_state != VDEV_STATE_CANT_OPEN)) {
|
(vs->vs_state != VDEV_STATE_CANT_OPEN)) {
|
||||||
zed_log_msg(LOG_INFO, " not autoreplacing since disk isn't in "
|
|
||||||
"a bad state (currently %d)", vs->vs_state);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvlist_lookup_string(vdev, "new_devid", &new_devid);
|
nvlist_lookup_string(vdev, "new_devid", &new_devid);
|
||||||
|
|
||||||
if (is_mpath_wholedisk) {
|
if (is_dm) {
|
||||||
/* Don't label device mapper or multipath disks. */
|
/* Don't label device mapper or multipath disks. */
|
||||||
} else if (!labeled) {
|
} else if (!labeled) {
|
||||||
/*
|
/*
|
||||||
@@ -497,15 +435,7 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
ret = zpool_vdev_attach(zhp, fullpath, path, nvroot, B_TRUE, B_FALSE);
|
||||||
* Prefer sequential resilvering when supported (mirrors and dRAID),
|
|
||||||
* otherwise fallback to a traditional healing resilver.
|
|
||||||
*/
|
|
||||||
ret = zpool_vdev_attach(zhp, fullpath, path, nvroot, B_TRUE, B_TRUE);
|
|
||||||
if (ret != 0) {
|
|
||||||
ret = zpool_vdev_attach(zhp, fullpath, path, nvroot,
|
|
||||||
B_TRUE, B_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
zed_log_msg(LOG_INFO, " zpool_vdev_replace: %s with %s (%s)",
|
zed_log_msg(LOG_INFO, " zpool_vdev_replace: %s with %s (%s)",
|
||||||
fullpath, path, (ret == 0) ? "no errors" :
|
fullpath, path, (ret == 0) ? "no errors" :
|
||||||
@@ -584,11 +514,8 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
|
|||||||
* the dp->dd_compare value.
|
* the dp->dd_compare value.
|
||||||
*/
|
*/
|
||||||
if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 ||
|
if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 ||
|
||||||
strcmp(dp->dd_compare, path) != 0) {
|
strcmp(dp->dd_compare, path) != 0)
|
||||||
zed_log_msg(LOG_INFO, " %s: no match (%s != vdev %s)",
|
|
||||||
__func__, dp->dd_compare, path);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched %s on %s",
|
zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched %s on %s",
|
||||||
dp->dd_prop, path);
|
dp->dd_prop, path);
|
||||||
@@ -636,8 +563,6 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data)
|
|||||||
ZPOOL_CONFIG_VDEV_TREE, &nvl);
|
ZPOOL_CONFIG_VDEV_TREE, &nvl);
|
||||||
zfs_iter_vdev(zhp, nvl, data);
|
zfs_iter_vdev(zhp, nvl, data);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
zed_log_msg(LOG_INFO, "%s: no config\n", __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -686,72 +611,6 @@ devphys_iter(const char *physical, const char *devid, zfs_process_func_t func,
|
|||||||
return (data.dd_found);
|
return (data.dd_found);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Given a device identifier, find any vdevs with a matching by-vdev
|
|
||||||
* path. Normally we shouldn't need this as the comparison would be
|
|
||||||
* made earlier in the devphys_iter(). For example, if we were replacing
|
|
||||||
* /dev/disk/by-vdev/L28, normally devphys_iter() would match the
|
|
||||||
* ZPOOL_CONFIG_PHYS_PATH of "L28" from the old disk config to "L28"
|
|
||||||
* of the new disk config. However, we've seen cases where
|
|
||||||
* ZPOOL_CONFIG_PHYS_PATH was not in the config for the old disk. Here's
|
|
||||||
* an example of a real 2-disk mirror pool where one disk was force
|
|
||||||
* faulted:
|
|
||||||
*
|
|
||||||
* com.delphix:vdev_zap_top: 129
|
|
||||||
* children[0]:
|
|
||||||
* type: 'disk'
|
|
||||||
* id: 0
|
|
||||||
* guid: 14309659774640089719
|
|
||||||
* path: '/dev/disk/by-vdev/L28'
|
|
||||||
* whole_disk: 0
|
|
||||||
* DTL: 654
|
|
||||||
* create_txg: 4
|
|
||||||
* com.delphix:vdev_zap_leaf: 1161
|
|
||||||
* faulted: 1
|
|
||||||
* aux_state: 'external'
|
|
||||||
* children[1]:
|
|
||||||
* type: 'disk'
|
|
||||||
* id: 1
|
|
||||||
* guid: 16002508084177980912
|
|
||||||
* path: '/dev/disk/by-vdev/L29'
|
|
||||||
* devid: 'dm-uuid-mpath-35000c500a61d68a3'
|
|
||||||
* phys_path: 'L29'
|
|
||||||
* vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32'
|
|
||||||
* whole_disk: 0
|
|
||||||
* DTL: 1028
|
|
||||||
* create_txg: 4
|
|
||||||
* com.delphix:vdev_zap_leaf: 131
|
|
||||||
*
|
|
||||||
* So in the case above, the only thing we could compare is the path.
|
|
||||||
*
|
|
||||||
* We can do this because we assume by-vdev paths are authoritative as physical
|
|
||||||
* paths. We could not assume this for normal paths like /dev/sda since the
|
|
||||||
* physical location /dev/sda points to could change over time.
|
|
||||||
*/
|
|
||||||
static boolean_t
|
|
||||||
by_vdev_path_iter(const char *by_vdev_path, const char *devid,
|
|
||||||
zfs_process_func_t func, boolean_t is_slice)
|
|
||||||
{
|
|
||||||
dev_data_t data = { 0 };
|
|
||||||
|
|
||||||
data.dd_compare = by_vdev_path;
|
|
||||||
data.dd_func = func;
|
|
||||||
data.dd_prop = ZPOOL_CONFIG_PATH;
|
|
||||||
data.dd_found = B_FALSE;
|
|
||||||
data.dd_islabeled = is_slice;
|
|
||||||
data.dd_new_devid = devid;
|
|
||||||
|
|
||||||
if (strncmp(by_vdev_path, DEV_BYVDEV_PATH,
|
|
||||||
strlen(DEV_BYVDEV_PATH)) != 0) {
|
|
||||||
/* by_vdev_path doesn't start with "/dev/disk/by-vdev/" */
|
|
||||||
return (B_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
|
|
||||||
|
|
||||||
return (data.dd_found);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a device identifier, find any vdevs with a matching devid.
|
* Given a device identifier, find any vdevs with a matching devid.
|
||||||
* On Linux we can match devid directly which is always a whole disk.
|
* On Linux we can match devid directly which is always a whole disk.
|
||||||
@@ -773,27 +632,6 @@ devid_iter(const char *devid, zfs_process_func_t func, boolean_t is_slice)
|
|||||||
return (data.dd_found);
|
return (data.dd_found);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Given a device guid, find any vdevs with a matching guid.
|
|
||||||
*/
|
|
||||||
static boolean_t
|
|
||||||
guid_iter(uint64_t pool_guid, uint64_t vdev_guid, const char *devid,
|
|
||||||
zfs_process_func_t func, boolean_t is_slice)
|
|
||||||
{
|
|
||||||
dev_data_t data = { 0 };
|
|
||||||
|
|
||||||
data.dd_func = func;
|
|
||||||
data.dd_found = B_FALSE;
|
|
||||||
data.dd_pool_guid = pool_guid;
|
|
||||||
data.dd_vdev_guid = vdev_guid;
|
|
||||||
data.dd_islabeled = is_slice;
|
|
||||||
data.dd_new_devid = devid;
|
|
||||||
|
|
||||||
(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
|
|
||||||
|
|
||||||
return (data.dd_found);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle a EC_DEV_ADD.ESC_DISK event.
|
* Handle a EC_DEV_ADD.ESC_DISK event.
|
||||||
*
|
*
|
||||||
@@ -816,21 +654,16 @@ guid_iter(uint64_t pool_guid, uint64_t vdev_guid, const char *devid,
|
|||||||
static int
|
static int
|
||||||
zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi)
|
zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi)
|
||||||
{
|
{
|
||||||
char *devpath = NULL, *devid = NULL;
|
char *devpath = NULL, *devid;
|
||||||
uint64_t pool_guid = 0, vdev_guid = 0;
|
|
||||||
boolean_t is_slice;
|
boolean_t is_slice;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expecting a devid string and an optional physical location and guid
|
* Expecting a devid string and an optional physical location
|
||||||
*/
|
*/
|
||||||
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0) {
|
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0)
|
||||||
zed_log_msg(LOG_INFO, "%s: no dev identifier\n", __func__);
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
|
||||||
|
|
||||||
(void) nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devpath);
|
(void) nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devpath);
|
||||||
(void) nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &pool_guid);
|
|
||||||
(void) nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &vdev_guid);
|
|
||||||
|
|
||||||
is_slice = (nvlist_lookup_boolean(nvl, DEV_IS_PART) == 0);
|
is_slice = (nvlist_lookup_boolean(nvl, DEV_IS_PART) == 0);
|
||||||
|
|
||||||
@@ -841,28 +674,12 @@ zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi)
|
|||||||
* Iterate over all vdevs looking for a match in the following order:
|
* Iterate over all vdevs looking for a match in the following order:
|
||||||
* 1. ZPOOL_CONFIG_DEVID (identifies the unique disk)
|
* 1. ZPOOL_CONFIG_DEVID (identifies the unique disk)
|
||||||
* 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location).
|
* 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location).
|
||||||
* 3. ZPOOL_CONFIG_GUID (identifies unique vdev).
|
*
|
||||||
* 4. ZPOOL_CONFIG_PATH for /dev/disk/by-vdev devices only (since
|
* For disks, we only want to pay attention to vdevs marked as whole
|
||||||
* by-vdev paths represent physical paths).
|
* disks or are a multipath device.
|
||||||
*/
|
*/
|
||||||
if (devid_iter(devid, zfs_process_add, is_slice))
|
if (!devid_iter(devid, zfs_process_add, is_slice) && devpath != NULL)
|
||||||
return (0);
|
(void) devphys_iter(devpath, devid, zfs_process_add, is_slice);
|
||||||
if (devpath != NULL && devphys_iter(devpath, devid, zfs_process_add,
|
|
||||||
is_slice))
|
|
||||||
return (0);
|
|
||||||
if (vdev_guid != 0)
|
|
||||||
(void) guid_iter(pool_guid, vdev_guid, devid, zfs_process_add,
|
|
||||||
is_slice);
|
|
||||||
|
|
||||||
if (devpath != NULL) {
|
|
||||||
/* Can we match a /dev/disk/by-vdev/ path? */
|
|
||||||
char by_vdev_path[MAXPATHLEN];
|
|
||||||
snprintf(by_vdev_path, sizeof (by_vdev_path),
|
|
||||||
"/dev/disk/by-vdev/%s", devpath);
|
|
||||||
if (by_vdev_path_iter(by_vdev_path, devid, zfs_process_add,
|
|
||||||
is_slice))
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@@ -1093,7 +910,6 @@ zfs_slm_init()
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_setname_np(g_zfs_tid, "enum-pools");
|
|
||||||
list_create(&g_device_list, sizeof (struct pendingdev),
|
list_create(&g_device_list, sizeof (struct pendingdev),
|
||||||
offsetof(struct pendingdev, pd_node));
|
offsetof(struct pendingdev, pd_node));
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
#include <sys/fm/fs/zfs.h>
|
#include <sys/fm/fs/zfs.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"
|
||||||
@@ -220,18 +219,12 @@ 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;
|
||||||
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 set, add the "ashift" pool property to the spare nvlist */
|
||||||
if (source != ZPROP_SRC_DEFAULT)
|
if (source != ZPROP_SRC_DEFAULT)
|
||||||
(void) nvlist_add_uint64(spares[s],
|
(void) nvlist_add_uint64(spares[s],
|
||||||
@@ -244,7 +237,7 @@ replace_with_spare(fmd_hdl_t *hdl, zpool_handle_t *zhp, nvlist_t *vdev)
|
|||||||
dev_name, 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, B_FALSE) == 0) {
|
||||||
free(dev_name);
|
free(dev_name);
|
||||||
nvlist_free(replacement);
|
nvlist_free(replacement);
|
||||||
return (B_TRUE);
|
return (B_TRUE);
|
||||||
@@ -335,7 +328,7 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
|
|||||||
*/
|
*/
|
||||||
if (strcmp(class, "resource.fs.zfs.removed") == 0 ||
|
if (strcmp(class, "resource.fs.zfs.removed") == 0 ||
|
||||||
(strcmp(class, "resource.fs.zfs.statechange") == 0 &&
|
(strcmp(class, "resource.fs.zfs.statechange") == 0 &&
|
||||||
(state == VDEV_STATE_REMOVED || state == VDEV_STATE_FAULTED))) {
|
state == VDEV_STATE_REMOVED)) {
|
||||||
char *devtype;
|
char *devtype;
|
||||||
char *devname;
|
char *devname;
|
||||||
|
|
||||||
@@ -506,7 +499,6 @@ 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);
|
(void) replace_with_spare(hdl, zhp, vdev);
|
||||||
|
|
||||||
zpool_close(zhp);
|
zpool_close(zhp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+24
-26
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
@@ -60,8 +60,8 @@ _setup_sig_handlers(void)
|
|||||||
zed_log_die("Failed to initialize sigset");
|
zed_log_die("Failed to initialize sigset");
|
||||||
|
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
|
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
|
|
||||||
if (sigaction(SIGPIPE, &sa, NULL) < 0)
|
if (sigaction(SIGPIPE, &sa, NULL) < 0)
|
||||||
zed_log_die("Failed to ignore SIGPIPE");
|
zed_log_die("Failed to ignore SIGPIPE");
|
||||||
|
|
||||||
@@ -75,10 +75,6 @@ _setup_sig_handlers(void)
|
|||||||
sa.sa_handler = _hup_handler;
|
sa.sa_handler = _hup_handler;
|
||||||
if (sigaction(SIGHUP, &sa, NULL) < 0)
|
if (sigaction(SIGHUP, &sa, NULL) < 0)
|
||||||
zed_log_die("Failed to register SIGHUP handler");
|
zed_log_die("Failed to register SIGHUP handler");
|
||||||
|
|
||||||
(void) sigaddset(&sa.sa_mask, SIGCHLD);
|
|
||||||
if (pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL) < 0)
|
|
||||||
zed_log_die("Failed to block SIGCHLD");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -216,20 +212,22 @@ _finish_daemonize(void)
|
|||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct zed_conf zcp;
|
struct zed_conf *zcp;
|
||||||
uint64_t saved_eid;
|
uint64_t saved_eid;
|
||||||
int64_t saved_etime[2];
|
int64_t saved_etime[2];
|
||||||
|
|
||||||
zed_log_init(argv[0]);
|
zed_log_init(argv[0]);
|
||||||
zed_log_stderr_open(LOG_NOTICE);
|
zed_log_stderr_open(LOG_NOTICE);
|
||||||
zed_conf_init(&zcp);
|
zcp = zed_conf_create();
|
||||||
zed_conf_parse_opts(&zcp, argc, argv);
|
zed_conf_parse_opts(zcp, argc, argv);
|
||||||
if (zcp.do_verbose)
|
if (zcp->do_verbose)
|
||||||
zed_log_stderr_open(LOG_INFO);
|
zed_log_stderr_open(LOG_INFO);
|
||||||
|
|
||||||
if (geteuid() != 0)
|
if (geteuid() != 0)
|
||||||
zed_log_die("Must be run as root");
|
zed_log_die("Must be run as root");
|
||||||
|
|
||||||
|
zed_conf_parse_file(zcp);
|
||||||
|
|
||||||
zed_file_close_from(STDERR_FILENO + 1);
|
zed_file_close_from(STDERR_FILENO + 1);
|
||||||
|
|
||||||
(void) umask(0);
|
(void) umask(0);
|
||||||
@@ -237,32 +235,32 @@ main(int argc, char *argv[])
|
|||||||
if (chdir("/") < 0)
|
if (chdir("/") < 0)
|
||||||
zed_log_die("Failed to change to root directory");
|
zed_log_die("Failed to change to root directory");
|
||||||
|
|
||||||
if (zed_conf_scan_dir(&zcp) < 0)
|
if (zed_conf_scan_dir(zcp) < 0)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
if (!zcp.do_foreground) {
|
if (!zcp->do_foreground) {
|
||||||
_start_daemonize();
|
_start_daemonize();
|
||||||
zed_log_syslog_open(LOG_DAEMON);
|
zed_log_syslog_open(LOG_DAEMON);
|
||||||
}
|
}
|
||||||
_setup_sig_handlers();
|
_setup_sig_handlers();
|
||||||
|
|
||||||
if (zcp.do_memlock)
|
if (zcp->do_memlock)
|
||||||
_lock_memory();
|
_lock_memory();
|
||||||
|
|
||||||
if ((zed_conf_write_pid(&zcp) < 0) && (!zcp.do_force))
|
if ((zed_conf_write_pid(zcp) < 0) && (!zcp->do_force))
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
if (!zcp.do_foreground)
|
if (!zcp->do_foreground)
|
||||||
_finish_daemonize();
|
_finish_daemonize();
|
||||||
|
|
||||||
zed_log_msg(LOG_NOTICE,
|
zed_log_msg(LOG_NOTICE,
|
||||||
"ZFS Event Daemon %s-%s (PID %d)",
|
"ZFS Event Daemon %s-%s (PID %d)",
|
||||||
ZFS_META_VERSION, ZFS_META_RELEASE, (int)getpid());
|
ZFS_META_VERSION, ZFS_META_RELEASE, (int)getpid());
|
||||||
|
|
||||||
if (zed_conf_open_state(&zcp) < 0)
|
if (zed_conf_open_state(zcp) < 0)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
if (zed_conf_read_state(&zcp, &saved_eid, saved_etime) < 0)
|
if (zed_conf_read_state(zcp, &saved_eid, saved_etime) < 0)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
idle:
|
idle:
|
||||||
@@ -271,38 +269,38 @@ idle:
|
|||||||
* successful.
|
* successful.
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
if (!zed_event_init(&zcp))
|
if (!zed_event_init(zcp))
|
||||||
break;
|
break;
|
||||||
/* Wait for some time and try again. tunable? */
|
/* Wait for some time and try again. tunable? */
|
||||||
sleep(30);
|
sleep(30);
|
||||||
} while (!_got_exit && zcp.do_idle);
|
} while (!_got_exit && zcp->do_idle);
|
||||||
|
|
||||||
if (_got_exit)
|
if (_got_exit)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
zed_event_seek(&zcp, saved_eid, saved_etime);
|
zed_event_seek(zcp, saved_eid, saved_etime);
|
||||||
|
|
||||||
while (!_got_exit) {
|
while (!_got_exit) {
|
||||||
int rv;
|
int rv;
|
||||||
if (_got_hup) {
|
if (_got_hup) {
|
||||||
_got_hup = 0;
|
_got_hup = 0;
|
||||||
(void) zed_conf_scan_dir(&zcp);
|
(void) zed_conf_scan_dir(zcp);
|
||||||
}
|
}
|
||||||
rv = zed_event_service(&zcp);
|
rv = zed_event_service(zcp);
|
||||||
|
|
||||||
/* ENODEV: When kernel module is unloaded (osx) */
|
/* ENODEV: When kernel module is unloaded (osx) */
|
||||||
if (rv != 0)
|
if (rv == ENODEV)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
zed_log_msg(LOG_NOTICE, "Exiting");
|
zed_log_msg(LOG_NOTICE, "Exiting");
|
||||||
zed_event_fini(&zcp);
|
zed_event_fini(zcp);
|
||||||
|
|
||||||
if (zcp.do_idle && !_got_exit)
|
if (zcp->do_idle && !_got_exit)
|
||||||
goto idle;
|
goto idle;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
zed_conf_destroy(&zcp);
|
zed_conf_destroy(zcp);
|
||||||
zed_log_fini();
|
zed_log_fini();
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
include $(top_srcdir)/config/Rules.am
|
include $(top_srcdir)/config/Rules.am
|
||||||
include $(top_srcdir)/config/Substfiles.am
|
include $(top_srcdir)/config/Substfiles.am
|
||||||
include $(top_srcdir)/config/Shellcheck.am
|
|
||||||
|
|
||||||
EXTRA_DIST += README
|
EXTRA_DIST += README
|
||||||
|
|
||||||
@@ -52,6 +51,3 @@ install-data-hook:
|
|||||||
ln -s "$(zedexecdir)/$${f}" "$(DESTDIR)$(zedconfdir)"; \
|
ln -s "$(zedexecdir)/$${f}" "$(DESTDIR)$(zedconfdir)"; \
|
||||||
done
|
done
|
||||||
chmod 0600 "$(DESTDIR)$(zedconfdir)/zed.rc"
|
chmod 0600 "$(DESTDIR)$(zedconfdir)/zed.rc"
|
||||||
|
|
||||||
# False positive: 1>&"${ZED_FLOCK_FD}" looks suspiciously similar to a >&filename bash extension
|
|
||||||
CHECKBASHISMS_IGNORE = -e 'should be >word 2>&1' -e '&"$${ZED_FLOCK_FD}"'
|
|
||||||
|
|||||||
@@ -12,11 +12,15 @@
|
|||||||
|
|
||||||
zed_exit_if_ignoring_this_event
|
zed_exit_if_ignoring_this_event
|
||||||
|
|
||||||
zed_lock "${ZED_DEBUG_LOG}"
|
lockfile="$(basename -- "${ZED_DEBUG_LOG}").lock"
|
||||||
{
|
|
||||||
printenv | sort
|
|
||||||
echo
|
|
||||||
} 1>&"${ZED_FLOCK_FD}"
|
|
||||||
zed_unlock "${ZED_DEBUG_LOG}"
|
|
||||||
|
|
||||||
|
umask 077
|
||||||
|
zed_lock "${lockfile}"
|
||||||
|
exec >> "${ZED_DEBUG_LOG}"
|
||||||
|
|
||||||
|
printenv | sort
|
||||||
|
echo
|
||||||
|
|
||||||
|
exec >&-
|
||||||
|
zed_unlock "${lockfile}"
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ if [ "${ZED_SYSLOG_DISPLAY_GUIDS}" = "1" ]; then
|
|||||||
[ -n "${ZEVENT_VDEV_GUID}" ] && msg="${msg} vdev_guid=${ZEVENT_VDEV_GUID}"
|
[ -n "${ZEVENT_VDEV_GUID}" ] && msg="${msg} vdev_guid=${ZEVENT_VDEV_GUID}"
|
||||||
else
|
else
|
||||||
[ -n "${ZEVENT_POOL}" ] && msg="${msg} pool='${ZEVENT_POOL}'"
|
[ -n "${ZEVENT_POOL}" ] && msg="${msg} pool='${ZEVENT_POOL}'"
|
||||||
[ -n "${ZEVENT_VDEV_PATH}" ] && msg="${msg} vdev=${ZEVENT_VDEV_PATH##*/}"
|
[ -n "${ZEVENT_VDEV_PATH}" ] && msg="${msg} vdev=$(basename "${ZEVENT_VDEV_PATH}")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# log pool state if state is anything other than 'ACTIVE'
|
# log pool state if state is anything other than 'ACTIVE'
|
||||||
@@ -42,7 +42,6 @@ fi
|
|||||||
msg="${msg} delay=$((ZEVENT_ZIO_DELAY / 1000000))ms"
|
msg="${msg} delay=$((ZEVENT_ZIO_DELAY / 1000000))ms"
|
||||||
|
|
||||||
# list the bookmark data together
|
# list the bookmark data together
|
||||||
# shellcheck disable=SC2153
|
|
||||||
[ -n "${ZEVENT_ZIO_OBJSET}" ] && \
|
[ -n "${ZEVENT_ZIO_OBJSET}" ] && \
|
||||||
msg="${msg} bookmark=${ZEVENT_ZIO_OBJSET}:${ZEVENT_ZIO_OBJECT}:${ZEVENT_ZIO_LEVEL}:${ZEVENT_ZIO_BLKID}"
|
msg="${msg} bookmark=${ZEVENT_ZIO_OBJSET}:${ZEVENT_ZIO_OBJECT}:${ZEVENT_ZIO_LEVEL}:${ZEVENT_ZIO_BLKID}"
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ zed_rate_limit "${rate_limit_tag}" || exit 3
|
|||||||
|
|
||||||
umask 077
|
umask 077
|
||||||
note_subject="ZFS ${ZEVENT_SUBCLASS} error for ${ZEVENT_POOL} on $(hostname)"
|
note_subject="ZFS ${ZEVENT_SUBCLASS} error for ${ZEVENT_POOL} on $(hostname)"
|
||||||
note_pathname="$(mktemp)"
|
note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
|
||||||
{
|
{
|
||||||
echo "ZFS has detected a data error:"
|
echo "ZFS has detected a data error:"
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
# Rate-limit the notification based in part on the filename.
|
# Rate-limit the notification based in part on the filename.
|
||||||
#
|
#
|
||||||
rate_limit_tag="${ZEVENT_POOL};${ZEVENT_SUBCLASS};${0##*/}"
|
rate_limit_tag="${ZEVENT_POOL};${ZEVENT_SUBCLASS};$(basename -- "$0")"
|
||||||
rate_limit_interval="${ZED_NOTIFY_INTERVAL_SECS}"
|
rate_limit_interval="${ZED_NOTIFY_INTERVAL_SECS}"
|
||||||
zed_rate_limit "${rate_limit_tag}" "${rate_limit_interval}" || exit 3
|
zed_rate_limit "${rate_limit_tag}" "${rate_limit_interval}" || exit 3
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ umask 077
|
|||||||
pool_str="${ZEVENT_POOL:+" for ${ZEVENT_POOL}"}"
|
pool_str="${ZEVENT_POOL:+" for ${ZEVENT_POOL}"}"
|
||||||
host_str=" on $(hostname)"
|
host_str=" on $(hostname)"
|
||||||
note_subject="ZFS ${ZEVENT_SUBCLASS} event${pool_str}${host_str}"
|
note_subject="ZFS ${ZEVENT_SUBCLASS} event${pool_str}${host_str}"
|
||||||
note_pathname="$(mktemp)"
|
note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
|
||||||
{
|
{
|
||||||
echo "ZFS has posted the following event:"
|
echo "ZFS has posted the following event:"
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
# Track changes to enumerated pools for use in early-boot
|
# Track changes to enumerated pools for use in early-boot
|
||||||
set -ef
|
set -ef
|
||||||
|
|
||||||
FSLIST="@sysconfdir@/zfs/zfs-list.cache/${ZEVENT_POOL}"
|
FSLIST_DIR="@sysconfdir@/zfs/zfs-list.cache"
|
||||||
FSLIST_TMP="@runstatedir@/zfs-list.cache@${ZEVENT_POOL}"
|
FSLIST_TMP="@runstatedir@/zfs-list.cache.new"
|
||||||
|
FSLIST="${FSLIST_DIR}/${ZEVENT_POOL}"
|
||||||
|
|
||||||
# If the pool specific cache file is not writeable, abort
|
# If the pool specific cache file is not writeable, abort
|
||||||
[ -w "${FSLIST}" ] || exit 0
|
[ -w "${FSLIST}" ] || exit 0
|
||||||
@@ -13,20 +14,20 @@ FSLIST_TMP="@runstatedir@/zfs-list.cache@${ZEVENT_POOL}"
|
|||||||
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
||||||
|
|
||||||
[ "$ZEVENT_SUBCLASS" != "history_event" ] && exit 0
|
[ "$ZEVENT_SUBCLASS" != "history_event" ] && exit 0
|
||||||
zed_check_cmd "${ZFS}" sort diff
|
zed_check_cmd "${ZFS}" sort diff grep
|
||||||
|
|
||||||
# If we are acting on a snapshot, we have nothing to do
|
# If we are acting on a snapshot, we have nothing to do
|
||||||
[ "${ZEVENT_HISTORY_DSNAME%@*}" = "${ZEVENT_HISTORY_DSNAME}" ] || exit 0
|
printf '%s' "${ZEVENT_HISTORY_DSNAME}" | grep '@' && exit 0
|
||||||
|
|
||||||
# We lock the output file to avoid simultaneous writes.
|
# We obtain a lock on zfs-list to avoid any simultaneous writes.
|
||||||
# If we run into trouble, log and drop the lock
|
# If we run into trouble, log and drop the lock
|
||||||
abort_alter() {
|
abort_alter() {
|
||||||
zed_log_msg "Error updating zfs-list.cache for ${ZEVENT_POOL}!"
|
zed_log_msg "Error updating zfs-list.cache!"
|
||||||
zed_unlock "${FSLIST}"
|
zed_unlock zfs-list
|
||||||
}
|
}
|
||||||
|
|
||||||
finished() {
|
finished() {
|
||||||
zed_unlock "${FSLIST}"
|
zed_unlock zfs-list
|
||||||
trap - EXIT
|
trap - EXIT
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
@@ -36,7 +37,7 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
export)
|
export)
|
||||||
zed_lock "${FSLIST}"
|
zed_lock zfs-list
|
||||||
trap abort_alter EXIT
|
trap abort_alter EXIT
|
||||||
echo > "${FSLIST}"
|
echo > "${FSLIST}"
|
||||||
finished
|
finished
|
||||||
@@ -62,7 +63,7 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
zed_lock "${FSLIST}"
|
zed_lock zfs-list
|
||||||
trap abort_alter EXIT
|
trap abort_alter EXIT
|
||||||
|
|
||||||
PROPS="name,mountpoint,canmount,atime,relatime,devices,exec\
|
PROPS="name,mountpoint,canmount,atime,relatime,devices,exec\
|
||||||
@@ -78,7 +79,7 @@ PROPS="name,mountpoint,canmount,atime,relatime,devices,exec\
|
|||||||
sort "${FSLIST_TMP}" -o "${FSLIST_TMP}"
|
sort "${FSLIST_TMP}" -o "${FSLIST_TMP}"
|
||||||
|
|
||||||
# Don't modify the file if it hasn't changed
|
# Don't modify the file if it hasn't changed
|
||||||
diff -q "${FSLIST_TMP}" "${FSLIST}" || cat "${FSLIST_TMP}" > "${FSLIST}"
|
diff -q "${FSLIST_TMP}" "${FSLIST}" || mv "${FSLIST_TMP}" "${FSLIST}"
|
||||||
rm -f "${FSLIST_TMP}"
|
rm -f "${FSLIST_TMP}"
|
||||||
|
|
||||||
finished
|
finished
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ fi
|
|||||||
|
|
||||||
umask 077
|
umask 077
|
||||||
note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)"
|
note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)"
|
||||||
note_pathname="$(mktemp)"
|
note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
|
||||||
{
|
{
|
||||||
echo "ZFS has finished a ${action}:"
|
echo "ZFS has finished a ${action}:"
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# Turn off/on vdevs' enclosure fault LEDs when their pool's state changes.
|
# Turn off/on the VDEV's enclosure fault LEDs when the pool's state changes.
|
||||||
#
|
#
|
||||||
# Turn a vdev's fault LED on if it becomes FAULTED, DEGRADED or UNAVAIL.
|
# Turn the VDEV's fault LED on if it becomes FAULTED, DEGRADED or UNAVAIL.
|
||||||
# Turn its LED off when it's back ONLINE again.
|
# Turn the LED off when it's back ONLINE again.
|
||||||
#
|
#
|
||||||
# This script run in two basic modes:
|
# This script run in two basic modes:
|
||||||
#
|
#
|
||||||
# 1. If $ZEVENT_VDEV_ENC_SYSFS_PATH and $ZEVENT_VDEV_STATE_STR are set, then
|
# 1. If $ZEVENT_VDEV_ENC_SYSFS_PATH and $ZEVENT_VDEV_STATE_STR are set, then
|
||||||
# only set the LED for that particular vdev. This is the case for statechange
|
# only set the LED for that particular VDEV. This is the case for statechange
|
||||||
# events and some vdev_* events.
|
# events and some vdev_* events.
|
||||||
#
|
#
|
||||||
# 2. If those vars are not set, then check the state of all vdevs in the pool
|
# 2. If those vars are not set, then check the state of all VDEVs in the pool
|
||||||
# and set the LEDs accordingly. This is the case for pool_import events.
|
# and set the LEDs accordingly. This is the case for pool_import events.
|
||||||
#
|
#
|
||||||
# Note that this script requires that your enclosure be supported by the
|
# Note that this script requires that your enclosure be supported by the
|
||||||
# Linux SCSI Enclosure services (SES) driver. The script will do nothing
|
# Linux SCSI enclosure services (ses) driver. The script will do nothing
|
||||||
# if you have no enclosure, or if your enclosure isn't supported.
|
# if you have no enclosure, or if your enclosure isn't supported.
|
||||||
#
|
#
|
||||||
# Exit codes:
|
# Exit codes:
|
||||||
@@ -29,8 +29,7 @@
|
|||||||
[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
|
[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
|
||||||
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
||||||
|
|
||||||
if [ ! -d /sys/class/enclosure ] && [ ! -d /sys/bus/pci/slots ] ; then
|
if [ ! -d /sys/class/enclosure ] ; then
|
||||||
# No JBOD enclosure or NVMe slots
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -60,10 +59,6 @@ check_and_set_led()
|
|||||||
file="$1"
|
file="$1"
|
||||||
val="$2"
|
val="$2"
|
||||||
|
|
||||||
if [ -z "$val" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -e "$file" ] ; then
|
if [ ! -e "$file" ] ; then
|
||||||
return 3
|
return 3
|
||||||
fi
|
fi
|
||||||
@@ -71,11 +66,11 @@ check_and_set_led()
|
|||||||
# If another process is accessing the LED when we attempt to update it,
|
# If another process is accessing the LED when we attempt to update it,
|
||||||
# the update will be lost so retry until the LED actually changes or we
|
# the update will be lost so retry until the LED actually changes or we
|
||||||
# timeout.
|
# timeout.
|
||||||
for _ in 1 2 3 4 5; do
|
for _ in $(seq 1 5); do
|
||||||
# We want to check the current state first, since writing to the
|
# We want to check the current state first, since writing to the
|
||||||
# 'fault' entry always causes a SES command, even if the
|
# 'fault' entry always causes a SES command, even if the
|
||||||
# current state is already what you want.
|
# current state is already what you want.
|
||||||
read -r current < "${file}"
|
current=$(cat "${file}")
|
||||||
|
|
||||||
# On some enclosures if you write 1 to fault, and read it back,
|
# On some enclosures if you write 1 to fault, and read it back,
|
||||||
# it will return 2. Treat all non-zero values as 1 for
|
# it will return 2. Treat all non-zero values as 1 for
|
||||||
@@ -90,84 +85,27 @@ check_and_set_led()
|
|||||||
else
|
else
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
|
||||||
|
|
||||||
# Fault LEDs for JBODs and NVMe drives are handled a little differently.
|
|
||||||
#
|
|
||||||
# On JBODs the fault LED is called 'fault' and on a path like this:
|
|
||||||
#
|
|
||||||
# /sys/class/enclosure/0:0:1:0/SLOT 10/fault
|
|
||||||
#
|
|
||||||
# On NVMe it's called 'attention' and on a path like this:
|
|
||||||
#
|
|
||||||
# /sys/bus/pci/slot/0/attention
|
|
||||||
#
|
|
||||||
# This function returns the full path to the fault LED file for a given
|
|
||||||
# enclosure/slot directory.
|
|
||||||
#
|
|
||||||
path_to_led()
|
|
||||||
{
|
|
||||||
dir=$1
|
|
||||||
if [ -f "$dir/fault" ] ; then
|
|
||||||
echo "$dir/fault"
|
|
||||||
elif [ -f "$dir/attention" ] ; then
|
|
||||||
echo "$dir/attention"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state_to_val()
|
state_to_val()
|
||||||
{
|
{
|
||||||
state="$1"
|
state="$1"
|
||||||
case "$state" in
|
if [ "$state" = "FAULTED" ] || [ "$state" = "DEGRADED" ] || \
|
||||||
FAULTED|DEGRADED|UNAVAIL)
|
[ "$state" = "UNAVAIL" ] ; then
|
||||||
echo 1
|
echo 1
|
||||||
;;
|
elif [ "$state" = "ONLINE" ] ; then
|
||||||
ONLINE)
|
echo 0
|
||||||
echo 0
|
fi
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# process_pool ([pool])
|
||||||
#
|
#
|
||||||
# Given a nvme name like 'nvme0n1', pass back its slot directory
|
# Iterate through a pool (or pools) and set the VDEV's enclosure slot LEDs to
|
||||||
# like "/sys/bus/pci/slots/0"
|
# the VDEV's state.
|
||||||
#
|
|
||||||
nvme_dev_to_slot()
|
|
||||||
{
|
|
||||||
dev="$1"
|
|
||||||
|
|
||||||
# Get the address "0000:01:00.0"
|
|
||||||
address=$(cat "/sys/class/block/$dev/device/address")
|
|
||||||
|
|
||||||
# For each /sys/bus/pci/slots subdir that is an actual number
|
|
||||||
# (rather than weird directories like "1-3/").
|
|
||||||
# shellcheck disable=SC2010
|
|
||||||
for i in $(ls /sys/bus/pci/slots/ | grep -E "^[0-9]+$") ; do
|
|
||||||
this_address=$(cat "/sys/bus/pci/slots/$i/address")
|
|
||||||
|
|
||||||
# The format of address is a little different between
|
|
||||||
# /sys/class/block/$dev/device/address and
|
|
||||||
# /sys/bus/pci/slots/
|
|
||||||
#
|
|
||||||
# address= "0000:01:00.0"
|
|
||||||
# this_address = "0000:01:00"
|
|
||||||
#
|
|
||||||
if echo "$address" | grep -Eq ^"$this_address" ; then
|
|
||||||
echo "/sys/bus/pci/slots/$i"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# process_pool (pool)
|
|
||||||
#
|
|
||||||
# Iterate through a pool and set the vdevs' enclosure slot LEDs to
|
|
||||||
# those vdevs' state.
|
|
||||||
#
|
#
|
||||||
# Arguments
|
# Arguments
|
||||||
# pool: Pool name.
|
# pool: Optional pool name. If not specified, iterate though all pools.
|
||||||
#
|
#
|
||||||
# Return
|
# Return
|
||||||
# 0 on success, 3 on missing sysfs path
|
# 0 on success, 3 on missing sysfs path
|
||||||
@@ -175,27 +113,19 @@ nvme_dev_to_slot()
|
|||||||
process_pool()
|
process_pool()
|
||||||
{
|
{
|
||||||
pool="$1"
|
pool="$1"
|
||||||
|
|
||||||
# The output will be the vdevs only (from "grep '/dev/'"):
|
|
||||||
#
|
|
||||||
# U45 ONLINE 0 0 0 /dev/sdk 0
|
|
||||||
# U46 ONLINE 0 0 0 /dev/sdm 0
|
|
||||||
# U47 ONLINE 0 0 0 /dev/sdn 0
|
|
||||||
# U50 ONLINE 0 0 0 /dev/sdbn 0
|
|
||||||
#
|
|
||||||
ZPOOL_SCRIPTS_AS_ROOT=1 $ZPOOL status -c upath,fault_led "$pool" | grep '/dev/' | (
|
|
||||||
rc=0
|
rc=0
|
||||||
while read -r vdev state _ _ _ therest; do
|
|
||||||
# Read out current LED value and path
|
|
||||||
# Get dev name (like 'sda')
|
|
||||||
dev=$(basename "$(echo "$therest" | awk '{print $(NF-1)}')")
|
|
||||||
vdev_enc_sysfs_path=$(realpath "/sys/class/block/$dev/device/enclosure_device"*)
|
|
||||||
if [ ! -d "$vdev_enc_sysfs_path" ] ; then
|
|
||||||
# This is not a JBOD disk, but it could be a PCI NVMe drive
|
|
||||||
vdev_enc_sysfs_path=$(nvme_dev_to_slot "$dev")
|
|
||||||
fi
|
|
||||||
|
|
||||||
current_val=$(echo "$therest" | awk '{print $NF}')
|
# Lookup all the current LED values and paths in parallel
|
||||||
|
#shellcheck disable=SC2016
|
||||||
|
cmd='echo led_token=$(cat "$VDEV_ENC_SYSFS_PATH/fault"),"$VDEV_ENC_SYSFS_PATH",'
|
||||||
|
out=$($ZPOOL status -vc "$cmd" "$pool" | grep 'led_token=')
|
||||||
|
|
||||||
|
#shellcheck disable=SC2034
|
||||||
|
echo "$out" | while read -r vdev state read write chksum therest; do
|
||||||
|
# Read out current LED value and path
|
||||||
|
tmp=$(echo "$therest" | sed 's/^.*led_token=//g')
|
||||||
|
vdev_enc_sysfs_path=$(echo "$tmp" | awk -F ',' '{print $2}')
|
||||||
|
current_val=$(echo "$tmp" | awk -F ',' '{print $1}')
|
||||||
|
|
||||||
if [ "$current_val" != "0" ] ; then
|
if [ "$current_val" != "0" ] ; then
|
||||||
current_val=1
|
current_val=1
|
||||||
@@ -206,33 +136,40 @@ process_pool()
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
led_path=$(path_to_led "$vdev_enc_sysfs_path")
|
if [ ! -e "$vdev_enc_sysfs_path/fault" ] ; then
|
||||||
if [ ! -e "$led_path" ] ; then
|
#shellcheck disable=SC2030
|
||||||
rc=3
|
rc=1
|
||||||
zed_log_msg "vdev $vdev '$led_path' doesn't exist"
|
zed_log_msg "vdev $vdev '$file/fault' doesn't exist"
|
||||||
continue
|
continue;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
val=$(state_to_val "$state")
|
val=$(state_to_val "$state")
|
||||||
|
|
||||||
if [ "$current_val" = "$val" ] ; then
|
if [ "$current_val" = "$val" ] ; then
|
||||||
# LED is already set correctly
|
# LED is already set correctly
|
||||||
continue
|
continue;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! check_and_set_led "$led_path" "$val"; then
|
if ! check_and_set_led "$vdev_enc_sysfs_path/fault" "$val"; then
|
||||||
rc=3
|
rc=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done
|
done
|
||||||
exit "$rc"; )
|
|
||||||
|
#shellcheck disable=SC2031
|
||||||
|
if [ "$rc" = "0" ] ; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
# We didn't see a sysfs entry that we wanted to set
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ -n "$ZEVENT_VDEV_ENC_SYSFS_PATH" ] && [ -n "$ZEVENT_VDEV_STATE_STR" ] ; then
|
if [ -n "$ZEVENT_VDEV_ENC_SYSFS_PATH" ] && [ -n "$ZEVENT_VDEV_STATE_STR" ] ; then
|
||||||
# Got a statechange for an individual vdev
|
# Got a statechange for an individual VDEV
|
||||||
val=$(state_to_val "$ZEVENT_VDEV_STATE_STR")
|
val=$(state_to_val "$ZEVENT_VDEV_STATE_STR")
|
||||||
vdev=$(basename "$ZEVENT_VDEV_PATH")
|
vdev=$(basename "$ZEVENT_VDEV_PATH")
|
||||||
ledpath=$(path_to_led "$ZEVENT_VDEV_ENC_SYSFS_PATH")
|
check_and_set_led "$ZEVENT_VDEV_ENC_SYSFS_PATH/fault" "$val"
|
||||||
check_and_set_led "$ledpath" "$val"
|
|
||||||
else
|
else
|
||||||
# Process the entire pool
|
# Process the entire pool
|
||||||
poolname=$(zed_guid_to_pool "$ZEVENT_POOL_GUID")
|
poolname=$(zed_guid_to_pool "$ZEVENT_POOL_GUID")
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# Send notification in response to a fault induced statechange
|
# Send notification in response to a fault induced statechange
|
||||||
#
|
#
|
||||||
# ZEVENT_SUBCLASS: 'statechange'
|
# ZEVENT_SUBCLASS: 'statechange'
|
||||||
# ZEVENT_VDEV_STATE_STR: 'DEGRADED', 'FAULTED', 'REMOVED', or 'UNAVAIL'
|
# ZEVENT_VDEV_STATE_STR: 'DEGRADED', 'FAULTED' or 'REMOVED'
|
||||||
#
|
#
|
||||||
# Exit codes:
|
# Exit codes:
|
||||||
# 0: notification sent
|
# 0: notification sent
|
||||||
@@ -31,14 +31,13 @@
|
|||||||
|
|
||||||
if [ "${ZEVENT_VDEV_STATE_STR}" != "FAULTED" ] \
|
if [ "${ZEVENT_VDEV_STATE_STR}" != "FAULTED" ] \
|
||||||
&& [ "${ZEVENT_VDEV_STATE_STR}" != "DEGRADED" ] \
|
&& [ "${ZEVENT_VDEV_STATE_STR}" != "DEGRADED" ] \
|
||||||
&& [ "${ZEVENT_VDEV_STATE_STR}" != "REMOVED" ] \
|
&& [ "${ZEVENT_VDEV_STATE_STR}" != "REMOVED" ]; then
|
||||||
&& [ "${ZEVENT_VDEV_STATE_STR}" != "UNAVAIL" ]; then
|
|
||||||
exit 3
|
exit 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
umask 077
|
umask 077
|
||||||
note_subject="ZFS device fault for pool ${ZEVENT_POOL_GUID} on $(hostname)"
|
note_subject="ZFS device fault for pool ${ZEVENT_POOL_GUID} on $(hostname)"
|
||||||
note_pathname="$(mktemp)"
|
note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
|
||||||
{
|
{
|
||||||
if [ "${ZEVENT_VDEV_STATE_STR}" = "FAULTED" ] ; then
|
if [ "${ZEVENT_VDEV_STATE_STR}" = "FAULTED" ] ; then
|
||||||
echo "The number of I/O errors associated with a ZFS device exceeded"
|
echo "The number of I/O errors associated with a ZFS device exceeded"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ zed_check_cmd "${ZPOOL}" || exit 9
|
|||||||
|
|
||||||
umask 077
|
umask 077
|
||||||
note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)"
|
note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)"
|
||||||
note_pathname="$(mktemp)"
|
note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
|
||||||
{
|
{
|
||||||
echo "ZFS has finished a trim:"
|
echo "ZFS has finished a trim:"
|
||||||
echo
|
echo
|
||||||
|
|||||||
+20
-109
@@ -77,7 +77,7 @@ zed_log_msg()
|
|||||||
zed_log_err()
|
zed_log_err()
|
||||||
{
|
{
|
||||||
logger -p "${ZED_SYSLOG_PRIORITY}" -t "${ZED_SYSLOG_TAG}" -- "error:" \
|
logger -p "${ZED_SYSLOG_PRIORITY}" -t "${ZED_SYSLOG_TAG}" -- "error:" \
|
||||||
"${0##*/}:""${ZEVENT_EID:+" eid=${ZEVENT_EID}:"}" "$@"
|
"$(basename -- "$0"):""${ZEVENT_EID:+" eid=${ZEVENT_EID}:"}" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -126,8 +126,10 @@ zed_lock()
|
|||||||
|
|
||||||
# Obtain a lock on the file bound to the given file descriptor.
|
# Obtain a lock on the file bound to the given file descriptor.
|
||||||
#
|
#
|
||||||
eval "exec ${fd}>> '${lockfile}'"
|
eval "exec ${fd}> '${lockfile}'"
|
||||||
if ! err="$(flock --exclusive "${fd}" 2>&1)"; then
|
err="$(flock --exclusive "${fd}" 2>&1)"
|
||||||
|
# shellcheck disable=SC2181
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
zed_log_err "failed to lock \"${lockfile}\": ${err}"
|
zed_log_err "failed to lock \"${lockfile}\": ${err}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -163,7 +165,9 @@ zed_unlock()
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Release the lock and close the file descriptor.
|
# Release the lock and close the file descriptor.
|
||||||
if ! err="$(flock --unlock "${fd}" 2>&1)"; then
|
err="$(flock --unlock "${fd}" 2>&1)"
|
||||||
|
# shellcheck disable=SC2181
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
zed_log_err "failed to unlock \"${lockfile}\": ${err}"
|
zed_log_err "failed to unlock \"${lockfile}\": ${err}"
|
||||||
fi
|
fi
|
||||||
eval "exec ${fd}>&-"
|
eval "exec ${fd}>&-"
|
||||||
@@ -202,10 +206,6 @@ zed_notify()
|
|||||||
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
|
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
|
||||||
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
|
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
|
||||||
|
|
||||||
zed_notify_pushover "${subject}" "${pathname}"; rv=$?
|
|
||||||
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
|
|
||||||
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
|
|
||||||
|
|
||||||
[ "${num_success}" -gt 0 ] && return 0
|
[ "${num_success}" -gt 0 ] && return 0
|
||||||
[ "${num_failure}" -gt 0 ] && return 1
|
[ "${num_failure}" -gt 0 ] && return 1
|
||||||
return 2
|
return 2
|
||||||
@@ -224,8 +224,6 @@ zed_notify()
|
|||||||
# ZED_EMAIL_OPTS. This undergoes the following keyword substitutions:
|
# ZED_EMAIL_OPTS. This undergoes the following keyword substitutions:
|
||||||
# - @ADDRESS@ is replaced with the space-delimited recipient email address(es)
|
# - @ADDRESS@ is replaced with the space-delimited recipient email address(es)
|
||||||
# - @SUBJECT@ is replaced with the notification subject
|
# - @SUBJECT@ is replaced with the notification subject
|
||||||
# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification
|
|
||||||
#
|
|
||||||
#
|
#
|
||||||
# Arguments
|
# Arguments
|
||||||
# subject: notification subject
|
# subject: notification subject
|
||||||
@@ -243,7 +241,7 @@ zed_notify()
|
|||||||
#
|
#
|
||||||
zed_notify_email()
|
zed_notify_email()
|
||||||
{
|
{
|
||||||
local subject="${1:-"ZED notification"}"
|
local subject="$1"
|
||||||
local pathname="${2:-"/dev/null"}"
|
local pathname="${2:-"/dev/null"}"
|
||||||
|
|
||||||
: "${ZED_EMAIL_PROG:="mail"}"
|
: "${ZED_EMAIL_PROG:="mail"}"
|
||||||
@@ -260,30 +258,19 @@ zed_notify_email()
|
|||||||
[ -n "${subject}" ] || return 1
|
[ -n "${subject}" ] || return 1
|
||||||
if [ ! -r "${pathname}" ]; then
|
if [ ! -r "${pathname}" ]; then
|
||||||
zed_log_err \
|
zed_log_err \
|
||||||
"${ZED_EMAIL_PROG##*/} cannot read \"${pathname}\""
|
"$(basename "${ZED_EMAIL_PROG}") cannot read \"${pathname}\""
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# construct cmdline options
|
ZED_EMAIL_OPTS="$(echo "${ZED_EMAIL_OPTS}" \
|
||||||
ZED_EMAIL_OPTS_PARSED="$(echo "${ZED_EMAIL_OPTS}" \
|
|
||||||
| sed -e "s/@ADDRESS@/${ZED_EMAIL_ADDR}/g" \
|
| sed -e "s/@ADDRESS@/${ZED_EMAIL_ADDR}/g" \
|
||||||
-e "s/@SUBJECT@/${subject}/g")"
|
-e "s/@SUBJECT@/${subject}/g")"
|
||||||
|
|
||||||
# pipe message to email prog
|
# shellcheck disable=SC2086
|
||||||
# shellcheck disable=SC2086,SC2248
|
eval "${ZED_EMAIL_PROG}" ${ZED_EMAIL_OPTS} < "${pathname}" >/dev/null 2>&1
|
||||||
{
|
|
||||||
# no subject passed as option?
|
|
||||||
if [ "${ZED_EMAIL_OPTS%@SUBJECT@*}" = "${ZED_EMAIL_OPTS}" ] ; then
|
|
||||||
# inject subject header
|
|
||||||
printf "Subject: %s\n" "${subject}"
|
|
||||||
fi
|
|
||||||
# output message
|
|
||||||
cat "${pathname}"
|
|
||||||
} |
|
|
||||||
eval ${ZED_EMAIL_PROG} ${ZED_EMAIL_OPTS_PARSED} >/dev/null 2>&1
|
|
||||||
rv=$?
|
rv=$?
|
||||||
if [ "${rv}" -ne 0 ]; then
|
if [ "${rv}" -ne 0 ]; then
|
||||||
zed_log_err "${ZED_EMAIL_PROG##*/} exit=${rv}"
|
zed_log_err "$(basename "${ZED_EMAIL_PROG}") exit=${rv}"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
@@ -380,7 +367,7 @@ zed_notify_pushbullet()
|
|||||||
#
|
#
|
||||||
# Notification via Slack Webhook <https://api.slack.com/incoming-webhooks>.
|
# Notification via Slack Webhook <https://api.slack.com/incoming-webhooks>.
|
||||||
# The Webhook URL (ZED_SLACK_WEBHOOK_URL) identifies this client to the
|
# The Webhook URL (ZED_SLACK_WEBHOOK_URL) identifies this client to the
|
||||||
# Slack channel.
|
# Slack channel.
|
||||||
#
|
#
|
||||||
# Requires awk, curl, and sed executables to be installed in the standard PATH.
|
# Requires awk, curl, and sed executables to be installed in the standard PATH.
|
||||||
#
|
#
|
||||||
@@ -430,7 +417,7 @@ zed_notify_slack_webhook()
|
|||||||
|
|
||||||
# Construct the JSON message for posting.
|
# Construct the JSON message for posting.
|
||||||
#
|
#
|
||||||
msg_json="$(printf '{"text": "*%s*\\n%s"}' "${subject}" "${msg_body}" )"
|
msg_json="$(printf '{"text": "*%s*\n%s"}' "${subject}" "${msg_body}" )"
|
||||||
|
|
||||||
# Send the POST request and check for errors.
|
# Send the POST request and check for errors.
|
||||||
#
|
#
|
||||||
@@ -450,84 +437,6 @@ zed_notify_slack_webhook()
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# zed_notify_pushover (subject, pathname)
|
|
||||||
#
|
|
||||||
# Send a notification via Pushover <https://pushover.net/>.
|
|
||||||
# The access token (ZED_PUSHOVER_TOKEN) identifies this client to the
|
|
||||||
# Pushover server. The user token (ZED_PUSHOVER_USER) defines the user or
|
|
||||||
# group to which the notification will be sent.
|
|
||||||
#
|
|
||||||
# Requires curl and sed executables to be installed in the standard PATH.
|
|
||||||
#
|
|
||||||
# References
|
|
||||||
# https://pushover.net/api
|
|
||||||
#
|
|
||||||
# Arguments
|
|
||||||
# subject: notification subject
|
|
||||||
# pathname: pathname containing the notification message (OPTIONAL)
|
|
||||||
#
|
|
||||||
# Globals
|
|
||||||
# ZED_PUSHOVER_TOKEN
|
|
||||||
# ZED_PUSHOVER_USER
|
|
||||||
#
|
|
||||||
# Return
|
|
||||||
# 0: notification sent
|
|
||||||
# 1: notification failed
|
|
||||||
# 2: not configured
|
|
||||||
#
|
|
||||||
zed_notify_pushover()
|
|
||||||
{
|
|
||||||
local subject="$1"
|
|
||||||
local pathname="${2:-"/dev/null"}"
|
|
||||||
local msg_body
|
|
||||||
local msg_out
|
|
||||||
local msg_err
|
|
||||||
local url="https://api.pushover.net/1/messages.json"
|
|
||||||
|
|
||||||
[ -n "${ZED_PUSHOVER_TOKEN}" ] && [ -n "${ZED_PUSHOVER_USER}" ] || return 2
|
|
||||||
|
|
||||||
if [ ! -r "${pathname}" ]; then
|
|
||||||
zed_log_err "pushover cannot read \"${pathname}\""
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
zed_check_cmd "curl" "sed" || return 1
|
|
||||||
|
|
||||||
# Read the message body in.
|
|
||||||
#
|
|
||||||
msg_body="$(cat "${pathname}")"
|
|
||||||
|
|
||||||
if [ -z "${msg_body}" ]
|
|
||||||
then
|
|
||||||
msg_body=$subject
|
|
||||||
subject=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Send the POST request and check for errors.
|
|
||||||
#
|
|
||||||
msg_out="$( \
|
|
||||||
curl \
|
|
||||||
--form-string "token=${ZED_PUSHOVER_TOKEN}" \
|
|
||||||
--form-string "user=${ZED_PUSHOVER_USER}" \
|
|
||||||
--form-string "message=${msg_body}" \
|
|
||||||
--form-string "title=${subject}" \
|
|
||||||
"${url}" \
|
|
||||||
2>/dev/null \
|
|
||||||
)"; rv=$?
|
|
||||||
if [ "${rv}" -ne 0 ]; then
|
|
||||||
zed_log_err "curl exit=${rv}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
msg_err="$(echo "${msg_out}" \
|
|
||||||
| sed -n -e 's/.*"errors" *:.*\[\(.*\)\].*/\1/p')"
|
|
||||||
if [ -n "${msg_err}" ]; then
|
|
||||||
zed_log_err "pushover \"${msg_err}"\"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# zed_rate_limit (tag, [interval])
|
# zed_rate_limit (tag, [interval])
|
||||||
#
|
#
|
||||||
# Check whether an event of a given type [tag] has already occurred within the
|
# Check whether an event of a given type [tag] has already occurred within the
|
||||||
@@ -602,8 +511,10 @@ zed_guid_to_pool()
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
guid="$(printf "%u" "$1")"
|
guid=$(printf "%llu" "$1")
|
||||||
$ZPOOL get -H -ovalue,name guid | awk '$1 == '"$guid"' {print $2; exit}'
|
if [ -n "$guid" ] ; then
|
||||||
|
$ZPOOL get -H -ovalue,name guid | awk '$1=='"$guid"' {print $2}'
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# zed_exit_if_ignoring_this_event
|
# zed_exit_if_ignoring_this_event
|
||||||
|
|||||||
+4
-22
@@ -13,9 +13,9 @@
|
|||||||
# Email address of the zpool administrator for receipt of notifications;
|
# Email address of the zpool administrator for receipt of notifications;
|
||||||
# multiple addresses can be specified if they are delimited by whitespace.
|
# multiple addresses can be specified if they are delimited by whitespace.
|
||||||
# Email will only be sent if ZED_EMAIL_ADDR is defined.
|
# Email will only be sent if ZED_EMAIL_ADDR is defined.
|
||||||
# Enabled by default; comment to disable.
|
# Disabled by default; uncomment to enable.
|
||||||
#
|
#
|
||||||
ZED_EMAIL_ADDR="root"
|
#ZED_EMAIL_ADDR="root"
|
||||||
|
|
||||||
##
|
##
|
||||||
# Name or path of executable responsible for sending notifications via email;
|
# Name or path of executable responsible for sending notifications via email;
|
||||||
@@ -30,7 +30,6 @@ ZED_EMAIL_ADDR="root"
|
|||||||
# The string @SUBJECT@ will be replaced with the notification subject;
|
# The string @SUBJECT@ will be replaced with the notification subject;
|
||||||
# this should be protected with quotes to prevent word-splitting.
|
# this should be protected with quotes to prevent word-splitting.
|
||||||
# Email will only be sent if ZED_EMAIL_ADDR is defined.
|
# Email will only be sent if ZED_EMAIL_ADDR is defined.
|
||||||
# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification
|
|
||||||
#
|
#
|
||||||
#ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"
|
#ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"
|
||||||
|
|
||||||
@@ -83,23 +82,6 @@ ZED_EMAIL_ADDR="root"
|
|||||||
#
|
#
|
||||||
#ZED_SLACK_WEBHOOK_URL=""
|
#ZED_SLACK_WEBHOOK_URL=""
|
||||||
|
|
||||||
##
|
|
||||||
# Pushover token.
|
|
||||||
# This defines the application from which the notification will be sent.
|
|
||||||
# <https://pushover.net/api#registration>
|
|
||||||
# Disabled by default; uncomment to enable.
|
|
||||||
# ZED_PUSHOVER_USER, below, must also be configured.
|
|
||||||
#
|
|
||||||
#ZED_PUSHOVER_TOKEN=""
|
|
||||||
|
|
||||||
##
|
|
||||||
# Pushover user key.
|
|
||||||
# This defines which user or group will receive Pushover notifications.
|
|
||||||
# <https://pushover.net/api#identifiers>
|
|
||||||
# Disabled by default; uncomment to enable.
|
|
||||||
# ZED_PUSHOVER_TOKEN, above, must also be configured.
|
|
||||||
#ZED_PUSHOVER_USER=""
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Default directory for zed state files.
|
# Default directory for zed state files.
|
||||||
#
|
#
|
||||||
@@ -107,8 +89,8 @@ ZED_EMAIL_ADDR="root"
|
|||||||
|
|
||||||
##
|
##
|
||||||
# Turn on/off enclosure LEDs when drives get DEGRADED/FAULTED. This works for
|
# Turn on/off enclosure LEDs when drives get DEGRADED/FAULTED. This works for
|
||||||
# device mapper and multipath devices as well. This works with JBOD enclosures
|
# device mapper and multipath devices as well. Your enclosure must be
|
||||||
# and NVMe PCI drives (assuming they're supported by Linux in sysfs).
|
# supported by the Linux SES driver for this to work.
|
||||||
#
|
#
|
||||||
ZED_USE_ENCLOSURE_LEDS=1
|
ZED_USE_ENCLOSURE_LEDS=1
|
||||||
|
|
||||||
|
|||||||
+16
-1
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
@@ -15,6 +15,11 @@
|
|||||||
#ifndef ZED_H
|
#ifndef ZED_H
|
||||||
#define ZED_H
|
#define ZED_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Absolute path for the default zed configuration file.
|
||||||
|
*/
|
||||||
|
#define ZED_CONF_FILE SYSCONFDIR "/zfs/zed.conf"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Absolute path for the default zed pid file.
|
* Absolute path for the default zed pid file.
|
||||||
*/
|
*/
|
||||||
@@ -30,6 +35,16 @@
|
|||||||
*/
|
*/
|
||||||
#define ZED_ZEDLET_DIR SYSCONFDIR "/zfs/zed.d"
|
#define ZED_ZEDLET_DIR SYSCONFDIR "/zfs/zed.d"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserved for future use.
|
||||||
|
*/
|
||||||
|
#define ZED_MAX_EVENTS 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserved for future use.
|
||||||
|
*/
|
||||||
|
#define ZED_MIN_EVENTS 0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* String prefix for ZED variables passed via environment variables.
|
* String prefix for ZED variables passed via environment variables.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+124
-95
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -33,26 +32,43 @@
|
|||||||
#include "zed_strings.h"
|
#include "zed_strings.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise the configuration with default values.
|
* Return a new configuration with default values.
|
||||||
*/
|
*/
|
||||||
void
|
struct zed_conf *
|
||||||
zed_conf_init(struct zed_conf *zcp)
|
zed_conf_create(void)
|
||||||
{
|
{
|
||||||
memset(zcp, 0, sizeof (*zcp));
|
struct zed_conf *zcp;
|
||||||
|
|
||||||
/* zcp->zfs_hdl opened in zed_event_init() */
|
zcp = calloc(1, sizeof (*zcp));
|
||||||
/* zcp->zedlets created in zed_conf_scan_dir() */
|
if (!zcp)
|
||||||
|
goto nomem;
|
||||||
|
|
||||||
zcp->pid_fd = -1; /* opened in zed_conf_write_pid() */
|
zcp->syslog_facility = LOG_DAEMON;
|
||||||
zcp->state_fd = -1; /* opened in zed_conf_open_state() */
|
zcp->min_events = ZED_MIN_EVENTS;
|
||||||
zcp->zevent_fd = -1; /* opened in zed_event_init() */
|
zcp->max_events = ZED_MAX_EVENTS;
|
||||||
|
zcp->pid_fd = -1;
|
||||||
|
zcp->zedlets = NULL; /* created via zed_conf_scan_dir() */
|
||||||
|
zcp->state_fd = -1; /* opened via zed_conf_open_state() */
|
||||||
|
zcp->zfs_hdl = NULL; /* opened via zed_event_init() */
|
||||||
|
zcp->zevent_fd = -1; /* opened via zed_event_init() */
|
||||||
|
|
||||||
zcp->max_jobs = 16;
|
if (!(zcp->conf_file = strdup(ZED_CONF_FILE)))
|
||||||
|
goto nomem;
|
||||||
|
|
||||||
if (!(zcp->pid_file = strdup(ZED_PID_FILE)) ||
|
if (!(zcp->pid_file = strdup(ZED_PID_FILE)))
|
||||||
!(zcp->zedlet_dir = strdup(ZED_ZEDLET_DIR)) ||
|
goto nomem;
|
||||||
!(zcp->state_file = strdup(ZED_STATE_FILE)))
|
|
||||||
zed_log_die("Failed to create conf: %s", strerror(errno));
|
if (!(zcp->zedlet_dir = strdup(ZED_ZEDLET_DIR)))
|
||||||
|
goto nomem;
|
||||||
|
|
||||||
|
if (!(zcp->state_file = strdup(ZED_STATE_FILE)))
|
||||||
|
goto nomem;
|
||||||
|
|
||||||
|
return (zcp);
|
||||||
|
|
||||||
|
nomem:
|
||||||
|
zed_log_die("Failed to create conf: %s", strerror(errno));
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -63,6 +79,9 @@ zed_conf_init(struct zed_conf *zcp)
|
|||||||
void
|
void
|
||||||
zed_conf_destroy(struct zed_conf *zcp)
|
zed_conf_destroy(struct zed_conf *zcp)
|
||||||
{
|
{
|
||||||
|
if (!zcp)
|
||||||
|
return;
|
||||||
|
|
||||||
if (zcp->state_fd >= 0) {
|
if (zcp->state_fd >= 0) {
|
||||||
if (close(zcp->state_fd) < 0)
|
if (close(zcp->state_fd) < 0)
|
||||||
zed_log_msg(LOG_WARNING,
|
zed_log_msg(LOG_WARNING,
|
||||||
@@ -83,6 +102,10 @@ zed_conf_destroy(struct zed_conf *zcp)
|
|||||||
zcp->pid_file, strerror(errno));
|
zcp->pid_file, strerror(errno));
|
||||||
zcp->pid_fd = -1;
|
zcp->pid_fd = -1;
|
||||||
}
|
}
|
||||||
|
if (zcp->conf_file) {
|
||||||
|
free(zcp->conf_file);
|
||||||
|
zcp->conf_file = NULL;
|
||||||
|
}
|
||||||
if (zcp->pid_file) {
|
if (zcp->pid_file) {
|
||||||
free(zcp->pid_file);
|
free(zcp->pid_file);
|
||||||
zcp->pid_file = NULL;
|
zcp->pid_file = NULL;
|
||||||
@@ -99,6 +122,7 @@ zed_conf_destroy(struct zed_conf *zcp)
|
|||||||
zed_strings_destroy(zcp->zedlets);
|
zed_strings_destroy(zcp->zedlets);
|
||||||
zcp->zedlets = NULL;
|
zcp->zedlets = NULL;
|
||||||
}
|
}
|
||||||
|
free(zcp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -108,52 +132,46 @@ zed_conf_destroy(struct zed_conf *zcp)
|
|||||||
* otherwise, output to stderr and exit with a failure status.
|
* otherwise, output to stderr and exit with a failure status.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
_zed_conf_display_help(const char *prog, boolean_t got_err)
|
_zed_conf_display_help(const char *prog, int got_err)
|
||||||
{
|
{
|
||||||
struct opt { const char *o, *d, *v; };
|
|
||||||
|
|
||||||
FILE *fp = got_err ? stderr : stdout;
|
FILE *fp = got_err ? stderr : stdout;
|
||||||
|
int w1 = 4; /* width of leading whitespace */
|
||||||
struct opt *oo;
|
int w2 = 8; /* width of L-justified option field */
|
||||||
struct opt iopts[] = {
|
|
||||||
{ .o = "-h", .d = "Display help" },
|
|
||||||
{ .o = "-L", .d = "Display license information" },
|
|
||||||
{ .o = "-V", .d = "Display version information" },
|
|
||||||
{},
|
|
||||||
};
|
|
||||||
struct opt nopts[] = {
|
|
||||||
{ .o = "-v", .d = "Be verbose" },
|
|
||||||
{ .o = "-f", .d = "Force daemon to run" },
|
|
||||||
{ .o = "-F", .d = "Run daemon in the foreground" },
|
|
||||||
{ .o = "-I",
|
|
||||||
.d = "Idle daemon until kernel module is (re)loaded" },
|
|
||||||
{ .o = "-M", .d = "Lock all pages in memory" },
|
|
||||||
{ .o = "-P", .d = "$PATH for ZED to use (only used by ZTS)" },
|
|
||||||
{ .o = "-Z", .d = "Zero state file" },
|
|
||||||
{},
|
|
||||||
};
|
|
||||||
struct opt vopts[] = {
|
|
||||||
{ .o = "-d DIR", .d = "Read enabled ZEDLETs from DIR.",
|
|
||||||
.v = ZED_ZEDLET_DIR },
|
|
||||||
{ .o = "-p FILE", .d = "Write daemon's PID to FILE.",
|
|
||||||
.v = ZED_PID_FILE },
|
|
||||||
{ .o = "-s FILE", .d = "Write daemon's state to FILE.",
|
|
||||||
.v = ZED_STATE_FILE },
|
|
||||||
{ .o = "-j JOBS", .d = "Start at most JOBS at once.",
|
|
||||||
.v = "16" },
|
|
||||||
{},
|
|
||||||
};
|
|
||||||
|
|
||||||
fprintf(fp, "Usage: %s [OPTION]...\n", (prog ? prog : "zed"));
|
fprintf(fp, "Usage: %s [OPTION]...\n", (prog ? prog : "zed"));
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
for (oo = iopts; oo->o; ++oo)
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-h",
|
||||||
fprintf(fp, " %*s %s\n", -8, oo->o, oo->d);
|
"Display help.");
|
||||||
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-L",
|
||||||
|
"Display license information.");
|
||||||
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-V",
|
||||||
|
"Display version information.");
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
for (oo = nopts; oo->o; ++oo)
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-v",
|
||||||
fprintf(fp, " %*s %s\n", -8, oo->o, oo->d);
|
"Be verbose.");
|
||||||
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-f",
|
||||||
|
"Force daemon to run.");
|
||||||
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-F",
|
||||||
|
"Run daemon in the foreground.");
|
||||||
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-I",
|
||||||
|
"Idle daemon until kernel module is (re)loaded.");
|
||||||
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-M",
|
||||||
|
"Lock all pages in memory.");
|
||||||
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-P",
|
||||||
|
"$PATH for ZED to use (only used by ZTS).");
|
||||||
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-Z",
|
||||||
|
"Zero state file.");
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
for (oo = vopts; oo->o; ++oo)
|
#if 0
|
||||||
fprintf(fp, " %*s %s [%s]\n", -8, oo->o, oo->d, oo->v);
|
fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-c FILE",
|
||||||
|
"Read configuration from FILE.", ZED_CONF_FILE);
|
||||||
|
#endif
|
||||||
|
fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-d DIR",
|
||||||
|
"Read enabled ZEDLETs from DIR.", ZED_ZEDLET_DIR);
|
||||||
|
fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-p FILE",
|
||||||
|
"Write daemon's PID to FILE.", ZED_PID_FILE);
|
||||||
|
fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-s FILE",
|
||||||
|
"Write daemon's state to FILE.", ZED_STATE_FILE);
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
|
|
||||||
exit(got_err ? EXIT_FAILURE : EXIT_SUCCESS);
|
exit(got_err ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
@@ -165,14 +183,20 @@ _zed_conf_display_help(const char *prog, boolean_t got_err)
|
|||||||
static void
|
static void
|
||||||
_zed_conf_display_license(void)
|
_zed_conf_display_license(void)
|
||||||
{
|
{
|
||||||
printf(
|
const char **pp;
|
||||||
"The ZFS Event Daemon (ZED) is distributed under the terms of the\n"
|
const char *text[] = {
|
||||||
" Common Development and Distribution License (CDDL-1.0)\n"
|
"The ZFS Event Daemon (ZED) is distributed under the terms of the",
|
||||||
" <http://opensource.org/licenses/CDDL-1.0>.\n"
|
" Common Development and Distribution License (CDDL-1.0)",
|
||||||
"\n"
|
" <http://opensource.org/licenses/CDDL-1.0>.",
|
||||||
|
"",
|
||||||
"Developed at Lawrence Livermore National Laboratory"
|
"Developed at Lawrence Livermore National Laboratory"
|
||||||
" (LLNL-CODE-403049).\n"
|
" (LLNL-CODE-403049).",
|
||||||
"\n");
|
"",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
for (pp = text; *pp; pp++)
|
||||||
|
printf("%s\n", *pp);
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
@@ -207,19 +231,16 @@ _zed_conf_parse_path(char **resultp, const char *path)
|
|||||||
|
|
||||||
if (path[0] == '/') {
|
if (path[0] == '/') {
|
||||||
*resultp = strdup(path);
|
*resultp = strdup(path);
|
||||||
|
} else if (!getcwd(buf, sizeof (buf))) {
|
||||||
|
zed_log_die("Failed to get current working dir: %s",
|
||||||
|
strerror(errno));
|
||||||
|
} else if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf)) {
|
||||||
|
zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG));
|
||||||
|
} else if (strlcat(buf, path, sizeof (buf)) >= sizeof (buf)) {
|
||||||
|
zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG));
|
||||||
} else {
|
} else {
|
||||||
if (!getcwd(buf, sizeof (buf)))
|
|
||||||
zed_log_die("Failed to get current working dir: %s",
|
|
||||||
strerror(errno));
|
|
||||||
|
|
||||||
if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf) ||
|
|
||||||
strlcat(buf, path, sizeof (buf)) >= sizeof (buf))
|
|
||||||
zed_log_die("Failed to copy path: %s",
|
|
||||||
strerror(ENAMETOOLONG));
|
|
||||||
|
|
||||||
*resultp = strdup(buf);
|
*resultp = strdup(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*resultp)
|
if (!*resultp)
|
||||||
zed_log_die("Failed to copy path: %s", strerror(ENOMEM));
|
zed_log_die("Failed to copy path: %s", strerror(ENOMEM));
|
||||||
}
|
}
|
||||||
@@ -230,9 +251,8 @@ _zed_conf_parse_path(char **resultp, const char *path)
|
|||||||
void
|
void
|
||||||
zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
||||||
{
|
{
|
||||||
const char * const opts = ":hLVd:p:P:s:vfFMZIj:";
|
const char * const opts = ":hLVc:d:p:P:s:vfFMZI";
|
||||||
int opt;
|
int opt;
|
||||||
unsigned long raw;
|
|
||||||
|
|
||||||
if (!zcp || !argv || !argv[0])
|
if (!zcp || !argv || !argv[0])
|
||||||
zed_log_die("Failed to parse options: Internal error");
|
zed_log_die("Failed to parse options: Internal error");
|
||||||
@@ -242,7 +262,7 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
|||||||
while ((opt = getopt(argc, argv, opts)) != -1) {
|
while ((opt = getopt(argc, argv, opts)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
_zed_conf_display_help(argv[0], B_FALSE);
|
_zed_conf_display_help(argv[0], EXIT_SUCCESS);
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
_zed_conf_display_license();
|
_zed_conf_display_license();
|
||||||
@@ -250,6 +270,9 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
|||||||
case 'V':
|
case 'V':
|
||||||
_zed_conf_display_version();
|
_zed_conf_display_version();
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
_zed_conf_parse_path(&zcp->conf_file, optarg);
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
_zed_conf_parse_path(&zcp->zedlet_dir, optarg);
|
_zed_conf_parse_path(&zcp->zedlet_dir, optarg);
|
||||||
break;
|
break;
|
||||||
@@ -280,30 +303,31 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
|||||||
case 'Z':
|
case 'Z':
|
||||||
zcp->do_zero = 1;
|
zcp->do_zero = 1;
|
||||||
break;
|
break;
|
||||||
case 'j':
|
|
||||||
errno = 0;
|
|
||||||
raw = strtoul(optarg, NULL, 0);
|
|
||||||
if (errno == ERANGE || raw > INT16_MAX) {
|
|
||||||
zed_log_die("%lu is too many jobs", raw);
|
|
||||||
} if (raw == 0) {
|
|
||||||
zed_log_die("0 jobs makes no sense");
|
|
||||||
} else {
|
|
||||||
zcp->max_jobs = raw;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
if (optopt == '?')
|
if (optopt == '?')
|
||||||
_zed_conf_display_help(argv[0], B_FALSE);
|
_zed_conf_display_help(argv[0], EXIT_SUCCESS);
|
||||||
|
|
||||||
fprintf(stderr, "%s: Invalid option '-%c'\n\n",
|
fprintf(stderr, "%s: %s '-%c'\n\n", argv[0],
|
||||||
argv[0], optopt);
|
"Invalid option", optopt);
|
||||||
_zed_conf_display_help(argv[0], B_TRUE);
|
_zed_conf_display_help(argv[0], EXIT_FAILURE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the configuration file into the configuration [zcp].
|
||||||
|
*
|
||||||
|
* FIXME: Not yet implemented.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
zed_conf_parse_file(struct zed_conf *zcp)
|
||||||
|
{
|
||||||
|
if (!zcp)
|
||||||
|
zed_log_die("Failed to parse config: %s", strerror(EINVAL));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan the [zcp] zedlet_dir for files to exec based on the event class.
|
* Scan the [zcp] zedlet_dir for files to exec based on the event class.
|
||||||
* Files must be executable by user, but not writable by group or other.
|
* Files must be executable by user, but not writable by group or other.
|
||||||
@@ -311,6 +335,8 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
|||||||
*
|
*
|
||||||
* Return 0 on success with an updated set of zedlets,
|
* Return 0 on success with an updated set of zedlets,
|
||||||
* or -1 on error with errno set.
|
* or -1 on error with errno set.
|
||||||
|
*
|
||||||
|
* FIXME: Check if zedlet_dir and all parent dirs are secure.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
zed_conf_scan_dir(struct zed_conf *zcp)
|
zed_conf_scan_dir(struct zed_conf *zcp)
|
||||||
@@ -426,6 +452,8 @@ zed_conf_scan_dir(struct zed_conf *zcp)
|
|||||||
int
|
int
|
||||||
zed_conf_write_pid(struct zed_conf *zcp)
|
zed_conf_write_pid(struct zed_conf *zcp)
|
||||||
{
|
{
|
||||||
|
const mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
||||||
|
const mode_t filemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
int n;
|
int n;
|
||||||
char *p;
|
char *p;
|
||||||
@@ -453,7 +481,7 @@ zed_conf_write_pid(struct zed_conf *zcp)
|
|||||||
if (p)
|
if (p)
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
if ((mkdirp(buf, 0755) < 0) && (errno != EEXIST)) {
|
if ((mkdirp(buf, dirmode) < 0) && (errno != EEXIST)) {
|
||||||
zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s",
|
zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s",
|
||||||
buf, strerror(errno));
|
buf, strerror(errno));
|
||||||
goto err;
|
goto err;
|
||||||
@@ -463,7 +491,7 @@ zed_conf_write_pid(struct zed_conf *zcp)
|
|||||||
*/
|
*/
|
||||||
mask = umask(0);
|
mask = umask(0);
|
||||||
umask(mask | 022);
|
umask(mask | 022);
|
||||||
zcp->pid_fd = open(zcp->pid_file, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
|
zcp->pid_fd = open(zcp->pid_file, (O_RDWR | O_CREAT), filemode);
|
||||||
umask(mask);
|
umask(mask);
|
||||||
if (zcp->pid_fd < 0) {
|
if (zcp->pid_fd < 0) {
|
||||||
zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s",
|
zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s",
|
||||||
@@ -500,7 +528,7 @@ zed_conf_write_pid(struct zed_conf *zcp)
|
|||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
|
zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
|
||||||
zcp->pid_file, strerror(errno));
|
zcp->pid_file, strerror(errno));
|
||||||
} else if (write(zcp->pid_fd, buf, n) != n) {
|
} else if (zed_file_write_n(zcp->pid_fd, buf, n) != n) {
|
||||||
zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
|
zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
|
||||||
zcp->pid_file, strerror(errno));
|
zcp->pid_file, strerror(errno));
|
||||||
} else if (fdatasync(zcp->pid_fd) < 0) {
|
} else if (fdatasync(zcp->pid_fd) < 0) {
|
||||||
@@ -528,6 +556,7 @@ int
|
|||||||
zed_conf_open_state(struct zed_conf *zcp)
|
zed_conf_open_state(struct zed_conf *zcp)
|
||||||
{
|
{
|
||||||
char dirbuf[PATH_MAX];
|
char dirbuf[PATH_MAX];
|
||||||
|
mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
||||||
int n;
|
int n;
|
||||||
char *p;
|
char *p;
|
||||||
int rv;
|
int rv;
|
||||||
@@ -549,7 +578,7 @@ zed_conf_open_state(struct zed_conf *zcp)
|
|||||||
if (p)
|
if (p)
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
if ((mkdirp(dirbuf, 0755) < 0) && (errno != EEXIST)) {
|
if ((mkdirp(dirbuf, dirmode) < 0) && (errno != EEXIST)) {
|
||||||
zed_log_msg(LOG_WARNING,
|
zed_log_msg(LOG_WARNING,
|
||||||
"Failed to create directory \"%s\": %s",
|
"Failed to create directory \"%s\": %s",
|
||||||
dirbuf, strerror(errno));
|
dirbuf, strerror(errno));
|
||||||
@@ -567,7 +596,7 @@ zed_conf_open_state(struct zed_conf *zcp)
|
|||||||
(void) unlink(zcp->state_file);
|
(void) unlink(zcp->state_file);
|
||||||
|
|
||||||
zcp->state_fd = open(zcp->state_file,
|
zcp->state_fd = open(zcp->state_file,
|
||||||
O_RDWR | O_CREAT | O_CLOEXEC, 0644);
|
(O_RDWR | O_CREAT), (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
|
||||||
if (zcp->state_fd < 0) {
|
if (zcp->state_fd < 0) {
|
||||||
zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s",
|
zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s",
|
||||||
zcp->state_file, strerror(errno));
|
zcp->state_file, strerror(errno));
|
||||||
|
|||||||
+22
-18
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
@@ -20,39 +20,43 @@
|
|||||||
#include "zed_strings.h"
|
#include "zed_strings.h"
|
||||||
|
|
||||||
struct zed_conf {
|
struct zed_conf {
|
||||||
|
unsigned do_force:1; /* true if force enabled */
|
||||||
|
unsigned do_foreground:1; /* true if run in foreground */
|
||||||
|
unsigned do_memlock:1; /* true if locking memory */
|
||||||
|
unsigned do_verbose:1; /* true if verbosity enabled */
|
||||||
|
unsigned do_zero:1; /* true if zeroing state */
|
||||||
|
unsigned do_idle:1; /* true if idle enabled */
|
||||||
|
int syslog_facility; /* syslog facility value */
|
||||||
|
int min_events; /* RESERVED FOR FUTURE USE */
|
||||||
|
int max_events; /* RESERVED FOR FUTURE USE */
|
||||||
|
char *conf_file; /* abs path to config file */
|
||||||
char *pid_file; /* abs path to pid file */
|
char *pid_file; /* abs path to pid file */
|
||||||
char *zedlet_dir; /* abs path to zedlet dir */
|
|
||||||
char *state_file; /* abs path to state file */
|
|
||||||
|
|
||||||
libzfs_handle_t *zfs_hdl; /* handle to libzfs */
|
|
||||||
zed_strings_t *zedlets; /* names of enabled zedlets */
|
|
||||||
char *path; /* custom $PATH for zedlets to use */
|
|
||||||
|
|
||||||
int pid_fd; /* fd to pid file for lock */
|
int pid_fd; /* fd to pid file for lock */
|
||||||
|
char *zedlet_dir; /* abs path to zedlet dir */
|
||||||
|
zed_strings_t *zedlets; /* names of enabled zedlets */
|
||||||
|
char *state_file; /* abs path to state file */
|
||||||
int state_fd; /* fd to state file */
|
int state_fd; /* fd to state file */
|
||||||
|
libzfs_handle_t *zfs_hdl; /* handle to libzfs */
|
||||||
int zevent_fd; /* fd for access to zevents */
|
int zevent_fd; /* fd for access to zevents */
|
||||||
|
char *path; /* custom $PATH for zedlets to use */
|
||||||
int16_t max_jobs; /* max zedlets to run at one time */
|
|
||||||
|
|
||||||
boolean_t do_force:1; /* true if force enabled */
|
|
||||||
boolean_t do_foreground:1; /* true if run in foreground */
|
|
||||||
boolean_t do_memlock:1; /* true if locking memory */
|
|
||||||
boolean_t do_verbose:1; /* true if verbosity enabled */
|
|
||||||
boolean_t do_zero:1; /* true if zeroing state */
|
|
||||||
boolean_t do_idle:1; /* true if idle enabled */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void zed_conf_init(struct zed_conf *zcp);
|
struct zed_conf *zed_conf_create(void);
|
||||||
|
|
||||||
void zed_conf_destroy(struct zed_conf *zcp);
|
void zed_conf_destroy(struct zed_conf *zcp);
|
||||||
|
|
||||||
void zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv);
|
void zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv);
|
||||||
|
|
||||||
|
void zed_conf_parse_file(struct zed_conf *zcp);
|
||||||
|
|
||||||
int zed_conf_scan_dir(struct zed_conf *zcp);
|
int zed_conf_scan_dir(struct zed_conf *zcp);
|
||||||
|
|
||||||
int zed_conf_write_pid(struct zed_conf *zcp);
|
int zed_conf_write_pid(struct zed_conf *zcp);
|
||||||
|
|
||||||
int zed_conf_open_state(struct zed_conf *zcp);
|
int zed_conf_open_state(struct zed_conf *zcp);
|
||||||
|
|
||||||
int zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[]);
|
int zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[]);
|
||||||
|
|
||||||
int zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[]);
|
int zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[]);
|
||||||
|
|
||||||
#endif /* !ZED_CONF_H */
|
#endif /* !ZED_CONF_H */
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ zed_udev_event(const char *class, const char *subclass, nvlist_t *nvl)
|
|||||||
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PATH, strval);
|
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PATH, strval);
|
||||||
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &strval) == 0)
|
if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &strval) == 0)
|
||||||
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_IDENTIFIER, strval);
|
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_IDENTIFIER, strval);
|
||||||
if (nvlist_lookup_boolean(nvl, DEV_IS_PART) == B_TRUE)
|
|
||||||
zed_log_msg(LOG_INFO, "\t%s: B_TRUE", DEV_IS_PART);
|
|
||||||
if (nvlist_lookup_string(nvl, DEV_PHYS_PATH, &strval) == 0)
|
if (nvlist_lookup_string(nvl, DEV_PHYS_PATH, &strval) == 0)
|
||||||
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PHYS_PATH, strval);
|
zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PHYS_PATH, strval);
|
||||||
if (nvlist_lookup_uint64(nvl, DEV_SIZE, &numval) == 0)
|
if (nvlist_lookup_uint64(nvl, DEV_SIZE, &numval) == 0)
|
||||||
@@ -215,11 +213,6 @@ zed_udev_monitor(void *arg)
|
|||||||
if (type != NULL && type[0] != '\0' &&
|
if (type != NULL && type[0] != '\0' &&
|
||||||
strcmp(type, "disk") == 0 &&
|
strcmp(type, "disk") == 0 &&
|
||||||
part != NULL && part[0] != '\0') {
|
part != NULL && part[0] != '\0') {
|
||||||
zed_log_msg(LOG_INFO,
|
|
||||||
"%s: skip %s since it has a %s partition already",
|
|
||||||
__func__,
|
|
||||||
udev_device_get_property_value(dev, "DEVNAME"),
|
|
||||||
part);
|
|
||||||
/* skip and wait for partition event */
|
/* skip and wait for partition event */
|
||||||
udev_device_unref(dev);
|
udev_device_unref(dev);
|
||||||
continue;
|
continue;
|
||||||
@@ -234,11 +227,6 @@ zed_udev_monitor(void *arg)
|
|||||||
sectors = udev_device_get_sysattr_value(dev, "size");
|
sectors = udev_device_get_sysattr_value(dev, "size");
|
||||||
if (sectors != NULL &&
|
if (sectors != NULL &&
|
||||||
strtoull(sectors, NULL, 10) < MINIMUM_SECTORS) {
|
strtoull(sectors, NULL, 10) < MINIMUM_SECTORS) {
|
||||||
zed_log_msg(LOG_INFO,
|
|
||||||
"%s: %s sectors %s < %llu (minimum)",
|
|
||||||
__func__,
|
|
||||||
udev_device_get_property_value(dev, "DEVNAME"),
|
|
||||||
sectors, MINIMUM_SECTORS);
|
|
||||||
udev_device_unref(dev);
|
udev_device_unref(dev);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -391,7 +379,6 @@ zed_disk_event_init()
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_setname_np(g_mon_tid, "udev monitor");
|
|
||||||
zed_log_msg(LOG_INFO, "zed_disk_event_init");
|
zed_log_msg(LOG_INFO, "zed_disk_event_init");
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
|
|||||||
+30
-52
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <libzfs_core.h>
|
#include <libzfs.h> /* FIXME: Replace with libzfs_core. */
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -54,7 +54,7 @@ zed_event_init(struct zed_conf *zcp)
|
|||||||
zed_log_die("Failed to initialize libzfs");
|
zed_log_die("Failed to initialize libzfs");
|
||||||
}
|
}
|
||||||
|
|
||||||
zcp->zevent_fd = open(ZFS_DEV, O_RDWR | O_CLOEXEC);
|
zcp->zevent_fd = open(ZFS_DEV, O_RDWR);
|
||||||
if (zcp->zevent_fd < 0) {
|
if (zcp->zevent_fd < 0) {
|
||||||
if (zcp->do_idle)
|
if (zcp->do_idle)
|
||||||
return (-1);
|
return (-1);
|
||||||
@@ -96,47 +96,6 @@ zed_event_fini(struct zed_conf *zcp)
|
|||||||
libzfs_fini(zcp->zfs_hdl);
|
libzfs_fini(zcp->zfs_hdl);
|
||||||
zcp->zfs_hdl = NULL;
|
zcp->zfs_hdl = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
zed_exec_fini();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_bump_event_queue_length(void)
|
|
||||||
{
|
|
||||||
int zzlm = -1, wr;
|
|
||||||
char qlen_buf[12] = {0}; /* parameter is int => max "-2147483647\n" */
|
|
||||||
long int qlen;
|
|
||||||
|
|
||||||
zzlm = open("/sys/module/zfs/parameters/zfs_zevent_len_max", O_RDWR);
|
|
||||||
if (zzlm < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (read(zzlm, qlen_buf, sizeof (qlen_buf)) < 0)
|
|
||||||
goto done;
|
|
||||||
qlen_buf[sizeof (qlen_buf) - 1] = '\0';
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
qlen = strtol(qlen_buf, NULL, 10);
|
|
||||||
if (errno == ERANGE)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (qlen <= 0)
|
|
||||||
qlen = 512; /* default zfs_zevent_len_max value */
|
|
||||||
else
|
|
||||||
qlen *= 2;
|
|
||||||
|
|
||||||
if (qlen > INT_MAX)
|
|
||||||
qlen = INT_MAX;
|
|
||||||
wr = snprintf(qlen_buf, sizeof (qlen_buf), "%ld", qlen);
|
|
||||||
|
|
||||||
if (pwrite(zzlm, qlen_buf, wr, 0) < 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
zed_log_msg(LOG_WARNING, "Bumping queue length to %ld", qlen);
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (zzlm > -1)
|
|
||||||
(void) close(zzlm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -177,7 +136,10 @@ zed_event_seek(struct zed_conf *zcp, uint64_t saved_eid, int64_t saved_etime[])
|
|||||||
|
|
||||||
if (n_dropped > 0) {
|
if (n_dropped > 0) {
|
||||||
zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
|
zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
|
||||||
_bump_event_queue_length();
|
/*
|
||||||
|
* FIXME: Increase max size of event nvlist in
|
||||||
|
* /sys/module/zfs/parameters/zfs_zevent_len_max ?
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
|
if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
|
||||||
zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
|
zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
|
||||||
@@ -249,7 +211,7 @@ _zed_event_value_is_hex(const char *name)
|
|||||||
*
|
*
|
||||||
* All environment variables in [zsp] should be added through this function.
|
* All environment variables in [zsp] should be added through this function.
|
||||||
*/
|
*/
|
||||||
static __attribute__((format(printf, 5, 6))) int
|
static int
|
||||||
_zed_event_add_var(uint64_t eid, zed_strings_t *zsp,
|
_zed_event_add_var(uint64_t eid, zed_strings_t *zsp,
|
||||||
const char *prefix, const char *name, const char *fmt, ...)
|
const char *prefix, const char *name, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
@@ -624,6 +586,8 @@ _zed_event_add_string_array(uint64_t eid, zed_strings_t *zsp,
|
|||||||
* Convert the nvpair [nvp] to a string which is added to the environment
|
* Convert the nvpair [nvp] to a string which is added to the environment
|
||||||
* of the child process.
|
* of the child process.
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
|
*
|
||||||
|
* FIXME: Refactor with cmd/zpool/zpool_main.c:zpool_do_events_nvprint()?
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
_zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
|
_zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
|
||||||
@@ -722,11 +686,23 @@ _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
|
|||||||
_zed_event_add_var(eid, zsp, prefix, name,
|
_zed_event_add_var(eid, zsp, prefix, name,
|
||||||
"%llu", (u_longlong_t)i64);
|
"%llu", (u_longlong_t)i64);
|
||||||
break;
|
break;
|
||||||
|
case DATA_TYPE_NVLIST:
|
||||||
|
_zed_event_add_var(eid, zsp, prefix, name,
|
||||||
|
"%s", "_NOT_IMPLEMENTED_"); /* FIXME */
|
||||||
|
break;
|
||||||
case DATA_TYPE_STRING:
|
case DATA_TYPE_STRING:
|
||||||
(void) nvpair_value_string(nvp, &str);
|
(void) nvpair_value_string(nvp, &str);
|
||||||
_zed_event_add_var(eid, zsp, prefix, name,
|
_zed_event_add_var(eid, zsp, prefix, name,
|
||||||
"%s", (str ? str : "<NULL>"));
|
"%s", (str ? str : "<NULL>"));
|
||||||
break;
|
break;
|
||||||
|
case DATA_TYPE_BOOLEAN_ARRAY:
|
||||||
|
_zed_event_add_var(eid, zsp, prefix, name,
|
||||||
|
"%s", "_NOT_IMPLEMENTED_"); /* FIXME */
|
||||||
|
break;
|
||||||
|
case DATA_TYPE_BYTE_ARRAY:
|
||||||
|
_zed_event_add_var(eid, zsp, prefix, name,
|
||||||
|
"%s", "_NOT_IMPLEMENTED_"); /* FIXME */
|
||||||
|
break;
|
||||||
case DATA_TYPE_INT8_ARRAY:
|
case DATA_TYPE_INT8_ARRAY:
|
||||||
_zed_event_add_int8_array(eid, zsp, prefix, nvp);
|
_zed_event_add_int8_array(eid, zsp, prefix, nvp);
|
||||||
break;
|
break;
|
||||||
@@ -754,11 +730,9 @@ _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
|
|||||||
case DATA_TYPE_STRING_ARRAY:
|
case DATA_TYPE_STRING_ARRAY:
|
||||||
_zed_event_add_string_array(eid, zsp, prefix, nvp);
|
_zed_event_add_string_array(eid, zsp, prefix, nvp);
|
||||||
break;
|
break;
|
||||||
case DATA_TYPE_NVLIST:
|
|
||||||
case DATA_TYPE_BOOLEAN_ARRAY:
|
|
||||||
case DATA_TYPE_BYTE_ARRAY:
|
|
||||||
case DATA_TYPE_NVLIST_ARRAY:
|
case DATA_TYPE_NVLIST_ARRAY:
|
||||||
_zed_event_add_var(eid, zsp, prefix, name, "_NOT_IMPLEMENTED_");
|
_zed_event_add_var(eid, zsp, prefix, name,
|
||||||
|
"%s", "_NOT_IMPLEMENTED_"); /* FIXME */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@@ -938,7 +912,10 @@ zed_event_service(struct zed_conf *zcp)
|
|||||||
|
|
||||||
if (n_dropped > 0) {
|
if (n_dropped > 0) {
|
||||||
zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
|
zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
|
||||||
_bump_event_queue_length();
|
/*
|
||||||
|
* FIXME: Increase max size of event nvlist in
|
||||||
|
* /sys/module/zfs/parameters/zfs_zevent_len_max ?
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
|
if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
|
||||||
zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
|
zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
|
||||||
@@ -976,7 +953,8 @@ zed_event_service(struct zed_conf *zcp)
|
|||||||
|
|
||||||
_zed_event_add_time_strings(eid, zsp, etime);
|
_zed_event_add_time_strings(eid, zsp, etime);
|
||||||
|
|
||||||
zed_exec_process(eid, class, subclass, zcp, zsp);
|
zed_exec_process(eid, class, subclass,
|
||||||
|
zcp->zedlet_dir, zcp->zedlets, zsp, zcp->zevent_fd);
|
||||||
|
|
||||||
zed_conf_write_state(zcp, eid, etime);
|
zed_conf_write_state(zcp, eid, etime);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
|
|||||||
+60
-197
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
@@ -18,55 +18,17 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
|
||||||
#include <sys/avl.h>
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include "zed_exec.h"
|
#include "zed_exec.h"
|
||||||
|
#include "zed_file.h"
|
||||||
#include "zed_log.h"
|
#include "zed_log.h"
|
||||||
#include "zed_strings.h"
|
#include "zed_strings.h"
|
||||||
|
|
||||||
#define ZEVENT_FILENO 3
|
#define ZEVENT_FILENO 3
|
||||||
|
|
||||||
struct launched_process_node {
|
|
||||||
avl_node_t node;
|
|
||||||
pid_t pid;
|
|
||||||
uint64_t eid;
|
|
||||||
char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
_launched_process_node_compare(const void *x1, const void *x2)
|
|
||||||
{
|
|
||||||
pid_t p1;
|
|
||||||
pid_t p2;
|
|
||||||
|
|
||||||
assert(x1 != NULL);
|
|
||||||
assert(x2 != NULL);
|
|
||||||
|
|
||||||
p1 = ((const struct launched_process_node *) x1)->pid;
|
|
||||||
p2 = ((const struct launched_process_node *) x2)->pid;
|
|
||||||
|
|
||||||
if (p1 < p2)
|
|
||||||
return (-1);
|
|
||||||
else if (p1 == p2)
|
|
||||||
return (0);
|
|
||||||
else
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static pthread_t _reap_children_tid = (pthread_t)-1;
|
|
||||||
static volatile boolean_t _reap_children_stop;
|
|
||||||
static avl_tree_t _launched_processes;
|
|
||||||
static pthread_mutex_t _launched_processes_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
static int16_t _launched_processes_limit;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create an environment string array for passing to execve() using the
|
* Create an environment string array for passing to execve() using the
|
||||||
* NAME=VALUE strings in container [zsp].
|
* NAME=VALUE strings in container [zsp].
|
||||||
@@ -117,26 +79,20 @@ _zed_exec_create_env(zed_strings_t *zsp)
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
_zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
|
_zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
|
||||||
char *env[], int zfd, boolean_t in_foreground)
|
char *env[], int zfd)
|
||||||
{
|
{
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
int n;
|
int n;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int fd;
|
int fd;
|
||||||
struct launched_process_node *node;
|
pid_t wpid;
|
||||||
sigset_t mask;
|
int status;
|
||||||
struct timespec launch_timeout =
|
|
||||||
{ .tv_sec = 0, .tv_nsec = 200 * 1000 * 1000, };
|
|
||||||
|
|
||||||
assert(dir != NULL);
|
assert(dir != NULL);
|
||||||
assert(prog != NULL);
|
assert(prog != NULL);
|
||||||
assert(env != NULL);
|
assert(env != NULL);
|
||||||
assert(zfd >= 0);
|
assert(zfd >= 0);
|
||||||
|
|
||||||
while (__atomic_load_n(&_launched_processes_limit,
|
|
||||||
__ATOMIC_SEQ_CST) <= 0)
|
|
||||||
(void) nanosleep(&launch_timeout, NULL);
|
|
||||||
|
|
||||||
n = snprintf(path, sizeof (path), "%s/%s", dir, prog);
|
n = snprintf(path, sizeof (path), "%s/%s", dir, prog);
|
||||||
if ((n < 0) || (n >= sizeof (path))) {
|
if ((n < 0) || (n >= sizeof (path))) {
|
||||||
zed_log_msg(LOG_WARNING,
|
zed_log_msg(LOG_WARNING,
|
||||||
@@ -144,179 +100,101 @@ _zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
|
|||||||
prog, eid, strerror(ENAMETOOLONG));
|
prog, eid, strerror(ENAMETOOLONG));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
(void) pthread_mutex_lock(&_launched_processes_lock);
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
(void) pthread_mutex_unlock(&_launched_processes_lock);
|
|
||||||
zed_log_msg(LOG_WARNING,
|
zed_log_msg(LOG_WARNING,
|
||||||
"Failed to fork \"%s\" for eid=%llu: %s",
|
"Failed to fork \"%s\" for eid=%llu: %s",
|
||||||
prog, eid, strerror(errno));
|
prog, eid, strerror(errno));
|
||||||
return;
|
return;
|
||||||
} else if (pid == 0) {
|
} else if (pid == 0) {
|
||||||
(void) sigemptyset(&mask);
|
|
||||||
(void) sigprocmask(SIG_SETMASK, &mask, NULL);
|
|
||||||
|
|
||||||
(void) umask(022);
|
(void) umask(022);
|
||||||
if (in_foreground && /* we're already devnulled if daemonised */
|
if ((fd = open("/dev/null", O_RDWR)) != -1) {
|
||||||
(fd = open("/dev/null", O_RDWR | O_CLOEXEC)) != -1) {
|
|
||||||
(void) dup2(fd, STDIN_FILENO);
|
(void) dup2(fd, STDIN_FILENO);
|
||||||
(void) dup2(fd, STDOUT_FILENO);
|
(void) dup2(fd, STDOUT_FILENO);
|
||||||
(void) dup2(fd, STDERR_FILENO);
|
(void) dup2(fd, STDERR_FILENO);
|
||||||
}
|
}
|
||||||
(void) dup2(zfd, ZEVENT_FILENO);
|
(void) dup2(zfd, ZEVENT_FILENO);
|
||||||
|
zed_file_close_from(ZEVENT_FILENO + 1);
|
||||||
execle(path, prog, NULL, env);
|
execle(path, prog, NULL, env);
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parent process */
|
/* parent process */
|
||||||
|
|
||||||
node = calloc(1, sizeof (*node));
|
|
||||||
if (node) {
|
|
||||||
node->pid = pid;
|
|
||||||
node->eid = eid;
|
|
||||||
node->name = strdup(prog);
|
|
||||||
|
|
||||||
avl_add(&_launched_processes, node);
|
|
||||||
}
|
|
||||||
(void) pthread_mutex_unlock(&_launched_processes_lock);
|
|
||||||
|
|
||||||
__atomic_sub_fetch(&_launched_processes_limit, 1, __ATOMIC_SEQ_CST);
|
|
||||||
zed_log_msg(LOG_INFO, "Invoking \"%s\" eid=%llu pid=%d",
|
zed_log_msg(LOG_INFO, "Invoking \"%s\" eid=%llu pid=%d",
|
||||||
prog, eid, pid);
|
prog, eid, pid);
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
/* FIXME: Timeout rogue child processes with sigalarm? */
|
||||||
_nop(int sig)
|
|
||||||
{}
|
|
||||||
|
|
||||||
static void *
|
/*
|
||||||
_reap_children(void *arg)
|
* Wait for child process using WNOHANG to limit
|
||||||
{
|
* the time spent waiting to 10 seconds (10,000ms).
|
||||||
struct launched_process_node node, *pnode;
|
*/
|
||||||
pid_t pid;
|
for (n = 0; n < 1000; n++) {
|
||||||
int status;
|
wpid = waitpid(pid, &status, WNOHANG);
|
||||||
struct rusage usage;
|
if (wpid == (pid_t)-1) {
|
||||||
struct sigaction sa = {};
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
zed_log_msg(LOG_WARNING,
|
||||||
|
"Failed to wait for \"%s\" eid=%llu pid=%d",
|
||||||
|
prog, eid, pid);
|
||||||
|
break;
|
||||||
|
} else if (wpid == 0) {
|
||||||
|
struct timespec t;
|
||||||
|
|
||||||
(void) sigfillset(&sa.sa_mask);
|
/* child still running */
|
||||||
(void) sigdelset(&sa.sa_mask, SIGCHLD);
|
t.tv_sec = 0;
|
||||||
(void) pthread_sigmask(SIG_SETMASK, &sa.sa_mask, NULL);
|
t.tv_nsec = 10000000; /* 10ms */
|
||||||
|
(void) nanosleep(&t, NULL);
|
||||||
(void) sigemptyset(&sa.sa_mask);
|
continue;
|
||||||
sa.sa_handler = _nop;
|
|
||||||
sa.sa_flags = SA_NOCLDSTOP;
|
|
||||||
(void) sigaction(SIGCHLD, &sa, NULL);
|
|
||||||
|
|
||||||
for (_reap_children_stop = B_FALSE; !_reap_children_stop; ) {
|
|
||||||
(void) pthread_mutex_lock(&_launched_processes_lock);
|
|
||||||
pid = wait4(0, &status, WNOHANG, &usage);
|
|
||||||
|
|
||||||
if (pid == 0 || pid == (pid_t)-1) {
|
|
||||||
(void) pthread_mutex_unlock(&_launched_processes_lock);
|
|
||||||
if (pid == 0 || errno == ECHILD)
|
|
||||||
pause();
|
|
||||||
else if (errno != EINTR)
|
|
||||||
zed_log_msg(LOG_WARNING,
|
|
||||||
"Failed to wait for children: %s",
|
|
||||||
strerror(errno));
|
|
||||||
} else {
|
|
||||||
memset(&node, 0, sizeof (node));
|
|
||||||
node.pid = pid;
|
|
||||||
pnode = avl_find(&_launched_processes, &node, NULL);
|
|
||||||
if (pnode) {
|
|
||||||
memcpy(&node, pnode, sizeof (node));
|
|
||||||
|
|
||||||
avl_remove(&_launched_processes, pnode);
|
|
||||||
free(pnode);
|
|
||||||
}
|
|
||||||
(void) pthread_mutex_unlock(&_launched_processes_lock);
|
|
||||||
__atomic_add_fetch(&_launched_processes_limit, 1,
|
|
||||||
__ATOMIC_SEQ_CST);
|
|
||||||
|
|
||||||
usage.ru_utime.tv_sec += usage.ru_stime.tv_sec;
|
|
||||||
usage.ru_utime.tv_usec += usage.ru_stime.tv_usec;
|
|
||||||
usage.ru_utime.tv_sec +=
|
|
||||||
usage.ru_utime.tv_usec / (1000 * 1000);
|
|
||||||
usage.ru_utime.tv_usec %= 1000 * 1000;
|
|
||||||
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
zed_log_msg(LOG_INFO,
|
|
||||||
"Finished \"%s\" eid=%llu pid=%d "
|
|
||||||
"time=%llu.%06us exit=%d",
|
|
||||||
node.name, node.eid, pid,
|
|
||||||
(unsigned long long) usage.ru_utime.tv_sec,
|
|
||||||
(unsigned int) usage.ru_utime.tv_usec,
|
|
||||||
WEXITSTATUS(status));
|
|
||||||
} else if (WIFSIGNALED(status)) {
|
|
||||||
zed_log_msg(LOG_INFO,
|
|
||||||
"Finished \"%s\" eid=%llu pid=%d "
|
|
||||||
"time=%llu.%06us sig=%d/%s",
|
|
||||||
node.name, node.eid, pid,
|
|
||||||
(unsigned long long) usage.ru_utime.tv_sec,
|
|
||||||
(unsigned int) usage.ru_utime.tv_usec,
|
|
||||||
WTERMSIG(status),
|
|
||||||
strsignal(WTERMSIG(status)));
|
|
||||||
} else {
|
|
||||||
zed_log_msg(LOG_INFO,
|
|
||||||
"Finished \"%s\" eid=%llu pid=%d "
|
|
||||||
"time=%llu.%06us status=0x%X",
|
|
||||||
node.name, node.eid,
|
|
||||||
(unsigned long long) usage.ru_utime.tv_sec,
|
|
||||||
(unsigned int) usage.ru_utime.tv_usec,
|
|
||||||
(unsigned int) status);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(node.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
zed_log_msg(LOG_INFO,
|
||||||
|
"Finished \"%s\" eid=%llu pid=%d exit=%d",
|
||||||
|
prog, eid, pid, WEXITSTATUS(status));
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
zed_log_msg(LOG_INFO,
|
||||||
|
"Finished \"%s\" eid=%llu pid=%d sig=%d/%s",
|
||||||
|
prog, eid, pid, WTERMSIG(status),
|
||||||
|
strsignal(WTERMSIG(status)));
|
||||||
|
} else {
|
||||||
|
zed_log_msg(LOG_INFO,
|
||||||
|
"Finished \"%s\" eid=%llu pid=%d status=0x%X",
|
||||||
|
prog, eid, (unsigned int) status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (NULL);
|
/*
|
||||||
}
|
* kill child process after 10 seconds
|
||||||
|
*/
|
||||||
void
|
if (wpid == 0) {
|
||||||
zed_exec_fini(void)
|
zed_log_msg(LOG_WARNING, "Killing hung \"%s\" pid=%d",
|
||||||
{
|
prog, pid);
|
||||||
struct launched_process_node *node;
|
(void) kill(pid, SIGKILL);
|
||||||
void *ck = NULL;
|
(void) waitpid(pid, &status, 0);
|
||||||
|
|
||||||
if (_reap_children_tid == (pthread_t)-1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_reap_children_stop = B_TRUE;
|
|
||||||
(void) pthread_kill(_reap_children_tid, SIGCHLD);
|
|
||||||
(void) pthread_join(_reap_children_tid, NULL);
|
|
||||||
|
|
||||||
while ((node = avl_destroy_nodes(&_launched_processes, &ck)) != NULL) {
|
|
||||||
free(node->name);
|
|
||||||
free(node);
|
|
||||||
}
|
}
|
||||||
avl_destroy(&_launched_processes);
|
|
||||||
|
|
||||||
(void) pthread_mutex_destroy(&_launched_processes_lock);
|
|
||||||
(void) pthread_mutex_init(&_launched_processes_lock, NULL);
|
|
||||||
|
|
||||||
_reap_children_tid = (pthread_t)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process the event [eid] by synchronously invoking all zedlets with a
|
* Process the event [eid] by synchronously invoking all zedlets with a
|
||||||
* matching class prefix.
|
* matching class prefix.
|
||||||
*
|
*
|
||||||
* Each executable in [zcp->zedlets] from the directory [zcp->zedlet_dir]
|
* Each executable in [zedlets] from the directory [dir] is matched against
|
||||||
* is matched against the event's [class], [subclass], and the "all" class
|
* the event's [class], [subclass], and the "all" class (which matches
|
||||||
* (which matches all events).
|
* all events). Every zedlet with a matching class prefix is invoked.
|
||||||
* Every zedlet with a matching class prefix is invoked.
|
|
||||||
* The NAME=VALUE strings in [envs] will be passed to the zedlet as
|
* The NAME=VALUE strings in [envs] will be passed to the zedlet as
|
||||||
* environment variables.
|
* environment variables.
|
||||||
*
|
*
|
||||||
* The file descriptor [zcp->zevent_fd] is the zevent_fd used to track the
|
* The file descriptor [zfd] is the zevent_fd used to track the
|
||||||
* current cursor location within the zevent nvlist.
|
* current cursor location within the zevent nvlist.
|
||||||
*
|
*
|
||||||
* Return 0 on success, -1 on error.
|
* Return 0 on success, -1 on error.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
zed_exec_process(uint64_t eid, const char *class, const char *subclass,
|
zed_exec_process(uint64_t eid, const char *class, const char *subclass,
|
||||||
struct zed_conf *zcp, zed_strings_t *envs)
|
const char *dir, zed_strings_t *zedlets, zed_strings_t *envs, int zfd)
|
||||||
{
|
{
|
||||||
const char *class_strings[4];
|
const char *class_strings[4];
|
||||||
const char *allclass = "all";
|
const char *allclass = "all";
|
||||||
@@ -325,22 +203,9 @@ zed_exec_process(uint64_t eid, const char *class, const char *subclass,
|
|||||||
char **e;
|
char **e;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if (!zcp->zedlet_dir || !zcp->zedlets || !envs || zcp->zevent_fd < 0)
|
if (!dir || !zedlets || !envs || zfd < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
if (_reap_children_tid == (pthread_t)-1) {
|
|
||||||
_launched_processes_limit = zcp->max_jobs;
|
|
||||||
|
|
||||||
if (pthread_create(&_reap_children_tid, NULL,
|
|
||||||
_reap_children, NULL) != 0)
|
|
||||||
return (-1);
|
|
||||||
pthread_setname_np(_reap_children_tid, "reap ZEDLETs");
|
|
||||||
|
|
||||||
avl_create(&_launched_processes, _launched_process_node_compare,
|
|
||||||
sizeof (struct launched_process_node),
|
|
||||||
offsetof(struct launched_process_node, node));
|
|
||||||
}
|
|
||||||
|
|
||||||
csp = class_strings;
|
csp = class_strings;
|
||||||
|
|
||||||
if (class)
|
if (class)
|
||||||
@@ -356,13 +221,11 @@ zed_exec_process(uint64_t eid, const char *class, const char *subclass,
|
|||||||
|
|
||||||
e = _zed_exec_create_env(envs);
|
e = _zed_exec_create_env(envs);
|
||||||
|
|
||||||
for (z = zed_strings_first(zcp->zedlets); z;
|
for (z = zed_strings_first(zedlets); z; z = zed_strings_next(zedlets)) {
|
||||||
z = zed_strings_next(zcp->zedlets)) {
|
|
||||||
for (csp = class_strings; *csp; csp++) {
|
for (csp = class_strings; *csp; csp++) {
|
||||||
n = strlen(*csp);
|
n = strlen(*csp);
|
||||||
if ((strncmp(z, *csp, n) == 0) && !isalpha(z[n]))
|
if ((strncmp(z, *csp, n) == 0) && !isalpha(z[n]))
|
||||||
_zed_exec_fork_child(eid, zcp->zedlet_dir,
|
_zed_exec_fork_child(eid, dir, z, e, zfd);
|
||||||
z, e, zcp->zevent_fd, zcp->do_foreground);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(e);
|
free(e);
|
||||||
|
|||||||
+3
-5
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
@@ -17,11 +17,9 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "zed_strings.h"
|
#include "zed_strings.h"
|
||||||
#include "zed_conf.h"
|
|
||||||
|
|
||||||
void zed_exec_fini(void);
|
|
||||||
|
|
||||||
int zed_exec_process(uint64_t eid, const char *class, const char *subclass,
|
int zed_exec_process(uint64_t eid, const char *class, const char *subclass,
|
||||||
struct zed_conf *zcp, zed_strings_t *envs);
|
const char *dir, zed_strings_t *zedlets, zed_strings_t *envs,
|
||||||
|
int zevent_fd);
|
||||||
|
|
||||||
#endif /* !ZED_EXEC_H */
|
#endif /* !ZED_EXEC_H */
|
||||||
|
|||||||
+97
-21
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
@@ -12,17 +12,73 @@
|
|||||||
* You may not use this file except in compliance with the license.
|
* You may not use this file except in compliance with the license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "zed_file.h"
|
#include "zed_file.h"
|
||||||
#include "zed_log.h"
|
#include "zed_log.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read up to [n] bytes from [fd] into [buf].
|
||||||
|
* Return the number of bytes read, 0 on EOF, or -1 on error.
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
zed_file_read_n(int fd, void *buf, size_t n)
|
||||||
|
{
|
||||||
|
unsigned char *p;
|
||||||
|
size_t n_left;
|
||||||
|
ssize_t n_read;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
n_left = n;
|
||||||
|
while (n_left > 0) {
|
||||||
|
if ((n_read = read(fd, p, n_left)) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
} else if (n_read == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n_left -= n_read;
|
||||||
|
p += n_read;
|
||||||
|
}
|
||||||
|
return (n - n_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write [n] bytes from [buf] out to [fd].
|
||||||
|
* Return the number of bytes written, or -1 on error.
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
zed_file_write_n(int fd, void *buf, size_t n)
|
||||||
|
{
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t n_left;
|
||||||
|
ssize_t n_written;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
n_left = n;
|
||||||
|
while (n_left > 0) {
|
||||||
|
if ((n_written = write(fd, p, n_left)) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
}
|
||||||
|
n_left -= n_written;
|
||||||
|
p += n_written;
|
||||||
|
}
|
||||||
|
return (n);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set an exclusive advisory lock on the open file descriptor [fd].
|
* Set an exclusive advisory lock on the open file descriptor [fd].
|
||||||
* Return 0 on success, 1 if a conflicting lock is held by another process,
|
* Return 0 on success, 1 if a conflicting lock is held by another process,
|
||||||
@@ -104,13 +160,6 @@ zed_file_is_locked(int fd)
|
|||||||
return (lock.l_pid);
|
return (lock.l_pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if __APPLE__
|
|
||||||
#define PROC_SELF_FD "/dev/fd"
|
|
||||||
#else /* Linux-compatible layout */
|
|
||||||
#define PROC_SELF_FD "/proc/self/fd"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close all open file descriptors greater than or equal to [lowfd].
|
* Close all open file descriptors greater than or equal to [lowfd].
|
||||||
* Any errors encountered while closing file descriptors are ignored.
|
* Any errors encountered while closing file descriptors are ignored.
|
||||||
@@ -118,24 +167,51 @@ zed_file_is_locked(int fd)
|
|||||||
void
|
void
|
||||||
zed_file_close_from(int lowfd)
|
zed_file_close_from(int lowfd)
|
||||||
{
|
{
|
||||||
int errno_bak = errno;
|
const int maxfd_def = 256;
|
||||||
int maxfd = 0;
|
int errno_bak;
|
||||||
|
struct rlimit rl;
|
||||||
|
int maxfd;
|
||||||
int fd;
|
int fd;
|
||||||
DIR *fddir;
|
|
||||||
struct dirent *fdent;
|
|
||||||
|
|
||||||
if ((fddir = opendir(PROC_SELF_FD)) != NULL) {
|
errno_bak = errno;
|
||||||
while ((fdent = readdir(fddir)) != NULL) {
|
|
||||||
fd = atoi(fdent->d_name);
|
if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
|
||||||
if (fd > maxfd && fd != dirfd(fddir))
|
maxfd = maxfd_def;
|
||||||
maxfd = fd;
|
} else if (rl.rlim_max == RLIM_INFINITY) {
|
||||||
}
|
maxfd = maxfd_def;
|
||||||
(void) closedir(fddir);
|
|
||||||
} else {
|
} else {
|
||||||
maxfd = sysconf(_SC_OPEN_MAX);
|
maxfd = rl.rlim_max;
|
||||||
}
|
}
|
||||||
for (fd = lowfd; fd < maxfd; fd++)
|
for (fd = lowfd; fd < maxfd; fd++)
|
||||||
(void) close(fd);
|
(void) close(fd);
|
||||||
|
|
||||||
errno = errno_bak;
|
errno = errno_bak;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the CLOEXEC flag on file descriptor [fd] so it will be automatically
|
||||||
|
* closed upon successful execution of one of the exec functions.
|
||||||
|
* Return 0 on success, or -1 on error.
|
||||||
|
*
|
||||||
|
* FIXME: No longer needed?
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
zed_file_close_on_exec(int fd)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
errno = EBADF;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
flags = fcntl(fd, F_GETFD);
|
||||||
|
if (flags == -1)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
flags |= FD_CLOEXEC;
|
||||||
|
|
||||||
|
if (fcntl(fd, F_SETFD, flags) == -1)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|||||||
+7
-1
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
@@ -18,6 +18,10 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
ssize_t zed_file_read_n(int fd, void *buf, size_t n);
|
||||||
|
|
||||||
|
ssize_t zed_file_write_n(int fd, void *buf, size_t n);
|
||||||
|
|
||||||
int zed_file_lock(int fd);
|
int zed_file_lock(int fd);
|
||||||
|
|
||||||
int zed_file_unlock(int fd);
|
int zed_file_unlock(int fd);
|
||||||
@@ -26,4 +30,6 @@ pid_t zed_file_is_locked(int fd);
|
|||||||
|
|
||||||
void zed_file_close_from(int fd);
|
void zed_file_close_from(int fd);
|
||||||
|
|
||||||
|
int zed_file_close_on_exec(int fd);
|
||||||
|
|
||||||
#endif /* !ZED_FILE_H */
|
#endif /* !ZED_FILE_H */
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
||||||
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
||||||
* Refer to the OpenZFS git commit log for authoritative copyright attribution.
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the terms of the
|
* The contents of this file are subject to the terms of the
|
||||||
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
||||||
|
|||||||
+22
-191
@@ -53,6 +53,7 @@
|
|||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <sys/debug.h>
|
||||||
#include <sys/list.h>
|
#include <sys/list.h>
|
||||||
#include <sys/mkdev.h>
|
#include <sys/mkdev.h>
|
||||||
#include <sys/mntent.h>
|
#include <sys/mntent.h>
|
||||||
@@ -70,6 +71,7 @@
|
|||||||
#include <zfs_prop.h>
|
#include <zfs_prop.h>
|
||||||
#include <zfs_deleg.h>
|
#include <zfs_deleg.h>
|
||||||
#include <libzutil.h>
|
#include <libzutil.h>
|
||||||
|
#include <libuutil.h>
|
||||||
#ifdef HAVE_IDMAP
|
#ifdef HAVE_IDMAP
|
||||||
#include <aclutils.h>
|
#include <aclutils.h>
|
||||||
#include <directory.h>
|
#include <directory.h>
|
||||||
@@ -268,7 +270,7 @@ get_usage(zfs_help_t idx)
|
|||||||
return (gettext("\tclone [-p] [-o property=value] ... "
|
return (gettext("\tclone [-p] [-o property=value] ... "
|
||||||
"<snapshot> <filesystem|volume>\n"));
|
"<snapshot> <filesystem|volume>\n"));
|
||||||
case HELP_CREATE:
|
case HELP_CREATE:
|
||||||
return (gettext("\tcreate [-Pnpuv] [-o property=value] ... "
|
return (gettext("\tcreate [-Pnpv] [-o property=value] ... "
|
||||||
"<filesystem>\n"
|
"<filesystem>\n"
|
||||||
"\tcreate [-Pnpsv] [-b blocksize] [-o property=value] ... "
|
"\tcreate [-Pnpsv] [-b blocksize] [-o property=value] ... "
|
||||||
"-V <size> <volume>\n"));
|
"-V <size> <volume>\n"));
|
||||||
@@ -317,7 +319,7 @@ get_usage(zfs_help_t idx)
|
|||||||
case HELP_SEND:
|
case HELP_SEND:
|
||||||
return (gettext("\tsend [-DnPpRvLecwhb] [-[i|I] snapshot] "
|
return (gettext("\tsend [-DnPpRvLecwhb] [-[i|I] snapshot] "
|
||||||
"<snapshot>\n"
|
"<snapshot>\n"
|
||||||
"\tsend [-DnvPLecw] [-i snapshot|bookmark] "
|
"\tsend [-nvPLecw] [-i snapshot|bookmark] "
|
||||||
"<filesystem|volume|snapshot>\n"
|
"<filesystem|volume|snapshot>\n"
|
||||||
"\tsend [-DnPpvLec] [-i bookmark|snapshot] "
|
"\tsend [-DnPpvLec] [-i bookmark|snapshot] "
|
||||||
"--redact <bookmark> <snapshot>\n"
|
"--redact <bookmark> <snapshot>\n"
|
||||||
@@ -728,32 +730,6 @@ finish_progress(char *done)
|
|||||||
pt_header = NULL;
|
pt_header = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function checks if the passed fd refers to /dev/null or /dev/zero */
|
|
||||||
#ifdef __linux__
|
|
||||||
static boolean_t
|
|
||||||
is_dev_nullzero(int fd)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
fstat(fd, &st);
|
|
||||||
return (major(st.st_rdev) == 1 && (minor(st.st_rdev) == 3 /* null */ ||
|
|
||||||
minor(st.st_rdev) == 5 /* zero */));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
|
||||||
note_dev_error(int err, int fd)
|
|
||||||
{
|
|
||||||
#ifdef __linux__
|
|
||||||
if (err == EINVAL && is_dev_nullzero(fd)) {
|
|
||||||
(void) fprintf(stderr,
|
|
||||||
gettext("Error: Writing directly to /dev/{null,zero} files"
|
|
||||||
" on certain kernels is not currently implemented.\n"
|
|
||||||
"(As a workaround, "
|
|
||||||
"try \"zfs send [...] | cat > /dev/null\")\n"));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type)
|
zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type)
|
||||||
{
|
{
|
||||||
@@ -916,107 +892,6 @@ usage:
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Return a default volblocksize for the pool which always uses more than
|
|
||||||
* half of the data sectors. This primarily applies to dRAID which always
|
|
||||||
* writes full stripe widths.
|
|
||||||
*/
|
|
||||||
static uint64_t
|
|
||||||
default_volblocksize(zpool_handle_t *zhp, nvlist_t *props)
|
|
||||||
{
|
|
||||||
uint64_t volblocksize, asize = SPA_MINBLOCKSIZE;
|
|
||||||
nvlist_t *tree, **vdevs;
|
|
||||||
uint_t nvdevs;
|
|
||||||
|
|
||||||
nvlist_t *config = zpool_get_config(zhp, NULL);
|
|
||||||
|
|
||||||
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) != 0 ||
|
|
||||||
nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN,
|
|
||||||
&vdevs, &nvdevs) != 0) {
|
|
||||||
return (ZVOL_DEFAULT_BLOCKSIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < nvdevs; i++) {
|
|
||||||
nvlist_t *nv = vdevs[i];
|
|
||||||
uint64_t ashift, ndata, nparity;
|
|
||||||
|
|
||||||
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ASHIFT, &ashift) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_DRAID_NDATA,
|
|
||||||
&ndata) == 0) {
|
|
||||||
/* dRAID minimum allocation width */
|
|
||||||
asize = MAX(asize, ndata * (1ULL << ashift));
|
|
||||||
} else if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
|
|
||||||
&nparity) == 0) {
|
|
||||||
/* raidz minimum allocation width */
|
|
||||||
if (nparity == 1)
|
|
||||||
asize = MAX(asize, 2 * (1ULL << ashift));
|
|
||||||
else
|
|
||||||
asize = MAX(asize, 4 * (1ULL << ashift));
|
|
||||||
} else {
|
|
||||||
/* mirror or (non-redundant) leaf vdev */
|
|
||||||
asize = MAX(asize, 1ULL << ashift);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate the target volblocksize such that more than half
|
|
||||||
* of the asize is used. The following table is for 4k sectors.
|
|
||||||
*
|
|
||||||
* n asize blksz used | n asize blksz used
|
|
||||||
* -------------------------+---------------------------------
|
|
||||||
* 1 4,096 8,192 100% | 9 36,864 32,768 88%
|
|
||||||
* 2 8,192 8,192 100% | 10 40,960 32,768 80%
|
|
||||||
* 3 12,288 8,192 66% | 11 45,056 32,768 72%
|
|
||||||
* 4 16,384 16,384 100% | 12 49,152 32,768 66%
|
|
||||||
* 5 20,480 16,384 80% | 13 53,248 32,768 61%
|
|
||||||
* 6 24,576 16,384 66% | 14 57,344 32,768 57%
|
|
||||||
* 7 28,672 16,384 57% | 15 61,440 32,768 53%
|
|
||||||
* 8 32,768 32,768 100% | 16 65,536 65,636 100%
|
|
||||||
*
|
|
||||||
* This is primarily a concern for dRAID which always allocates
|
|
||||||
* a full stripe width. For dRAID the default stripe width is
|
|
||||||
* n=8 in which case the volblocksize is set to 32k. Ignoring
|
|
||||||
* compression there are no unused sectors. This same reasoning
|
|
||||||
* applies to raidz[2,3] so target 4 sectors to minimize waste.
|
|
||||||
*/
|
|
||||||
uint64_t tgt_volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
|
|
||||||
while (tgt_volblocksize * 2 <= asize)
|
|
||||||
tgt_volblocksize *= 2;
|
|
||||||
|
|
||||||
const char *prop = zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE);
|
|
||||||
if (nvlist_lookup_uint64(props, prop, &volblocksize) == 0) {
|
|
||||||
|
|
||||||
/* Issue a warning when a non-optimal size is requested. */
|
|
||||||
if (volblocksize < ZVOL_DEFAULT_BLOCKSIZE) {
|
|
||||||
(void) fprintf(stderr, gettext("Warning: "
|
|
||||||
"volblocksize (%llu) is less than the default "
|
|
||||||
"minimum block size (%llu).\nTo reduce wasted "
|
|
||||||
"space a volblocksize of %llu is recommended.\n"),
|
|
||||||
(u_longlong_t)volblocksize,
|
|
||||||
(u_longlong_t)ZVOL_DEFAULT_BLOCKSIZE,
|
|
||||||
(u_longlong_t)tgt_volblocksize);
|
|
||||||
} else if (volblocksize < tgt_volblocksize) {
|
|
||||||
(void) fprintf(stderr, gettext("Warning: "
|
|
||||||
"volblocksize (%llu) is much less than the "
|
|
||||||
"minimum allocation\nunit (%llu), which wastes "
|
|
||||||
"at least %llu%% of space. To reduce wasted "
|
|
||||||
"space,\nuse a larger volblocksize (%llu is "
|
|
||||||
"recommended), fewer dRAID data disks\n"
|
|
||||||
"per group, or smaller sector size (ashift).\n"),
|
|
||||||
(u_longlong_t)volblocksize, (u_longlong_t)asize,
|
|
||||||
(u_longlong_t)((100 * (asize - volblocksize)) /
|
|
||||||
asize), (u_longlong_t)tgt_volblocksize);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
volblocksize = tgt_volblocksize;
|
|
||||||
fnvlist_add_uint64(props, prop, volblocksize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (volblocksize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* zfs create [-Pnpv] [-o prop=value] ... fs
|
* zfs create [-Pnpv] [-o prop=value] ... fs
|
||||||
* zfs create [-Pnpsv] [-b blocksize] [-o prop=value] ... -V vol size
|
* zfs create [-Pnpsv] [-b blocksize] [-o prop=value] ... -V vol size
|
||||||
@@ -1036,8 +911,6 @@ default_volblocksize(zpool_handle_t *zhp, nvlist_t *props)
|
|||||||
* check of arguments and properties, but does not check for permissions,
|
* check of arguments and properties, but does not check for permissions,
|
||||||
* available space, etc.
|
* available space, etc.
|
||||||
*
|
*
|
||||||
* The '-u' flag prevents the newly created file system from being mounted.
|
|
||||||
*
|
|
||||||
* The '-v' flag is for verbose output.
|
* The '-v' flag is for verbose output.
|
||||||
*
|
*
|
||||||
* The '-P' flag is used for parseable output. It implies '-v'.
|
* The '-P' flag is used for parseable output. It implies '-v'.
|
||||||
@@ -1054,19 +927,17 @@ zfs_do_create(int argc, char **argv)
|
|||||||
boolean_t bflag = B_FALSE;
|
boolean_t bflag = B_FALSE;
|
||||||
boolean_t parents = B_FALSE;
|
boolean_t parents = B_FALSE;
|
||||||
boolean_t dryrun = B_FALSE;
|
boolean_t dryrun = B_FALSE;
|
||||||
boolean_t nomount = B_FALSE;
|
|
||||||
boolean_t verbose = B_FALSE;
|
boolean_t verbose = B_FALSE;
|
||||||
boolean_t parseable = B_FALSE;
|
boolean_t parseable = B_FALSE;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
nvlist_t *props;
|
nvlist_t *props;
|
||||||
uint64_t intval;
|
uint64_t intval;
|
||||||
char *strval;
|
|
||||||
|
|
||||||
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
|
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
|
||||||
nomem();
|
nomem();
|
||||||
|
|
||||||
/* check options */
|
/* check options */
|
||||||
while ((c = getopt(argc, argv, ":PV:b:nso:puv")) != -1) {
|
while ((c = getopt(argc, argv, ":PV:b:nso:pv")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'V':
|
case 'V':
|
||||||
type = ZFS_TYPE_VOLUME;
|
type = ZFS_TYPE_VOLUME;
|
||||||
@@ -1113,9 +984,6 @@ zfs_do_create(int argc, char **argv)
|
|||||||
case 's':
|
case 's':
|
||||||
noreserve = B_TRUE;
|
noreserve = B_TRUE;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
|
||||||
nomount = B_TRUE;
|
|
||||||
break;
|
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = B_TRUE;
|
verbose = B_TRUE;
|
||||||
break;
|
break;
|
||||||
@@ -1135,11 +1003,6 @@ zfs_do_create(int argc, char **argv)
|
|||||||
"used when creating a volume\n"));
|
"used when creating a volume\n"));
|
||||||
goto badusage;
|
goto badusage;
|
||||||
}
|
}
|
||||||
if (nomount && type != ZFS_TYPE_FILESYSTEM) {
|
|
||||||
(void) fprintf(stderr, gettext("'-u' can only be "
|
|
||||||
"used when creating a filesystem\n"));
|
|
||||||
goto badusage;
|
|
||||||
}
|
|
||||||
|
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
@@ -1155,7 +1018,7 @@ zfs_do_create(int argc, char **argv)
|
|||||||
goto badusage;
|
goto badusage;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dryrun || type == ZFS_TYPE_VOLUME) {
|
if (dryrun || (type == ZFS_TYPE_VOLUME && !noreserve)) {
|
||||||
char msg[ZFS_MAX_DATASET_NAME_LEN * 2];
|
char msg[ZFS_MAX_DATASET_NAME_LEN * 2];
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
@@ -1177,24 +1040,18 @@ zfs_do_create(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if volsize is not a multiple of volblocksize, round it up to the
|
||||||
|
* nearest multiple of the volblocksize
|
||||||
|
*/
|
||||||
if (type == ZFS_TYPE_VOLUME) {
|
if (type == ZFS_TYPE_VOLUME) {
|
||||||
const char *prop = zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE);
|
uint64_t volblocksize;
|
||||||
uint64_t volblocksize = default_volblocksize(zpool_handle,
|
|
||||||
real_props);
|
|
||||||
|
|
||||||
if (volblocksize != ZVOL_DEFAULT_BLOCKSIZE &&
|
if (nvlist_lookup_uint64(props,
|
||||||
nvlist_lookup_string(props, prop, &strval) != 0) {
|
zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
|
||||||
if (asprintf(&strval, "%llu",
|
&volblocksize) != 0)
|
||||||
(u_longlong_t)volblocksize) == -1)
|
volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
|
||||||
nomem();
|
|
||||||
nvlist_add_string(props, prop, strval);
|
|
||||||
free(strval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If volsize is not a multiple of volblocksize, round it
|
|
||||||
* up to the nearest multiple of the volblocksize.
|
|
||||||
*/
|
|
||||||
if (volsize % volblocksize) {
|
if (volsize % volblocksize) {
|
||||||
volsize = P2ROUNDUP_TYPED(volsize, volblocksize,
|
volsize = P2ROUNDUP_TYPED(volsize, volblocksize,
|
||||||
uint64_t);
|
uint64_t);
|
||||||
@@ -1207,9 +1064,11 @@ zfs_do_create(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (type == ZFS_TYPE_VOLUME && !noreserve) {
|
if (type == ZFS_TYPE_VOLUME && !noreserve) {
|
||||||
uint64_t spa_version;
|
uint64_t spa_version;
|
||||||
zfs_prop_t resv_prop;
|
zfs_prop_t resv_prop;
|
||||||
|
char *strval;
|
||||||
|
|
||||||
spa_version = zpool_get_prop_int(zpool_handle,
|
spa_version = zpool_get_prop_int(zpool_handle,
|
||||||
ZPOOL_PROP_VERSION, NULL);
|
ZPOOL_PROP_VERSION, NULL);
|
||||||
@@ -1300,11 +1159,6 @@ zfs_do_create(int argc, char **argv)
|
|||||||
log_history = B_FALSE;
|
log_history = B_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nomount) {
|
|
||||||
ret = 0;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = zfs_mount_and_share(g_zfs, argv[0], ZFS_TYPE_DATASET);
|
ret = zfs_mount_and_share(g_zfs, argv[0], ZFS_TYPE_DATASET);
|
||||||
error:
|
error:
|
||||||
nvlist_free(props);
|
nvlist_free(props);
|
||||||
@@ -4402,7 +4256,6 @@ zfs_do_send(int argc, char **argv)
|
|||||||
|
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
{"replicate", no_argument, NULL, 'R'},
|
{"replicate", no_argument, NULL, 'R'},
|
||||||
{"skip-missing", no_argument, NULL, 's'},
|
|
||||||
{"redact", required_argument, NULL, 'd'},
|
{"redact", required_argument, NULL, 'd'},
|
||||||
{"props", no_argument, NULL, 'p'},
|
{"props", no_argument, NULL, 'p'},
|
||||||
{"parsable", no_argument, NULL, 'P'},
|
{"parsable", no_argument, NULL, 'P'},
|
||||||
@@ -4421,7 +4274,7 @@ zfs_do_send(int argc, char **argv)
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* check options */
|
/* check options */
|
||||||
while ((c = getopt_long(argc, argv, ":i:I:RsDpvnPLeht:cwbd:S",
|
while ((c = getopt_long(argc, argv, ":i:I:RDpvnPLeht:cwbd:S",
|
||||||
long_options, NULL)) != -1) {
|
long_options, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'i':
|
case 'i':
|
||||||
@@ -4438,9 +4291,6 @@ zfs_do_send(int argc, char **argv)
|
|||||||
case 'R':
|
case 'R':
|
||||||
flags.replicate = B_TRUE;
|
flags.replicate = B_TRUE;
|
||||||
break;
|
break;
|
||||||
case 's':
|
|
||||||
flags.skipmissing = B_TRUE;
|
|
||||||
break;
|
|
||||||
case 'd':
|
case 'd':
|
||||||
redactbook = optarg;
|
redactbook = optarg;
|
||||||
break;
|
break;
|
||||||
@@ -4598,23 +4448,11 @@ zfs_do_send(int argc, char **argv)
|
|||||||
|
|
||||||
err = zfs_send_saved(zhp, &flags, STDOUT_FILENO,
|
err = zfs_send_saved(zhp, &flags, STDOUT_FILENO,
|
||||||
resume_token);
|
resume_token);
|
||||||
if (err != 0)
|
|
||||||
note_dev_error(errno, STDOUT_FILENO);
|
|
||||||
zfs_close(zhp);
|
zfs_close(zhp);
|
||||||
return (err != 0);
|
return (err != 0);
|
||||||
} else if (resume_token != NULL) {
|
} else if (resume_token != NULL) {
|
||||||
err = zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
|
return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
|
||||||
resume_token);
|
resume_token));
|
||||||
if (err != 0)
|
|
||||||
note_dev_error(errno, STDOUT_FILENO);
|
|
||||||
return (err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags.skipmissing && !flags.replicate) {
|
|
||||||
(void) fprintf(stderr,
|
|
||||||
gettext("skip-missing flag can only be used in "
|
|
||||||
"conjunction with replicate\n"));
|
|
||||||
usage(B_FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -4658,8 +4496,6 @@ zfs_do_send(int argc, char **argv)
|
|||||||
err = zfs_send_one(zhp, fromname, STDOUT_FILENO, &flags,
|
err = zfs_send_one(zhp, fromname, STDOUT_FILENO, &flags,
|
||||||
redactbook);
|
redactbook);
|
||||||
zfs_close(zhp);
|
zfs_close(zhp);
|
||||||
if (err != 0)
|
|
||||||
note_dev_error(errno, STDOUT_FILENO);
|
|
||||||
return (err != 0);
|
return (err != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4736,7 +4572,6 @@ zfs_do_send(int argc, char **argv)
|
|||||||
nvlist_free(dbgnv);
|
nvlist_free(dbgnv);
|
||||||
}
|
}
|
||||||
zfs_close(zhp);
|
zfs_close(zhp);
|
||||||
note_dev_error(errno, STDOUT_FILENO);
|
|
||||||
|
|
||||||
return (err != 0);
|
return (err != 0);
|
||||||
}
|
}
|
||||||
@@ -6593,7 +6428,7 @@ zfs_do_holds(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* 1. collect holds data, set format options
|
* 1. collect holds data, set format options
|
||||||
*/
|
*/
|
||||||
ret = zfs_for_each(1, argv + i, flags, types, NULL, NULL, limit,
|
ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit,
|
||||||
holds_callback, &cb);
|
holds_callback, &cb);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
++errors;
|
++errors;
|
||||||
@@ -7475,7 +7310,6 @@ unshare_unmount(int op, int argc, char **argv)
|
|||||||
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
|
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
|
||||||
ZFS_CANMOUNT_NOAUTO)
|
ZFS_CANMOUNT_NOAUTO)
|
||||||
continue;
|
continue;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -7672,7 +7506,7 @@ zfs_do_diff(int argc, char **argv)
|
|||||||
int c;
|
int c;
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "FHth")) != -1) {
|
while ((c = getopt(argc, argv, "FHt")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'F':
|
case 'F':
|
||||||
flags |= ZFS_DIFF_CLASSIFY;
|
flags |= ZFS_DIFF_CLASSIFY;
|
||||||
@@ -7683,9 +7517,6 @@ zfs_do_diff(int argc, char **argv)
|
|||||||
case 't':
|
case 't':
|
||||||
flags |= ZFS_DIFF_TIMESTAMP;
|
flags |= ZFS_DIFF_TIMESTAMP;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
|
||||||
flags |= ZFS_DIFF_NO_MANGLE;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
(void) fprintf(stderr,
|
(void) fprintf(stderr,
|
||||||
gettext("invalid option '%c'\n"), optopt);
|
gettext("invalid option '%c'\n"), optopt);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ libzfs_handle_t *g_zfs;
|
|||||||
static void
|
static void
|
||||||
usage(int err)
|
usage(int err)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: zfs_ids_to_path [-v] <pool> <objset id> "
|
fprintf(stderr, "Usage: [-v] zfs_ids_to_path <pool> <objset id> "
|
||||||
"<object id>\n");
|
"<object id>\n");
|
||||||
exit(err);
|
exit(err);
|
||||||
}
|
}
|
||||||
@@ -63,11 +63,11 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
uint64_t objset, object;
|
uint64_t objset, object;
|
||||||
if (sscanf(argv[1], "%llu", (u_longlong_t *)&objset) != 1) {
|
if (sscanf(argv[1], "%llu", (u_longlong_t *)&objset) != 1) {
|
||||||
(void) fprintf(stderr, "Invalid objset id: %s\n", argv[1]);
|
(void) fprintf(stderr, "Invalid objset id: %s\n", argv[2]);
|
||||||
usage(2);
|
usage(2);
|
||||||
}
|
}
|
||||||
if (sscanf(argv[2], "%llu", (u_longlong_t *)&object) != 1) {
|
if (sscanf(argv[2], "%llu", (u_longlong_t *)&object) != 1) {
|
||||||
(void) fprintf(stderr, "Invalid object id: %s\n", argv[2]);
|
(void) fprintf(stderr, "Invalid object id: %s\n", argv[3]);
|
||||||
usage(3);
|
usage(3);
|
||||||
}
|
}
|
||||||
if ((g_zfs = libzfs_init()) == NULL) {
|
if ((g_zfs = libzfs_init()) == NULL) {
|
||||||
@@ -76,7 +76,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
zpool_handle_t *pool = zpool_open(g_zfs, argv[0]);
|
zpool_handle_t *pool = zpool_open(g_zfs, argv[0]);
|
||||||
if (pool == NULL) {
|
if (pool == NULL) {
|
||||||
fprintf(stderr, "Could not open pool %s\n", argv[0]);
|
fprintf(stderr, "Could not open pool %s\n", argv[1]);
|
||||||
libzfs_fini(g_zfs);
|
libzfs_fini(g_zfs);
|
||||||
return (5);
|
return (5);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static void usage(void);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
@@ -58,11 +60,12 @@ int
|
|||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
/* default file path, can be optionally set by user */
|
/* default file path, can be optionally set by user */
|
||||||
const char *path = "/etc/hostid";
|
char path[PATH_MAX] = "/etc/hostid";
|
||||||
/* holds converted user input or lrand48() generated value */
|
/* holds converted user input or lrand48() generated value */
|
||||||
unsigned long input_i = 0;
|
unsigned long input_i = 0;
|
||||||
|
|
||||||
int opt;
|
int opt;
|
||||||
|
int pathlen;
|
||||||
int force_fwrite = 0;
|
int force_fwrite = 0;
|
||||||
while ((opt = getopt_long(argc, argv, "fo:h?", 0, 0)) != -1) {
|
while ((opt = getopt_long(argc, argv, "fo:h?", 0, 0)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
@@ -70,7 +73,14 @@ main(int argc, char **argv)
|
|||||||
force_fwrite = 1;
|
force_fwrite = 1;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
path = optarg;
|
pathlen = snprintf(path, sizeof (path), "%s", optarg);
|
||||||
|
if (pathlen >= sizeof (path)) {
|
||||||
|
fprintf(stderr, "%s\n", strerror(EOVERFLOW));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else if (pathlen < 1) {
|
||||||
|
fprintf(stderr, "%s\n", strerror(EINVAL));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
@@ -108,7 +118,7 @@ main(int argc, char **argv)
|
|||||||
if (force_fwrite == 0 && stat(path, &fstat) == 0 &&
|
if (force_fwrite == 0 && stat(path, &fstat) == 0 &&
|
||||||
S_ISREG(fstat.st_mode)) {
|
S_ISREG(fstat.st_mode)) {
|
||||||
fprintf(stderr, "%s: %s\n", path, strerror(EEXIST));
|
fprintf(stderr, "%s: %s\n", path, strerror(EEXIST));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -127,7 +137,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we need just 4 bytes in native endianness
|
* we need just 4 bytes in native endianess
|
||||||
* not using sethostid() because it may be missing or just a stub
|
* not using sethostid() because it may be missing or just a stub
|
||||||
*/
|
*/
|
||||||
uint32_t hostid = input_i;
|
uint32_t hostid = input_i;
|
||||||
|
|||||||
+2
-53
@@ -1,5 +1,4 @@
|
|||||||
include $(top_srcdir)/config/Rules.am
|
include $(top_srcdir)/config/Rules.am
|
||||||
include $(top_srcdir)/config/Shellcheck.am
|
|
||||||
|
|
||||||
AM_CFLAGS += $(LIBBLKID_CFLAGS) $(LIBUUID_CFLAGS)
|
AM_CFLAGS += $(LIBBLKID_CFLAGS) $(LIBUUID_CFLAGS)
|
||||||
|
|
||||||
@@ -26,8 +25,7 @@ zpool_LDADD = \
|
|||||||
$(abs_top_builddir)/lib/libzfs/libzfs.la \
|
$(abs_top_builddir)/lib/libzfs/libzfs.la \
|
||||||
$(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \
|
$(abs_top_builddir)/lib/libzfs_core/libzfs_core.la \
|
||||||
$(abs_top_builddir)/lib/libnvpair/libnvpair.la \
|
$(abs_top_builddir)/lib/libnvpair/libnvpair.la \
|
||||||
$(abs_top_builddir)/lib/libuutil/libuutil.la \
|
$(abs_top_builddir)/lib/libuutil/libuutil.la
|
||||||
$(abs_top_builddir)/lib/libzutil/libzutil.la
|
|
||||||
|
|
||||||
zpool_LDADD += $(LTLIBINTL)
|
zpool_LDADD += $(LTLIBINTL)
|
||||||
|
|
||||||
@@ -41,7 +39,7 @@ include $(top_srcdir)/config/CppCheck.am
|
|||||||
zpoolconfdir = $(sysconfdir)/zfs/zpool.d
|
zpoolconfdir = $(sysconfdir)/zfs/zpool.d
|
||||||
zpoolexecdir = $(zfsexecdir)/zpool.d
|
zpoolexecdir = $(zfsexecdir)/zpool.d
|
||||||
|
|
||||||
EXTRA_DIST = zpool.d/README compatibility.d
|
EXTRA_DIST = zpool.d/README
|
||||||
|
|
||||||
dist_zpoolexec_SCRIPTS = \
|
dist_zpoolexec_SCRIPTS = \
|
||||||
zpool.d/dm-deps \
|
zpool.d/dm-deps \
|
||||||
@@ -131,52 +129,6 @@ zpoolconfdefaults = \
|
|||||||
test_progress \
|
test_progress \
|
||||||
test_ended
|
test_ended
|
||||||
|
|
||||||
zpoolcompatdir = $(pkgdatadir)/compatibility.d
|
|
||||||
|
|
||||||
dist_zpoolcompat_DATA = \
|
|
||||||
compatibility.d/compat-2018 \
|
|
||||||
compatibility.d/compat-2019 \
|
|
||||||
compatibility.d/compat-2020 \
|
|
||||||
compatibility.d/compat-2021 \
|
|
||||||
compatibility.d/freebsd-11.0 \
|
|
||||||
compatibility.d/freebsd-11.2 \
|
|
||||||
compatibility.d/freebsd-11.3 \
|
|
||||||
compatibility.d/freenas-9.10.2 \
|
|
||||||
compatibility.d/grub2 \
|
|
||||||
compatibility.d/openzfsonosx-1.7.0 \
|
|
||||||
compatibility.d/openzfsonosx-1.8.1 \
|
|
||||||
compatibility.d/openzfsonosx-1.9.3 \
|
|
||||||
compatibility.d/openzfs-2.0-freebsd \
|
|
||||||
compatibility.d/openzfs-2.0-linux \
|
|
||||||
compatibility.d/openzfs-2.1-freebsd \
|
|
||||||
compatibility.d/openzfs-2.1-linux \
|
|
||||||
compatibility.d/zol-0.6.1 \
|
|
||||||
compatibility.d/zol-0.6.4 \
|
|
||||||
compatibility.d/zol-0.6.5 \
|
|
||||||
compatibility.d/zol-0.7 \
|
|
||||||
compatibility.d/zol-0.8
|
|
||||||
|
|
||||||
# canonical <- alias symbolic link pairs
|
|
||||||
# eg: "2018" is a link to "compat-2018"
|
|
||||||
zpoolcompatlinks = \
|
|
||||||
"compat-2018 2018" \
|
|
||||||
"compat-2019 2019" \
|
|
||||||
"compat-2020 2020" \
|
|
||||||
"compat-2021 2021" \
|
|
||||||
"freebsd-11.0 freebsd-11.1" \
|
|
||||||
"freebsd-11.0 freenas-11.0" \
|
|
||||||
"freebsd-11.2 freenas-11.2" \
|
|
||||||
"freebsd-11.3 freebsd-11.4" \
|
|
||||||
"freebsd-11.3 freebsd-12.0" \
|
|
||||||
"freebsd-11.3 freebsd-12.1" \
|
|
||||||
"freebsd-11.3 freebsd-12.2" \
|
|
||||||
"freebsd-11.3 freenas-11.3" \
|
|
||||||
"freenas-11.0 freenas-11.1" \
|
|
||||||
"openzfsonosx-1.9.3 openzfsonosx-1.9.4" \
|
|
||||||
"openzfs-2.0-freebsd truenas-12.0" \
|
|
||||||
"zol-0.7 ubuntu-18.04" \
|
|
||||||
"zol-0.8 ubuntu-20.04"
|
|
||||||
|
|
||||||
install-data-hook:
|
install-data-hook:
|
||||||
$(MKDIR_P) "$(DESTDIR)$(zpoolconfdir)"
|
$(MKDIR_P) "$(DESTDIR)$(zpoolconfdir)"
|
||||||
for f in $(zpoolconfdefaults); do \
|
for f in $(zpoolconfdefaults); do \
|
||||||
@@ -184,6 +136,3 @@ install-data-hook:
|
|||||||
-L "$(DESTDIR)$(zpoolconfdir)/$${f}" || \
|
-L "$(DESTDIR)$(zpoolconfdir)/$${f}" || \
|
||||||
ln -s "$(zpoolexecdir)/$${f}" "$(DESTDIR)$(zpoolconfdir)"; \
|
ln -s "$(zpoolexecdir)/$${f}" "$(DESTDIR)$(zpoolconfdir)"; \
|
||||||
done
|
done
|
||||||
for l in $(zpoolcompatlinks); do \
|
|
||||||
(cd "$(DESTDIR)$(zpoolcompatdir)"; ln -sf $${l} ); \
|
|
||||||
done
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
# Features supported by all Tier 1 platforms as of 2018
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
spacemap_histogram
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Features supported by all Tier 1 platforms as of 2019
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Features supported by all Tier 1 platforms as of 2020
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Features supported by all Tier 1 platforms as of 2021
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
device_removal
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
spacemap_v2
|
|
||||||
zpool_checkpoint
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Features supported by FreeBSD 11.0
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Features supported by FreeBSD 11.2
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
device_removal
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
zpool_checkpoint
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Features supported by FreeBSD 11.3
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
device_removal
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
spacemap_v2
|
|
||||||
zpool_checkpoint
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# Features supported by FreeNAS 9.10.2
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
spacemap_histogram
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Features which are supported by GRUB2
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
spacemap_histogram
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# Features supported by OpenZFS 2.0 on FreeBSD
|
|
||||||
allocation_classes
|
|
||||||
async_destroy
|
|
||||||
bookmark_v2
|
|
||||||
bookmark_written
|
|
||||||
bookmarks
|
|
||||||
device_rebuild
|
|
||||||
device_removal
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
encryption
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
large_dnode
|
|
||||||
livelist
|
|
||||||
log_spacemap
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
project_quota
|
|
||||||
redacted_datasets
|
|
||||||
redaction_bookmarks
|
|
||||||
resilver_defer
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
spacemap_v2
|
|
||||||
userobj_accounting
|
|
||||||
zpool_checkpoint
|
|
||||||
zstd_compress
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# Features supported by OpenZFS 2.0 on Linux
|
|
||||||
allocation_classes
|
|
||||||
async_destroy
|
|
||||||
bookmark_v2
|
|
||||||
bookmark_written
|
|
||||||
bookmarks
|
|
||||||
device_rebuild
|
|
||||||
device_removal
|
|
||||||
edonr
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
encryption
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
large_dnode
|
|
||||||
livelist
|
|
||||||
log_spacemap
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
project_quota
|
|
||||||
redacted_datasets
|
|
||||||
redaction_bookmarks
|
|
||||||
resilver_defer
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
spacemap_v2
|
|
||||||
userobj_accounting
|
|
||||||
zpool_checkpoint
|
|
||||||
zstd_compress
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# Features supported by OpenZFS 2.1 on FreeBSD
|
|
||||||
allocation_classes
|
|
||||||
async_destroy
|
|
||||||
bookmark_v2
|
|
||||||
bookmark_written
|
|
||||||
bookmarks
|
|
||||||
device_rebuild
|
|
||||||
device_removal
|
|
||||||
draid
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
encryption
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
large_dnode
|
|
||||||
livelist
|
|
||||||
log_spacemap
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
project_quota
|
|
||||||
redacted_datasets
|
|
||||||
redaction_bookmarks
|
|
||||||
resilver_defer
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
spacemap_v2
|
|
||||||
userobj_accounting
|
|
||||||
zpool_checkpoint
|
|
||||||
zstd_compress
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# Features supported by OpenZFS 2.1 on Linux
|
|
||||||
allocation_classes
|
|
||||||
async_destroy
|
|
||||||
bookmark_v2
|
|
||||||
bookmark_written
|
|
||||||
bookmarks
|
|
||||||
device_rebuild
|
|
||||||
device_removal
|
|
||||||
draid
|
|
||||||
edonr
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
encryption
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
large_dnode
|
|
||||||
livelist
|
|
||||||
log_spacemap
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
project_quota
|
|
||||||
redacted_datasets
|
|
||||||
redaction_bookmarks
|
|
||||||
resilver_defer
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
spacemap_v2
|
|
||||||
userobj_accounting
|
|
||||||
zpool_checkpoint
|
|
||||||
zstd_compress
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Features supported by OpenZFSonOSX 1.7.0
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
edonr
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Features supported by OpenZFSonOSX 1.8.1
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
device_removal
|
|
||||||
edonr
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
encryption
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
spacemap_v2
|
|
||||||
zpool_checkpoint
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Features supported by OpenZFSonOSX 1.9.3
|
|
||||||
allocation_classes
|
|
||||||
async_destroy
|
|
||||||
bookmark_v2
|
|
||||||
bookmarks
|
|
||||||
device_removal
|
|
||||||
edonr
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
encryption
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
large_dnode
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
project_quota
|
|
||||||
resilver_defer
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
spacemap_v2
|
|
||||||
userobj_accounting
|
|
||||||
zpool_checkpoint
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# Features supported by ZFSonLinux v0.6.1
|
|
||||||
async_destroy
|
|
||||||
empty_bpobj
|
|
||||||
lz4_compress
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# Features supported by ZFSonLinux v0.6.4
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
hole_birth
|
|
||||||
lz4_compress
|
|
||||||
spacemap_histogram
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Features supported by ZFSonLinux v0.6.5
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
lz4_compress
|
|
||||||
spacemap_histogram
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Features supported by ZFSonLinux v0.7
|
|
||||||
async_destroy
|
|
||||||
bookmarks
|
|
||||||
edonr
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
large_dnode
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
userobj_accounting
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Features supported by ZFSonLinux v0.8
|
|
||||||
allocation_classes
|
|
||||||
async_destroy
|
|
||||||
bookmark_v2
|
|
||||||
bookmarks
|
|
||||||
device_removal
|
|
||||||
edonr
|
|
||||||
embedded_data
|
|
||||||
empty_bpobj
|
|
||||||
enabled_txg
|
|
||||||
encryption
|
|
||||||
extensible_dataset
|
|
||||||
filesystem_limits
|
|
||||||
hole_birth
|
|
||||||
large_blocks
|
|
||||||
large_dnode
|
|
||||||
lz4_compress
|
|
||||||
multi_vdev_crash_dump
|
|
||||||
obsolete_counts
|
|
||||||
project_quota
|
|
||||||
resilver_defer
|
|
||||||
sha512
|
|
||||||
skein
|
|
||||||
spacemap_histogram
|
|
||||||
spacemap_v2
|
|
||||||
userobj_accounting
|
|
||||||
zpool_checkpoint
|
|
||||||
@@ -101,18 +101,3 @@ check_sector_size_database(char *path, int *sector_size)
|
|||||||
{
|
{
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
after_zpool_upgrade(zpool_handle_t *zhp)
|
|
||||||
{
|
|
||||||
char bootfs[ZPOOL_MAXPROPLEN];
|
|
||||||
|
|
||||||
if (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
|
|
||||||
sizeof (bootfs), NULL, B_FALSE) == 0 &&
|
|
||||||
strcmp(bootfs, "-") != 0) {
|
|
||||||
(void) printf(gettext("Pool '%s' has the bootfs "
|
|
||||||
"property set, you might need to update\nthe boot "
|
|
||||||
"code. See gptzfsboot(8) and loader.efi(8) for "
|
|
||||||
"details.\n"), zpool_get_name(zhp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -79,6 +79,9 @@
|
|||||||
|
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
#include <scsi/sg.h>
|
#include <scsi/sg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/efi_partition.h>
|
#include <sys/efi_partition.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/vtoc.h>
|
#include <sys/vtoc.h>
|
||||||
@@ -405,8 +408,3 @@ check_device(const char *path, boolean_t force,
|
|||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
after_zpool_upgrade(zpool_handle_t *zhp)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,12 +16,14 @@ if [ -L "$dev" ] ; then
|
|||||||
dev=$(readlink "$dev")
|
dev=$(readlink "$dev")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dev="${dev##*/}"
|
dev=$(basename "$dev")
|
||||||
val=""
|
val=""
|
||||||
if [ -d "/sys/class/block/$dev/slaves" ] ; then
|
if [ -d "/sys/class/block/$dev/slaves" ] ; then
|
||||||
# ls -C: output in columns, no newlines, two spaces (change to one)
|
# ls -C: output in columns, no newlines
|
||||||
# shellcheck disable=SC2012
|
val=$(ls -C "/sys/class/block/$dev/slaves")
|
||||||
val=$(ls -C "/sys/class/block/$dev/slaves" | tr -s '[:space:]' ' ')
|
|
||||||
|
# ls -C will print two spaces between files; change to one space.
|
||||||
|
val=$(echo "$val" | sed -r 's/[[:blank:]]+/ /g')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "dm-deps=$val"
|
echo "dm-deps=$val"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ iostat: Show iostat values since boot (summary page).
|
|||||||
iostat-1s: Do a single 1-second iostat sample and show values.
|
iostat-1s: Do a single 1-second iostat sample and show values.
|
||||||
iostat-10s: Do a single 10-second iostat sample and show values."
|
iostat-10s: Do a single 10-second iostat sample and show values."
|
||||||
|
|
||||||
script="${0##*/}"
|
script=$(basename "$0")
|
||||||
if [ "$1" = "-h" ] ; then
|
if [ "$1" = "-h" ] ; then
|
||||||
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
||||||
exit
|
exit
|
||||||
@@ -42,7 +42,7 @@ else
|
|||||||
${brief:+"-y"} \
|
${brief:+"-y"} \
|
||||||
${interval:+"$interval"} \
|
${interval:+"$interval"} \
|
||||||
${interval:+"1"} \
|
${interval:+"1"} \
|
||||||
"$VDEV_UPATH" | grep -v '^$' | tail -n 2)
|
"$VDEV_UPATH" | awk NF | tail -n 2)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ fi
|
|||||||
cols=$(echo "$out" | head -n 1)
|
cols=$(echo "$out" | head -n 1)
|
||||||
|
|
||||||
# Get the values and tab separate them to make them cut-able.
|
# Get the values and tab separate them to make them cut-able.
|
||||||
vals=$(echo "$out" | tail -n 1 | tr -s '[:space:]' '\t')
|
vals=$(echo "$out" | tail -n 1 | sed -r 's/[[:blank:]]+/\t/g')
|
||||||
|
|
||||||
i=0
|
i=0
|
||||||
for col in $cols ; do
|
for col in $cols ; do
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ size: Show the disk capacity.
|
|||||||
vendor: Show the disk vendor.
|
vendor: Show the disk vendor.
|
||||||
lsblk: Show the disk size, vendor, and model number."
|
lsblk: Show the disk size, vendor, and model number."
|
||||||
|
|
||||||
script="${0##*/}"
|
script=$(basename "$0")
|
||||||
|
|
||||||
if [ "$1" = "-h" ] ; then
|
if [ "$1" = "-h" ] ; then
|
||||||
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
||||||
|
|||||||
+8
-12
@@ -4,23 +4,19 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
if [ "$1" = "-h" ] ; then
|
if [ "$1" = "-h" ] ; then
|
||||||
echo "Show whether a vdev is a file, hdd, ssd, or iscsi."
|
echo "Show whether a vdev is a file, hdd, or ssd."
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -b "$VDEV_UPATH" ]; then
|
if [ -b "$VDEV_UPATH" ]; then
|
||||||
device="${VDEV_UPATH##*/}"
|
device=$(basename "$VDEV_UPATH")
|
||||||
read -r val 2>/dev/null < "/sys/block/$device/queue/rotational"
|
val=$(cat "/sys/block/$device/queue/rotational" 2>/dev/null)
|
||||||
case "$val" in
|
if [ "$val" = "0" ]; then
|
||||||
0) MEDIA="ssd" ;;
|
MEDIA="ssd"
|
||||||
1) MEDIA="hdd" ;;
|
fi
|
||||||
esac
|
|
||||||
|
|
||||||
vpd_pg83="/sys/block/$device/device/vpd_pg83"
|
if [ "$val" = "1" ]; then
|
||||||
if [ -f "$vpd_pg83" ]; then
|
MEDIA="hdd"
|
||||||
if grep -q --binary "iqn." "$vpd_pg83"; then
|
|
||||||
MEDIA="iscsi"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [ -f "$VDEV_UPATH" ]; then
|
if [ -f "$VDEV_UPATH" ]; then
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ fault_led: Show value of the disk enclosure slot fault LED.
|
|||||||
locate_led: Show value of the disk enclosure slot locate LED.
|
locate_led: Show value of the disk enclosure slot locate LED.
|
||||||
ses: Show disk's enc, enc device, slot, and fault/locate LED values."
|
ses: Show disk's enc, enc device, slot, and fault/locate LED values."
|
||||||
|
|
||||||
script="${0##*/}"
|
script=$(basename "$0")
|
||||||
if [ "$1" = "-h" ] ; then
|
if [ "$1" = "-h" ] ; then
|
||||||
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
||||||
exit
|
exit
|
||||||
@@ -41,13 +41,7 @@ for i in $scripts ; do
|
|||||||
val=$(ls "$VDEV_ENC_SYSFS_PATH/../device/scsi_generic" 2>/dev/null)
|
val=$(ls "$VDEV_ENC_SYSFS_PATH/../device/scsi_generic" 2>/dev/null)
|
||||||
;;
|
;;
|
||||||
fault_led)
|
fault_led)
|
||||||
# JBODs fault LED is called 'fault', NVMe fault LED is called
|
val=$(cat "$VDEV_ENC_SYSFS_PATH/fault" 2>/dev/null)
|
||||||
# 'attention'.
|
|
||||||
if [ -f "$VDEV_ENC_SYSFS_PATH/fault" ] ; then
|
|
||||||
val=$(cat "$VDEV_ENC_SYSFS_PATH/fault" 2>/dev/null)
|
|
||||||
elif [ -f "$VDEV_ENC_SYSFS_PATH/attention" ] ; then
|
|
||||||
val=$(cat "$VDEV_ENC_SYSFS_PATH/attention" 2>/dev/null)
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
locate_led)
|
locate_led)
|
||||||
val=$(cat "$VDEV_ENC_SYSFS_PATH/locate" 2>/dev/null)
|
val=$(cat "$VDEV_ENC_SYSFS_PATH/locate" 2>/dev/null)
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ get_filename_from_dir()
|
|||||||
num_files=$(find "$dir" -maxdepth 1 -type f | wc -l)
|
num_files=$(find "$dir" -maxdepth 1 -type f | wc -l)
|
||||||
mod=$((pid % num_files))
|
mod=$((pid % num_files))
|
||||||
i=0
|
i=0
|
||||||
find "$dir" -type f -printf '%f\n' | while read -r file ; do
|
find "$dir" -type f -printf "%f\n" | while read -r file ; do
|
||||||
if [ "$mod" = "$i" ] ; then
|
if [ "$mod" = "$i" ] ; then
|
||||||
echo "$file"
|
echo "$file"
|
||||||
break
|
break
|
||||||
@@ -62,14 +62,17 @@ get_filename_from_dir()
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
script="${0##*/}"
|
script=$(basename "$0")
|
||||||
|
|
||||||
if [ "$1" = "-h" ] ; then
|
if [ "$1" = "-h" ] ; then
|
||||||
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -b "$VDEV_UPATH" ] && PATH="/usr/sbin:$PATH" command -v smartctl > /dev/null || [ -n "$samples" ] ; then
|
smartctl_path=$(command -v smartctl)
|
||||||
|
|
||||||
|
# shellcheck disable=SC2015
|
||||||
|
if [ -b "$VDEV_UPATH" ] && [ -x "$smartctl_path" ] || [ -n "$samples" ] ; then
|
||||||
if [ -n "$samples" ] ; then
|
if [ -n "$samples" ] ; then
|
||||||
# cat a smartctl output text file instead of running smartctl
|
# cat a smartctl output text file instead of running smartctl
|
||||||
# on a vdev (only used for developer testing).
|
# on a vdev (only used for developer testing).
|
||||||
@@ -77,7 +80,7 @@ if [ -b "$VDEV_UPATH" ] && PATH="/usr/sbin:$PATH" command -v smartctl > /dev/nul
|
|||||||
echo "file=$file"
|
echo "file=$file"
|
||||||
raw_out=$(cat "$samples/$file")
|
raw_out=$(cat "$samples/$file")
|
||||||
else
|
else
|
||||||
raw_out=$(sudo smartctl -a "$VDEV_UPATH")
|
raw_out=$(eval "sudo $smartctl_path -a $VDEV_UPATH")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# What kind of drive are we? Look for the right line in smartctl:
|
# What kind of drive are we? Look for the right line in smartctl:
|
||||||
@@ -228,11 +231,11 @@ esac
|
|||||||
with_vals=$(echo "$out" | grep -E "$scripts")
|
with_vals=$(echo "$out" | grep -E "$scripts")
|
||||||
if [ -n "$with_vals" ]; then
|
if [ -n "$with_vals" ]; then
|
||||||
echo "$with_vals"
|
echo "$with_vals"
|
||||||
without_vals=$(echo "$scripts" | tr '|' '\n' |
|
without_vals=$(echo "$scripts" | tr "|" "\n" |
|
||||||
grep -v -E "$(echo "$with_vals" |
|
grep -v -E "$(echo "$with_vals" |
|
||||||
awk -F "=" '{print $1}')" | awk '{print $0"="}')
|
awk -F "=" '{print $1}')" | awk '{print $0"="}')
|
||||||
else
|
else
|
||||||
without_vals=$(echo "$scripts" | tr '|' '\n' | awk '{print $0"="}')
|
without_vals=$(echo "$scripts" | tr "|" "\n" | awk '{print $0"="}')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$without_vals" ]; then
|
if [ -n "$without_vals" ]; then
|
||||||
|
|||||||
+52
-13
@@ -264,6 +264,51 @@ for_each_pool(int argc, char **argv, boolean_t unavail,
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
for_each_vdev_cb(zpool_handle_t *zhp, nvlist_t *nv, pool_vdev_iter_f func,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
nvlist_t **child;
|
||||||
|
uint_t c, children;
|
||||||
|
int ret = 0;
|
||||||
|
int i;
|
||||||
|
char *type;
|
||||||
|
|
||||||
|
const char *list[] = {
|
||||||
|
ZPOOL_CONFIG_SPARES,
|
||||||
|
ZPOOL_CONFIG_L2CACHE,
|
||||||
|
ZPOOL_CONFIG_CHILDREN
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(list); i++) {
|
||||||
|
if (nvlist_lookup_nvlist_array(nv, list[i], &child,
|
||||||
|
&children) == 0) {
|
||||||
|
for (c = 0; c < children; c++) {
|
||||||
|
uint64_t ishole = 0;
|
||||||
|
|
||||||
|
(void) nvlist_lookup_uint64(child[c],
|
||||||
|
ZPOOL_CONFIG_IS_HOLE, &ishole);
|
||||||
|
|
||||||
|
if (ishole)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret |= for_each_vdev_cb(zhp, child[c], func,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
|
||||||
|
return (ret);
|
||||||
|
|
||||||
|
/* Don't run our function on root vdevs */
|
||||||
|
if (strcmp(type, VDEV_TYPE_ROOT) != 0) {
|
||||||
|
ret |= func(zhp, nv, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the equivalent of for_each_pool() for vdevs. It iterates thorough
|
* This is the equivalent of for_each_pool() for vdevs. It iterates thorough
|
||||||
* all vdevs in the pool, ignoring root vdevs and holes, calling func() on
|
* all vdevs in the pool, ignoring root vdevs and holes, calling func() on
|
||||||
@@ -282,7 +327,7 @@ for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data)
|
|||||||
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||||
&nvroot) == 0);
|
&nvroot) == 0);
|
||||||
}
|
}
|
||||||
return (for_each_vdev_cb((void *) zhp, nvroot, func, data));
|
return (for_each_vdev_cb(zhp, nvroot, func, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -449,25 +494,19 @@ vdev_run_cmd(vdev_cmd_data_t *data, char *cmd)
|
|||||||
/* Setup our custom environment variables */
|
/* Setup our custom environment variables */
|
||||||
rc = asprintf(&env[1], "VDEV_PATH=%s",
|
rc = asprintf(&env[1], "VDEV_PATH=%s",
|
||||||
data->path ? data->path : "");
|
data->path ? data->path : "");
|
||||||
if (rc == -1) {
|
if (rc == -1)
|
||||||
env[1] = NULL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
rc = asprintf(&env[2], "VDEV_UPATH=%s",
|
rc = asprintf(&env[2], "VDEV_UPATH=%s",
|
||||||
data->upath ? data->upath : "");
|
data->upath ? data->upath : "");
|
||||||
if (rc == -1) {
|
if (rc == -1)
|
||||||
env[2] = NULL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
rc = asprintf(&env[3], "VDEV_ENC_SYSFS_PATH=%s",
|
rc = asprintf(&env[3], "VDEV_ENC_SYSFS_PATH=%s",
|
||||||
data->vdev_enc_sysfs_path ?
|
data->vdev_enc_sysfs_path ?
|
||||||
data->vdev_enc_sysfs_path : "");
|
data->vdev_enc_sysfs_path : "");
|
||||||
if (rc == -1) {
|
if (rc == -1)
|
||||||
env[3] = NULL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
/* Run the command */
|
/* Run the command */
|
||||||
rc = libzfs_run_process_get_stdout_nopath(cmd, argv, env, &lines,
|
rc = libzfs_run_process_get_stdout_nopath(cmd, argv, env, &lines,
|
||||||
@@ -486,7 +525,8 @@ out:
|
|||||||
|
|
||||||
/* Start with i = 1 since env[0] was statically allocated */
|
/* Start with i = 1 since env[0] was statically allocated */
|
||||||
for (i = 1; i < ARRAY_SIZE(env); i++)
|
for (i = 1; i < ARRAY_SIZE(env); i++)
|
||||||
free(env[i]);
|
if (env[i] != NULL)
|
||||||
|
free(env[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -558,7 +598,7 @@ vdev_run_cmd_thread(void *cb_cmd_data)
|
|||||||
|
|
||||||
/* For each vdev in the pool run a command */
|
/* For each vdev in the pool run a command */
|
||||||
static int
|
static int
|
||||||
for_each_vdev_run_cb(void *zhp_data, nvlist_t *nv, void *cb_vcdl)
|
for_each_vdev_run_cb(zpool_handle_t *zhp, nvlist_t *nv, void *cb_vcdl)
|
||||||
{
|
{
|
||||||
vdev_cmd_data_list_t *vcdl = cb_vcdl;
|
vdev_cmd_data_list_t *vcdl = cb_vcdl;
|
||||||
vdev_cmd_data_t *data;
|
vdev_cmd_data_t *data;
|
||||||
@@ -566,7 +606,6 @@ for_each_vdev_run_cb(void *zhp_data, nvlist_t *nv, void *cb_vcdl)
|
|||||||
char *vname = NULL;
|
char *vname = NULL;
|
||||||
char *vdev_enc_sysfs_path = NULL;
|
char *vdev_enc_sysfs_path = NULL;
|
||||||
int i, match = 0;
|
int i, match = 0;
|
||||||
zpool_handle_t *zhp = zhp_data;
|
|
||||||
|
|
||||||
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
|
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
|
||||||
return (1);
|
return (1);
|
||||||
|
|||||||
+56
-338
@@ -31,8 +31,6 @@
|
|||||||
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
|
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
|
||||||
* Copyright (c) 2017, Intel Corporation.
|
* Copyright (c) 2017, Intel Corporation.
|
||||||
* Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com>
|
* Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com>
|
||||||
* Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
|
|
||||||
* Copyright [2021] Hewlett Packard Enterprise Development LP
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@@ -126,9 +124,6 @@ static int zpool_do_version(int, char **);
|
|||||||
|
|
||||||
static int zpool_do_wait(int, char **);
|
static int zpool_do_wait(int, char **);
|
||||||
|
|
||||||
static zpool_compat_status_t zpool_do_load_compat(
|
|
||||||
const char *, boolean_t *);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These libumem hooks provide a reasonable set of defaults for the allocator's
|
* These libumem hooks provide a reasonable set of defaults for the allocator's
|
||||||
* debugging facilities.
|
* debugging facilities.
|
||||||
@@ -533,7 +528,7 @@ usage(boolean_t requested)
|
|||||||
(void) fprintf(fp, "YES disabled | enabled | active\n");
|
(void) fprintf(fp, "YES disabled | enabled | active\n");
|
||||||
|
|
||||||
(void) fprintf(fp, gettext("\nThe feature@ properties must be "
|
(void) fprintf(fp, gettext("\nThe feature@ properties must be "
|
||||||
"appended with a feature name.\nSee zpool-features(7).\n"));
|
"appended with a feature name.\nSee zpool-features(5).\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -787,8 +782,6 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props,
|
|||||||
|
|
||||||
if (poolprop) {
|
if (poolprop) {
|
||||||
const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
|
const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
|
||||||
const char *cname =
|
|
||||||
zpool_prop_to_name(ZPOOL_PROP_COMPATIBILITY);
|
|
||||||
|
|
||||||
if ((prop = zpool_name_to_prop(propname)) == ZPOOL_PROP_INVAL &&
|
if ((prop = zpool_name_to_prop(propname)) == ZPOOL_PROP_INVAL &&
|
||||||
!zpool_prop_feature(propname)) {
|
!zpool_prop_feature(propname)) {
|
||||||
@@ -811,22 +804,6 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props,
|
|||||||
return (2);
|
return (2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* if version is specified, only "legacy" compatibility
|
|
||||||
* may be requested
|
|
||||||
*/
|
|
||||||
if ((prop == ZPOOL_PROP_COMPATIBILITY &&
|
|
||||||
strcmp(propval, ZPOOL_COMPAT_LEGACY) != 0 &&
|
|
||||||
nvlist_exists(proplist, vname)) ||
|
|
||||||
(prop == ZPOOL_PROP_VERSION &&
|
|
||||||
nvlist_exists(proplist, cname) &&
|
|
||||||
strcmp(fnvlist_lookup_string(proplist, cname),
|
|
||||||
ZPOOL_COMPAT_LEGACY) != 0)) {
|
|
||||||
(void) fprintf(stderr, gettext("when 'version' is "
|
|
||||||
"specified, the 'compatibility' feature may only "
|
|
||||||
"be set to '" ZPOOL_COMPAT_LEGACY "'\n"));
|
|
||||||
return (2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zpool_prop_feature(propname))
|
if (zpool_prop_feature(propname))
|
||||||
normnm = propname;
|
normnm = propname;
|
||||||
@@ -1069,7 +1046,7 @@ zpool_do_add(int argc, char **argv)
|
|||||||
free(vname);
|
free(vname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* And finally the spares */
|
/* And finaly the spares */
|
||||||
if (nvlist_lookup_nvlist_array(poolnvroot, ZPOOL_CONFIG_SPARES,
|
if (nvlist_lookup_nvlist_array(poolnvroot, ZPOOL_CONFIG_SPARES,
|
||||||
&sparechild, &sparechildren) == 0 && sparechildren > 0) {
|
&sparechild, &sparechildren) == 0 && sparechildren > 0) {
|
||||||
hadspare = B_TRUE;
|
hadspare = B_TRUE;
|
||||||
@@ -1215,26 +1192,6 @@ zpool_do_remove(int argc, char **argv)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Return 1 if a vdev is active (being used in a pool)
|
|
||||||
* Return 0 if a vdev is inactive (offlined or faulted, or not in active pool)
|
|
||||||
*
|
|
||||||
* This is useful for checking if a disk in an active pool is offlined or
|
|
||||||
* faulted.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
vdev_is_active(char *vdev_path)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
fd = open(vdev_path, O_EXCL);
|
|
||||||
if (fd < 0) {
|
|
||||||
return (1); /* cant open O_EXCL - disk is active */
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
return (0); /* disk is inactive in the pool */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* zpool labelclear [-f] <vdev>
|
* zpool labelclear [-f] <vdev>
|
||||||
*
|
*
|
||||||
@@ -1344,23 +1301,9 @@ zpool_do_labelclear(int argc, char **argv)
|
|||||||
case POOL_STATE_ACTIVE:
|
case POOL_STATE_ACTIVE:
|
||||||
case POOL_STATE_SPARE:
|
case POOL_STATE_SPARE:
|
||||||
case POOL_STATE_L2CACHE:
|
case POOL_STATE_L2CACHE:
|
||||||
/*
|
|
||||||
* We allow the user to call 'zpool offline -f'
|
|
||||||
* on an offlined disk in an active pool. We can check if
|
|
||||||
* the disk is online by calling vdev_is_active().
|
|
||||||
*/
|
|
||||||
if (force && !vdev_is_active(vdev))
|
|
||||||
break;
|
|
||||||
|
|
||||||
(void) fprintf(stderr, gettext(
|
(void) fprintf(stderr, gettext(
|
||||||
"%s is a member (%s) of pool \"%s\""),
|
"%s is a member (%s) of pool \"%s\"\n"),
|
||||||
vdev, zpool_pool_state_to_name(state), name);
|
vdev, zpool_pool_state_to_name(state), name);
|
||||||
|
|
||||||
if (force) {
|
|
||||||
(void) fprintf(stderr, gettext(
|
|
||||||
". Offline the disk first to clear its label."));
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
@@ -1431,15 +1374,13 @@ zpool_do_create(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
boolean_t force = B_FALSE;
|
boolean_t force = B_FALSE;
|
||||||
boolean_t dryrun = B_FALSE;
|
boolean_t dryrun = B_FALSE;
|
||||||
boolean_t enable_pool_features = B_TRUE;
|
boolean_t enable_all_pool_feat = B_TRUE;
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
nvlist_t *nvroot = NULL;
|
nvlist_t *nvroot = NULL;
|
||||||
char *poolname;
|
char *poolname;
|
||||||
char *tname = NULL;
|
char *tname = NULL;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
char *altroot = NULL;
|
char *altroot = NULL;
|
||||||
char *compat = NULL;
|
|
||||||
char *mountpoint = NULL;
|
char *mountpoint = NULL;
|
||||||
nvlist_t *fsprops = NULL;
|
nvlist_t *fsprops = NULL;
|
||||||
nvlist_t *props = NULL;
|
nvlist_t *props = NULL;
|
||||||
@@ -1455,7 +1396,7 @@ zpool_do_create(int argc, char **argv)
|
|||||||
dryrun = B_TRUE;
|
dryrun = B_TRUE;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
enable_pool_features = B_FALSE;
|
enable_all_pool_feat = B_FALSE;
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
altroot = optarg;
|
altroot = optarg;
|
||||||
@@ -1493,14 +1434,11 @@ zpool_do_create(int argc, char **argv)
|
|||||||
ver = strtoull(propval, &end, 10);
|
ver = strtoull(propval, &end, 10);
|
||||||
if (*end == '\0' &&
|
if (*end == '\0' &&
|
||||||
ver < SPA_VERSION_FEATURES) {
|
ver < SPA_VERSION_FEATURES) {
|
||||||
enable_pool_features = B_FALSE;
|
enable_all_pool_feat = B_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT)
|
if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT)
|
||||||
altroot = propval;
|
altroot = propval;
|
||||||
if (zpool_name_to_prop(optarg) ==
|
|
||||||
ZPOOL_PROP_COMPATIBILITY)
|
|
||||||
compat = propval;
|
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
if ((propval = strchr(optarg, '=')) == NULL) {
|
if ((propval = strchr(optarg, '=')) == NULL) {
|
||||||
@@ -1694,27 +1632,10 @@ zpool_do_create(int argc, char **argv)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Load in feature set.
|
* Hand off to libzfs.
|
||||||
* Note: if compatibility property not given, we'll have
|
|
||||||
* NULL, which means 'all features'.
|
|
||||||
*/
|
*/
|
||||||
boolean_t requested_features[SPA_FEATURES];
|
spa_feature_t i;
|
||||||
if (zpool_do_load_compat(compat, requested_features) !=
|
for (i = 0; i < SPA_FEATURES; i++) {
|
||||||
ZPOOL_COMPATIBILITY_OK)
|
|
||||||
goto errout;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* props contains list of features to enable.
|
|
||||||
* For each feature:
|
|
||||||
* - remove it if feature@name=disabled
|
|
||||||
* - leave it there if feature@name=enabled
|
|
||||||
* - add it if:
|
|
||||||
* - enable_pool_features (ie: no '-d' or '-o version')
|
|
||||||
* - it's supported by the kernel module
|
|
||||||
* - it's in the requested feature set
|
|
||||||
* - warn if it's enabled but not in compat
|
|
||||||
*/
|
|
||||||
for (spa_feature_t i = 0; i < SPA_FEATURES; i++) {
|
|
||||||
char propname[MAXPATHLEN];
|
char propname[MAXPATHLEN];
|
||||||
char *propval;
|
char *propval;
|
||||||
zfeature_info_t *feat = &spa_feature_table[i];
|
zfeature_info_t *feat = &spa_feature_table[i];
|
||||||
@@ -1722,22 +1643,17 @@ zpool_do_create(int argc, char **argv)
|
|||||||
(void) snprintf(propname, sizeof (propname),
|
(void) snprintf(propname, sizeof (propname),
|
||||||
"feature@%s", feat->fi_uname);
|
"feature@%s", feat->fi_uname);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only features contained in props will be enabled:
|
||||||
|
* remove from the nvlist every ZFS_FEATURE_DISABLED
|
||||||
|
* value and add every missing ZFS_FEATURE_ENABLED if
|
||||||
|
* enable_all_pool_feat is set.
|
||||||
|
*/
|
||||||
if (!nvlist_lookup_string(props, propname, &propval)) {
|
if (!nvlist_lookup_string(props, propname, &propval)) {
|
||||||
if (strcmp(propval, ZFS_FEATURE_DISABLED) == 0)
|
if (strcmp(propval, ZFS_FEATURE_DISABLED) == 0)
|
||||||
(void) nvlist_remove_all(props,
|
(void) nvlist_remove_all(props,
|
||||||
propname);
|
propname);
|
||||||
if (strcmp(propval,
|
} else if (enable_all_pool_feat) {
|
||||||
ZFS_FEATURE_ENABLED) == 0 &&
|
|
||||||
!requested_features[i])
|
|
||||||
(void) fprintf(stderr, gettext(
|
|
||||||
"Warning: feature \"%s\" enabled "
|
|
||||||
"but is not in specified "
|
|
||||||
"'compatibility' feature set.\n"),
|
|
||||||
feat->fi_uname);
|
|
||||||
} else if (
|
|
||||||
enable_pool_features &&
|
|
||||||
feat->fi_zfs_mod_supported &&
|
|
||||||
requested_features[i]) {
|
|
||||||
ret = add_prop_list(propname,
|
ret = add_prop_list(propname,
|
||||||
ZFS_FEATURE_ENABLED, &props, B_TRUE);
|
ZFS_FEATURE_ENABLED, &props, B_TRUE);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
@@ -2093,7 +2009,7 @@ zpool_print_cmd(vdev_cmd_data_list_t *vcdl, const char *pool, char *path)
|
|||||||
* Mark empty values with dashes to make output
|
* Mark empty values with dashes to make output
|
||||||
* awk-able.
|
* awk-able.
|
||||||
*/
|
*/
|
||||||
if (val == NULL || is_blank_str(val))
|
if (is_blank_str(val))
|
||||||
val = "-";
|
val = "-";
|
||||||
|
|
||||||
printf("%*s", vcdl->uniq_cols_width[j], val);
|
printf("%*s", vcdl->uniq_cols_width[j], val);
|
||||||
@@ -2414,10 +2330,6 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
|
|||||||
(void) printf(gettext("all children offline"));
|
(void) printf(gettext("all children offline"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VDEV_AUX_BAD_LABEL:
|
|
||||||
(void) printf(gettext("invalid label"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
(void) printf(gettext("corrupted data"));
|
(void) printf(gettext("corrupted data"));
|
||||||
break;
|
break;
|
||||||
@@ -2463,7 +2375,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Display vdev initialization and trim status for leaves. */
|
/* Display vdev initialization and trim status for leaves */
|
||||||
if (children == 0) {
|
if (children == 0) {
|
||||||
print_status_initialize(vs, cb->cb_print_vdev_init);
|
print_status_initialize(vs, cb->cb_print_vdev_init);
|
||||||
print_status_trim(vs, cb->cb_print_vdev_trim);
|
print_status_trim(vs, cb->cb_print_vdev_trim);
|
||||||
@@ -2560,10 +2472,6 @@ print_import_config(status_cbdata_t *cb, const char *name, nvlist_t *nv,
|
|||||||
(void) printf(gettext("all children offline"));
|
(void) printf(gettext("all children offline"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VDEV_AUX_BAD_LABEL:
|
|
||||||
(void) printf(gettext("invalid label"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
(void) printf(gettext("corrupted data"));
|
(void) printf(gettext("corrupted data"));
|
||||||
break;
|
break;
|
||||||
@@ -2772,24 +2680,8 @@ show_import(nvlist_t *config, boolean_t report_error)
|
|||||||
|
|
||||||
case ZPOOL_STATUS_FEAT_DISABLED:
|
case ZPOOL_STATUS_FEAT_DISABLED:
|
||||||
printf_color(ANSI_BOLD, gettext("status: "));
|
printf_color(ANSI_BOLD, gettext("status: "));
|
||||||
printf_color(ANSI_YELLOW, gettext("Some supported "
|
printf_color(ANSI_YELLOW, gettext("Some supported features are "
|
||||||
"features are not enabled on the pool.\n\t"
|
"not enabled on the pool.\n"));
|
||||||
"(Note that they may be intentionally disabled "
|
|
||||||
"if the\n\t'compatibility' property is set.)\n"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZPOOL_STATUS_COMPATIBILITY_ERR:
|
|
||||||
printf_color(ANSI_BOLD, gettext("status: "));
|
|
||||||
printf_color(ANSI_YELLOW, gettext("Error reading or parsing "
|
|
||||||
"the file(s) indicated by the 'compatibility'\n"
|
|
||||||
"property.\n"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZPOOL_STATUS_INCOMPATIBLE_FEAT:
|
|
||||||
printf_color(ANSI_BOLD, gettext("status: "));
|
|
||||||
printf_color(ANSI_YELLOW, gettext("One or more features "
|
|
||||||
"are enabled on the pool despite not being\n"
|
|
||||||
"requested by the 'compatibility' property.\n"));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZPOOL_STATUS_UNSUP_FEAT_READ:
|
case ZPOOL_STATUS_UNSUP_FEAT_READ:
|
||||||
@@ -2881,12 +2773,6 @@ show_import(nvlist_t *config, boolean_t report_error)
|
|||||||
"imported using its name or numeric identifier, "
|
"imported using its name or numeric identifier, "
|
||||||
"though\n\tsome features will not be available "
|
"though\n\tsome features will not be available "
|
||||||
"without an explicit 'zpool upgrade'.\n"));
|
"without an explicit 'zpool upgrade'.\n"));
|
||||||
} else if (reason == ZPOOL_STATUS_COMPATIBILITY_ERR) {
|
|
||||||
(void) printf(gettext(" action: The pool can be "
|
|
||||||
"imported using its name or numeric\n\tidentifier, "
|
|
||||||
"though the file(s) indicated by its "
|
|
||||||
"'compatibility'\n\tproperty cannot be parsed at "
|
|
||||||
"this time.\n"));
|
|
||||||
} else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
|
} else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
|
||||||
(void) printf(gettext(" action: The pool can be "
|
(void) printf(gettext(" action: The pool can be "
|
||||||
"imported using its name or numeric "
|
"imported using its name or numeric "
|
||||||
@@ -3798,10 +3684,9 @@ zpool_do_import(int argc, char **argv)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = import_pools(pools, props, mntopts, flags,
|
err = import_pools(pools, props, mntopts, flags, argv[0],
|
||||||
argc >= 1 ? argv[0] : NULL,
|
argc == 1 ? NULL : argv[1], do_destroyed, pool_specified,
|
||||||
argc >= 2 ? argv[1] : NULL,
|
do_all, &idata);
|
||||||
do_destroyed, pool_specified, do_all, &idata);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're using the cachefile and we failed to import, then
|
* If we're using the cachefile and we failed to import, then
|
||||||
@@ -3821,10 +3706,9 @@ zpool_do_import(int argc, char **argv)
|
|||||||
nvlist_free(pools);
|
nvlist_free(pools);
|
||||||
pools = zpool_search_import(g_zfs, &idata, &libzfs_config_ops);
|
pools = zpool_search_import(g_zfs, &idata, &libzfs_config_ops);
|
||||||
|
|
||||||
err = import_pools(pools, props, mntopts, flags,
|
err = import_pools(pools, props, mntopts, flags, argv[0],
|
||||||
argc >= 1 ? argv[0] : NULL,
|
argc == 1 ? NULL : argv[1], do_destroyed, pool_specified,
|
||||||
argc >= 2 ? argv[1] : NULL,
|
do_all, &idata);
|
||||||
do_destroyed, pool_specified, do_all, &idata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -4825,7 +4709,7 @@ children:
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
|
vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
|
||||||
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
|
cb->cb_name_flags);
|
||||||
ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
|
ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
|
||||||
newchild[c], cb, depth + 2);
|
newchild[c], cb, depth + 2);
|
||||||
free(vname);
|
free(vname);
|
||||||
@@ -4868,7 +4752,7 @@ children:
|
|||||||
}
|
}
|
||||||
|
|
||||||
vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
|
vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
|
||||||
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
|
cb->cb_name_flags);
|
||||||
ret += print_vdev_stats(zhp, vname, oldnv ?
|
ret += print_vdev_stats(zhp, vname, oldnv ?
|
||||||
oldchild[c] : NULL, newchild[c], cb, depth + 2);
|
oldchild[c] : NULL, newchild[c], cb, depth + 2);
|
||||||
free(vname);
|
free(vname);
|
||||||
@@ -5165,12 +5049,11 @@ get_stat_flags(zpool_list_t *list)
|
|||||||
* Return 1 if cb_data->cb_vdev_names[0] is this vdev's name, 0 otherwise.
|
* Return 1 if cb_data->cb_vdev_names[0] is this vdev's name, 0 otherwise.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
is_vdev_cb(void *zhp_data, nvlist_t *nv, void *cb_data)
|
is_vdev_cb(zpool_handle_t *zhp, nvlist_t *nv, void *cb_data)
|
||||||
{
|
{
|
||||||
iostat_cbdata_t *cb = cb_data;
|
iostat_cbdata_t *cb = cb_data;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
zpool_handle_t *zhp = zhp_data;
|
|
||||||
|
|
||||||
name = zpool_vdev_name(g_zfs, zhp, nv, cb->cb_name_flags);
|
name = zpool_vdev_name(g_zfs, zhp, nv, cb->cb_name_flags);
|
||||||
|
|
||||||
@@ -6182,7 +6065,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
vname = zpool_vdev_name(g_zfs, zhp, child[c],
|
vname = zpool_vdev_name(g_zfs, zhp, child[c],
|
||||||
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
|
cb->cb_name_flags);
|
||||||
print_list_stats(zhp, vname, child[c], cb, depth + 2, B_FALSE);
|
print_list_stats(zhp, vname, child[c], cb, depth + 2, B_FALSE);
|
||||||
free(vname);
|
free(vname);
|
||||||
}
|
}
|
||||||
@@ -6216,7 +6099,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
|||||||
printed = B_TRUE;
|
printed = B_TRUE;
|
||||||
}
|
}
|
||||||
vname = zpool_vdev_name(g_zfs, zhp, child[c],
|
vname = zpool_vdev_name(g_zfs, zhp, child[c],
|
||||||
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
|
cb->cb_name_flags);
|
||||||
print_list_stats(zhp, vname, child[c], cb, depth + 2,
|
print_list_stats(zhp, vname, child[c], cb, depth + 2,
|
||||||
B_FALSE);
|
B_FALSE);
|
||||||
free(vname);
|
free(vname);
|
||||||
@@ -8121,9 +8004,7 @@ status_callback(zpool_handle_t *zhp, void *data)
|
|||||||
if (cbp->cb_explain &&
|
if (cbp->cb_explain &&
|
||||||
(reason == ZPOOL_STATUS_OK ||
|
(reason == ZPOOL_STATUS_OK ||
|
||||||
reason == ZPOOL_STATUS_VERSION_OLDER ||
|
reason == ZPOOL_STATUS_VERSION_OLDER ||
|
||||||
reason == ZPOOL_STATUS_FEAT_DISABLED ||
|
reason == ZPOOL_STATUS_FEAT_DISABLED)) {
|
||||||
reason == ZPOOL_STATUS_COMPATIBILITY_ERR ||
|
|
||||||
reason == ZPOOL_STATUS_INCOMPATIBLE_FEAT)) {
|
|
||||||
if (!cbp->cb_allpools) {
|
if (!cbp->cb_allpools) {
|
||||||
(void) printf(gettext("pool '%s' is healthy\n"),
|
(void) printf(gettext("pool '%s' is healthy\n"),
|
||||||
zpool_get_name(zhp));
|
zpool_get_name(zhp));
|
||||||
@@ -8298,40 +8179,14 @@ status_callback(zpool_handle_t *zhp, void *data)
|
|||||||
|
|
||||||
case ZPOOL_STATUS_FEAT_DISABLED:
|
case ZPOOL_STATUS_FEAT_DISABLED:
|
||||||
printf_color(ANSI_BOLD, gettext("status: "));
|
printf_color(ANSI_BOLD, gettext("status: "));
|
||||||
printf_color(ANSI_YELLOW, gettext("Some supported and "
|
printf_color(ANSI_YELLOW, gettext("Some supported features are "
|
||||||
"requested features are not enabled on the pool.\n\t"
|
"not enabled on the pool. The pool can\n\tstill be used, "
|
||||||
"The pool can still be used, but some features are "
|
"but some features are unavailable.\n"));
|
||||||
"unavailable.\n"));
|
|
||||||
printf_color(ANSI_BOLD, gettext("action: "));
|
printf_color(ANSI_BOLD, gettext("action: "));
|
||||||
printf_color(ANSI_YELLOW, gettext("Enable all features using "
|
printf_color(ANSI_YELLOW, gettext("Enable all features using "
|
||||||
"'zpool upgrade'. Once this is done,\n\tthe pool may no "
|
"'zpool upgrade'. Once this is done,\n\tthe pool may no "
|
||||||
"longer be accessible by software that does not support\n\t"
|
"longer be accessible by software that does not support\n\t"
|
||||||
"the features. See zpool-features(7) for details.\n"));
|
"the features. See zpool-features(5) for details.\n"));
|
||||||
break;
|
|
||||||
|
|
||||||
case ZPOOL_STATUS_COMPATIBILITY_ERR:
|
|
||||||
printf_color(ANSI_BOLD, gettext("status: "));
|
|
||||||
printf_color(ANSI_YELLOW, gettext("This pool has a "
|
|
||||||
"compatibility list specified, but it could not be\n\t"
|
|
||||||
"read/parsed at this time. The pool can still be used, "
|
|
||||||
"but this\n\tshould be investigated.\n"));
|
|
||||||
printf_color(ANSI_BOLD, gettext("action: "));
|
|
||||||
printf_color(ANSI_YELLOW, gettext("Check the value of the "
|
|
||||||
"'compatibility' property against the\n\t"
|
|
||||||
"appropriate file in " ZPOOL_SYSCONF_COMPAT_D " or "
|
|
||||||
ZPOOL_DATA_COMPAT_D ".\n"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZPOOL_STATUS_INCOMPATIBLE_FEAT:
|
|
||||||
printf_color(ANSI_BOLD, gettext("status: "));
|
|
||||||
printf_color(ANSI_YELLOW, gettext("One or more features "
|
|
||||||
"are enabled on the pool despite not being\n\t"
|
|
||||||
"requested by the 'compatibility' property.\n"));
|
|
||||||
printf_color(ANSI_BOLD, gettext("action: "));
|
|
||||||
printf_color(ANSI_YELLOW, gettext("Consider setting "
|
|
||||||
"'compatibility' to an appropriate value, or\n\t"
|
|
||||||
"adding needed features to the relevant file in\n\t"
|
|
||||||
ZPOOL_SYSCONF_COMPAT_D " or " ZPOOL_DATA_COMPAT_D ".\n"));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZPOOL_STATUS_UNSUP_FEAT_READ:
|
case ZPOOL_STATUS_UNSUP_FEAT_READ:
|
||||||
@@ -8793,11 +8648,6 @@ upgrade_version(zpool_handle_t *zhp, uint64_t version)
|
|||||||
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
|
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
|
||||||
&oldversion) == 0);
|
&oldversion) == 0);
|
||||||
|
|
||||||
char compat[ZFS_MAXPROPLEN];
|
|
||||||
if (zpool_get_prop(zhp, ZPOOL_PROP_COMPATIBILITY, compat,
|
|
||||||
ZFS_MAXPROPLEN, NULL, B_FALSE) != 0)
|
|
||||||
compat[0] = '\0';
|
|
||||||
|
|
||||||
assert(SPA_VERSION_IS_SUPPORTED(oldversion));
|
assert(SPA_VERSION_IS_SUPPORTED(oldversion));
|
||||||
assert(oldversion < version);
|
assert(oldversion < version);
|
||||||
|
|
||||||
@@ -8812,13 +8662,6 @@ upgrade_version(zpool_handle_t *zhp, uint64_t version)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(compat, ZPOOL_COMPAT_LEGACY) == 0) {
|
|
||||||
(void) fprintf(stderr, gettext("Upgrade not performed because "
|
|
||||||
"'compatibility' property set to '"
|
|
||||||
ZPOOL_COMPAT_LEGACY "'.\n"));
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = zpool_upgrade(zhp, version);
|
ret = zpool_upgrade(zhp, version);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return (ret);
|
return (ret);
|
||||||
@@ -8844,25 +8687,11 @@ upgrade_enable_all(zpool_handle_t *zhp, int *countp)
|
|||||||
boolean_t firstff = B_TRUE;
|
boolean_t firstff = B_TRUE;
|
||||||
nvlist_t *enabled = zpool_get_features(zhp);
|
nvlist_t *enabled = zpool_get_features(zhp);
|
||||||
|
|
||||||
char compat[ZFS_MAXPROPLEN];
|
|
||||||
if (zpool_get_prop(zhp, ZPOOL_PROP_COMPATIBILITY, compat,
|
|
||||||
ZFS_MAXPROPLEN, NULL, B_FALSE) != 0)
|
|
||||||
compat[0] = '\0';
|
|
||||||
|
|
||||||
boolean_t requested_features[SPA_FEATURES];
|
|
||||||
if (zpool_do_load_compat(compat, requested_features) !=
|
|
||||||
ZPOOL_COMPATIBILITY_OK)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
for (i = 0; i < SPA_FEATURES; i++) {
|
for (i = 0; i < SPA_FEATURES; i++) {
|
||||||
const char *fname = spa_feature_table[i].fi_uname;
|
const char *fname = spa_feature_table[i].fi_uname;
|
||||||
const char *fguid = spa_feature_table[i].fi_guid;
|
const char *fguid = spa_feature_table[i].fi_guid;
|
||||||
|
if (!nvlist_exists(enabled, fguid)) {
|
||||||
if (!spa_feature_table[i].fi_zfs_mod_supported)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!nvlist_exists(enabled, fguid) && requested_features[i]) {
|
|
||||||
char *propname;
|
char *propname;
|
||||||
verify(-1 != asprintf(&propname, "feature@%s", fname));
|
verify(-1 != asprintf(&propname, "feature@%s", fname));
|
||||||
ret = zpool_set_prop(zhp, propname,
|
ret = zpool_set_prop(zhp, propname,
|
||||||
@@ -8895,7 +8724,7 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
|
|||||||
upgrade_cbdata_t *cbp = arg;
|
upgrade_cbdata_t *cbp = arg;
|
||||||
nvlist_t *config;
|
nvlist_t *config;
|
||||||
uint64_t version;
|
uint64_t version;
|
||||||
boolean_t modified_pool = B_FALSE;
|
boolean_t printnl = B_FALSE;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
config = zpool_get_config(zhp, NULL);
|
config = zpool_get_config(zhp, NULL);
|
||||||
@@ -8909,7 +8738,7 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
|
|||||||
ret = upgrade_version(zhp, cbp->cb_version);
|
ret = upgrade_version(zhp, cbp->cb_version);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return (ret);
|
return (ret);
|
||||||
modified_pool = B_TRUE;
|
printnl = B_TRUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If they did "zpool upgrade -a", then we could
|
* If they did "zpool upgrade -a", then we could
|
||||||
@@ -8929,13 +8758,12 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
|
|||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
cbp->cb_first = B_FALSE;
|
cbp->cb_first = B_FALSE;
|
||||||
modified_pool = B_TRUE;
|
printnl = B_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modified_pool) {
|
if (printnl) {
|
||||||
(void) printf("\n");
|
(void) printf(gettext("\n"));
|
||||||
(void) after_zpool_upgrade(zhp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
@@ -8961,10 +8789,7 @@ upgrade_list_older_cb(zpool_handle_t *zhp, void *arg)
|
|||||||
"be upgraded to use feature flags. After "
|
"be upgraded to use feature flags. After "
|
||||||
"being upgraded, these pools\nwill no "
|
"being upgraded, these pools\nwill no "
|
||||||
"longer be accessible by software that does not "
|
"longer be accessible by software that does not "
|
||||||
"support feature\nflags.\n\n"
|
"support feature\nflags.\n\n"));
|
||||||
"Note that setting a pool's 'compatibility' "
|
|
||||||
"feature to '" ZPOOL_COMPAT_LEGACY "' will\n"
|
|
||||||
"inhibit upgrades.\n\n"));
|
|
||||||
(void) printf(gettext("VER POOL\n"));
|
(void) printf(gettext("VER POOL\n"));
|
||||||
(void) printf(gettext("--- ------------\n"));
|
(void) printf(gettext("--- ------------\n"));
|
||||||
cbp->cb_first = B_FALSE;
|
cbp->cb_first = B_FALSE;
|
||||||
@@ -8996,10 +8821,6 @@ upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
|
|||||||
for (i = 0; i < SPA_FEATURES; i++) {
|
for (i = 0; i < SPA_FEATURES; i++) {
|
||||||
const char *fguid = spa_feature_table[i].fi_guid;
|
const char *fguid = spa_feature_table[i].fi_guid;
|
||||||
const char *fname = spa_feature_table[i].fi_uname;
|
const char *fname = spa_feature_table[i].fi_uname;
|
||||||
|
|
||||||
if (!spa_feature_table[i].fi_zfs_mod_supported)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!nvlist_exists(enabled, fguid)) {
|
if (!nvlist_exists(enabled, fguid)) {
|
||||||
if (cbp->cb_first) {
|
if (cbp->cb_first) {
|
||||||
(void) printf(gettext("\nSome "
|
(void) printf(gettext("\nSome "
|
||||||
@@ -9009,12 +8830,8 @@ upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
|
|||||||
"pool may become incompatible with "
|
"pool may become incompatible with "
|
||||||
"software\nthat does not support "
|
"software\nthat does not support "
|
||||||
"the feature. See "
|
"the feature. See "
|
||||||
"zpool-features(7) for "
|
"zpool-features(5) for "
|
||||||
"details.\n\n"
|
"details.\n\n"));
|
||||||
"Note that the pool "
|
|
||||||
"'compatibility' feature can be "
|
|
||||||
"used to inhibit\nfeature "
|
|
||||||
"upgrades.\n\n"));
|
|
||||||
(void) printf(gettext("POOL "
|
(void) printf(gettext("POOL "
|
||||||
"FEATURE\n"));
|
"FEATURE\n"));
|
||||||
(void) printf(gettext("------"
|
(void) printf(gettext("------"
|
||||||
@@ -9048,7 +8865,7 @@ upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
|
|||||||
static int
|
static int
|
||||||
upgrade_one(zpool_handle_t *zhp, void *data)
|
upgrade_one(zpool_handle_t *zhp, void *data)
|
||||||
{
|
{
|
||||||
boolean_t modified_pool = B_FALSE;
|
boolean_t printnl = B_FALSE;
|
||||||
upgrade_cbdata_t *cbp = data;
|
upgrade_cbdata_t *cbp = data;
|
||||||
uint64_t cur_version;
|
uint64_t cur_version;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -9076,7 +8893,7 @@ upgrade_one(zpool_handle_t *zhp, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cur_version != cbp->cb_version) {
|
if (cur_version != cbp->cb_version) {
|
||||||
modified_pool = B_TRUE;
|
printnl = B_TRUE;
|
||||||
ret = upgrade_version(zhp, cbp->cb_version);
|
ret = upgrade_version(zhp, cbp->cb_version);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return (ret);
|
return (ret);
|
||||||
@@ -9089,17 +8906,16 @@ upgrade_one(zpool_handle_t *zhp, void *data)
|
|||||||
return (ret);
|
return (ret);
|
||||||
|
|
||||||
if (count != 0) {
|
if (count != 0) {
|
||||||
modified_pool = B_TRUE;
|
printnl = B_TRUE;
|
||||||
} else if (cur_version == SPA_VERSION) {
|
} else if (cur_version == SPA_VERSION) {
|
||||||
(void) printf(gettext("Pool '%s' already has all "
|
(void) printf(gettext("Pool '%s' already has all "
|
||||||
"supported and requested features enabled.\n"),
|
"supported features enabled.\n"),
|
||||||
zpool_get_name(zhp));
|
zpool_get_name(zhp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modified_pool) {
|
if (printnl) {
|
||||||
(void) printf("\n");
|
(void) printf(gettext("\n"));
|
||||||
(void) after_zpool_upgrade(zhp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
@@ -9194,8 +9010,6 @@ zpool_do_upgrade(int argc, char **argv)
|
|||||||
"---------------\n");
|
"---------------\n");
|
||||||
for (i = 0; i < SPA_FEATURES; i++) {
|
for (i = 0; i < SPA_FEATURES; i++) {
|
||||||
zfeature_info_t *fi = &spa_feature_table[i];
|
zfeature_info_t *fi = &spa_feature_table[i];
|
||||||
if (!fi->fi_zfs_mod_supported)
|
|
||||||
continue;
|
|
||||||
const char *ro =
|
const char *ro =
|
||||||
(fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
|
(fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
|
||||||
" (read-only compatible)" : "";
|
" (read-only compatible)" : "";
|
||||||
@@ -9256,8 +9070,8 @@ zpool_do_upgrade(int argc, char **argv)
|
|||||||
(void) printf(gettext("All pools are already "
|
(void) printf(gettext("All pools are already "
|
||||||
"formatted using feature flags.\n\n"));
|
"formatted using feature flags.\n\n"));
|
||||||
(void) printf(gettext("Every feature flags "
|
(void) printf(gettext("Every feature flags "
|
||||||
"pool already has all supported and "
|
"pool already has all supported features "
|
||||||
"requested features enabled.\n"));
|
"enabled.\n"));
|
||||||
} else {
|
} else {
|
||||||
(void) printf(gettext("All pools are already "
|
(void) printf(gettext("All pools are already "
|
||||||
"formatted with version %llu or higher.\n"),
|
"formatted with version %llu or higher.\n"),
|
||||||
@@ -9283,7 +9097,7 @@ zpool_do_upgrade(int argc, char **argv)
|
|||||||
|
|
||||||
if (cb.cb_first) {
|
if (cb.cb_first) {
|
||||||
(void) printf(gettext("Every feature flags pool has "
|
(void) printf(gettext("Every feature flags pool has "
|
||||||
"all supported and requested features enabled.\n"));
|
"all supported features enabled.\n"));
|
||||||
} else {
|
} else {
|
||||||
(void) printf(gettext("\n"));
|
(void) printf(gettext("\n"));
|
||||||
}
|
}
|
||||||
@@ -9312,7 +9126,7 @@ print_history_records(nvlist_t *nvhis, hist_cbdata_t *cb)
|
|||||||
&records, &numrecords) == 0);
|
&records, &numrecords) == 0);
|
||||||
for (i = 0; i < numrecords; i++) {
|
for (i = 0; i < numrecords; i++) {
|
||||||
nvlist_t *rec = records[i];
|
nvlist_t *rec = records[i];
|
||||||
char tbuf[64] = "";
|
char tbuf[30] = "";
|
||||||
|
|
||||||
if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
|
if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
|
||||||
time_t tsec;
|
time_t tsec;
|
||||||
@@ -9324,14 +9138,6 @@ print_history_records(nvlist_t *nvhis, hist_cbdata_t *cb)
|
|||||||
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
|
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nvlist_exists(rec, ZPOOL_HIST_ELAPSED_NS)) {
|
|
||||||
uint64_t elapsed_ns = fnvlist_lookup_int64(records[i],
|
|
||||||
ZPOOL_HIST_ELAPSED_NS);
|
|
||||||
(void) snprintf(tbuf + strlen(tbuf),
|
|
||||||
sizeof (tbuf) - strlen(tbuf),
|
|
||||||
" (%lldms)", (long long)elapsed_ns / 1000 / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
|
if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
|
||||||
(void) printf("%s %s", tbuf,
|
(void) printf("%s %s", tbuf,
|
||||||
fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
|
fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
|
||||||
@@ -10071,63 +9877,6 @@ set_callback(zpool_handle_t *zhp, void *data)
|
|||||||
int error;
|
int error;
|
||||||
set_cbdata_t *cb = (set_cbdata_t *)data;
|
set_cbdata_t *cb = (set_cbdata_t *)data;
|
||||||
|
|
||||||
/* Check if we have out-of-bounds features */
|
|
||||||
if (strcmp(cb->cb_propname, ZPOOL_CONFIG_COMPATIBILITY) == 0) {
|
|
||||||
boolean_t features[SPA_FEATURES];
|
|
||||||
if (zpool_do_load_compat(cb->cb_value, features) !=
|
|
||||||
ZPOOL_COMPATIBILITY_OK)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
nvlist_t *enabled = zpool_get_features(zhp);
|
|
||||||
spa_feature_t i;
|
|
||||||
for (i = 0; i < SPA_FEATURES; i++) {
|
|
||||||
const char *fguid = spa_feature_table[i].fi_guid;
|
|
||||||
if (nvlist_exists(enabled, fguid) && !features[i])
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i < SPA_FEATURES)
|
|
||||||
(void) fprintf(stderr, gettext("Warning: one or "
|
|
||||||
"more features already enabled on pool '%s'\n"
|
|
||||||
"are not present in this compatibility set.\n"),
|
|
||||||
zpool_get_name(zhp));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we're setting a feature, check it's in compatibility set */
|
|
||||||
if (zpool_prop_feature(cb->cb_propname) &&
|
|
||||||
strcmp(cb->cb_value, ZFS_FEATURE_ENABLED) == 0) {
|
|
||||||
char *fname = strchr(cb->cb_propname, '@') + 1;
|
|
||||||
spa_feature_t f;
|
|
||||||
|
|
||||||
if (zfeature_lookup_name(fname, &f) == 0) {
|
|
||||||
char compat[ZFS_MAXPROPLEN];
|
|
||||||
if (zpool_get_prop(zhp, ZPOOL_PROP_COMPATIBILITY,
|
|
||||||
compat, ZFS_MAXPROPLEN, NULL, B_FALSE) != 0)
|
|
||||||
compat[0] = '\0';
|
|
||||||
|
|
||||||
boolean_t features[SPA_FEATURES];
|
|
||||||
if (zpool_do_load_compat(compat, features) !=
|
|
||||||
ZPOOL_COMPATIBILITY_OK) {
|
|
||||||
(void) fprintf(stderr, gettext("Error: "
|
|
||||||
"cannot enable feature '%s' on pool '%s'\n"
|
|
||||||
"because the pool's 'compatibility' "
|
|
||||||
"property cannot be parsed.\n"),
|
|
||||||
fname, zpool_get_name(zhp));
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!features[f]) {
|
|
||||||
(void) fprintf(stderr, gettext("Error: "
|
|
||||||
"cannot enable feature '%s' on pool '%s'\n"
|
|
||||||
"as it is not specified in this pool's "
|
|
||||||
"current compatibility set.\n"
|
|
||||||
"Consider setting 'compatibility' to a "
|
|
||||||
"less restrictive set, or to 'off'.\n"),
|
|
||||||
fname, zpool_get_name(zhp));
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
|
error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
|
||||||
|
|
||||||
if (!error)
|
if (!error)
|
||||||
@@ -10258,8 +10007,7 @@ vdev_any_spare_replacing(nvlist_t *nv)
|
|||||||
(void) nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &vdev_type);
|
(void) nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &vdev_type);
|
||||||
|
|
||||||
if (strcmp(vdev_type, VDEV_TYPE_REPLACING) == 0 ||
|
if (strcmp(vdev_type, VDEV_TYPE_REPLACING) == 0 ||
|
||||||
strcmp(vdev_type, VDEV_TYPE_SPARE) == 0 ||
|
strcmp(vdev_type, VDEV_TYPE_SPARE) == 0) {
|
||||||
strcmp(vdev_type, VDEV_TYPE_DRAID_SPARE) == 0) {
|
|
||||||
return (B_TRUE);
|
return (B_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10644,36 +10392,6 @@ zpool_do_version(int argc, char **argv)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Do zpool_load_compat() and print error message on failure
|
|
||||||
*/
|
|
||||||
static zpool_compat_status_t
|
|
||||||
zpool_do_load_compat(const char *compat, boolean_t *list)
|
|
||||||
{
|
|
||||||
char report[1024];
|
|
||||||
|
|
||||||
zpool_compat_status_t ret;
|
|
||||||
|
|
||||||
ret = zpool_load_compat(compat, list, report, 1024);
|
|
||||||
switch (ret) {
|
|
||||||
|
|
||||||
case ZPOOL_COMPATIBILITY_OK:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZPOOL_COMPATIBILITY_NOFILES:
|
|
||||||
case ZPOOL_COMPATIBILITY_BADFILE:
|
|
||||||
case ZPOOL_COMPATIBILITY_BADTOKEN:
|
|
||||||
(void) fprintf(stderr, "Error: %s\n", report);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZPOOL_COMPATIBILITY_WARNTOKEN:
|
|
||||||
(void) fprintf(stderr, "Warning: %s\n", report);
|
|
||||||
ret = ZPOOL_COMPATIBILITY_OK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
|
|
||||||
#include <libnvpair.h>
|
#include <libnvpair.h>
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
#include <libzutil.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -68,6 +67,7 @@ int for_each_pool(int, char **, boolean_t unavail, zprop_list_t **,
|
|||||||
boolean_t, zpool_iter_f, void *);
|
boolean_t, zpool_iter_f, void *);
|
||||||
|
|
||||||
/* Vdev list functions */
|
/* Vdev list functions */
|
||||||
|
typedef int (*pool_vdev_iter_f)(zpool_handle_t *, nvlist_t *, void *);
|
||||||
int for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data);
|
int for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data);
|
||||||
|
|
||||||
typedef struct zpool_list zpool_list_t;
|
typedef struct zpool_list zpool_list_t;
|
||||||
@@ -129,7 +129,6 @@ int check_device(const char *path, boolean_t force,
|
|||||||
boolean_t check_sector_size_database(char *path, int *sector_size);
|
boolean_t check_sector_size_database(char *path, int *sector_size);
|
||||||
void vdev_error(const char *fmt, ...);
|
void vdev_error(const char *fmt, ...);
|
||||||
int check_file(const char *file, boolean_t force, boolean_t isspare);
|
int check_file(const char *file, boolean_t force, boolean_t isspare);
|
||||||
void after_zpool_upgrade(zpool_handle_t *zhp);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
+56
-345
@@ -86,6 +86,9 @@
|
|||||||
boolean_t error_seen;
|
boolean_t error_seen;
|
||||||
boolean_t is_force;
|
boolean_t is_force;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*PRINTFLIKE1*/
|
/*PRINTFLIKE1*/
|
||||||
void
|
void
|
||||||
vdev_error(const char *fmt, ...)
|
vdev_error(const char *fmt, ...)
|
||||||
@@ -219,9 +222,6 @@ is_spare(nvlist_t *config, const char *path)
|
|||||||
uint_t i, nspares;
|
uint_t i, nspares;
|
||||||
boolean_t inuse;
|
boolean_t inuse;
|
||||||
|
|
||||||
if (zpool_is_draid_spare(path))
|
|
||||||
return (B_TRUE);
|
|
||||||
|
|
||||||
if ((fd = open(path, O_RDONLY|O_DIRECT)) < 0)
|
if ((fd = open(path, O_RDONLY|O_DIRECT)) < 0)
|
||||||
return (B_FALSE);
|
return (B_FALSE);
|
||||||
|
|
||||||
@@ -267,10 +267,9 @@ is_spare(nvlist_t *config, const char *path)
|
|||||||
* /dev/xxx Complete disk path
|
* /dev/xxx Complete disk path
|
||||||
* /xxx Full path to file
|
* /xxx Full path to file
|
||||||
* xxx Shorthand for <zfs_vdev_paths>/xxx
|
* xxx Shorthand for <zfs_vdev_paths>/xxx
|
||||||
* draid* Virtual dRAID spare
|
|
||||||
*/
|
*/
|
||||||
static nvlist_t *
|
static nvlist_t *
|
||||||
make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
|
make_leaf_vdev(nvlist_t *props, const char *arg, uint64_t is_log)
|
||||||
{
|
{
|
||||||
char path[MAXPATHLEN];
|
char path[MAXPATHLEN];
|
||||||
struct stat64 statbuf;
|
struct stat64 statbuf;
|
||||||
@@ -310,17 +309,6 @@ make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
|
|||||||
|
|
||||||
/* After whole disk check restore original passed path */
|
/* After whole disk check restore original passed path */
|
||||||
strlcpy(path, arg, sizeof (path));
|
strlcpy(path, arg, sizeof (path));
|
||||||
} else if (zpool_is_draid_spare(arg)) {
|
|
||||||
if (!is_primary) {
|
|
||||||
(void) fprintf(stderr,
|
|
||||||
gettext("cannot open '%s': dRAID spares can only "
|
|
||||||
"be used to replace primary vdevs\n"), arg);
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
wholedisk = B_TRUE;
|
|
||||||
strlcpy(path, arg, sizeof (path));
|
|
||||||
type = VDEV_TYPE_DRAID_SPARE;
|
|
||||||
} else {
|
} else {
|
||||||
err = is_shorthand_path(arg, path, sizeof (path),
|
err = is_shorthand_path(arg, path, sizeof (path),
|
||||||
&statbuf, &wholedisk);
|
&statbuf, &wholedisk);
|
||||||
@@ -349,19 +337,17 @@ make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == NULL) {
|
/*
|
||||||
/*
|
* Determine whether this is a device or a file.
|
||||||
* Determine whether this is a device or a file.
|
*/
|
||||||
*/
|
if (wholedisk || S_ISBLK(statbuf.st_mode)) {
|
||||||
if (wholedisk || S_ISBLK(statbuf.st_mode)) {
|
type = VDEV_TYPE_DISK;
|
||||||
type = VDEV_TYPE_DISK;
|
} else if (S_ISREG(statbuf.st_mode)) {
|
||||||
} else if (S_ISREG(statbuf.st_mode)) {
|
type = VDEV_TYPE_FILE;
|
||||||
type = VDEV_TYPE_FILE;
|
} else {
|
||||||
} else {
|
(void) fprintf(stderr, gettext("cannot use '%s': must be a "
|
||||||
fprintf(stderr, gettext("cannot use '%s': must "
|
"block device or regular file\n"), path);
|
||||||
"be a block device or regular file\n"), path);
|
return (NULL);
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -372,7 +358,10 @@ make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
|
|||||||
verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
|
verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
|
||||||
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
|
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
|
||||||
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
|
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
|
||||||
|
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
|
||||||
|
if (is_log)
|
||||||
|
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_ALLOCATION_BIAS,
|
||||||
|
VDEV_ALLOC_BIAS_LOG) == 0);
|
||||||
if (strcmp(type, VDEV_TYPE_DISK) == 0)
|
if (strcmp(type, VDEV_TYPE_DISK) == 0)
|
||||||
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
|
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
|
||||||
(uint64_t)wholedisk) == 0);
|
(uint64_t)wholedisk) == 0);
|
||||||
@@ -443,16 +432,11 @@ typedef struct replication_level {
|
|||||||
|
|
||||||
#define ZPOOL_FUZZ (16 * 1024 * 1024)
|
#define ZPOOL_FUZZ (16 * 1024 * 1024)
|
||||||
|
|
||||||
/*
|
|
||||||
* N.B. For the purposes of comparing replication levels dRAID can be
|
|
||||||
* considered functionally equivalent to raidz.
|
|
||||||
*/
|
|
||||||
static boolean_t
|
static boolean_t
|
||||||
is_raidz_mirror(replication_level_t *a, replication_level_t *b,
|
is_raidz_mirror(replication_level_t *a, replication_level_t *b,
|
||||||
replication_level_t **raidz, replication_level_t **mirror)
|
replication_level_t **raidz, replication_level_t **mirror)
|
||||||
{
|
{
|
||||||
if ((strcmp(a->zprl_type, "raidz") == 0 ||
|
if (strcmp(a->zprl_type, "raidz") == 0 &&
|
||||||
strcmp(a->zprl_type, "draid") == 0) &&
|
|
||||||
strcmp(b->zprl_type, "mirror") == 0) {
|
strcmp(b->zprl_type, "mirror") == 0) {
|
||||||
*raidz = a;
|
*raidz = a;
|
||||||
*mirror = b;
|
*mirror = b;
|
||||||
@@ -461,22 +445,6 @@ is_raidz_mirror(replication_level_t *a, replication_level_t *b,
|
|||||||
return (B_FALSE);
|
return (B_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Comparison for determining if dRAID and raidz where passed in either order.
|
|
||||||
*/
|
|
||||||
static boolean_t
|
|
||||||
is_raidz_draid(replication_level_t *a, replication_level_t *b)
|
|
||||||
{
|
|
||||||
if ((strcmp(a->zprl_type, "raidz") == 0 ||
|
|
||||||
strcmp(a->zprl_type, "draid") == 0) &&
|
|
||||||
(strcmp(b->zprl_type, "raidz") == 0 ||
|
|
||||||
strcmp(b->zprl_type, "draid") == 0)) {
|
|
||||||
return (B_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (B_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a list of toplevel vdevs, return the current replication level. If
|
* Given a list of toplevel vdevs, return the current replication level. If
|
||||||
* the config is inconsistent, then NULL is returned. If 'fatal' is set, then
|
* the config is inconsistent, then NULL is returned. If 'fatal' is set, then
|
||||||
@@ -543,8 +511,7 @@ get_replication(nvlist_t *nvroot, boolean_t fatal)
|
|||||||
rep.zprl_type = type;
|
rep.zprl_type = type;
|
||||||
rep.zprl_children = 0;
|
rep.zprl_children = 0;
|
||||||
|
|
||||||
if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
|
if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
|
||||||
strcmp(type, VDEV_TYPE_DRAID) == 0) {
|
|
||||||
verify(nvlist_lookup_uint64(nv,
|
verify(nvlist_lookup_uint64(nv,
|
||||||
ZPOOL_CONFIG_NPARITY,
|
ZPOOL_CONFIG_NPARITY,
|
||||||
&rep.zprl_parity) == 0);
|
&rep.zprl_parity) == 0);
|
||||||
@@ -710,29 +677,6 @@ get_replication(nvlist_t *nvroot, boolean_t fatal)
|
|||||||
else
|
else
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
} else if (is_raidz_draid(&lastrep, &rep)) {
|
|
||||||
/*
|
|
||||||
* Accepted raidz and draid when they can
|
|
||||||
* handle the same number of disk failures.
|
|
||||||
*/
|
|
||||||
if (lastrep.zprl_parity != rep.zprl_parity) {
|
|
||||||
if (ret != NULL)
|
|
||||||
free(ret);
|
|
||||||
ret = NULL;
|
|
||||||
if (fatal)
|
|
||||||
vdev_error(gettext(
|
|
||||||
"mismatched replication "
|
|
||||||
"level: %s and %s vdevs "
|
|
||||||
"with different "
|
|
||||||
"redundancy, %llu vs. "
|
|
||||||
"%llu are present\n"),
|
|
||||||
lastrep.zprl_type,
|
|
||||||
rep.zprl_type,
|
|
||||||
lastrep.zprl_parity,
|
|
||||||
rep.zprl_parity);
|
|
||||||
else
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
} else if (strcmp(lastrep.zprl_type, rep.zprl_type) !=
|
} else if (strcmp(lastrep.zprl_type, rep.zprl_type) !=
|
||||||
0) {
|
0) {
|
||||||
if (ret != NULL)
|
if (ret != NULL)
|
||||||
@@ -1159,87 +1103,31 @@ is_device_in_use(nvlist_t *config, nvlist_t *nv, boolean_t force,
|
|||||||
return (anyinuse);
|
return (anyinuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the parity level extracted from a raidz or draid type.
|
|
||||||
* If the parity cannot be determined zero is returned.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
get_parity(const char *type)
|
|
||||||
{
|
|
||||||
long parity = 0;
|
|
||||||
const char *p;
|
|
||||||
|
|
||||||
if (strncmp(type, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0) {
|
|
||||||
p = type + strlen(VDEV_TYPE_RAIDZ);
|
|
||||||
|
|
||||||
if (*p == '\0') {
|
|
||||||
/* when unspecified default to single parity */
|
|
||||||
return (1);
|
|
||||||
} else if (*p == '0') {
|
|
||||||
/* no zero prefixes allowed */
|
|
||||||
return (0);
|
|
||||||
} else {
|
|
||||||
/* 0-3, no suffixes allowed */
|
|
||||||
char *end;
|
|
||||||
errno = 0;
|
|
||||||
parity = strtol(p, &end, 10);
|
|
||||||
if (errno != 0 || *end != '\0' ||
|
|
||||||
parity < 1 || parity > VDEV_RAIDZ_MAXPARITY) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (strncmp(type, VDEV_TYPE_DRAID,
|
|
||||||
strlen(VDEV_TYPE_DRAID)) == 0) {
|
|
||||||
p = type + strlen(VDEV_TYPE_DRAID);
|
|
||||||
|
|
||||||
if (*p == '\0' || *p == ':') {
|
|
||||||
/* when unspecified default to single parity */
|
|
||||||
return (1);
|
|
||||||
} else if (*p == '0') {
|
|
||||||
/* no zero prefixes allowed */
|
|
||||||
return (0);
|
|
||||||
} else {
|
|
||||||
/* 0-3, allowed suffixes: '\0' or ':' */
|
|
||||||
char *end;
|
|
||||||
errno = 0;
|
|
||||||
parity = strtol(p, &end, 10);
|
|
||||||
if (errno != 0 ||
|
|
||||||
parity < 1 || parity > VDEV_DRAID_MAXPARITY ||
|
|
||||||
(*end != '\0' && *end != ':')) {
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((int)parity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assign the minimum and maximum number of devices allowed for
|
|
||||||
* the specified type. On error NULL is returned, otherwise the
|
|
||||||
* type prefix is returned (raidz, mirror, etc).
|
|
||||||
*/
|
|
||||||
static const char *
|
static const char *
|
||||||
is_grouping(const char *type, int *mindev, int *maxdev)
|
is_grouping(const char *type, int *mindev, int *maxdev)
|
||||||
{
|
{
|
||||||
int nparity;
|
if (strncmp(type, "raidz", 5) == 0) {
|
||||||
|
const char *p = type + 5;
|
||||||
|
char *end;
|
||||||
|
long nparity;
|
||||||
|
|
||||||
|
if (*p == '\0') {
|
||||||
|
nparity = 1;
|
||||||
|
} else if (*p == '0') {
|
||||||
|
return (NULL); /* no zero prefixes allowed */
|
||||||
|
} else {
|
||||||
|
errno = 0;
|
||||||
|
nparity = strtol(p, &end, 10);
|
||||||
|
if (errno != 0 || nparity < 1 || nparity >= 255 ||
|
||||||
|
*end != '\0')
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (strncmp(type, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 ||
|
|
||||||
strncmp(type, VDEV_TYPE_DRAID, strlen(VDEV_TYPE_DRAID)) == 0) {
|
|
||||||
nparity = get_parity(type);
|
|
||||||
if (nparity == 0)
|
|
||||||
return (NULL);
|
|
||||||
if (mindev != NULL)
|
if (mindev != NULL)
|
||||||
*mindev = nparity + 1;
|
*mindev = nparity + 1;
|
||||||
if (maxdev != NULL)
|
if (maxdev != NULL)
|
||||||
*maxdev = 255;
|
*maxdev = 255;
|
||||||
|
return (VDEV_TYPE_RAIDZ);
|
||||||
if (strncmp(type, VDEV_TYPE_RAIDZ,
|
|
||||||
strlen(VDEV_TYPE_RAIDZ)) == 0) {
|
|
||||||
return (VDEV_TYPE_RAIDZ);
|
|
||||||
} else {
|
|
||||||
return (VDEV_TYPE_DRAID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxdev != NULL)
|
if (maxdev != NULL)
|
||||||
@@ -1279,163 +1167,6 @@ is_grouping(const char *type, int *mindev, int *maxdev)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Extract the configuration parameters encoded in the dRAID type and
|
|
||||||
* use them to generate a dRAID configuration. The expected format is:
|
|
||||||
*
|
|
||||||
* draid[<parity>][:<data><d|D>][:<children><c|C>][:<spares><s|S>]
|
|
||||||
*
|
|
||||||
* The intent is to be able to generate a good configuration when no
|
|
||||||
* additional information is provided. The only mandatory component
|
|
||||||
* of the 'type' is the 'draid' prefix. If a value is not provided
|
|
||||||
* then reasonable defaults are used. The optional components may
|
|
||||||
* appear in any order but the d/s/c suffix is required.
|
|
||||||
*
|
|
||||||
* Valid inputs:
|
|
||||||
* - data: number of data devices per group (1-255)
|
|
||||||
* - parity: number of parity blocks per group (1-3)
|
|
||||||
* - spares: number of distributed spare (0-100)
|
|
||||||
* - children: total number of devices (1-255)
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
* - zpool create tank draid <devices...>
|
|
||||||
* - zpool create tank draid2:8d:51c:2s <devices...>
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
draid_config_by_type(nvlist_t *nv, const char *type, uint64_t children)
|
|
||||||
{
|
|
||||||
uint64_t nparity = 1;
|
|
||||||
uint64_t nspares = 0;
|
|
||||||
uint64_t ndata = UINT64_MAX;
|
|
||||||
uint64_t ngroups = 1;
|
|
||||||
long value;
|
|
||||||
|
|
||||||
if (strncmp(type, VDEV_TYPE_DRAID, strlen(VDEV_TYPE_DRAID)) != 0)
|
|
||||||
return (EINVAL);
|
|
||||||
|
|
||||||
nparity = (uint64_t)get_parity(type);
|
|
||||||
if (nparity == 0)
|
|
||||||
return (EINVAL);
|
|
||||||
|
|
||||||
char *p = (char *)type;
|
|
||||||
while ((p = strchr(p, ':')) != NULL) {
|
|
||||||
char *end;
|
|
||||||
|
|
||||||
p = p + 1;
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
if (!isdigit(p[0])) {
|
|
||||||
(void) fprintf(stderr, gettext("invalid dRAID "
|
|
||||||
"syntax; expected [:<number><c|d|s>] not '%s'\n"),
|
|
||||||
type);
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Expected non-zero value with c/d/s suffix */
|
|
||||||
value = strtol(p, &end, 10);
|
|
||||||
char suffix = tolower(*end);
|
|
||||||
if (errno != 0 ||
|
|
||||||
(suffix != 'c' && suffix != 'd' && suffix != 's')) {
|
|
||||||
(void) fprintf(stderr, gettext("invalid dRAID "
|
|
||||||
"syntax; expected [:<number><c|d|s>] not '%s'\n"),
|
|
||||||
type);
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (suffix == 'c') {
|
|
||||||
if ((uint64_t)value != children) {
|
|
||||||
fprintf(stderr,
|
|
||||||
gettext("invalid number of dRAID children; "
|
|
||||||
"%llu required but %llu provided\n"),
|
|
||||||
(u_longlong_t)value,
|
|
||||||
(u_longlong_t)children);
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
} else if (suffix == 'd') {
|
|
||||||
ndata = (uint64_t)value;
|
|
||||||
} else if (suffix == 's') {
|
|
||||||
nspares = (uint64_t)value;
|
|
||||||
} else {
|
|
||||||
verify(0); /* Unreachable */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When a specific number of data disks is not provided limit a
|
|
||||||
* redundancy group to 8 data disks. This value was selected to
|
|
||||||
* provide a reasonable tradeoff between capacity and performance.
|
|
||||||
*/
|
|
||||||
if (ndata == UINT64_MAX) {
|
|
||||||
if (children > nspares + nparity) {
|
|
||||||
ndata = MIN(children - nspares - nparity, 8);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, gettext("request number of "
|
|
||||||
"distributed spares %llu and parity level %llu\n"
|
|
||||||
"leaves no disks available for data\n"),
|
|
||||||
(u_longlong_t)nspares, (u_longlong_t)nparity);
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify the maximum allowed group size is never exceeded. */
|
|
||||||
if (ndata == 0 || (ndata + nparity > children - nspares)) {
|
|
||||||
fprintf(stderr, gettext("requested number of dRAID data "
|
|
||||||
"disks per group %llu is too high,\nat most %llu disks "
|
|
||||||
"are available for data\n"), (u_longlong_t)ndata,
|
|
||||||
(u_longlong_t)(children - nspares - nparity));
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nparity == 0 || nparity > VDEV_DRAID_MAXPARITY) {
|
|
||||||
fprintf(stderr,
|
|
||||||
gettext("invalid dRAID parity level %llu; must be "
|
|
||||||
"between 1 and %d\n"), (u_longlong_t)nparity,
|
|
||||||
VDEV_DRAID_MAXPARITY);
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Verify the requested number of spares can be satisfied.
|
|
||||||
* An arbitrary limit of 100 distributed spares is applied.
|
|
||||||
*/
|
|
||||||
if (nspares > 100 || nspares > (children - (ndata + nparity))) {
|
|
||||||
fprintf(stderr,
|
|
||||||
gettext("invalid number of dRAID spares %llu; additional "
|
|
||||||
"disks would be required\n"), (u_longlong_t)nspares);
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify the requested number children is sufficient. */
|
|
||||||
if (children < (ndata + nparity + nspares)) {
|
|
||||||
fprintf(stderr, gettext("%llu disks were provided, but at "
|
|
||||||
"least %llu disks are required for this config\n"),
|
|
||||||
(u_longlong_t)children,
|
|
||||||
(u_longlong_t)(ndata + nparity + nspares));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (children > VDEV_DRAID_MAX_CHILDREN) {
|
|
||||||
fprintf(stderr, gettext("%llu disks were provided, but "
|
|
||||||
"dRAID only supports up to %u disks"),
|
|
||||||
(u_longlong_t)children, VDEV_DRAID_MAX_CHILDREN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate the minimum number of groups required to fill a slice.
|
|
||||||
* This is the LCM of the stripe width (ndata + nparity) and the
|
|
||||||
* number of data drives (children - nspares).
|
|
||||||
*/
|
|
||||||
while (ngroups * (ndata + nparity) % (children - nspares) != 0)
|
|
||||||
ngroups++;
|
|
||||||
|
|
||||||
/* Store the basic dRAID configuration. */
|
|
||||||
fnvlist_add_uint64(nv, ZPOOL_CONFIG_NPARITY, nparity);
|
|
||||||
fnvlist_add_uint64(nv, ZPOOL_CONFIG_DRAID_NDATA, ndata);
|
|
||||||
fnvlist_add_uint64(nv, ZPOOL_CONFIG_DRAID_NSPARES, nspares);
|
|
||||||
fnvlist_add_uint64(nv, ZPOOL_CONFIG_DRAID_NGROUPS, ngroups);
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct a syntactically valid vdev specification,
|
* Construct a syntactically valid vdev specification,
|
||||||
* and ensure that all devices and files exist and can be opened.
|
* and ensure that all devices and files exist and can be opened.
|
||||||
@@ -1447,8 +1178,8 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
{
|
{
|
||||||
nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
|
nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
|
||||||
int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
|
int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
|
||||||
const char *type, *fulltype;
|
const char *type;
|
||||||
boolean_t is_log, is_special, is_dedup, is_spare;
|
uint64_t is_log, is_special, is_dedup;
|
||||||
boolean_t seen_logs;
|
boolean_t seen_logs;
|
||||||
|
|
||||||
top = NULL;
|
top = NULL;
|
||||||
@@ -1458,20 +1189,18 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
nspares = 0;
|
nspares = 0;
|
||||||
nlogs = 0;
|
nlogs = 0;
|
||||||
nl2cache = 0;
|
nl2cache = 0;
|
||||||
is_log = is_special = is_dedup = is_spare = B_FALSE;
|
is_log = is_special = is_dedup = B_FALSE;
|
||||||
seen_logs = B_FALSE;
|
seen_logs = B_FALSE;
|
||||||
nvroot = NULL;
|
nvroot = NULL;
|
||||||
|
|
||||||
while (argc > 0) {
|
while (argc > 0) {
|
||||||
fulltype = argv[0];
|
|
||||||
nv = NULL;
|
nv = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it's a mirror, raidz, or draid the subsequent arguments
|
* If it's a mirror or raidz, the subsequent arguments are
|
||||||
* are its leaves -- until we encounter the next mirror,
|
* its leaves -- until we encounter the next mirror or raidz.
|
||||||
* raidz or draid.
|
|
||||||
*/
|
*/
|
||||||
if ((type = is_grouping(fulltype, &mindev, &maxdev)) != NULL) {
|
if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) {
|
||||||
nvlist_t **child = NULL;
|
nvlist_t **child = NULL;
|
||||||
int c, children = 0;
|
int c, children = 0;
|
||||||
|
|
||||||
@@ -1483,7 +1212,6 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
"specified only once\n"));
|
"specified only once\n"));
|
||||||
goto spec_out;
|
goto spec_out;
|
||||||
}
|
}
|
||||||
is_spare = B_TRUE;
|
|
||||||
is_log = is_special = is_dedup = B_FALSE;
|
is_log = is_special = is_dedup = B_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1497,7 +1225,8 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
}
|
}
|
||||||
seen_logs = B_TRUE;
|
seen_logs = B_TRUE;
|
||||||
is_log = B_TRUE;
|
is_log = B_TRUE;
|
||||||
is_special = is_dedup = is_spare = B_FALSE;
|
is_special = B_FALSE;
|
||||||
|
is_dedup = B_FALSE;
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
/*
|
/*
|
||||||
@@ -1509,7 +1238,8 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
|
|
||||||
if (strcmp(type, VDEV_ALLOC_BIAS_SPECIAL) == 0) {
|
if (strcmp(type, VDEV_ALLOC_BIAS_SPECIAL) == 0) {
|
||||||
is_special = B_TRUE;
|
is_special = B_TRUE;
|
||||||
is_log = is_dedup = is_spare = B_FALSE;
|
is_log = B_FALSE;
|
||||||
|
is_dedup = B_FALSE;
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
continue;
|
continue;
|
||||||
@@ -1517,7 +1247,8 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
|
|
||||||
if (strcmp(type, VDEV_ALLOC_BIAS_DEDUP) == 0) {
|
if (strcmp(type, VDEV_ALLOC_BIAS_DEDUP) == 0) {
|
||||||
is_dedup = B_TRUE;
|
is_dedup = B_TRUE;
|
||||||
is_log = is_special = is_spare = B_FALSE;
|
is_log = B_FALSE;
|
||||||
|
is_special = B_FALSE;
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
continue;
|
continue;
|
||||||
@@ -1531,8 +1262,7 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
"specified only once\n"));
|
"specified only once\n"));
|
||||||
goto spec_out;
|
goto spec_out;
|
||||||
}
|
}
|
||||||
is_log = is_special = B_FALSE;
|
is_log = is_special = is_dedup = B_FALSE;
|
||||||
is_dedup = is_spare = B_FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_log || is_special || is_dedup) {
|
if (is_log || is_special || is_dedup) {
|
||||||
@@ -1550,15 +1280,13 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
for (c = 1; c < argc; c++) {
|
for (c = 1; c < argc; c++) {
|
||||||
if (is_grouping(argv[c], NULL, NULL) != NULL)
|
if (is_grouping(argv[c], NULL, NULL) != NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
children++;
|
children++;
|
||||||
child = realloc(child,
|
child = realloc(child,
|
||||||
children * sizeof (nvlist_t *));
|
children * sizeof (nvlist_t *));
|
||||||
if (child == NULL)
|
if (child == NULL)
|
||||||
zpool_no_memory();
|
zpool_no_memory();
|
||||||
if ((nv = make_leaf_vdev(props, argv[c],
|
if ((nv = make_leaf_vdev(props, argv[c],
|
||||||
!(is_log || is_special || is_dedup ||
|
B_FALSE)) == NULL) {
|
||||||
is_spare))) == NULL) {
|
|
||||||
for (c = 0; c < children - 1; c++)
|
for (c = 0; c < children - 1; c++)
|
||||||
nvlist_free(child[c]);
|
nvlist_free(child[c]);
|
||||||
free(child);
|
free(child);
|
||||||
@@ -1607,11 +1335,10 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
type) == 0);
|
type) == 0);
|
||||||
verify(nvlist_add_uint64(nv,
|
verify(nvlist_add_uint64(nv,
|
||||||
ZPOOL_CONFIG_IS_LOG, is_log) == 0);
|
ZPOOL_CONFIG_IS_LOG, is_log) == 0);
|
||||||
if (is_log) {
|
if (is_log)
|
||||||
verify(nvlist_add_string(nv,
|
verify(nvlist_add_string(nv,
|
||||||
ZPOOL_CONFIG_ALLOCATION_BIAS,
|
ZPOOL_CONFIG_ALLOCATION_BIAS,
|
||||||
VDEV_ALLOC_BIAS_LOG) == 0);
|
VDEV_ALLOC_BIAS_LOG) == 0);
|
||||||
}
|
|
||||||
if (is_special) {
|
if (is_special) {
|
||||||
verify(nvlist_add_string(nv,
|
verify(nvlist_add_string(nv,
|
||||||
ZPOOL_CONFIG_ALLOCATION_BIAS,
|
ZPOOL_CONFIG_ALLOCATION_BIAS,
|
||||||
@@ -1627,15 +1354,6 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
ZPOOL_CONFIG_NPARITY,
|
ZPOOL_CONFIG_NPARITY,
|
||||||
mindev - 1) == 0);
|
mindev - 1) == 0);
|
||||||
}
|
}
|
||||||
if (strcmp(type, VDEV_TYPE_DRAID) == 0) {
|
|
||||||
if (draid_config_by_type(nv,
|
|
||||||
fulltype, children) != 0) {
|
|
||||||
for (c = 0; c < children; c++)
|
|
||||||
nvlist_free(child[c]);
|
|
||||||
free(child);
|
|
||||||
goto spec_out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
verify(nvlist_add_nvlist_array(nv,
|
verify(nvlist_add_nvlist_array(nv,
|
||||||
ZPOOL_CONFIG_CHILDREN, child,
|
ZPOOL_CONFIG_CHILDREN, child,
|
||||||
children) == 0);
|
children) == 0);
|
||||||
@@ -1649,19 +1367,12 @@ construct_spec(nvlist_t *props, int argc, char **argv)
|
|||||||
* We have a device. Pass off to make_leaf_vdev() to
|
* We have a device. Pass off to make_leaf_vdev() to
|
||||||
* construct the appropriate nvlist describing the vdev.
|
* construct the appropriate nvlist describing the vdev.
|
||||||
*/
|
*/
|
||||||
if ((nv = make_leaf_vdev(props, argv[0], !(is_log ||
|
if ((nv = make_leaf_vdev(props, argv[0],
|
||||||
is_special || is_dedup || is_spare))) == NULL)
|
is_log)) == NULL)
|
||||||
goto spec_out;
|
goto spec_out;
|
||||||
|
|
||||||
verify(nvlist_add_uint64(nv,
|
if (is_log)
|
||||||
ZPOOL_CONFIG_IS_LOG, is_log) == 0);
|
|
||||||
if (is_log) {
|
|
||||||
verify(nvlist_add_string(nv,
|
|
||||||
ZPOOL_CONFIG_ALLOCATION_BIAS,
|
|
||||||
VDEV_ALLOC_BIAS_LOG) == 0);
|
|
||||||
nlogs++;
|
nlogs++;
|
||||||
}
|
|
||||||
|
|
||||||
if (is_special) {
|
if (is_special) {
|
||||||
verify(nvlist_add_string(nv,
|
verify(nvlist_add_string(nv,
|
||||||
ZPOOL_CONFIG_ALLOCATION_BIAS,
|
ZPOOL_CONFIG_ALLOCATION_BIAS,
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
/zpool_influxdb
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user