├── CONTRIBUTORS.txt ├── COPYING ├── Makefile ├── README.md ├── examples ├── Makefile └── monitor │ ├── Makefile │ ├── monitor_check_vdostats_logicalSpace.pl │ ├── monitor_check_vdostats_physicalSpace.pl │ └── monitor_check_vdostats_savingPercent.pl ├── utils ├── Makefile ├── uds │ ├── Makefile │ ├── chapter-index.c │ ├── chapter-index.h │ ├── config.c │ ├── config.h │ ├── cpu.h │ ├── delta-index.c │ ├── delta-index.h │ ├── dm-bufio.c │ ├── errors.c │ ├── errors.h │ ├── event-count.c │ ├── event-count.h │ ├── fileUtils.c │ ├── fileUtils.h │ ├── funnel-queue.c │ ├── funnel-queue.h │ ├── funnel-requestqueue.h │ ├── geometry.c │ ├── geometry.h │ ├── hash-utils.h │ ├── hlist.h │ ├── index-layout.c │ ├── index-layout.h │ ├── index-page-map.c │ ├── index-page-map.h │ ├── index-session.c │ ├── index-session.h │ ├── index.c │ ├── index.h │ ├── indexer.h │ ├── io-factory.c │ ├── io-factory.h │ ├── linux │ │ ├── atomic.h │ │ ├── bitops.h │ │ ├── bits.h │ │ ├── blkdev.h │ │ ├── build_bug.h │ │ ├── cache.h │ │ ├── compiler.h │ │ ├── compiler_attributes.h │ │ ├── const.h │ │ ├── dm-bufio.h │ │ ├── err.h │ │ ├── limits.h │ │ ├── log2.h │ │ ├── mutex.h │ │ ├── random.h │ │ ├── types.h │ │ └── unaligned.h │ ├── logger.c │ ├── logger.h │ ├── memory-alloc.h │ ├── memoryAlloc.c │ ├── minisyslog.c │ ├── minisyslog.h │ ├── murmurhash3.c │ ├── murmurhash3.h │ ├── numeric.h │ ├── open-chapter.c │ ├── open-chapter.h │ ├── permassert.c │ ├── permassert.h │ ├── radix-sort.c │ ├── radix-sort.h │ ├── random.c │ ├── random.h │ ├── requestQueue.c │ ├── sparse-cache.c │ ├── sparse-cache.h │ ├── string-utils.c │ ├── string-utils.h │ ├── syscalls.c │ ├── syscalls.h │ ├── thread-utils.c │ ├── thread-utils.h │ ├── threadCondVar.c │ ├── threadMutex.c │ ├── threadSemaphore.c │ ├── time-utils.c │ ├── time-utils.h │ ├── volume-index.c │ ├── volume-index.h │ ├── volume.c │ └── volume.h └── vdo │ ├── Makefile │ ├── adaptlvm │ ├── blockMapUtils.c │ ├── blockMapUtils.h │ ├── constants.h │ ├── encodings.c │ ├── encodings.h │ ├── fileLayer.c │ ├── fileLayer.h │ ├── man │ ├── Makefile │ ├── adaptlvm.8 │ ├── vdoaudit.8 │ ├── vdodebugmetadata.8 │ ├── vdodumpblockmap.8 │ ├── vdodumpmetadata.8 │ ├── vdoforcerebuild.8 │ ├── vdoformat.8 │ ├── vdolistmetadata.8 │ ├── vdoreadonly.8 │ ├── vdorecover.8 │ └── vdostats.8 │ ├── messageStatsReader.c │ ├── parseUtils.c │ ├── parseUtils.h │ ├── physicalLayer.h │ ├── slabSummaryReader.c │ ├── slabSummaryReader.h │ ├── statistics.h │ ├── status-codes.c │ ├── status-codes.h │ ├── types.h │ ├── userVDO.c │ ├── userVDO.h │ ├── vdoConfig.c │ ├── vdoConfig.h │ ├── vdoStats.h │ ├── vdoStatsWriter.c │ ├── vdoVolumeUtils.c │ ├── vdoVolumeUtils.h │ ├── vdoaudit.c │ ├── vdodebugmetadata.c │ ├── vdodumpblockmap.c │ ├── vdodumpmetadata.c │ ├── vdoforcerebuild.c │ ├── vdoformat.c │ ├── vdolistmetadata.c │ ├── vdoreadonly.c │ ├── vdorecover │ ├── vdostats.bash │ └── vdostats.c └── vdo.spec /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | The Red Hat VDO Team: 2 | Principal Engineer/Lead Architect: 3 | J. corwin Coburn 4 | 5 | Primary Authors: 6 | Joseph Chapman 7 | Sweet Tea Dorminy 8 | *Thomas Jaskiewicz 9 | Bruce Johnston 10 | Susan McGhee 11 | Ken Raeburn 12 | Michael Sclafani 13 | Matthew Sakai 14 | Joseph Shimkus 15 | John Wiele 16 | 17 | Support, Testing, Documentation, and other things too numerous to mention: 18 | Chung Chung : 19 | Bryan Gurney 20 | *Simon J. Hernandez 21 | Jakub Krysl 22 | Marek Suchanek 23 | 24 | Project Management & Technical Direction: 25 | Jered Floyd 26 | Louis Imershein 27 | Dennis Keefe 28 | Andrew Walsh 29 | 30 | *former team members 31 | 32 | Other Contributors: 33 | Ji-Hyeon Gim : 34 | Updates for FC26/Kernel 4.13 35 | Vojtech Trefny 36 | Getting correct size of partitions 37 | Achilles Gaikwad 38 | Bash completion for the vdo and vdostats commands 39 | Jin-young Kwon 40 | Adding vdo --version command, and documentation fixes 41 | Francisco Vilmar Cardoso Ruviaro 42 | Typo corrections in vdo and uds 43 | Yukari Chiba 44 | User tools support for riscv64 45 | Yang Huang 46 | User tools support for loongarch64 47 | 48 | VDO was originally created at Permabit Technology Corporation, and was 49 | subsequently acquired and open-sourced by Red Hat. 50 | 51 | Former Members of the Permabit VDO Team: 52 | Engineers: 53 | Mark Amidon 54 | David Buckle 55 | Jacky Chu 56 | Joel Hoff 57 | Dimitri Kountourogianni 58 | Alexis Layton 59 | Michael Lee 60 | Rich Macchi 61 | Dave Paniriti 62 | Karl Ramm 63 | Hooman Vassef 64 | Assar Westurlund 65 | 66 | Support, Testing, Documentation, etc. 67 | Carl Alexander 68 | Mike Chu 69 | Mark Iskra 70 | Farid Jahanmir 71 | Francesca Koulikov 72 | Erik Lattimore 73 | Jennifer Levine 74 | Randy Long 75 | Steve Looby 76 | Uche Onyekwuluje 77 | Catherine Powell 78 | Jeff Pozz 79 | Sarmad Sada 80 | John Schmidt 81 | Omri Schwarz 82 | Jay Splaine 83 | John Welle 84 | Mary-Anne Wolf 85 | Devon Yablonski 86 | Robert Zupko 87 | 88 | Interns: 89 | Ari Entlich 90 | Lori Monteleone 91 | 92 | Project Management & Technical Direction: 93 | Michael Fortson 94 | 95 | Other Past Permabit Contributors (for early work on the index): 96 | James Clough 97 | Dave Golombek 98 | Albert Lin 99 | Edwin Olson 100 | Dave Pinkney 101 | Rich Brennan 102 | 103 | And Very Special Thanks To: 104 | Norman Margolis, who started the whole thing 105 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Red Hat 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | # 02110-1301, USA. 18 | # 19 | 20 | INSTALL = install 21 | INSTALLOWNER ?= -o root -g root 22 | name ?= vdo 23 | defaultdocdir ?= /usr/share/doc 24 | defaultlicensedir ?= /usr/share/licenses 25 | DOCDIR=$(DESTDIR)/$(defaultdocdir)/$(name) 26 | LICENSEDIR=$(DESTDIR)/$(defaultlicensedir)/$(name) 27 | 28 | SUBDIRS = examples utils 29 | 30 | .PHONY: all clean install 31 | all clean: 32 | for d in $(SUBDIRS); do \ 33 | $(MAKE) -C $$d $@ || exit 1; \ 34 | done 35 | 36 | install: 37 | $(INSTALL) $(INSTALLOWNER) -d $(DOCDIR) 38 | $(INSTALL) $(INSTALLOWNER) -D -m 644 COPYING -t $(LICENSEDIR) 39 | for d in $(SUBDIRS); do \ 40 | $(MAKE) -C $$d $@ || exit 1; \ 41 | done 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vdo 2 | 3 | A set of userspace tools for managing pools of deduplicated and/or compressed 4 | block storage. 5 | 6 | ## Background 7 | 8 | VDO is a device-mapper target that provides inline block-level deduplication, 9 | compression, and thin provisioning capabilities for primary storage. VDO 10 | is managed through LVM and can be integrated into any existing storage stack. 11 | 12 | Deduplication is a technique for reducing the consumption of storage resources 13 | by eliminating multiple copies of duplicate blocks. Compression takes the 14 | individual unique blocks and shrinks them with coding algorithms; these reduced 15 | blocks are then efficiently packed together into physical blocks. Thin 16 | provisioning manages the mapping from logical block addresses presented by VDO 17 | to where the data has actually been stored, and also eliminates any blocks of 18 | all zeroes. 19 | 20 | With deduplication, instead of writing the same data more than once each 21 | duplicate block is detected and recorded as a reference to the original 22 | block. VDO maintains a mapping from logical block addresses (presented to the 23 | storage layer above VDO) to physical block addresses on the storage layer 24 | under VDO. After deduplication, multiple logical block addresses may be mapped 25 | to the same physical block address; these are called shared blocks and are 26 | reference-counted by the software. 27 | 28 | With VDO's compression, blocks are compressed with the fast LZ4 algorithm, and 29 | collected together where possible so that multiple compressed blocks fit within 30 | a single 4 KB block on the underlying storage. Each logical block address is 31 | mapped to a physical block address and an index within it for the desired 32 | compressed data. All compressed blocks are individually reference-counted for 33 | correctness. 34 | 35 | Block sharing and block compression are invisible to applications using the 36 | storage, which read and write blocks as they would if VDO were not present. 37 | When a shared block is overwritten, a new physical block is allocated for 38 | storing the new block data to ensure that other logical block addresses that 39 | are mapped to the shared physical block are not modified. 40 | 41 | This repository contains a set of userspace tools for managing VDO volumes. 42 | These include "vdoformat" for creating new volumes, "vdostats" for extracting 43 | statistics from those volumes, and a variety of support and debugging tools 44 | which should not be necessary during ordinary operation. 45 | 46 | ## History 47 | 48 | VDO was originally developed by Permabit Technology Corp. as a proprietary set 49 | of kernel modules and userspace tools. This software and technology has been 50 | acquired by Red Hat and relicensed under the GPL (v2 or later). The kernel 51 | module has been merged into the upstream Linux kernel as dm-vdo. 52 | 53 | ## Documentation 54 | 55 | - [RHEL9 VDO Documentation](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/deduplicating_and_compressing_logical_volumes_on_rhel/index) 56 | - [RHEL8 VDO Documentation](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/deduplicating_and_compressing_storage/index) 57 | - [RHEL7 VDO Integration Guide](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/storage_administration_guide/vdo-integration) 58 | - [RHEL7 VDO Evaluation Guide](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/storage_administration_guide/vdo-evaluation) 59 | 60 | ## Releases 61 | 62 | The master branch of this repository is intended to be compatible with the most 63 | recent version of the Linux kernel. These packages are available in active 64 | Fedora releases with matching kernel versions. 65 | 66 | Version | Oldest Supported Linux Kernel Version 67 | ------- | -------------------------------------- 68 | 8.3.x.x | 6.9.0 69 | 70 | Each older branch of this repository is intended to work with a specific 71 | release of Enterprise Linux (Red Hat Enterprise Linux, CentOS, etc.). 72 | 73 | Version | Intended Enterprise Linux Release 74 | ------- | --------------------------------- 75 | 6.1.x.x | EL7 (3.10.0-*.el7) 76 | 6.2.x.x | EL8 (4.18.0-*.el8) 77 | 8.2.x.x | EL9 (5.14.0-*.el9) 78 | 79 | * Pre-built versions with the required modifications for older Fedora releases 80 | can be found [here](https://copr.fedorainfracloud.org/coprs/rhawalsh/dm-vdo) 81 | and can be used by running `dnf copr enable rhawalsh/dm-vdo`. 82 | 83 | ## Building 84 | 85 | In order to build the user-level programs, invoke the following command 86 | from the top directory of this tree: 87 | 88 | make 89 | 90 | After building the user-level programs, they may be installed in the 91 | standard locations by invoking the following command from the top directory 92 | of this tree, as the root user: 93 | 94 | make install 95 | 96 | ## Communication Channels and Contributions 97 | 98 | Community feedback, participation and patches are welcome to the 99 | [vdo-devel](https://github.com/dm-vdo/vdo-devel) repository, which is the 100 | parent of this one. This repository does not accept pull requests. 101 | 102 | ## Licensing 103 | 104 | [GPL v2.0 or later](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). 105 | All contributions retain ownership by their original author, but must also be 106 | licensed under the GPL 2.0 or later to be merged. 107 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Red Hat 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | # 02110-1301, USA. 18 | # 19 | 20 | SUBDIRS = monitor 21 | 22 | .PHONY: all clean install 23 | all clean install: 24 | for d in $(SUBDIRS); do \ 25 | $(MAKE) -C $$d $@ || exit 1; \ 26 | done 27 | -------------------------------------------------------------------------------- /examples/monitor/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Red Hat 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | # 02110-1301, USA. 18 | # 19 | 20 | INSTALLFILES=monitor_check_vdostats_logicalSpace.pl \ 21 | monitor_check_vdostats_physicalSpace.pl \ 22 | monitor_check_vdostats_savingPercent.pl 23 | 24 | 25 | INSTALL = install 26 | INSTALLOWNER ?= -o root -g root 27 | defaultdocdir ?= /usr/share/doc 28 | name ?= vdo 29 | 30 | INSTALLDIR=$(DESTDIR)/$(defaultdocdir)/$(name)/examples/monitor 31 | 32 | .PHONY: all clean install 33 | all:; 34 | 35 | clean:; 36 | 37 | install: 38 | $(INSTALL) $(INSTALLOWNER) -d $(INSTALLDIR) 39 | for i in $(INSTALLFILES); do \ 40 | $(INSTALL) $(INSTALLOWNER) -m 755 $$i $(INSTALLDIR); \ 41 | done 42 | -------------------------------------------------------------------------------- /examples/monitor/monitor_check_vdostats_logicalSpace.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | ## 4 | # Copyright Red Hat 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 | # 02110-1301, USA. 20 | # 21 | # monitor_check_vdostats_logicalSpace.pl [--warning |-w ] 22 | # [--critical |-c ] 23 | # 24 | # 25 | # This script parses the output of "vdostats --verbose" for a given VDO 26 | # volume, processes the "used percent" value, and returns a status code, 27 | # and a single-line output with status information. 28 | # 29 | # Options: 30 | # 31 | # -c : critical threshold equal to or greater than 32 | # percent. 33 | # 34 | # -w : warning threshold equal to or less than 35 | # percent. 36 | # 37 | # The "vdostats" program must be in the path used by "sudo". 38 | # 39 | ## 40 | 41 | use strict; 42 | use warnings FATAL => qw(all); 43 | use Getopt::Long; 44 | 45 | # Constants for the service status return values. 46 | use constant { 47 | MONITOR_SERVICE_OK => 0, 48 | MONITOR_SERVICE_WARNING => 1, 49 | MONITOR_SERVICE_CRITICAL => 2, 50 | MONITOR_SERVICE_UNKNOWN => 3, 51 | }; 52 | 53 | my $inputWarnThreshold = -1; 54 | my $inputCritThreshold = -1; 55 | 56 | GetOptions("critical=i" => \$inputCritThreshold, 57 | "warning=i" => \$inputWarnThreshold); 58 | 59 | # Default warning and critical thresholds for "logical used percent". 60 | my $warnThreshold = 80; 61 | my $critThreshold = 95; 62 | 63 | if ($inputWarnThreshold >= 0 && $inputWarnThreshold <= 100) { 64 | $warnThreshold = $inputWarnThreshold; 65 | } 66 | 67 | if ($inputCritThreshold >= 0 && $inputCritThreshold <= 100) { 68 | $critThreshold = $inputCritThreshold; 69 | } 70 | 71 | # A hash to hold the statistics names and values gathered from input. 72 | my %stats = (); 73 | 74 | # Vital statistics for general VDO health. This array contains only the 75 | # names of the desired statistics to store in the %stats hash. 76 | my @statNames = ( 77 | 'operating mode', 78 | 'data blocks used', 79 | 'overhead blocks used', 80 | 'logical blocks used', 81 | 'physical blocks', 82 | 'logical blocks', 83 | 'used percent', 84 | 'saving percent', 85 | '1k-blocks available', 86 | ); 87 | 88 | ############################################################################# 89 | # Get the statistics output for the given VDO device name, and filter the 90 | # desired stats values. 91 | ## 92 | sub getStats { 93 | if (!$ARGV[0]) { 94 | return; 95 | } 96 | my $deviceName = $ARGV[0]; 97 | my @verboseStatsOutput = `sudo vdostats $deviceName --verbose`; 98 | foreach my $statLabel (@statNames) { 99 | foreach my $inpline (@verboseStatsOutput) { 100 | if ($inpline =~ $statLabel) { 101 | $inpline =~ /.*: (.*)$/; 102 | my $statValue = $1; 103 | $stats{$statLabel} = $statValue; 104 | } 105 | } 106 | } 107 | } 108 | 109 | ############################################################################# 110 | # main 111 | ## 112 | if (scalar(@ARGV) != 1) { 113 | print("Usage: monitor_check_vdostats_logicalSpace.pl\n"); 114 | print(" [--warning |-w VALUE]\n"); 115 | print(" [--critical|-c VALUE]\n"); 116 | print(" \n"); 117 | exit(MONITOR_SERVICE_UNKNOWN); 118 | } 119 | 120 | getStats(); 121 | 122 | # If the stats table is empty, nothing was found; return unknown status. 123 | # Otherwise, print the stats. 124 | if (!%stats) { 125 | printf("Unable to load vdostats verbose output.\n"); 126 | exit(MONITOR_SERVICE_UNKNOWN); 127 | } 128 | 129 | # Calculate logical percent used, and print the value. 130 | my $logicalUsedPercent = (100 131 | * $stats{"logical blocks used"} 132 | / $stats{"logical blocks"}); 133 | printf("logical used: %.2f%%\n", $logicalUsedPercent); 134 | 135 | # Process the critical and warning thresholds. 136 | # If critThreshold is less than warnThreshold, the only used percentage 137 | # return codes will be "OK" or "CRITICAL". 138 | if ($logicalUsedPercent >= $warnThreshold 139 | && $logicalUsedPercent < $critThreshold) { 140 | exit(MONITOR_SERVICE_WARNING); 141 | } 142 | 143 | if ($logicalUsedPercent >= $critThreshold) { 144 | exit(MONITOR_SERVICE_CRITICAL); 145 | } 146 | 147 | if ($logicalUsedPercent >= 0 && $logicalUsedPercent < $warnThreshold) { 148 | exit(MONITOR_SERVICE_OK); 149 | } 150 | 151 | # Default exit condition. 152 | exit(MONITOR_SERVICE_UNKNOWN); 153 | -------------------------------------------------------------------------------- /examples/monitor/monitor_check_vdostats_savingPercent.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | ## 4 | # Copyright Red Hat 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 | # 02110-1301, USA. 20 | # 21 | # monitor_check_vdostats_savingPercent.pl [--warning |-w ] 22 | # [--critical |-c ] 23 | # 24 | # 25 | # This script parses the output of "vdostats --verbose" for a given VDO 26 | # volume, processes the "used percent" value, and returns a status code, 27 | # and a single-line output with status information. 28 | # 29 | # Options: 30 | # 31 | # -c : critical threshold equal to or greater than 32 | # percent. 33 | # 34 | # -w : warning threshold equal to or less than 35 | # percent. 36 | # 37 | # The "vdostats" program must be in the path used by "sudo". 38 | # 39 | ## 40 | 41 | use strict; 42 | use warnings FATAL => qw(all); 43 | use Getopt::Long; 44 | 45 | # Constants for the service status return values. 46 | use constant { 47 | MONITOR_SERVICE_OK => 0, 48 | MONITOR_SERVICE_WARNING => 1, 49 | MONITOR_SERVICE_CRITICAL => 2, 50 | MONITOR_SERVICE_UNKNOWN => 3, 51 | }; 52 | 53 | my $inputWarnThreshold = -1; 54 | my $inputCritThreshold = -1; 55 | 56 | GetOptions("critical=i" => \$inputCritThreshold, 57 | "warning=i" => \$inputWarnThreshold); 58 | 59 | # Default warning and critical thresholds for "logical used percent". 60 | my $warnThreshold = 50; 61 | my $critThreshold = 5; 62 | 63 | if ($inputWarnThreshold >= 0 && $inputWarnThreshold <= 100) { 64 | $warnThreshold = $inputWarnThreshold; 65 | } 66 | 67 | if ($inputCritThreshold >= 0 && $inputCritThreshold <= 100) { 68 | $critThreshold = $inputCritThreshold; 69 | } 70 | 71 | # A hash to hold the statistics names and values gathered from input. 72 | my %stats = (); 73 | 74 | # Vital statistics for general VDO health. This array contains only the 75 | # names of the desired statistics to store in the %stats hash. 76 | my @statNames = ( 77 | 'operating mode', 78 | 'data blocks used', 79 | 'overhead blocks used', 80 | 'logical blocks used', 81 | 'physical blocks', 82 | 'logical blocks', 83 | 'used percent', 84 | 'saving percent', 85 | '1k-blocks available', 86 | ); 87 | 88 | ############################################################################# 89 | # Get the statistics output for the given VDO device name, and filter the 90 | # desired stats values. 91 | ## 92 | sub getStats { 93 | if (!$ARGV[0]) { 94 | return; 95 | } 96 | my $deviceName = $ARGV[0]; 97 | my @verboseStatsOutput = `sudo vdostats $deviceName --verbose`; 98 | foreach my $statLabel (@statNames) { 99 | foreach my $inpline (@verboseStatsOutput) { 100 | if ($inpline =~ $statLabel) { 101 | $inpline =~ /.*: (.*)$/; 102 | my $statValue = $1; 103 | $stats{$statLabel} = $statValue; 104 | } 105 | } 106 | } 107 | } 108 | 109 | ############################################################################# 110 | # main 111 | ## 112 | if (scalar(@ARGV) != 1) { 113 | print("Usage: monitor_check_vdostats_savingPercent.pl\n"); 114 | print(" [--warning |-w VALUE]\n"); 115 | print(" [--critical|-c VALUE]\n"); 116 | print(" \n"); 117 | exit(MONITOR_SERVICE_UNKNOWN); 118 | } 119 | 120 | getStats(); 121 | 122 | # If the stats table is empty, nothing was found; return unknown status. 123 | # Otherwise, print the stats. 124 | if (!%stats) { 125 | printf("Unable to load vdostats verbose output.\n"); 126 | exit(MONITOR_SERVICE_UNKNOWN); 127 | } 128 | 129 | printf("saving percent: %s%%\n", $stats{"saving percent"}); 130 | 131 | # Process the critical and warning thresholds. 132 | # If critThreshold is less than warnThreshold, the only used percentage 133 | # return codes will be "OK" or "CRITICAL". 134 | 135 | # An empty VDO volume has a saving percent of "N/A" when 0 logical blocks 136 | # are used. This is interpreted as an "OK" status. 137 | if ($stats{"saving percent"} =~ "N/A") { 138 | exit(MONITOR_SERVICE_OK); 139 | } 140 | 141 | if ($stats{"saving percent"} <= $warnThreshold 142 | && $stats{"saving percent"} > $critThreshold) { 143 | exit(MONITOR_SERVICE_WARNING); 144 | } 145 | 146 | if ($stats{"saving percent"} <= $critThreshold) { 147 | exit(MONITOR_SERVICE_CRITICAL); 148 | } 149 | 150 | if ($stats{"saving percent"} > $warnThreshold) { 151 | exit(MONITOR_SERVICE_OK); 152 | } 153 | 154 | # Default exit condition. 155 | exit(MONITOR_SERVICE_UNKNOWN); 156 | -------------------------------------------------------------------------------- /utils/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Red Hat 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | # 02110-1301, USA. 18 | # 19 | 20 | SUBDIRS = uds vdo 21 | 22 | .PHONY: all clean install 23 | all clean install: 24 | for d in $(SUBDIRS); do \ 25 | $(MAKE) -C $$d $@ || exit 1; \ 26 | done 27 | -------------------------------------------------------------------------------- /utils/uds/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Red Hat 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | # 02110-1301, USA. 18 | # 19 | 20 | BUILD_VERSION = 8.3.1.1 21 | 22 | DEPDIR = .deps 23 | 24 | ifdef LLVM 25 | export CC := clang 26 | export LD := ld.ldd 27 | endif 28 | 29 | ifeq ($(origin CC), default) 30 | CC := gcc 31 | endif 32 | 33 | ifeq ($(findstring clang, $(CC)),clang) 34 | # Ignore additional warnings for clang 35 | WARNS = -Wno-compare-distinct-pointer-types \ 36 | -Wno-gnu-statement-expression \ 37 | -Wno-gnu-zero-variadic-macro-arguments \ 38 | -Wno-implicit-const-int-float-conversion \ 39 | -Wno-language-extension-token 40 | else 41 | WARNS = -Wcast-align \ 42 | -Wcast-qual \ 43 | -Wformat=2 \ 44 | -Wlogical-op 45 | endif 46 | 47 | WARNS += -Wall \ 48 | -Werror \ 49 | -Wextra \ 50 | -Winit-self \ 51 | -Wmissing-include-dirs \ 52 | -Wpointer-arith \ 53 | -Wredundant-decls \ 54 | -Wunused \ 55 | -Wwrite-strings 56 | 57 | C_WARNS = -Wbad-function-cast \ 58 | -Wfloat-equal \ 59 | -Wmissing-declarations \ 60 | -Wmissing-format-attribute \ 61 | -Wmissing-prototypes \ 62 | -Wnested-externs \ 63 | -Wold-style-definition \ 64 | -Wswitch-default 65 | 66 | OPT_FLAGS = -O3 -fno-omit-frame-pointer 67 | DEBUG_FLAGS = 68 | RPM_OPT_FLAGS ?= -fpic 69 | GLOBAL_FLAGS = $(RPM_OPT_FLAGS) -D_GNU_SOURCE -g $(OPT_FLAGS) \ 70 | $(WARNS) $(shell getconf LFS_CFLAGS) $(DEBUG_FLAGS) \ 71 | -DCURRENT_VERSION='"$(BUILD_VERSION)"' \ 72 | 73 | CFLAGS = $(GLOBAL_FLAGS) -I. -std=gnu11 -pedantic $(C_WARNS) $(MY_CFLAGS) 74 | LDFLAGS = $(RPM_LD_FLAGS) $(MY_LDFLAGS) 75 | 76 | MY_FLAGS = 77 | MY_CFLAGS = $(MY_FLAGS) 78 | MY_LDFLAGS = 79 | 80 | vpath %.c . 81 | 82 | UDS_OBJECTS = chapter-index.o \ 83 | config.o \ 84 | delta-index.o \ 85 | dm-bufio.o \ 86 | errors.o \ 87 | event-count.o \ 88 | fileUtils.o \ 89 | funnel-queue.o \ 90 | geometry.o \ 91 | index.o \ 92 | index-layout.o \ 93 | index-page-map.o \ 94 | index-session.o \ 95 | io-factory.o \ 96 | logger.o \ 97 | memoryAlloc.o \ 98 | minisyslog.o \ 99 | murmurhash3.o \ 100 | open-chapter.o \ 101 | permassert.o \ 102 | radix-sort.o \ 103 | random.o \ 104 | requestQueue.o \ 105 | sparse-cache.o \ 106 | string-utils.o \ 107 | syscalls.o \ 108 | threadCondVar.o \ 109 | threadMutex.o \ 110 | threadSemaphore.o \ 111 | thread-utils.o \ 112 | time-utils.o \ 113 | volume.o \ 114 | volume-index.o 115 | 116 | .PHONY: all 117 | all: libuds.a 118 | 119 | .PHONY: clean 120 | clean: 121 | rm -rf *.o *.a $(DEPDIR) 122 | 123 | .PHONY: install 124 | install:; 125 | 126 | libuds.a: $(UDS_OBJECTS) 127 | rm -f $@ 128 | ar cr $@ $^ 129 | 130 | %.s: %.c 131 | $(CC) $(CFLAGS) -S $^ 132 | 133 | 134 | ######################################################################## 135 | # Dependency processing 136 | 137 | %.o: %.c 138 | @mkdir -p $(DEPDIR)/$(@D) $(@D) 139 | $(COMPILE.c) -MD -MF $(DEPDIR)/$*.d.new -MP -MT $@ $< -o $@ 140 | if cmp -s $(DEPDIR)/$*.d $(DEPDIR)/$*.d.new; then \ 141 | rm -f $(DEPDIR)/$*.d.new ; \ 142 | else \ 143 | mv -f $(DEPDIR)/$*.d.new $(DEPDIR)/$*.d ; \ 144 | fi 145 | 146 | $(DEPDIR)/%.d: %.c 147 | @mkdir -p $(@D) 148 | $(CC) $(CFLAGS) -MM -MF $@ -MP -MT $*.o $< 149 | 150 | ifneq ($(MAKECMDGOALS),clean) 151 | -include $(UDS_OBJECTS:%.o=$(DEPDIR)/%.d) 152 | endif 153 | -------------------------------------------------------------------------------- /utils/uds/chapter-index.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_CHAPTER_INDEX_H 7 | #define UDS_CHAPTER_INDEX_H 8 | 9 | #include 10 | 11 | #include "delta-index.h" 12 | #include "geometry.h" 13 | 14 | /* 15 | * A chapter index for an open chapter is a mutable structure that tracks all the records that have 16 | * been added to the chapter. A chapter index for a closed chapter is similar except that it is 17 | * immutable because the contents of a closed chapter can never change, and the immutable structure 18 | * is more efficient. Both types of chapter index are implemented with a delta index. 19 | */ 20 | 21 | /* The value returned when no entry is found in the chapter index. */ 22 | #define NO_CHAPTER_INDEX_ENTRY U16_MAX 23 | 24 | struct open_chapter_index { 25 | const struct index_geometry *geometry; 26 | struct delta_index delta_index; 27 | u64 virtual_chapter_number; 28 | u64 volume_nonce; 29 | size_t memory_size; 30 | }; 31 | 32 | int __must_check uds_make_open_chapter_index(struct open_chapter_index **chapter_index, 33 | const struct index_geometry *geometry, 34 | u64 volume_nonce); 35 | 36 | void uds_free_open_chapter_index(struct open_chapter_index *chapter_index); 37 | 38 | void uds_empty_open_chapter_index(struct open_chapter_index *chapter_index, 39 | u64 virtual_chapter_number); 40 | 41 | int __must_check uds_put_open_chapter_index_record(struct open_chapter_index *chapter_index, 42 | const struct uds_record_name *name, 43 | u32 page_number); 44 | 45 | int __must_check uds_pack_open_chapter_index_page(struct open_chapter_index *chapter_index, 46 | u8 *memory, u32 first_list, 47 | bool last_page, u32 *lists_packed); 48 | 49 | int __must_check uds_initialize_chapter_index_page(struct delta_index_page *index_page, 50 | const struct index_geometry *geometry, 51 | u8 *page_buffer, u64 volume_nonce); 52 | 53 | int __must_check uds_validate_chapter_index_page(const struct delta_index_page *index_page, 54 | const struct index_geometry *geometry); 55 | 56 | int __must_check uds_search_chapter_index_page(struct delta_index_page *index_page, 57 | const struct index_geometry *geometry, 58 | const struct uds_record_name *name, 59 | u16 *record_page_ptr); 60 | 61 | #endif /* UDS_CHAPTER_INDEX_H */ 62 | -------------------------------------------------------------------------------- /utils/uds/config.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_CONFIG_H 7 | #define UDS_CONFIG_H 8 | 9 | #include "geometry.h" 10 | #include "indexer.h" 11 | #include "io-factory.h" 12 | 13 | /* 14 | * The uds_configuration records a variety of parameters used to configure a new UDS index. Some 15 | * parameters are provided by the client, while others are fixed or derived from user-supplied 16 | * values. It is created when an index is created, and it is recorded in the index metadata. 17 | */ 18 | 19 | enum { 20 | DEFAULT_VOLUME_INDEX_MEAN_DELTA = 4096, 21 | DEFAULT_CACHE_CHAPTERS = 7, 22 | DEFAULT_SPARSE_SAMPLE_RATE = 32, 23 | MAX_ZONES = 16, 24 | }; 25 | 26 | /* A set of configuration parameters for the indexer. */ 27 | struct uds_configuration { 28 | /* Storage device for the index */ 29 | struct block_device *bdev; 30 | 31 | /* The maximum allowable size of the index */ 32 | size_t size; 33 | 34 | /* The offset where the index should start */ 35 | off_t offset; 36 | 37 | /* Parameters for the volume */ 38 | 39 | /* The volume layout */ 40 | struct index_geometry *geometry; 41 | 42 | /* Index owner's nonce */ 43 | u64 nonce; 44 | 45 | /* The number of threads used to process index requests */ 46 | unsigned int zone_count; 47 | 48 | /* The number of threads used to read volume pages */ 49 | unsigned int read_threads; 50 | 51 | /* Size of the page cache and sparse chapter index cache in chapters */ 52 | u32 cache_chapters; 53 | 54 | /* Parameters for the volume index */ 55 | 56 | /* The mean delta for the volume index */ 57 | u32 volume_index_mean_delta; 58 | 59 | /* Sampling rate for sparse indexing */ 60 | u32 sparse_sample_rate; 61 | }; 62 | 63 | /* On-disk structure of data for a version 8.02 index. */ 64 | struct uds_configuration_8_02 { 65 | /* Smaller (16), Small (64) or large (256) indices */ 66 | u32 record_pages_per_chapter; 67 | /* Total number of chapters per volume */ 68 | u32 chapters_per_volume; 69 | /* Number of sparse chapters per volume */ 70 | u32 sparse_chapters_per_volume; 71 | /* Size of the page cache, in chapters */ 72 | u32 cache_chapters; 73 | /* Unused field */ 74 | u32 unused; 75 | /* The volume index mean delta to use */ 76 | u32 volume_index_mean_delta; 77 | /* Size of a page, used for both record pages and index pages */ 78 | u32 bytes_per_page; 79 | /* Sampling rate for sparse indexing */ 80 | u32 sparse_sample_rate; 81 | /* Index owner's nonce */ 82 | u64 nonce; 83 | /* Virtual chapter remapped from physical chapter 0 */ 84 | u64 remapped_virtual; 85 | /* New physical chapter which remapped chapter was moved to */ 86 | u64 remapped_physical; 87 | } __packed; 88 | 89 | /* On-disk structure of data for a version 6.02 index. */ 90 | struct uds_configuration_6_02 { 91 | /* Smaller (16), Small (64) or large (256) indices */ 92 | u32 record_pages_per_chapter; 93 | /* Total number of chapters per volume */ 94 | u32 chapters_per_volume; 95 | /* Number of sparse chapters per volume */ 96 | u32 sparse_chapters_per_volume; 97 | /* Size of the page cache, in chapters */ 98 | u32 cache_chapters; 99 | /* Unused field */ 100 | u32 unused; 101 | /* The volume index mean delta to use */ 102 | u32 volume_index_mean_delta; 103 | /* Size of a page, used for both record pages and index pages */ 104 | u32 bytes_per_page; 105 | /* Sampling rate for sparse indexing */ 106 | u32 sparse_sample_rate; 107 | /* Index owner's nonce */ 108 | u64 nonce; 109 | } __packed; 110 | 111 | int __must_check uds_make_configuration(const struct uds_parameters *params, 112 | struct uds_configuration **config_ptr); 113 | 114 | void uds_free_configuration(struct uds_configuration *config); 115 | 116 | int __must_check uds_validate_config_contents(struct buffered_reader *reader, 117 | struct uds_configuration *config); 118 | 119 | int __must_check uds_write_config_contents(struct buffered_writer *writer, 120 | struct uds_configuration *config, u32 version); 121 | 122 | void uds_log_configuration(struct uds_configuration *config); 123 | 124 | #endif /* UDS_CONFIG_H */ 125 | -------------------------------------------------------------------------------- /utils/uds/cpu.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_CPU_H 7 | #define UDS_CPU_H 8 | 9 | #include 10 | 11 | /** 12 | * uds_prefetch_address() - Minimize cache-miss latency by attempting to move data into a CPU cache 13 | * before it is accessed. 14 | * 15 | * @address: the address to fetch (may be invalid) 16 | * @for_write: must be constant at compile time--false if for reading, true if for writing 17 | */ 18 | static inline void uds_prefetch_address(const void *address, bool for_write) 19 | { 20 | /* 21 | * for_write won't be a constant if we are compiled with optimization turned off, in which 22 | * case prefetching really doesn't matter. clang can't figure out that if for_write is a 23 | * constant, it can be passed as the second, mandatorily constant argument to prefetch(), 24 | * at least currently on llvm 12. 25 | */ 26 | if (__builtin_constant_p(for_write)) { 27 | if (for_write) 28 | __builtin_prefetch(address, true); 29 | else 30 | __builtin_prefetch(address, false); 31 | } 32 | } 33 | 34 | /** 35 | * uds_prefetch_range() - Minimize cache-miss latency by attempting to move a range of addresses 36 | * into a CPU cache before they are accessed. 37 | * 38 | * @start: the starting address to fetch (may be invalid) 39 | * @size: the number of bytes in the address range 40 | * @for_write: must be constant at compile time--false if for reading, true if for writing 41 | */ 42 | static inline void uds_prefetch_range(const void *start, unsigned int size, 43 | bool for_write) 44 | { 45 | /* 46 | * Count the number of cache lines to fetch, allowing for the address range to span an 47 | * extra cache line boundary due to address alignment. 48 | */ 49 | const char *address = (const char *) start; 50 | unsigned int offset = ((uintptr_t) address % L1_CACHE_BYTES); 51 | unsigned int cache_lines = (1 + ((size + offset) / L1_CACHE_BYTES)); 52 | 53 | while (cache_lines-- > 0) { 54 | uds_prefetch_address(address, for_write); 55 | address += L1_CACHE_BYTES; 56 | } 57 | } 58 | 59 | #endif /* UDS_CPU_H */ 60 | -------------------------------------------------------------------------------- /utils/uds/errors.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_ERRORS_H 7 | #define UDS_ERRORS_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | /* Custom error codes and error-related utilities */ 14 | #define VDO_SUCCESS 0 15 | 16 | /* Valid status codes for internal UDS functions. */ 17 | enum uds_status_codes { 18 | /* Successful return */ 19 | UDS_SUCCESS = VDO_SUCCESS, 20 | /* Used as a base value for reporting internal errors */ 21 | UDS_ERROR_CODE_BASE = 1024, 22 | /* Index overflow */ 23 | UDS_OVERFLOW = UDS_ERROR_CODE_BASE, 24 | /* Invalid argument passed to internal routine */ 25 | UDS_INVALID_ARGUMENT, 26 | /* UDS data structures are in an invalid state */ 27 | UDS_BAD_STATE, 28 | /* Attempt to enter the same name into an internal structure twice */ 29 | UDS_DUPLICATE_NAME, 30 | /* An assertion failed */ 31 | UDS_ASSERTION_FAILED, 32 | /* A request has been queued for later processing (not an error) */ 33 | UDS_QUEUED, 34 | /* This error range has already been registered */ 35 | UDS_ALREADY_REGISTERED, 36 | /* Attempt to read or write data outside the valid range */ 37 | UDS_OUT_OF_RANGE, 38 | /* The index session is disabled */ 39 | UDS_DISABLED, 40 | /* The index configuration or volume format is no longer supported */ 41 | UDS_UNSUPPORTED_VERSION, 42 | /* Some index structure is corrupt */ 43 | UDS_CORRUPT_DATA, 44 | /* No index state found */ 45 | UDS_NO_INDEX, 46 | /* Attempt to access incomplete index save data */ 47 | UDS_INDEX_NOT_SAVED_CLEANLY, 48 | /* No directory was found where one was expected */ 49 | UDS_NO_DIRECTORY, 50 | /* Could not load modules */ 51 | UDS_EMODULE_LOAD, 52 | /* Unknown error */ 53 | UDS_UNKNOWN_ERROR, 54 | /* One more than the last UDS_INTERNAL error code */ 55 | UDS_ERROR_CODE_LAST, 56 | /* One more than the last error this block will ever use */ 57 | UDS_ERROR_CODE_BLOCK_END = UDS_ERROR_CODE_BASE + 440, 58 | }; 59 | 60 | enum { 61 | VDO_MAX_ERROR_NAME_SIZE = 80, 62 | VDO_MAX_ERROR_MESSAGE_SIZE = 128, 63 | }; 64 | 65 | struct error_info { 66 | const char *name; 67 | const char *message; 68 | }; 69 | 70 | const char * __must_check uds_string_error(int errnum, char *buf, size_t buflen); 71 | 72 | const char *uds_string_error_name(int errnum, char *buf, size_t buflen); 73 | 74 | int uds_status_to_errno(int error); 75 | 76 | int uds_register_error_block(const char *block_name, int first_error, 77 | int last_reserved_error, const struct error_info *infos, 78 | size_t info_size); 79 | 80 | #endif /* UDS_ERRORS_H */ 81 | -------------------------------------------------------------------------------- /utils/uds/event-count.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef EVENT_COUNT_H 7 | #define EVENT_COUNT_H 8 | 9 | #include "time-utils.h" 10 | 11 | /* 12 | * An event count is a lock-free equivalent of a condition variable. 13 | * 14 | * Using an event count, a lock-free producer/consumer can wait for a state change (adding an item 15 | * to an empty queue, for example) without spinning or falling back on the use of mutex-based 16 | * locks. Signalling is cheap when there are no waiters (a memory fence), and preparing to wait is 17 | * also inexpensive (an atomic add instruction). 18 | * 19 | * A lock-free producer should call event_count_broadcast() after any mutation to the lock-free 20 | * data structure that a consumer might be waiting on. The consumers should poll for work like 21 | * this: 22 | * 23 | * for (;;) { 24 | * // Fast path--no additional cost to consumer. 25 | * if (lockfree_dequeue(&item)) 26 | * return item; 27 | * // Two-step wait: get current token and poll state, either cancelling 28 | * // the wait or waiting for the token to be signalled. 29 | * event_token_t token = event_count_prepare(event_count); 30 | * if (lockfree_dequeue(&item)) { 31 | * event_count_cancel(event_count, token); 32 | * return item; 33 | * } 34 | * event_count_wait(event_count, token, NULL); 35 | * // State has changed, but must check condition again, so loop. 36 | * } 37 | * 38 | * Once event_count_prepare() is called, the caller should neither sleep nor perform long-running 39 | * or blocking actions before passing the token to event_count_cancel() or event_count_wait(). The 40 | * implementation is optimized for a short polling window, and will not perform well if there are 41 | * outstanding tokens that have been signalled but not waited upon. 42 | */ 43 | 44 | struct event_count; 45 | 46 | typedef unsigned int event_token_t; 47 | 48 | int __must_check make_event_count(struct event_count **count_ptr); 49 | 50 | void free_event_count(struct event_count *count); 51 | 52 | void event_count_broadcast(struct event_count *count); 53 | 54 | event_token_t __must_check event_count_prepare(struct event_count *count); 55 | 56 | void event_count_cancel(struct event_count *count, event_token_t token); 57 | 58 | bool event_count_wait(struct event_count *count, event_token_t token, 59 | const ktime_t *timeout); 60 | 61 | #endif /* EVENT_COUNT_H */ 62 | -------------------------------------------------------------------------------- /utils/uds/funnel-queue.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef VDO_FUNNEL_QUEUE_H 7 | #define VDO_FUNNEL_QUEUE_H 8 | 9 | #include 10 | #include 11 | 12 | /* 13 | * A funnel queue is a simple (almost) lock-free queue that accepts entries from multiple threads 14 | * (multi-producer) and delivers them to a single thread (single-consumer). "Funnel" is an attempt 15 | * to evoke the image of requests from more than one producer being "funneled down" to a single 16 | * consumer. 17 | * 18 | * This is an unsynchronized but thread-safe data structure when used as intended. There is no 19 | * mechanism to ensure that only one thread is consuming from the queue. If more than one thread 20 | * attempts to consume from the queue, the resulting behavior is undefined. Clients must not 21 | * directly access or manipulate the internals of the queue, which are only exposed for the purpose 22 | * of allowing the very simple enqueue operation to be inlined. 23 | * 24 | * The implementation requires that a funnel_queue_entry structure (a link pointer) is embedded in 25 | * the queue entries, and pointers to those structures are used exclusively by the queue. No macros 26 | * are defined to template the queue, so the offset of the funnel_queue_entry in the records placed 27 | * in the queue must all be the same so the client can derive their structure pointer from the 28 | * entry pointer returned by vdo_funnel_queue_poll(). 29 | * 30 | * Callers are wholly responsible for allocating and freeing the entries. Entries may be freed as 31 | * soon as they are returned since this queue is not susceptible to the "ABA problem" present in 32 | * many lock-free data structures. The queue is dynamically allocated to ensure cache-line 33 | * alignment, but no other dynamic allocation is used. 34 | * 35 | * The algorithm is not actually 100% lock-free. There is a single point in vdo_funnel_queue_put() 36 | * at which a preempted producer will prevent the consumers from seeing items added to the queue by 37 | * later producers, and only if the queue is short enough or the consumer fast enough for it to 38 | * reach what was the end of the queue at the time of the preemption. 39 | * 40 | * The consumer function, vdo_funnel_queue_poll(), will return NULL when the queue is empty. To 41 | * wait for data to consume, spin (if safe) or combine the queue with a struct event_count to 42 | * signal the presence of new entries. 43 | */ 44 | 45 | /* This queue link structure must be embedded in client entries. */ 46 | struct funnel_queue_entry { 47 | /* The next (newer) entry in the queue. */ 48 | struct funnel_queue_entry *next; 49 | }; 50 | 51 | /* 52 | * The dynamically allocated queue structure, which is allocated on a cache line boundary so the 53 | * producer and consumer fields in the structure will land on separate cache lines. This should be 54 | * consider opaque but it is exposed here so vdo_funnel_queue_put() can be inlined. 55 | */ 56 | struct __aligned(L1_CACHE_BYTES) funnel_queue { 57 | /* 58 | * The producers' end of the queue, an atomically exchanged pointer that will never be 59 | * NULL. 60 | */ 61 | struct funnel_queue_entry *newest; 62 | 63 | /* The consumer's end of the queue, which is owned by the consumer and never NULL. */ 64 | struct funnel_queue_entry *oldest __aligned(L1_CACHE_BYTES); 65 | 66 | /* A dummy entry used to provide the non-NULL invariants above. */ 67 | struct funnel_queue_entry stub; 68 | }; 69 | 70 | int __must_check vdo_make_funnel_queue(struct funnel_queue **queue_ptr); 71 | 72 | void vdo_free_funnel_queue(struct funnel_queue *queue); 73 | 74 | /* 75 | * Put an entry on the end of the queue. 76 | * 77 | * The entry pointer must be to the struct funnel_queue_entry embedded in the caller's data 78 | * structure. The caller must be able to derive the address of the start of their data structure 79 | * from the pointer that passed in here, so every entry in the queue must have the struct 80 | * funnel_queue_entry at the same offset within the client's structure. 81 | */ 82 | static inline void vdo_funnel_queue_put(struct funnel_queue *queue, 83 | struct funnel_queue_entry *entry) 84 | { 85 | struct funnel_queue_entry *previous; 86 | 87 | /* 88 | * Barrier requirements: All stores relating to the entry ("next" pointer, containing data 89 | * structure fields) must happen before the previous->next store making it visible to the 90 | * consumer. Also, the entry's "next" field initialization to NULL must happen before any 91 | * other producer threads can see the entry (the xchg) and try to update the "next" field. 92 | * 93 | * xchg implements a full barrier. 94 | */ 95 | WRITE_ONCE(entry->next, NULL); 96 | previous = xchg(&queue->newest, entry); 97 | /* 98 | * Preemptions between these two statements hide the rest of the queue from the consumer, 99 | * preventing consumption until the following assignment runs. 100 | */ 101 | WRITE_ONCE(previous->next, entry); 102 | } 103 | 104 | struct funnel_queue_entry *__must_check vdo_funnel_queue_poll(struct funnel_queue *queue); 105 | 106 | bool __must_check vdo_is_funnel_queue_empty(struct funnel_queue *queue); 107 | 108 | bool __must_check vdo_is_funnel_queue_idle(struct funnel_queue *queue); 109 | 110 | #endif /* VDO_FUNNEL_QUEUE_H */ 111 | -------------------------------------------------------------------------------- /utils/uds/funnel-requestqueue.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_REQUEST_QUEUE_H 7 | #define UDS_REQUEST_QUEUE_H 8 | 9 | #include "indexer.h" 10 | 11 | /* 12 | * A simple request queue which will handle new requests in the order in which they are received, 13 | * and will attempt to handle requeued requests before new ones. However, the nature of the 14 | * implementation means that it cannot guarantee this ordering; the prioritization is merely a 15 | * hint. 16 | */ 17 | 18 | struct uds_request_queue; 19 | 20 | typedef void (*uds_request_queue_processor_fn)(struct uds_request *); 21 | 22 | int __must_check uds_make_request_queue(const char *queue_name, 23 | uds_request_queue_processor_fn processor, 24 | struct uds_request_queue **queue_ptr); 25 | 26 | void uds_request_queue_enqueue(struct uds_request_queue *queue, 27 | struct uds_request *request); 28 | 29 | void uds_request_queue_finish(struct uds_request_queue *queue); 30 | 31 | #endif /* UDS_REQUEST_QUEUE_H */ 32 | -------------------------------------------------------------------------------- /utils/uds/geometry.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_INDEX_GEOMETRY_H 7 | #define UDS_INDEX_GEOMETRY_H 8 | 9 | #include "indexer.h" 10 | 11 | /* 12 | * The index_geometry records parameters that define the layout of a UDS index volume, and the size and 13 | * shape of various index structures. It is created when the index is created, and is referenced by 14 | * many index sub-components. 15 | */ 16 | 17 | struct index_geometry { 18 | /* Size of a chapter page, in bytes */ 19 | size_t bytes_per_page; 20 | /* Number of record pages in a chapter */ 21 | u32 record_pages_per_chapter; 22 | /* Total number of chapters in a volume */ 23 | u32 chapters_per_volume; 24 | /* Number of sparsely-indexed chapters in a volume */ 25 | u32 sparse_chapters_per_volume; 26 | /* Number of bits used to determine delta list numbers */ 27 | u8 chapter_delta_list_bits; 28 | /* Virtual chapter remapped from physical chapter 0 */ 29 | u64 remapped_virtual; 30 | /* New physical chapter where the remapped chapter can be found */ 31 | u64 remapped_physical; 32 | 33 | /* 34 | * The following properties are derived from the ones above, but they are computed and 35 | * recorded as fields for convenience. 36 | */ 37 | /* Total number of pages in a volume, excluding the header */ 38 | u32 pages_per_volume; 39 | /* Total number of bytes in a volume, including the header */ 40 | size_t bytes_per_volume; 41 | /* Number of pages in a chapter */ 42 | u32 pages_per_chapter; 43 | /* Number of index pages in a chapter index */ 44 | u32 index_pages_per_chapter; 45 | /* Number of records that fit on a page */ 46 | u32 records_per_page; 47 | /* Number of records that fit in a chapter */ 48 | u32 records_per_chapter; 49 | /* Number of records that fit in a volume */ 50 | u64 records_per_volume; 51 | /* Number of delta lists per chapter index */ 52 | u32 delta_lists_per_chapter; 53 | /* Mean delta for chapter indexes */ 54 | u32 chapter_mean_delta; 55 | /* Number of bits needed for record page numbers */ 56 | u8 chapter_payload_bits; 57 | /* Number of bits used to compute addresses for chapter delta lists */ 58 | u8 chapter_address_bits; 59 | /* Number of densely-indexed chapters in a volume */ 60 | u32 dense_chapters_per_volume; 61 | }; 62 | 63 | enum { 64 | /* The number of bytes in a record (name + metadata) */ 65 | BYTES_PER_RECORD = (UDS_RECORD_NAME_SIZE + UDS_RECORD_DATA_SIZE), 66 | 67 | /* The default length of a page in a chapter, in bytes */ 68 | DEFAULT_BYTES_PER_PAGE = 1024 * BYTES_PER_RECORD, 69 | 70 | /* The default maximum number of records per page */ 71 | DEFAULT_RECORDS_PER_PAGE = DEFAULT_BYTES_PER_PAGE / BYTES_PER_RECORD, 72 | 73 | /* The default number of record pages in a chapter */ 74 | DEFAULT_RECORD_PAGES_PER_CHAPTER = 256, 75 | 76 | /* The default number of record pages in a chapter for a small index */ 77 | SMALL_RECORD_PAGES_PER_CHAPTER = 64, 78 | 79 | /* The default number of chapters in a volume */ 80 | DEFAULT_CHAPTERS_PER_VOLUME = 1024, 81 | 82 | /* The default number of sparsely-indexed chapters in a volume */ 83 | DEFAULT_SPARSE_CHAPTERS_PER_VOLUME = 0, 84 | 85 | /* The log2 of the default mean delta */ 86 | DEFAULT_CHAPTER_MEAN_DELTA_BITS = 16, 87 | 88 | /* The log2 of the number of delta lists in a large chapter */ 89 | DEFAULT_CHAPTER_DELTA_LIST_BITS = 12, 90 | 91 | /* The log2 of the number of delta lists in a small chapter */ 92 | SMALL_CHAPTER_DELTA_LIST_BITS = 10, 93 | 94 | /* The number of header pages per volume */ 95 | HEADER_PAGES_PER_VOLUME = 1, 96 | }; 97 | 98 | int __must_check uds_make_index_geometry(size_t bytes_per_page, u32 record_pages_per_chapter, 99 | u32 chapters_per_volume, 100 | u32 sparse_chapters_per_volume, u64 remapped_virtual, 101 | u64 remapped_physical, 102 | struct index_geometry **geometry_ptr); 103 | 104 | int __must_check uds_copy_index_geometry(struct index_geometry *source, 105 | struct index_geometry **geometry_ptr); 106 | 107 | void uds_free_index_geometry(struct index_geometry *geometry); 108 | 109 | u32 __must_check uds_map_to_physical_chapter(const struct index_geometry *geometry, 110 | u64 virtual_chapter); 111 | 112 | /* 113 | * Check whether this geometry is reduced by a chapter. This will only be true if the volume was 114 | * converted from a non-lvm volume to an lvm volume. 115 | */ 116 | static inline bool __must_check 117 | uds_is_reduced_index_geometry(const struct index_geometry *geometry) 118 | { 119 | return !!(geometry->chapters_per_volume & 1); 120 | } 121 | 122 | static inline bool __must_check 123 | uds_is_sparse_index_geometry(const struct index_geometry *geometry) 124 | { 125 | return geometry->sparse_chapters_per_volume > 0; 126 | } 127 | 128 | bool __must_check uds_has_sparse_chapters(const struct index_geometry *geometry, 129 | u64 oldest_virtual_chapter, 130 | u64 newest_virtual_chapter); 131 | 132 | bool __must_check uds_is_chapter_sparse(const struct index_geometry *geometry, 133 | u64 oldest_virtual_chapter, 134 | u64 newest_virtual_chapter, 135 | u64 virtual_chapter_number); 136 | 137 | u32 __must_check uds_chapters_to_expire(const struct index_geometry *geometry, 138 | u64 newest_chapter); 139 | 140 | #endif /* UDS_INDEX_GEOMETRY_H */ 141 | -------------------------------------------------------------------------------- /utils/uds/hash-utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_HASH_UTILS_H 7 | #define UDS_HASH_UTILS_H 8 | 9 | #include "numeric.h" 10 | 11 | #include "geometry.h" 12 | #include "indexer.h" 13 | 14 | /* Utilities for extracting portions of a request name for various uses. */ 15 | 16 | /* How various portions of a record name are apportioned. */ 17 | enum { 18 | VOLUME_INDEX_BYTES_OFFSET = 0, 19 | VOLUME_INDEX_BYTES_COUNT = 8, 20 | CHAPTER_INDEX_BYTES_OFFSET = 8, 21 | CHAPTER_INDEX_BYTES_COUNT = 6, 22 | SAMPLE_BYTES_OFFSET = 14, 23 | SAMPLE_BYTES_COUNT = 2, 24 | }; 25 | 26 | static inline u64 uds_extract_chapter_index_bytes(const struct uds_record_name *name) 27 | { 28 | const u8 *chapter_bits = &name->name[CHAPTER_INDEX_BYTES_OFFSET]; 29 | u64 bytes = (u64) get_unaligned_be16(chapter_bits) << 32; 30 | 31 | bytes |= get_unaligned_be32(chapter_bits + 2); 32 | return bytes; 33 | } 34 | 35 | static inline u64 uds_extract_volume_index_bytes(const struct uds_record_name *name) 36 | { 37 | return get_unaligned_be64(&name->name[VOLUME_INDEX_BYTES_OFFSET]); 38 | } 39 | 40 | static inline u32 uds_extract_sampling_bytes(const struct uds_record_name *name) 41 | { 42 | return get_unaligned_be16(&name->name[SAMPLE_BYTES_OFFSET]); 43 | } 44 | 45 | /* Compute the chapter delta list for a given name. */ 46 | static inline u32 uds_hash_to_chapter_delta_list(const struct uds_record_name *name, 47 | const struct index_geometry *geometry) 48 | { 49 | return ((uds_extract_chapter_index_bytes(name) >> geometry->chapter_address_bits) & 50 | ((1 << geometry->chapter_delta_list_bits) - 1)); 51 | } 52 | 53 | /* Compute the chapter delta address for a given name. */ 54 | static inline u32 uds_hash_to_chapter_delta_address(const struct uds_record_name *name, 55 | const struct index_geometry *geometry) 56 | { 57 | return uds_extract_chapter_index_bytes(name) & ((1 << geometry->chapter_address_bits) - 1); 58 | } 59 | 60 | static inline unsigned int uds_name_to_hash_slot(const struct uds_record_name *name, 61 | unsigned int slot_count) 62 | { 63 | return (unsigned int) (uds_extract_chapter_index_bytes(name) % slot_count); 64 | } 65 | 66 | #endif /* UDS_HASH_UTILS_H */ 67 | -------------------------------------------------------------------------------- /utils/uds/hlist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef HLIST_H 21 | #define HLIST_H 22 | 23 | #include 24 | 25 | /* 26 | * An "hlist" is a doubly linked list with the listhead being a single pointer 27 | * to the head of the list. 28 | * 29 | * The Linux kernel provides an hlist implementation in . This 30 | * file defines the hlist interfaces used by UDS for the user mode build. 31 | * 32 | * The equivalent used in the user implementation is a LIST. 33 | */ 34 | 35 | struct hlist_head { 36 | struct hlist_node *first; 37 | }; 38 | 39 | struct hlist_node { 40 | struct hlist_node *next, **pprev; 41 | }; 42 | 43 | #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) 44 | 45 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member) 46 | 47 | #define hlist_entry_safe(ptr, type, member) \ 48 | __extension__({ typeof(ptr) ____ptr = (ptr); \ 49 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ 50 | }) 51 | 52 | /** 53 | * Iterate over list of given type 54 | * @param pos the type * to use as a loop cursor. 55 | * @param head the head for your list. 56 | * @param member the name of the hlist_node within the struct. 57 | */ 58 | #define hlist_for_each_entry(pos, head, member) \ 59 | for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member); \ 60 | pos; \ 61 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) 62 | 63 | /** 64 | * Add a new entry at the beginning of the hlist 65 | * @param n new entry to be added 66 | * @param h hlist head to add it after 67 | */ 68 | static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) 69 | { 70 | struct hlist_node *first = h->first; 71 | WRITE_ONCE(n->next, first); 72 | if (first) 73 | WRITE_ONCE(first->pprev, &n->next); 74 | WRITE_ONCE(h->first, n); 75 | WRITE_ONCE(n->pprev, &h->first); 76 | } 77 | 78 | /** 79 | * Delete the specified hlist_node from its list 80 | * @param n Node to delete. 81 | */ 82 | static inline void hlist_del(struct hlist_node *n) 83 | { 84 | struct hlist_node *next = n->next; 85 | struct hlist_node **pprev = n->pprev; 86 | 87 | WRITE_ONCE(*pprev, next); 88 | if (next) 89 | WRITE_ONCE(next->pprev, pprev); 90 | } 91 | 92 | /** 93 | * Is the specified hlist_head structure an empty hlist? 94 | * @param h Structure to check. 95 | */ 96 | static inline int hlist_empty(const struct hlist_head *h) 97 | { 98 | return !READ_ONCE(h->first); 99 | } 100 | 101 | #endif /* HLIST_H */ 102 | -------------------------------------------------------------------------------- /utils/uds/index-layout.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_INDEX_LAYOUT_H 7 | #define UDS_INDEX_LAYOUT_H 8 | 9 | #include "config.h" 10 | #include "indexer.h" 11 | #include "io-factory.h" 12 | 13 | /* 14 | * The index layout describes the format of the index on the underlying storage, and is responsible 15 | * for creating those structures when the index is first created. It also validates the index data 16 | * when loading a saved index, and updates it when saving the index. 17 | */ 18 | 19 | struct index_layout; 20 | 21 | int __must_check uds_make_index_layout(struct uds_configuration *config, bool new_layout, 22 | struct index_layout **layout_ptr); 23 | 24 | void uds_free_index_layout(struct index_layout *layout); 25 | 26 | int __must_check uds_replace_index_layout_storage(struct index_layout *layout, 27 | struct block_device *bdev); 28 | 29 | int __must_check uds_load_index_state(struct index_layout *layout, 30 | struct uds_index *index); 31 | 32 | int __must_check uds_save_index_state(struct index_layout *layout, 33 | struct uds_index *index); 34 | 35 | int __must_check uds_discard_open_chapter(struct index_layout *layout); 36 | 37 | u64 __must_check uds_get_volume_nonce(struct index_layout *layout); 38 | 39 | int __must_check uds_open_volume_bufio(struct index_layout *layout, size_t block_size, 40 | unsigned int reserved_buffers, 41 | struct dm_bufio_client **client_ptr); 42 | 43 | #endif /* UDS_INDEX_LAYOUT_H */ 44 | -------------------------------------------------------------------------------- /utils/uds/index-page-map.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_INDEX_PAGE_MAP_H 7 | #define UDS_INDEX_PAGE_MAP_H 8 | 9 | #include "geometry.h" 10 | #include "io-factory.h" 11 | 12 | /* 13 | * The index maintains a page map which records how the chapter delta lists are distributed among 14 | * the index pages for each chapter, allowing the volume to be efficient about reading only pages 15 | * that it knows it will need. 16 | */ 17 | 18 | struct index_page_map { 19 | const struct index_geometry *geometry; 20 | u64 last_update; 21 | u32 entries_per_chapter; 22 | u16 *entries; 23 | }; 24 | 25 | int __must_check uds_make_index_page_map(const struct index_geometry *geometry, 26 | struct index_page_map **map_ptr); 27 | 28 | void uds_free_index_page_map(struct index_page_map *map); 29 | 30 | int __must_check uds_read_index_page_map(struct index_page_map *map, 31 | struct buffered_reader *reader); 32 | 33 | int __must_check uds_write_index_page_map(struct index_page_map *map, 34 | struct buffered_writer *writer); 35 | 36 | void uds_update_index_page_map(struct index_page_map *map, u64 virtual_chapter_number, 37 | u32 chapter_number, u32 index_page_number, 38 | u32 delta_list_number); 39 | 40 | u32 __must_check uds_find_index_page_number(const struct index_page_map *map, 41 | const struct uds_record_name *name, 42 | u32 chapter_number); 43 | 44 | void uds_get_list_number_bounds(const struct index_page_map *map, u32 chapter_number, 45 | u32 index_page_number, u32 *lowest_list, 46 | u32 *highest_list); 47 | 48 | u64 uds_compute_index_page_map_save_size(const struct index_geometry *geometry); 49 | 50 | #endif /* UDS_INDEX_PAGE_MAP_H */ 51 | -------------------------------------------------------------------------------- /utils/uds/index-session.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_INDEX_SESSION_H 7 | #define UDS_INDEX_SESSION_H 8 | 9 | #include 10 | #include 11 | 12 | #include "thread-utils.h" 13 | 14 | #include "config.h" 15 | #include "indexer.h" 16 | 17 | /* 18 | * The index session mediates all interactions with a UDS index. Once the index session is created, 19 | * it can be used to open, close, suspend, or recreate an index. It implements the majority of the 20 | * functions in the top-level UDS API. 21 | * 22 | * If any deduplication request fails due to an internal error, the index is marked disabled. It 23 | * will not accept any further requests and can only be closed. Closing the index will clear the 24 | * disabled flag, and the index can then be reopened and recovered using the same index session. 25 | */ 26 | 27 | struct __aligned(L1_CACHE_BYTES) session_stats { 28 | /* Post requests that found an entry */ 29 | u64 posts_found; 30 | /* Post requests found in the open chapter */ 31 | u64 posts_found_open_chapter; 32 | /* Post requests found in the dense index */ 33 | u64 posts_found_dense; 34 | /* Post requests found in the sparse index */ 35 | u64 posts_found_sparse; 36 | /* Post requests that did not find an entry */ 37 | u64 posts_not_found; 38 | /* Update requests that found an entry */ 39 | u64 updates_found; 40 | /* Update requests that did not find an entry */ 41 | u64 updates_not_found; 42 | /* Delete requests that found an entry */ 43 | u64 deletions_found; 44 | /* Delete requests that did not find an entry */ 45 | u64 deletions_not_found; 46 | /* Query requests that found an entry */ 47 | u64 queries_found; 48 | /* Query requests that did not find an entry */ 49 | u64 queries_not_found; 50 | /* Total number of requests */ 51 | u64 requests; 52 | }; 53 | 54 | enum index_suspend_status { 55 | /* An index load has started but the index is not ready for use. */ 56 | INDEX_OPENING = 0, 57 | /* The index is able to handle requests. */ 58 | INDEX_READY, 59 | /* The index is attempting to suspend a rebuild. */ 60 | INDEX_SUSPENDING, 61 | /* An index rebuild has been suspended. */ 62 | INDEX_SUSPENDED, 63 | /* An index rebuild is being stopped in order to shut down. */ 64 | INDEX_FREEING, 65 | }; 66 | 67 | struct index_load_context { 68 | struct mutex mutex; 69 | struct cond_var cond; 70 | enum index_suspend_status status; 71 | }; 72 | 73 | struct uds_index_session { 74 | unsigned int state; 75 | struct uds_index *index; 76 | struct uds_request_queue *callback_queue; 77 | struct uds_parameters parameters; 78 | struct index_load_context load_context; 79 | struct mutex request_mutex; 80 | struct cond_var request_cond; 81 | int request_count; 82 | struct session_stats stats; 83 | }; 84 | 85 | #endif /* UDS_INDEX_SESSION_H */ 86 | -------------------------------------------------------------------------------- /utils/uds/index.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_INDEX_H 7 | #define UDS_INDEX_H 8 | 9 | #include "index-layout.h" 10 | #include "index-session.h" 11 | #include "open-chapter.h" 12 | #include "volume.h" 13 | #include "volume-index.h" 14 | 15 | /* 16 | * The index is a high-level structure which represents the totality of the UDS index. It manages 17 | * the queues for incoming requests and dispatches them to the appropriate sub-components like the 18 | * volume or the volume index. It also manages administrative tasks such as saving and loading the 19 | * index. 20 | * 21 | * The index is divided into a number of independent zones and assigns each request to a zone based 22 | * on its name. Most sub-components are similarly divided into zones as well so that requests in 23 | * each zone usually operate without interference or coordination between zones. 24 | */ 25 | 26 | typedef void (*index_callback_fn)(struct uds_request *request); 27 | 28 | struct index_zone { 29 | struct uds_index *index; 30 | struct open_chapter_zone *open_chapter; 31 | struct open_chapter_zone *writing_chapter; 32 | u64 oldest_virtual_chapter; 33 | u64 newest_virtual_chapter; 34 | unsigned int id; 35 | }; 36 | 37 | struct uds_index { 38 | bool has_saved_open_chapter; 39 | bool need_to_save; 40 | struct index_load_context *load_context; 41 | struct index_layout *layout; 42 | struct volume_index *volume_index; 43 | struct volume *volume; 44 | unsigned int zone_count; 45 | struct index_zone **zones; 46 | 47 | u64 oldest_virtual_chapter; 48 | u64 newest_virtual_chapter; 49 | 50 | u64 last_save; 51 | u64 prev_save; 52 | struct chapter_writer *chapter_writer; 53 | 54 | index_callback_fn callback; 55 | struct uds_request_queue *triage_queue; 56 | struct uds_request_queue *zone_queues[]; 57 | }; 58 | 59 | enum request_stage { 60 | STAGE_TRIAGE, 61 | STAGE_INDEX, 62 | STAGE_MESSAGE, 63 | }; 64 | 65 | int __must_check uds_make_index(struct uds_configuration *config, 66 | enum uds_open_index_type open_type, 67 | struct index_load_context *load_context, 68 | index_callback_fn callback, struct uds_index **new_index); 69 | 70 | int __must_check uds_save_index(struct uds_index *index); 71 | 72 | void uds_free_index(struct uds_index *index); 73 | 74 | int __must_check uds_replace_index_storage(struct uds_index *index, 75 | struct block_device *bdev); 76 | 77 | void uds_get_index_stats(struct uds_index *index, struct uds_index_stats *counters); 78 | 79 | void uds_enqueue_request(struct uds_request *request, enum request_stage stage); 80 | 81 | void uds_wait_for_idle_index(struct uds_index *index); 82 | 83 | #endif /* UDS_INDEX_H */ 84 | -------------------------------------------------------------------------------- /utils/uds/io-factory.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_IO_FACTORY_H 7 | #define UDS_IO_FACTORY_H 8 | 9 | #include 10 | 11 | /* 12 | * The I/O factory manages all low-level I/O operations to the underlying storage device. Its main 13 | * clients are the index layout and the volume. The buffered reader and buffered writer interfaces 14 | * are helpers for accessing data in a contiguous range of storage blocks. 15 | */ 16 | 17 | struct buffered_reader; 18 | struct buffered_writer; 19 | 20 | struct io_factory; 21 | 22 | enum { 23 | UDS_BLOCK_SIZE = 4096, 24 | SECTORS_PER_BLOCK = UDS_BLOCK_SIZE >> SECTOR_SHIFT, 25 | }; 26 | 27 | int __must_check uds_make_io_factory(struct block_device *bdev, 28 | struct io_factory **factory_ptr); 29 | 30 | int __must_check uds_replace_storage(struct io_factory *factory, 31 | struct block_device *bdev); 32 | 33 | void uds_put_io_factory(struct io_factory *factory); 34 | 35 | size_t __must_check uds_get_writable_size(struct io_factory *factory); 36 | 37 | int __must_check uds_make_bufio(struct io_factory *factory, off_t block_offset, 38 | size_t block_size, unsigned int reserved_buffers, 39 | struct dm_bufio_client **client_ptr); 40 | 41 | int __must_check uds_make_buffered_reader(struct io_factory *factory, off_t offset, 42 | u64 block_count, 43 | struct buffered_reader **reader_ptr); 44 | 45 | void uds_free_buffered_reader(struct buffered_reader *reader); 46 | 47 | int __must_check uds_read_from_buffered_reader(struct buffered_reader *reader, u8 *data, 48 | size_t length); 49 | 50 | int __must_check uds_verify_buffered_data(struct buffered_reader *reader, const u8 *value, 51 | size_t length); 52 | 53 | int __must_check uds_make_buffered_writer(struct io_factory *factory, off_t offset, 54 | u64 block_count, 55 | struct buffered_writer **writer_ptr); 56 | 57 | void uds_free_buffered_writer(struct buffered_writer *buffer); 58 | 59 | int __must_check uds_write_to_buffered_writer(struct buffered_writer *writer, 60 | const u8 *data, size_t length); 61 | 62 | int __must_check uds_flush_buffered_writer(struct buffered_writer *writer); 63 | 64 | #endif /* UDS_IO_FACTORY_H */ 65 | -------------------------------------------------------------------------------- /utils/uds/linux/bitops.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * These are the small parts of linux/bits.h that we actually require for 4 | * unit testing, reimplemented without all of the architecture specific 5 | * macros. 6 | * 7 | * Copyright 2023 Red Hat 8 | * 9 | */ 10 | 11 | #ifndef _TOOLS_LINUX_BITOPS_H_ 12 | #define _TOOLS_LINUX_BITOPS_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | // From vdso/const.h 19 | #define UL(x) (_UL(x)) 20 | #define ULL(x) (_ULL(x)) 21 | 22 | #define BITS_PER_LONG 64 23 | #define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG)) 24 | #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) 25 | #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) 26 | 27 | #define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) 28 | #define BITS_TO_LONGS(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) 29 | #define BITS_TO_U64(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u64)) 30 | #define BITS_TO_U32(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u32)) 31 | #define BITS_TO_BYTES(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) 32 | 33 | /** 34 | * __set_bit - Set a bit in memory 35 | * @nr: the bit to set 36 | * @addr: the address to start counting from 37 | * 38 | * Unlike set_bit(), this function is non-atomic and may be reordered. 39 | * If it's called on the same region of memory simultaneously, the effect 40 | * may be that only one operation succeeds. 41 | **/ 42 | static inline void __set_bit(int nr, volatile unsigned long *addr) 43 | { 44 | unsigned long mask = BIT_MASK(nr); 45 | 46 | addr[BIT_WORD(nr)] |= mask; 47 | } 48 | 49 | /**********************************************************************/ 50 | static inline void __clear_bit(int nr, volatile unsigned long *addr) 51 | { 52 | unsigned long mask = BIT_MASK(nr); 53 | 54 | addr[BIT_WORD(nr)] &= ~mask; 55 | } 56 | 57 | /** 58 | * test_bit - Determine whether a bit is set 59 | * @nr: bit number to test 60 | * @addr: Address to start counting from 61 | **/ 62 | static inline int test_bit(int nr, const volatile unsigned long *addr) 63 | { 64 | return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); 65 | } 66 | 67 | /**********************************************************************/ 68 | unsigned long __must_check 69 | find_next_zero_bit(const unsigned long *addr, 70 | unsigned long size, 71 | unsigned long offset); 72 | 73 | /**********************************************************************/ 74 | unsigned long __must_check 75 | find_first_zero_bit(const unsigned long *addr, 76 | unsigned long size); 77 | 78 | #endif /* _TOOLS_LINUX_BITOPS_H_ */ 79 | 80 | -------------------------------------------------------------------------------- /utils/uds/linux/bits.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_LINUX_BITS_H 7 | #define UDS_LINUX_BITS_H 8 | 9 | /* 10 | * User-space header providing necessary define provided by the same kernel-space header. 11 | */ 12 | 13 | #define BITS_PER_BYTE 8 14 | 15 | #endif /* UDS_LINUX_BITS_H */ 16 | -------------------------------------------------------------------------------- /utils/uds/linux/blkdev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Unit test requirements from linux/blkdev.h and other kernel headers. 3 | */ 4 | 5 | #ifndef LINUX_BLKDEV_H 6 | #define LINUX_BLKDEV_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define SECTOR_SHIFT 9 14 | #define SECTOR_SIZE 512 15 | #define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */ 16 | 17 | /* Defined in linux/kdev_t.h */ 18 | #define MINORBITS 20 19 | #define MINORMASK ((1U << MINORBITS) - 1) 20 | 21 | #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) 22 | #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) 23 | 24 | #define format_dev_t(buffer, dev) \ 25 | sprintf(buffer, "%u:%u", MAJOR(dev), MINOR(dev)) 26 | 27 | /* Defined in linux/blk_types.h */ 28 | typedef u32 __bitwise blk_opf_t; 29 | typedef unsigned int blk_qc_t; 30 | 31 | typedef u8 __bitwise blk_status_t; 32 | #define BLK_STS_OK 0 33 | #define BLK_STS_NOSPC ((blk_status_t)3) 34 | #define BLK_STS_RESOURCE ((blk_status_t)9) 35 | #define BLK_STS_IOERR ((blk_status_t)10) 36 | 37 | /* hack for vdo, don't use elsewhere */ 38 | #define BLK_STS_VDO_INJECTED ((blk_status_t)31) 39 | 40 | struct bio; 41 | 42 | struct block_device { 43 | int fd; 44 | dev_t bd_dev; 45 | 46 | /* This is only here for bdev_nr_bytes(). */ 47 | loff_t size; 48 | }; 49 | 50 | /* Defined in linux/blk-core.c */ 51 | static const struct { 52 | int error; 53 | const char *name; 54 | } blk_errors[] = { 55 | [BLK_STS_OK] = { 0, "" }, 56 | [BLK_STS_NOSPC] = { -ENOSPC, "critical space allocation" }, 57 | [BLK_STS_RESOURCE] = { -ENOMEM, "kernel resource" }, 58 | 59 | /* error specifically for VDO unit tests */ 60 | [BLK_STS_VDO_INJECTED] = { 31, "vdo injected error" }, 61 | /* everything else not covered above: */ 62 | [BLK_STS_IOERR] = { -EIO, "I/O" }, 63 | }; 64 | 65 | /**********************************************************************/ 66 | static inline int blk_status_to_errno(blk_status_t status) 67 | { 68 | int idx = (int) status; 69 | 70 | return blk_errors[idx].error; 71 | } 72 | 73 | /**********************************************************************/ 74 | static inline blk_status_t errno_to_blk_status(int error) 75 | { 76 | unsigned int i; 77 | 78 | for (i = 0; i < ARRAY_SIZE(blk_errors); i++) { 79 | if (blk_errors[i].error == error) 80 | return (blk_status_t)i; 81 | } 82 | 83 | return BLK_STS_IOERR; 84 | } 85 | 86 | /**********************************************************************/ 87 | void submit_bio_noacct(struct bio *bio); 88 | 89 | /**********************************************************************/ 90 | static inline loff_t bdev_nr_bytes(struct block_device *bdev) 91 | { 92 | return bdev->size; 93 | } 94 | 95 | #endif // LINUX_BLKDEV_H 96 | -------------------------------------------------------------------------------- /utils/uds/linux/build_bug.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef _LINUX_BUILD_BUG_H 7 | #define _LINUX_BUILD_BUG_H 8 | 9 | #define BUILD_BUG_ON(condition) \ 10 | BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition) 11 | 12 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) 13 | 14 | #define _compiletime_assert(condition, msg, prefix, suffix) \ 15 | __compiletime_assert(condition, msg, prefix, suffix) 16 | 17 | #define compiletime_assert(condition, msg) \ 18 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) 19 | 20 | #define __compiletime_assert(condition, msg, prefix, suffix) do { } while (0) 21 | 22 | #endif /* _LINUX_BUILD_BUG_H */ 23 | -------------------------------------------------------------------------------- /utils/uds/linux/cache.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * User space definitions for things in linux/cache.h 4 | * 5 | * Copyright 2023 Red Hat 6 | */ 7 | 8 | #ifndef __LINUX_CACHE_H 9 | #define __LINUX_CACHE_H 10 | 11 | #include 12 | 13 | #if defined(__PPC__) 14 | /* N.B.: Some PPC processors have smaller cache lines. */ 15 | #define L1_CACHE_BYTES 128 16 | #elif defined(__s390x__) 17 | #define L1_CACHE_BYTES 256 18 | #elif defined(__x86_64__) || defined(__aarch64__) || defined(__riscv) || defined (__loongarch64) 19 | #define L1_CACHE_BYTES 64 20 | #else 21 | #error "unknown cache line size" 22 | #endif 23 | 24 | #endif /* __LINUX_CACHE_H */ 25 | -------------------------------------------------------------------------------- /utils/uds/linux/compiler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef LINUX_COMPILER_H 7 | #define LINUX_COMPILER_H 8 | 9 | #include 10 | 11 | /* 12 | * CPU Branch-prediction hints, courtesy of GCC. Defining these as inline functions instead of 13 | * macros spoils their magic, sadly. 14 | */ 15 | #define likely(expr) __builtin_expect(!!(expr), 1) 16 | #define unlikely(expr) __builtin_expect(!!(expr), 0) 17 | 18 | /* 19 | * Count the elements in a static array while attempting to catch some type errors. (See 20 | * http://stackoverflow.com/a/1598827 for an explanation.) 21 | */ 22 | #define ARRAY_SIZE(x) ((sizeof(x) / sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 23 | 24 | /* Defined in linux/container_of.h */ 25 | #define container_of(ptr, type, member) \ 26 | __extension__({ \ 27 | __typeof__(((type *) 0)->member) * __mptr = (ptr); \ 28 | (type *) ((char *) __mptr - offsetof(type, member)); \ 29 | }) 30 | 31 | #endif /* LINUX_COMPILER_H */ 32 | -------------------------------------------------------------------------------- /utils/uds/linux/compiler_attributes.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * User space attribute defines to match the ones in the kernel's 4 | * linux/compiler_attributes.h 5 | * 6 | * Copyright 2023 Red Hat 7 | */ 8 | #ifndef LINUX_COMPILER_ATTRIBUTES_H 9 | #define LINUX_COMPILER_ATTRIBUTES_H 10 | 11 | #define __always_unused __attribute__((unused)) 12 | #define __maybe_unused __attribute__((unused)) 13 | #define __must_check __attribute__((warn_unused_result)) 14 | #define noinline __attribute__((__noinline__)) 15 | #define __packed __attribute__((packed)) 16 | #define __printf(a, b) __attribute__((__format__(printf, a, b))) 17 | #define __aligned(x) __attribute__((__aligned__(x))) 18 | #define __must_hold(x) 19 | #define __releases(x) 20 | 21 | #if __has_attribute(__fallthrough__) 22 | #define fallthrough __attribute__((__fallthrough__)) 23 | #else 24 | #define fallthrough do {} while (0) /* fallthrough */ 25 | #endif 26 | 27 | #endif /* LINUX_COMPILER_ATTRIBUTES_H */ 28 | -------------------------------------------------------------------------------- /utils/uds/linux/const.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Definitions from linux/const.h that we actually require for 4 | * unit testing. 5 | * 6 | * Copyright 2023 Red Hat 7 | * 8 | */ 9 | 10 | #ifndef _UAPI_LINUX_CONST_H 11 | #define _UAPI_LINUX_CONST_H 12 | 13 | /* Some constant macros are used in both assembler and 14 | * C code. Therefore we cannot annotate them always with 15 | * 'UL' and other type specifiers unilaterally. We 16 | * use the following macros to deal with this. 17 | * 18 | * Similarly, _AT() will cast an expression with a type in C, but 19 | * leave it unchanged in asm. 20 | */ 21 | 22 | /* Macros for dealing with constants. */ 23 | #ifdef __ASSEMBLY__ 24 | #define _AC(X,Y) X 25 | #define _AT(T,X) X 26 | #else 27 | #define __AC(X,Y) (X##Y) 28 | #define _AC(X,Y) __AC(X,Y) 29 | #define _AT(T,X) ((T)(X)) 30 | #endif 31 | 32 | #define _UL(x) (_AC(x, UL)) 33 | #define _ULL(x) (_AC(x, ULL)) 34 | 35 | #define _BITUL(x) (_UL(1) << (x)) 36 | #define _BITULL(x) (_ULL(1) << (x)) 37 | 38 | #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) 39 | #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) 40 | 41 | #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 42 | 43 | #endif /* _UAPI_LINUX_CONST_H */ 44 | -------------------------------------------------------------------------------- /utils/uds/linux/dm-bufio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LINUX_DM_BUFIO_H 21 | #define LINUX_DM_BUFIO_H 22 | 23 | #include 24 | 25 | /* These are just the parts of dm-bufio interface that UDS uses. */ 26 | 27 | struct dm_bufio_client; 28 | struct dm_buffer; 29 | 30 | /* 31 | * Flags for dm_bufio_client_create 32 | */ 33 | #define DM_BUFIO_CLIENT_NO_SLEEP 0x1 34 | 35 | struct dm_bufio_client * 36 | dm_bufio_client_create(struct block_device *bdev, 37 | unsigned block_size, 38 | unsigned reserved_buffers, 39 | unsigned aux_size, 40 | void (*alloc_callback)(struct dm_buffer *), 41 | void (*write_callback)(struct dm_buffer *), 42 | unsigned int flags); 43 | 44 | void dm_bufio_client_destroy(struct dm_bufio_client *client); 45 | 46 | void dm_bufio_set_sector_offset(struct dm_bufio_client *client, 47 | sector_t start); 48 | 49 | void *dm_bufio_new(struct dm_bufio_client *client, 50 | sector_t block, 51 | struct dm_buffer **buffer_ptr); 52 | 53 | void *dm_bufio_read(struct dm_bufio_client *client, 54 | sector_t block, 55 | struct dm_buffer **buffer_ptr); 56 | 57 | void dm_bufio_prefetch(struct dm_bufio_client *client, 58 | sector_t block, 59 | unsigned block_count); 60 | 61 | void dm_bufio_release(struct dm_buffer *buffer); 62 | 63 | void dm_bufio_release_move(struct dm_buffer *buffer, sector_t new_block); 64 | 65 | void dm_bufio_mark_buffer_dirty(struct dm_buffer *buffer); 66 | 67 | int dm_bufio_write_dirty_buffers(struct dm_bufio_client *client); 68 | 69 | void *dm_bufio_get_block_data(struct dm_buffer *buffer); 70 | 71 | #endif /* LINUX_DM_BUFIO_H */ 72 | -------------------------------------------------------------------------------- /utils/uds/linux/err.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef LINUX_ERR_H 7 | #define LINUX_ERR_H 8 | 9 | #include 10 | #include 11 | 12 | #define MAX_ERRNO 4095 13 | 14 | #define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO) 15 | 16 | static inline void * __must_check ERR_PTR(long error) 17 | { 18 | return (void *) error; 19 | } 20 | 21 | static inline long __must_check PTR_ERR(const void *ptr) 22 | { 23 | return (long) ptr; 24 | } 25 | 26 | static inline bool __must_check IS_ERR(const void *ptr) 27 | { 28 | return IS_ERR_VALUE((unsigned long)ptr); 29 | } 30 | 31 | #endif /* LINUX_ERR_H */ 32 | -------------------------------------------------------------------------------- /utils/uds/linux/limits.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_LINUX_LIMITS_H 7 | #define UDS_LINUX_LIMITS_H 8 | 9 | #include 10 | #include 11 | 12 | #define U8_MAX ((u8)~0ul) 13 | #define S8_MAX ((s8)(U8_MAX >> 1)) 14 | #define U16_MAX ((u16)~0ul) 15 | #define S16_MAX ((s16)(U16_MAX >> 1)) 16 | #define U32_MAX ((u32)~0ul) 17 | #define S32_MAX ((s32)(U32_MAX >> 1)) 18 | #define U64_MAX ((u64)~0ul) 19 | #define S64_MAX ((s64)(U64_MAX >> 1)) 20 | 21 | /* 22 | * NAME_MAX and PATH_MAX were copied from /usr/include/limits/linux.h. 23 | */ 24 | #define NAME_MAX 255 25 | #define PATH_MAX 4096 26 | 27 | #endif /* UDS_LINUX_LIMITS_H */ 28 | -------------------------------------------------------------------------------- /utils/uds/linux/log2.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef _LINUX_LOG2_H 7 | #define _LINUX_LOG2_H 8 | 9 | #include "permassert.h" 10 | 11 | /* Compute the number of bits to represent n */ 12 | static inline unsigned int bits_per(unsigned int n) 13 | { 14 | unsigned int bits = 1; 15 | 16 | while (n > 1) { 17 | n >>= 1; 18 | bits++; 19 | } 20 | 21 | return bits; 22 | } 23 | 24 | /** 25 | * is_power_of_2() - Return true if and only if a number is a power of two. 26 | */ 27 | static inline bool is_power_of_2(uint64_t n) 28 | { 29 | return (n > 0) && ((n & (n - 1)) == 0); 30 | } 31 | 32 | /** 33 | * ilog2() - Efficiently calculate the base-2 logarithm of a number truncated 34 | * to an integer value. 35 | * @n: The input value. 36 | * 37 | * This also happens to be the bit index of the highest-order non-zero bit in 38 | * the binary representation of the number, which can easily be used to 39 | * calculate the bit shift corresponding to a bit mask or an array capacity, 40 | * or to calculate the binary floor or ceiling (next lowest or highest power 41 | * of two). 42 | * 43 | * Return: The integer log2 of the value, or -1 if the value is zero. 44 | */ 45 | static inline int ilog2(uint64_t n) 46 | { 47 | VDO_ASSERT_LOG_ONLY(n != 0, "ilog2() may not be passed 0"); 48 | /* 49 | * Many CPUs, including x86, directly support this calculation, so use 50 | * the GCC function for counting the number of leading high-order zero 51 | * bits. 52 | */ 53 | return 63 - __builtin_clzll(n); 54 | } 55 | 56 | #endif /* _LINUX_LOG2_H */ 57 | -------------------------------------------------------------------------------- /utils/uds/linux/mutex.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Wrap our own mutexes to mimic the kernel. 4 | * 5 | * Copyright 2023 Red Hat 6 | * 7 | */ 8 | 9 | #ifndef LINUX_MUTEX_H 10 | #define LINUX_MUTEX_H 11 | 12 | #include "thread-utils.h" 13 | 14 | #define DEFINE_MUTEX(mutexname) \ 15 | struct mutex mutexname = UDS_MUTEX_INITIALIZER 16 | 17 | #define mutex_destroy(mutex) uds_destroy_mutex(mutex) 18 | #define mutex_init(mutex) \ 19 | VDO_ASSERT_LOG_ONLY(uds_init_mutex(mutex) == UDS_SUCCESS, \ 20 | "mutex init succeeds") 21 | #define mutex_lock(mutex) uds_lock_mutex(mutex) 22 | #define mutex_unlock(mutex) uds_unlock_mutex(mutex) 23 | 24 | #endif // LINUX_MUTEX_H 25 | -------------------------------------------------------------------------------- /utils/uds/linux/random.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef LINUX_RANDOM_H 7 | #define LINUX_RANDOM_H 8 | 9 | #include 10 | 11 | void get_random_bytes(void *buffer, size_t byte_count); 12 | 13 | #endif /* LINUX_RANDOM_H */ 14 | -------------------------------------------------------------------------------- /utils/uds/linux/types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_LINUX_TYPES_H 7 | #define UDS_LINUX_TYPES_H 8 | 9 | /* 10 | * General system type definitions. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | typedef int8_t s8; 20 | typedef uint8_t u8; 21 | typedef int16_t s16; 22 | typedef uint16_t u16; 23 | typedef int32_t s32; 24 | typedef uint32_t u32; 25 | typedef int64_t s64; 26 | typedef uint64_t u64; 27 | 28 | typedef s8 __s8; 29 | typedef u8 __u8; 30 | typedef s16 __s16; 31 | typedef u16 __u16; 32 | typedef s32 __s32; 33 | typedef u32 __u32; 34 | typedef s64 __s64; 35 | typedef u64 __u64; 36 | 37 | #define __bitwise 38 | typedef __u16 __bitwise __le16; 39 | typedef __u16 __bitwise __be16; 40 | typedef __u32 __bitwise __le32; 41 | typedef __u32 __bitwise __be32; 42 | typedef __u64 __bitwise __le64; 43 | typedef __u64 __bitwise __be64; 44 | 45 | #define __aligned_u64 __u64 __attribute__((aligned(8))) 46 | 47 | typedef unsigned int fmode_t; 48 | #define FMODE_READ (fmode_t) 0x1 49 | #define FMODE_WRITE (fmode_t) 0x2 50 | 51 | typedef int pid_t; 52 | typedef u64 sector_t; 53 | 54 | #endif /* UDS_LINUX_TYPES_H */ 55 | -------------------------------------------------------------------------------- /utils/uds/linux/unaligned.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef LINUX_UNALIGNED_H 21 | #define LINUX_UNALIGNED_H 22 | 23 | #include 24 | #include 25 | 26 | /* Type safe comparison macros, similar to the ones in linux/minmax.h. */ 27 | 28 | /* 29 | * If pointers to types are comparable (without dereferencing them and 30 | * potentially causing side effects) then types are the same. 31 | */ 32 | #define __typecheck(x, y) \ 33 | (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1))) 34 | 35 | /* 36 | * Hack for VDO to replace use of the kernel's __is_constexpr() in __cmp_ macros. 37 | * VDO cannot use __is_constexpr() due to it relying on a GCC extension to allow sizeof(void). 38 | */ 39 | #define __constcheck(x, y) \ 40 | (__builtin_constant_p(x) && __builtin_constant_p(y)) 41 | 42 | /* It takes two levels of macro expansion to compose the unique temp names. */ 43 | #define ___PASTE(a,b) a##b 44 | #define __PASTE(a,b) ___PASTE(a,b) 45 | #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) 46 | 47 | /* Defined in linux/minmax.h */ 48 | #define __cmp_op_min < 49 | #define __cmp_op_max > 50 | 51 | #define __cmp(op, x, y) ((x) __cmp_op_##op (y) ? (x) : (y)) 52 | 53 | #define __cmp_once(op, x, y, unique_x, unique_y) \ 54 | __extension__({ \ 55 | typeof(x) unique_x = (x); \ 56 | typeof(y) unique_y = (y); \ 57 | __cmp(op, unique_x, unique_y); \ 58 | }) 59 | 60 | #define __careful_cmp(op, x, y) \ 61 | __builtin_choose_expr( \ 62 | (__typecheck(x, y) && __constcheck(x, y)), \ 63 | __cmp(op, x, y), \ 64 | __cmp_once(op, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_))) 65 | 66 | #define min(x, y) __careful_cmp(min, x, y) 67 | #define max(x, y) __careful_cmp(max, x, y) 68 | 69 | /* Defined in linux/minmax.h */ 70 | #define swap(a, b) \ 71 | do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) 72 | 73 | /* Defined in linux/math.h */ 74 | #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 75 | 76 | /* Defined in asm/unaligned.h */ 77 | static inline uint16_t get_unaligned_le16(const void *p) 78 | { 79 | return __le16_to_cpup((const __le16 *)p); 80 | } 81 | 82 | static inline uint32_t get_unaligned_le32(const void *p) 83 | { 84 | return __le32_to_cpup((const __le32 *)p); 85 | } 86 | 87 | static inline uint64_t get_unaligned_le64(const void *p) 88 | { 89 | return __le64_to_cpup((const __le64 *)p); 90 | } 91 | 92 | static inline uint16_t get_unaligned_be16(const void *p) 93 | { 94 | return __be16_to_cpup((const __be16 *)p); 95 | } 96 | 97 | static inline uint32_t get_unaligned_be32(const void *p) 98 | { 99 | return __be32_to_cpup((const __be32 *)p); 100 | } 101 | 102 | static inline uint64_t get_unaligned_be64(const void *p) 103 | { 104 | return __be64_to_cpup((const __be64 *)p); 105 | } 106 | 107 | static inline void put_unaligned_le16(uint16_t val, void *p) 108 | { 109 | *((__le16 *)p) = __cpu_to_le16(val); 110 | } 111 | 112 | static inline void put_unaligned_le32(uint32_t val, void *p) 113 | { 114 | *((__le32 *)p) = __cpu_to_le32(val); 115 | } 116 | 117 | static inline void put_unaligned_le64(uint64_t val, void *p) 118 | { 119 | *((__le64 *)p) = __cpu_to_le64(val); 120 | } 121 | 122 | static inline void put_unaligned_be16(uint16_t val, void *p) 123 | { 124 | *((__be16 *)p) = __cpu_to_be16(val); 125 | } 126 | 127 | static inline void put_unaligned_be32(uint32_t val, void *p) 128 | { 129 | *((__be32 *)p) = __cpu_to_be32(val); 130 | } 131 | 132 | static inline void put_unaligned_be64(uint64_t val, void *p) 133 | { 134 | *((__be64 *)p) = __cpu_to_be64(val); 135 | } 136 | 137 | #endif /* LINUX_UNALIGNED_H */ 138 | -------------------------------------------------------------------------------- /utils/uds/logger.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef VDO_LOGGER_H 7 | #define VDO_LOGGER_H 8 | 9 | #include 10 | #include "minisyslog.h" 11 | 12 | /* Custom logging utilities for UDS */ 13 | 14 | #define VDO_LOG_EMERG LOG_EMERG 15 | #define VDO_LOG_ALERT LOG_ALERT 16 | #define VDO_LOG_CRIT LOG_CRIT 17 | #define VDO_LOG_ERR LOG_ERR 18 | #define VDO_LOG_WARNING LOG_WARNING 19 | #define VDO_LOG_NOTICE LOG_NOTICE 20 | #define VDO_LOG_INFO LOG_INFO 21 | #define VDO_LOG_DEBUG LOG_DEBUG 22 | 23 | #define VDO_LOGGING_MODULE_NAME "vdo" 24 | 25 | /* Apply a rate limiter to a log method call. */ 26 | #define vdo_log_ratelimit(log_fn, ...) log_fn(__VA_ARGS__) 27 | 28 | int vdo_get_log_level(void); 29 | 30 | int vdo_log_string_to_priority(const char *string); 31 | 32 | const char *vdo_log_priority_to_string(int priority); 33 | 34 | void vdo_log_embedded_message(int priority, const char *module, const char *prefix, 35 | const char *fmt1, va_list args1, const char *fmt2, ...) 36 | __printf(4, 0) __printf(6, 7); 37 | 38 | void vdo_log_backtrace(int priority); 39 | 40 | /* All log functions will preserve the caller's value of errno. */ 41 | 42 | #define vdo_log_strerror(priority, errnum, ...) \ 43 | __vdo_log_strerror(priority, errnum, VDO_LOGGING_MODULE_NAME, __VA_ARGS__) 44 | 45 | int __vdo_log_strerror(int priority, int errnum, const char *module, 46 | const char *format, ...) 47 | __printf(4, 5); 48 | 49 | int vdo_vlog_strerror(int priority, int errnum, const char *module, const char *format, 50 | va_list args) 51 | __printf(4, 0); 52 | 53 | /* Log an error prefixed with the string associated with the errnum. */ 54 | #define vdo_log_error_strerror(errnum, ...) \ 55 | vdo_log_strerror(VDO_LOG_ERR, errnum, __VA_ARGS__) 56 | 57 | #define vdo_log_debug_strerror(errnum, ...) \ 58 | vdo_log_strerror(VDO_LOG_DEBUG, errnum, __VA_ARGS__) 59 | 60 | #define vdo_log_info_strerror(errnum, ...) \ 61 | vdo_log_strerror(VDO_LOG_INFO, errnum, __VA_ARGS__) 62 | 63 | #define vdo_log_warning_strerror(errnum, ...) \ 64 | vdo_log_strerror(VDO_LOG_WARNING, errnum, __VA_ARGS__) 65 | 66 | #define vdo_log_fatal_strerror(errnum, ...) \ 67 | vdo_log_strerror(VDO_LOG_CRIT, errnum, __VA_ARGS__) 68 | 69 | void vdo_log_message(int priority, const char *format, ...) 70 | __printf(2, 3); 71 | 72 | #define vdo_log_debug(...) vdo_log_message(VDO_LOG_DEBUG, __VA_ARGS__) 73 | 74 | #define vdo_log_info(...) vdo_log_message(VDO_LOG_INFO, __VA_ARGS__) 75 | 76 | #define vdo_log_warning(...) vdo_log_message(VDO_LOG_WARNING, __VA_ARGS__) 77 | 78 | #define vdo_log_error(...) vdo_log_message(VDO_LOG_ERR, __VA_ARGS__) 79 | 80 | #define vdo_log_fatal(...) vdo_log_message(VDO_LOG_CRIT, __VA_ARGS__) 81 | 82 | void vdo_pause_for_logger(void); 83 | 84 | void open_vdo_logger(void); 85 | #endif /* VDO_LOGGER_H */ 86 | -------------------------------------------------------------------------------- /utils/uds/memoryAlloc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "logger.h" 11 | #include "memory-alloc.h" 12 | 13 | enum { DEFAULT_MALLOC_ALIGNMENT = 2 * sizeof(size_t) }; // glibc malloc 14 | 15 | /** 16 | * Allocate storage based on memory size and alignment, logging an error if 17 | * the allocation fails. The memory will be zeroed. 18 | * 19 | * @param size The size of an object 20 | * @param align The required alignment 21 | * @param what What is being allocated (for error logging) 22 | * @param ptr A pointer to hold the allocated memory 23 | * 24 | * @return VDO_SUCCESS or an error code 25 | **/ 26 | int vdo_allocate_memory(size_t size, size_t align, const char *what, void *ptr) 27 | { 28 | int result; 29 | void *p; 30 | 31 | if (ptr == NULL) 32 | return UDS_INVALID_ARGUMENT; 33 | 34 | if (size == 0) { 35 | // We can skip the malloc call altogether. 36 | *((void **) ptr) = NULL; 37 | return VDO_SUCCESS; 38 | } 39 | 40 | if (align > DEFAULT_MALLOC_ALIGNMENT) { 41 | result = posix_memalign(&p, align, size); 42 | if (result != 0) { 43 | if (what != NULL) 44 | vdo_log_error_strerror(result, 45 | "failed to posix_memalign %s (%zu bytes)", 46 | what, 47 | size); 48 | 49 | return -result; 50 | } 51 | } else { 52 | p = malloc(size); 53 | if (p == NULL) { 54 | result = errno; 55 | if (what != NULL) 56 | vdo_log_error_strerror(result, 57 | "failed to allocate %s (%zu bytes)", 58 | what, 59 | size); 60 | 61 | return -result; 62 | } 63 | } 64 | 65 | memset(p, 0, size); 66 | *((void **) ptr) = p; 67 | return VDO_SUCCESS; 68 | } 69 | 70 | /* 71 | * Allocate storage based on memory size, failing immediately if the required 72 | * memory is not available. The memory will be zeroed. 73 | * 74 | * @param size The size of an object. 75 | * @param what What is being allocated (for error logging) 76 | * 77 | * @return pointer to the allocated memory, or NULL if the required space is 78 | * not available. 79 | */ 80 | void *vdo_allocate_memory_nowait(size_t size, const char *what) 81 | { 82 | void *p = NULL; 83 | 84 | vdo_allocate(size, char *, what, &p); 85 | return p; 86 | } 87 | 88 | /**********************************************************************/ 89 | void vdo_free(void *ptr) 90 | { 91 | free(ptr); 92 | } 93 | 94 | /** 95 | * Reallocate dynamically allocated memory. There are no alignment guarantees 96 | * for the reallocated memory. If the new memory is larger than the old memory, 97 | * the new space will be zeroed. 98 | * 99 | * @param ptr The memory to reallocate. 100 | * @param old_size The old size of the memory 101 | * @param size The new size to allocate 102 | * @param what What is being allocated (for error logging) 103 | * @param new_ptr A pointer to hold the reallocated pointer 104 | * 105 | * @return VDO_SUCCESS or an error code 106 | **/ 107 | int vdo_reallocate_memory(void *ptr, 108 | size_t old_size, 109 | size_t size, 110 | const char *what, 111 | void *new_ptr) 112 | { 113 | char *new = realloc(ptr, size); 114 | 115 | if ((new == NULL) && (size != 0)) 116 | return vdo_log_error_strerror(-errno, 117 | "failed to reallocate %s (%zu bytes)", 118 | what, 119 | size); 120 | 121 | if (size > old_size) 122 | memset(new + old_size, 0, size - old_size); 123 | 124 | *((void **) new_ptr) = new; 125 | return VDO_SUCCESS; 126 | } 127 | 128 | /**********************************************************************/ 129 | int vdo_duplicate_string(const char *string, 130 | const char *what, 131 | char **new_string) 132 | { 133 | int result; 134 | u8 *dup = NULL; 135 | 136 | result = vdo_allocate(strlen(string) + 1, u8, what, &dup); 137 | if (result != VDO_SUCCESS) 138 | return result; 139 | 140 | memcpy(dup, string, strlen(string) + 1); 141 | *new_string = (char *) dup; 142 | return VDO_SUCCESS; 143 | } 144 | -------------------------------------------------------------------------------- /utils/uds/minisyslog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef MINISYSLOG_H 21 | #define MINISYSLOG_H 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | /** 29 | * @file 30 | * 31 | * Replacements for the syslog library functions so that the library 32 | * calls do not conflict with the application calling syslog. 33 | **/ 34 | 35 | /** 36 | * Open the logger. The function mimics the openlog() c-library function. 37 | * 38 | * @param ident The identity string to prepended to all log messages 39 | * @param option The logger options (see the openlog(3) man page). 40 | * @param facility The type of program logging the message. 41 | **/ 42 | void mini_openlog(const char *ident, int option, int facility); 43 | 44 | /** 45 | * Log a message. This function mimics the syslog() c-library function. 46 | * 47 | * @param priority The priority level of the message 48 | * @param format A printf style message format 49 | **/ 50 | void mini_syslog(int priority, const char *format, ...) 51 | __printf(2, 3); 52 | 53 | /** 54 | * Log a message. This function mimics the vsyslog() c-library function. 55 | * 56 | * @param priority The priority level of the message 57 | * @param format A printf style message format 58 | * @param ap An argument list obtained from stdarg() 59 | **/ 60 | void mini_vsyslog(int priority, const char *format, va_list ap) 61 | __printf(2, 0); 62 | 63 | /** 64 | * Log a message pack consisting of multiple variable sections. 65 | * 66 | * @param priority the priority at which to log the message 67 | * @param prefix optional string prefix to message, may be NULL 68 | * @param fmt1 format of message first part, may be NULL 69 | * @param args1 arguments for message first part 70 | * @param fmt2 format of message second part, may be NULL 71 | * @param args2 arguments for message second part 72 | **/ 73 | void mini_syslog_pack(int priority, 74 | const char *prefix, 75 | const char *fmt1, 76 | va_list args1, 77 | const char *fmt2, 78 | va_list args2) 79 | __printf(3, 0) __printf(5, 0); 80 | 81 | /** 82 | * Close a logger. This function mimics the closelog() c-library function. 83 | **/ 84 | void mini_closelog(void); 85 | 86 | #endif /* MINI_SYSLOG_H */ 87 | -------------------------------------------------------------------------------- /utils/uds/murmurhash3.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.1+ 2 | /* 3 | * MurmurHash3 was written by Austin Appleby, and is placed in the public 4 | * domain. The author hereby disclaims copyright to this source code. 5 | * 6 | * Adapted by John Wiele (jwiele@redhat.com). 7 | */ 8 | 9 | #include "murmurhash3.h" 10 | 11 | #include 12 | 13 | static inline u64 rotl64(u64 x, s8 r) 14 | { 15 | return (x << r) | (x >> (64 - r)); 16 | } 17 | 18 | #define ROTL64(x, y) rotl64(x, y) 19 | 20 | /* Finalization mix - force all bits of a hash block to avalanche */ 21 | 22 | static __always_inline u64 fmix64(u64 k) 23 | { 24 | k ^= k >> 33; 25 | k *= 0xff51afd7ed558ccdLLU; 26 | k ^= k >> 33; 27 | k *= 0xc4ceb9fe1a85ec53LLU; 28 | k ^= k >> 33; 29 | 30 | return k; 31 | } 32 | 33 | void murmurhash3_128(const void *key, const int len, const u32 seed, void *out) 34 | { 35 | const u8 *data = key; 36 | const int nblocks = len / 16; 37 | 38 | u64 h1 = seed; 39 | u64 h2 = seed; 40 | 41 | const u64 c1 = 0x87c37b91114253d5LLU; 42 | const u64 c2 = 0x4cf5ad432745937fLLU; 43 | 44 | u64 *hash_out = out; 45 | 46 | /* body */ 47 | int i; 48 | 49 | for (i = 0; i < nblocks; i++) { 50 | u64 k1 = get_unaligned_le64(&data[i * 16]); 51 | u64 k2 = get_unaligned_le64(&data[i * 16 + 8]); 52 | 53 | k1 *= c1; 54 | k1 = ROTL64(k1, 31); 55 | k1 *= c2; 56 | h1 ^= k1; 57 | 58 | h1 = ROTL64(h1, 27); 59 | h1 += h2; 60 | h1 = h1 * 5 + 0x52dce729; 61 | 62 | k2 *= c2; 63 | k2 = ROTL64(k2, 33); 64 | k2 *= c1; 65 | h2 ^= k2; 66 | 67 | h2 = ROTL64(h2, 31); 68 | h2 += h1; 69 | h2 = h2 * 5 + 0x38495ab5; 70 | } 71 | 72 | /* tail */ 73 | 74 | { 75 | const u8 *tail = (const u8 *)(data + nblocks * 16); 76 | 77 | u64 k1 = 0; 78 | u64 k2 = 0; 79 | 80 | switch (len & 15) { 81 | case 15: 82 | k2 ^= ((u64)tail[14]) << 48; 83 | fallthrough; 84 | case 14: 85 | k2 ^= ((u64)tail[13]) << 40; 86 | fallthrough; 87 | case 13: 88 | k2 ^= ((u64)tail[12]) << 32; 89 | fallthrough; 90 | case 12: 91 | k2 ^= ((u64)tail[11]) << 24; 92 | fallthrough; 93 | case 11: 94 | k2 ^= ((u64)tail[10]) << 16; 95 | fallthrough; 96 | case 10: 97 | k2 ^= ((u64)tail[9]) << 8; 98 | fallthrough; 99 | case 9: 100 | k2 ^= ((u64)tail[8]) << 0; 101 | k2 *= c2; 102 | k2 = ROTL64(k2, 33); 103 | k2 *= c1; 104 | h2 ^= k2; 105 | fallthrough; 106 | 107 | case 8: 108 | k1 ^= ((u64)tail[7]) << 56; 109 | fallthrough; 110 | case 7: 111 | k1 ^= ((u64)tail[6]) << 48; 112 | fallthrough; 113 | case 6: 114 | k1 ^= ((u64)tail[5]) << 40; 115 | fallthrough; 116 | case 5: 117 | k1 ^= ((u64)tail[4]) << 32; 118 | fallthrough; 119 | case 4: 120 | k1 ^= ((u64)tail[3]) << 24; 121 | fallthrough; 122 | case 3: 123 | k1 ^= ((u64)tail[2]) << 16; 124 | fallthrough; 125 | case 2: 126 | k1 ^= ((u64)tail[1]) << 8; 127 | fallthrough; 128 | case 1: 129 | k1 ^= ((u64)tail[0]) << 0; 130 | k1 *= c1; 131 | k1 = ROTL64(k1, 31); 132 | k1 *= c2; 133 | h1 ^= k1; 134 | break; 135 | default: 136 | break; 137 | } 138 | } 139 | /* finalization */ 140 | 141 | h1 ^= len; 142 | h2 ^= len; 143 | 144 | h1 += h2; 145 | h2 += h1; 146 | 147 | h1 = fmix64(h1); 148 | h2 = fmix64(h2); 149 | 150 | h1 += h2; 151 | h2 += h1; 152 | 153 | put_unaligned_le64(h1, &hash_out[0]); 154 | put_unaligned_le64(h2, &hash_out[1]); 155 | } 156 | -------------------------------------------------------------------------------- /utils/uds/murmurhash3.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ 2 | /* 3 | * MurmurHash3 was written by Austin Appleby, and is placed in the public 4 | * domain. The author hereby disclaims copyright to this source code. 5 | */ 6 | 7 | #ifndef _MURMURHASH3_H_ 8 | #define _MURMURHASH3_H_ 9 | 10 | #include 11 | #include 12 | 13 | void murmurhash3_128(const void *key, int len, u32 seed, void *out); 14 | 15 | #endif /* _MURMURHASH3_H_ */ 16 | -------------------------------------------------------------------------------- /utils/uds/numeric.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_NUMERIC_H 7 | #define UDS_NUMERIC_H 8 | 9 | #include 10 | #include 11 | 12 | /* 13 | * These utilities encode or decode a number from an offset in a larger data buffer and then 14 | * advance the offset pointer to the next field in the buffer. 15 | */ 16 | 17 | static inline void decode_s64_le(const u8 *buffer, size_t *offset, s64 *decoded) 18 | { 19 | *decoded = get_unaligned_le64(buffer + *offset); 20 | *offset += sizeof(s64); 21 | } 22 | 23 | static inline void encode_s64_le(u8 *data, size_t *offset, s64 to_encode) 24 | { 25 | put_unaligned_le64(to_encode, data + *offset); 26 | *offset += sizeof(s64); 27 | } 28 | 29 | static inline void decode_u64_le(const u8 *buffer, size_t *offset, u64 *decoded) 30 | { 31 | *decoded = get_unaligned_le64(buffer + *offset); 32 | *offset += sizeof(u64); 33 | } 34 | 35 | static inline void encode_u64_le(u8 *data, size_t *offset, u64 to_encode) 36 | { 37 | put_unaligned_le64(to_encode, data + *offset); 38 | *offset += sizeof(u64); 39 | } 40 | 41 | static inline void decode_s32_le(const u8 *buffer, size_t *offset, s32 *decoded) 42 | { 43 | *decoded = get_unaligned_le32(buffer + *offset); 44 | *offset += sizeof(s32); 45 | } 46 | 47 | static inline void encode_s32_le(u8 *data, size_t *offset, s32 to_encode) 48 | { 49 | put_unaligned_le32(to_encode, data + *offset); 50 | *offset += sizeof(s32); 51 | } 52 | 53 | static inline void decode_u32_le(const u8 *buffer, size_t *offset, u32 *decoded) 54 | { 55 | *decoded = get_unaligned_le32(buffer + *offset); 56 | *offset += sizeof(u32); 57 | } 58 | 59 | static inline void encode_u32_le(u8 *data, size_t *offset, u32 to_encode) 60 | { 61 | put_unaligned_le32(to_encode, data + *offset); 62 | *offset += sizeof(u32); 63 | } 64 | 65 | static inline void decode_u16_le(const u8 *buffer, size_t *offset, u16 *decoded) 66 | { 67 | *decoded = get_unaligned_le16(buffer + *offset); 68 | *offset += sizeof(u16); 69 | } 70 | 71 | static inline void encode_u16_le(u8 *data, size_t *offset, u16 to_encode) 72 | { 73 | put_unaligned_le16(to_encode, data + *offset); 74 | *offset += sizeof(u16); 75 | } 76 | 77 | #endif /* UDS_NUMERIC_H */ 78 | -------------------------------------------------------------------------------- /utils/uds/open-chapter.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_OPEN_CHAPTER_H 7 | #define UDS_OPEN_CHAPTER_H 8 | 9 | #include "chapter-index.h" 10 | #include "geometry.h" 11 | #include "index.h" 12 | #include "volume.h" 13 | 14 | /* 15 | * The open chapter tracks the newest records in memory. Like the index as a whole, each open 16 | * chapter is divided into a number of independent zones which are interleaved when the chapter is 17 | * committed to the volume. 18 | */ 19 | 20 | enum { 21 | OPEN_CHAPTER_RECORD_NUMBER_BITS = 23, 22 | }; 23 | 24 | struct open_chapter_zone_slot { 25 | /* If non-zero, the record number addressed by this hash slot */ 26 | unsigned int record_number : OPEN_CHAPTER_RECORD_NUMBER_BITS; 27 | /* If true, the record at the index of this hash slot was deleted */ 28 | bool deleted : 1; 29 | } __packed; 30 | 31 | struct open_chapter_zone { 32 | /* The maximum number of records that can be stored */ 33 | unsigned int capacity; 34 | /* The number of records stored */ 35 | unsigned int size; 36 | /* The number of deleted records */ 37 | unsigned int deletions; 38 | /* Array of chunk records, 1-based */ 39 | struct uds_volume_record *records; 40 | /* The number of slots in the hash table */ 41 | unsigned int slot_count; 42 | /* The hash table slots, referencing virtual record numbers */ 43 | struct open_chapter_zone_slot slots[]; 44 | }; 45 | 46 | int __must_check uds_make_open_chapter(const struct index_geometry *geometry, 47 | unsigned int zone_count, 48 | struct open_chapter_zone **open_chapter_ptr); 49 | 50 | void uds_reset_open_chapter(struct open_chapter_zone *open_chapter); 51 | 52 | void uds_search_open_chapter(struct open_chapter_zone *open_chapter, 53 | const struct uds_record_name *name, 54 | struct uds_record_data *metadata, bool *found); 55 | 56 | int __must_check uds_put_open_chapter(struct open_chapter_zone *open_chapter, 57 | const struct uds_record_name *name, 58 | const struct uds_record_data *metadata); 59 | 60 | void uds_remove_from_open_chapter(struct open_chapter_zone *open_chapter, 61 | const struct uds_record_name *name); 62 | 63 | void uds_free_open_chapter(struct open_chapter_zone *open_chapter); 64 | 65 | int __must_check uds_close_open_chapter(struct open_chapter_zone **chapter_zones, 66 | unsigned int zone_count, struct volume *volume, 67 | struct open_chapter_index *chapter_index, 68 | struct uds_volume_record *collated_records, 69 | u64 virtual_chapter_number); 70 | 71 | int __must_check uds_save_open_chapter(struct uds_index *index, 72 | struct buffered_writer *writer); 73 | 74 | int __must_check uds_load_open_chapter(struct uds_index *index, 75 | struct buffered_reader *reader); 76 | 77 | u64 uds_compute_saved_open_chapter_size(struct index_geometry *geometry); 78 | 79 | #endif /* UDS_OPEN_CHAPTER_H */ 80 | -------------------------------------------------------------------------------- /utils/uds/permassert.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #include "permassert.h" 7 | 8 | #include "errors.h" 9 | #include "logger.h" 10 | 11 | #ifdef NDEBUG 12 | #define DEBUGGING_OFF 13 | #undef NDEBUG 14 | #endif /* NDEBUG */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "string-utils.h" 22 | #include "thread-utils.h" 23 | 24 | #ifdef DEBUGGING_OFF 25 | static bool exit_on_assertion_failure; 26 | #else /* not DEBUGGING_OFF */ 27 | static bool exit_on_assertion_failure = true; 28 | #endif /* DEBUGGING_OFF */ 29 | 30 | static const char *EXIT_ON_ASSERTION_FAILURE_VARIABLE = "UDS_EXIT_ON_ASSERTION_FAILURE"; 31 | 32 | static atomic_t init_once = ATOMIC_INIT(0); 33 | static struct mutex mutex = UDS_MUTEX_INITIALIZER; 34 | 35 | static void initialize(void) 36 | { 37 | uds_initialize_mutex(&mutex, !UDS_DO_ASSERTIONS); 38 | char *exit_on_assertion_failure_string = getenv(EXIT_ON_ASSERTION_FAILURE_VARIABLE); 39 | if (exit_on_assertion_failure_string != NULL) { 40 | exit_on_assertion_failure = 41 | (strcasecmp(exit_on_assertion_failure_string, "true") == 0); 42 | } 43 | } 44 | 45 | bool set_exit_on_assertion_failure(bool should_exit) 46 | { 47 | bool previous_setting; 48 | 49 | vdo_perform_once(&init_once, initialize); 50 | uds_lock_mutex(&mutex); 51 | previous_setting = exit_on_assertion_failure; 52 | exit_on_assertion_failure = should_exit; 53 | uds_unlock_mutex(&mutex); 54 | return previous_setting; 55 | } 56 | 57 | int vdo_assertion_failed(const char *expression_string, const char *file_name, 58 | int line_number, const char *format, ...) 59 | { 60 | va_list args; 61 | 62 | va_start(args, format); 63 | 64 | vdo_log_embedded_message(VDO_LOG_ERR, VDO_LOGGING_MODULE_NAME, "assertion \"", 65 | format, args, "\" (%s) failed at %s:%d", 66 | expression_string, file_name, line_number); 67 | vdo_log_backtrace(VDO_LOG_ERR); 68 | 69 | vdo_perform_once(&init_once, initialize); 70 | uds_lock_mutex(&mutex); 71 | if (exit_on_assertion_failure) { 72 | __assert_fail(expression_string, file_name, line_number, 73 | __ASSERT_FUNCTION); 74 | } 75 | uds_unlock_mutex(&mutex); 76 | 77 | va_end(args); 78 | 79 | return UDS_ASSERTION_FAILED; 80 | } 81 | -------------------------------------------------------------------------------- /utils/uds/permassert.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef PERMASSERT_H 7 | #define PERMASSERT_H 8 | 9 | #include 10 | #include 11 | 12 | #include "errors.h" 13 | 14 | /* Utilities for asserting that certain conditions are met */ 15 | 16 | #define STRINGIFY(X) #X 17 | 18 | /* 19 | * A hack to apply the "warn if unused" attribute to an integral expression. 20 | * 21 | * Since GCC doesn't propagate the warn_unused_result attribute to conditional expressions 22 | * incorporating calls to functions with that attribute, this function can be used to wrap such an 23 | * expression. With optimization enabled, this function contributes no additional instructions, but 24 | * the warn_unused_result attribute still applies to the code calling it. 25 | */ 26 | static inline int __must_check vdo_must_use(int value) 27 | { 28 | return value; 29 | } 30 | 31 | /* Assert that an expression is true and return an error if it is not. */ 32 | #define VDO_ASSERT(expr, ...) vdo_must_use(__VDO_ASSERT(expr, __VA_ARGS__)) 33 | 34 | /* Log a message if the expression is not true. */ 35 | #define VDO_ASSERT_LOG_ONLY(expr, ...) __VDO_ASSERT(expr, __VA_ARGS__) 36 | 37 | #define __VDO_ASSERT(expr, ...) \ 38 | (likely(expr) ? VDO_SUCCESS \ 39 | : vdo_assertion_failed(STRINGIFY(expr), __FILE__, __LINE__, __VA_ARGS__)) 40 | 41 | /* Log an assertion failure message. */ 42 | int vdo_assertion_failed(const char *expression_string, const char *file_name, 43 | int line_number, const char *format, ...) 44 | __printf(4, 5); 45 | 46 | #define STATIC_ASSERT(expr) \ 47 | do { \ 48 | switch (0) { \ 49 | case 0: \ 50 | ; \ 51 | fallthrough; \ 52 | case expr: \ 53 | ; \ 54 | fallthrough; \ 55 | default: \ 56 | break; \ 57 | } \ 58 | } while (0) 59 | 60 | #define STATIC_ASSERT_SIZEOF(type, expected_size) STATIC_ASSERT(sizeof(type) == (expected_size)) 61 | 62 | /* Set whether or not to exit on an assertion failure, for tests. */ 63 | bool set_exit_on_assertion_failure(bool should_exit); 64 | 65 | #endif /* PERMASSERT_H */ 66 | -------------------------------------------------------------------------------- /utils/uds/radix-sort.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_RADIX_SORT_H 7 | #define UDS_RADIX_SORT_H 8 | 9 | #include 10 | 11 | /* 12 | * Radix sort is implemented using an American Flag sort, an unstable, in-place 8-bit radix 13 | * exchange sort. This is adapted from the algorithm in the paper by Peter M. McIlroy, Keith 14 | * Bostic, and M. Douglas McIlroy, "Engineering Radix Sort". 15 | * 16 | * http://www.usenix.org/publications/compsystems/1993/win_mcilroy.pdf 17 | */ 18 | 19 | struct radix_sorter; 20 | 21 | int __must_check uds_make_radix_sorter(unsigned int count, struct radix_sorter **sorter); 22 | 23 | void uds_free_radix_sorter(struct radix_sorter *sorter); 24 | 25 | int __must_check uds_radix_sort(struct radix_sorter *sorter, const unsigned char *keys[], 26 | unsigned int count, unsigned short length); 27 | 28 | #endif /* UDS_RADIX_SORT_H */ 29 | -------------------------------------------------------------------------------- /utils/uds/random.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "random.h" 10 | 11 | void get_random_bytes(void *buffer, size_t byte_count) 12 | { 13 | uint64_t rand_num = 0; 14 | uint64_t rand_mask = 0; 15 | const uint64_t multiplier = (uint64_t) RAND_MAX + 1; 16 | u8 *data = buffer; 17 | size_t i; 18 | 19 | for (i = 0; i < byte_count; i++) { 20 | if (rand_mask < 0xff) { 21 | rand_num = rand_num * multiplier + random(); 22 | rand_mask = rand_mask * multiplier + RAND_MAX; 23 | } 24 | data[i] = rand_num & 0xff; 25 | rand_num >>= 8; 26 | rand_mask >>= 8; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /utils/uds/random.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef RANDOM_H 7 | #define RANDOM_H 8 | 9 | #include 10 | 11 | #endif /* RANDOM_H */ 12 | -------------------------------------------------------------------------------- /utils/uds/sparse-cache.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_SPARSE_CACHE_H 7 | #define UDS_SPARSE_CACHE_H 8 | 9 | #include "geometry.h" 10 | #include "indexer.h" 11 | 12 | /* 13 | * The sparse cache is a cache of entire chapter indexes from sparse chapters used for searching 14 | * for names after all other search paths have failed. It contains only complete chapter indexes; 15 | * record pages from sparse chapters and single index pages used for resolving hooks are kept in 16 | * the regular page cache in the volume. 17 | * 18 | * The most important property of this cache is the absence of synchronization for read operations. 19 | * Safe concurrent access to the cache by the zone threads is controlled by the triage queue and 20 | * the barrier requests it issues to the zone queues. The set of cached chapters does not and must 21 | * not change between the carefully coordinated calls to uds_update_sparse_cache() from the zone 22 | * threads. Outside of updates, every zone will get the same result when calling 23 | * uds_sparse_cache_contains() as every other zone. 24 | */ 25 | 26 | struct index_zone; 27 | struct sparse_cache; 28 | 29 | int __must_check uds_make_sparse_cache(const struct index_geometry *geometry, 30 | unsigned int capacity, unsigned int zone_count, 31 | struct sparse_cache **cache_ptr); 32 | 33 | void uds_free_sparse_cache(struct sparse_cache *cache); 34 | 35 | bool uds_sparse_cache_contains(struct sparse_cache *cache, u64 virtual_chapter, 36 | unsigned int zone_number); 37 | 38 | int __must_check uds_update_sparse_cache(struct index_zone *zone, u64 virtual_chapter); 39 | 40 | void uds_invalidate_sparse_cache(struct sparse_cache *cache); 41 | 42 | int __must_check uds_search_sparse_cache(struct index_zone *zone, 43 | const struct uds_record_name *name, 44 | u64 *virtual_chapter_ptr, u16 *record_page_ptr); 45 | 46 | #endif /* UDS_SPARSE_CACHE_H */ 47 | -------------------------------------------------------------------------------- /utils/uds/string-utils.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #include "string-utils.h" 7 | 8 | #include "errors.h" 9 | #include "logger.h" 10 | #include "memory-alloc.h" 11 | 12 | int vdo_alloc_sprintf(const char *what, char **strp, const char *fmt, ...) 13 | { 14 | va_list args; 15 | int result; 16 | int count; 17 | 18 | if (strp == NULL) 19 | return UDS_INVALID_ARGUMENT; 20 | 21 | va_start(args, fmt); 22 | count = vsnprintf(NULL, 0, fmt, args) + 1; 23 | va_end(args); 24 | result = vdo_allocate(count, char, what, strp); 25 | if (result == VDO_SUCCESS) { 26 | va_start(args, fmt); 27 | vsnprintf(*strp, count, fmt, args); 28 | va_end(args); 29 | } 30 | 31 | if ((result != VDO_SUCCESS) && (what != NULL)) 32 | vdo_log_error("cannot allocate %s", what); 33 | 34 | return result; 35 | } 36 | 37 | char *vdo_append_to_buffer(char *buffer, char *buf_end, const char *fmt, ...) 38 | { 39 | va_list args; 40 | size_t n; 41 | 42 | va_start(args, fmt); 43 | n = vsnprintf(buffer, buf_end - buffer, fmt, args); 44 | if (n >= (size_t) (buf_end - buffer)) 45 | buffer = buf_end; 46 | else 47 | buffer += n; 48 | va_end(args); 49 | 50 | return buffer; 51 | } 52 | -------------------------------------------------------------------------------- /utils/uds/string-utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef VDO_STRING_UTILS_H 7 | #define VDO_STRING_UTILS_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /* Utilities related to string manipulation */ 16 | 17 | static inline const char *vdo_bool_to_string(bool value) 18 | { 19 | return value ? "true" : "false"; 20 | } 21 | 22 | /* 23 | * Allocate memory to contain a formatted string. The caller is responsible for 24 | * freeing the allocated memory. 25 | */ 26 | int __must_check vdo_alloc_sprintf(const char *what, char **strp, const char *fmt, ...) 27 | __printf(3, 4); 28 | 29 | /* Append a formatted string to the end of a buffer. */ 30 | char *vdo_append_to_buffer(char *buffer, char *buf_end, const char *fmt, ...) 31 | __printf(3, 4); 32 | 33 | #endif /* VDO_STRING_UTILS_H */ 34 | -------------------------------------------------------------------------------- /utils/uds/syscalls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #include "syscalls.h" 21 | 22 | #include 23 | #include 24 | 25 | #include "permassert.h" 26 | 27 | /**********************************************************************/ 28 | int logging_read(int fd, 29 | void *buf, 30 | size_t count, 31 | const char *context, 32 | ssize_t *bytes_read_ptr) 33 | { 34 | int result; 35 | do { 36 | result = check_io_errors(read(fd, buf, count), 37 | __func__, 38 | context, 39 | bytes_read_ptr); 40 | } while (result == EINTR); 41 | return result; 42 | } 43 | 44 | /**********************************************************************/ 45 | static int logging_pread_interruptible(int fd, 46 | void *buf, 47 | size_t count, 48 | off_t offset, 49 | const char *context, 50 | ssize_t *bytes_read_ptr) 51 | { 52 | return check_io_errors(pread(fd, buf, count, offset), 53 | __func__, 54 | context, 55 | bytes_read_ptr); 56 | } 57 | 58 | /**********************************************************************/ 59 | int logging_pread(int fd, 60 | void *buf, 61 | size_t count, 62 | off_t offset, 63 | const char *context, 64 | ssize_t *bytes_read_ptr) 65 | { 66 | int result; 67 | do { 68 | result = logging_pread_interruptible(fd, buf, count, offset, 69 | context, bytes_read_ptr); 70 | } while (result == EINTR); 71 | 72 | return result; 73 | } 74 | 75 | /**********************************************************************/ 76 | int logging_write(int fd, 77 | const void *buf, 78 | size_t count, 79 | const char *context, 80 | ssize_t *bytes_written_ptr) 81 | { 82 | int result; 83 | do { 84 | result = check_io_errors(write(fd, buf, count), 85 | __func__, 86 | context, 87 | bytes_written_ptr); 88 | } while (result == EINTR); 89 | 90 | return result; 91 | } 92 | 93 | /**********************************************************************/ 94 | static int logging_pwrite_interruptible(int fd, 95 | const void *buf, 96 | size_t count, 97 | off_t offset, 98 | const char *context, 99 | ssize_t *bytes_written_ptr) 100 | { 101 | return check_io_errors(pwrite(fd, buf, count, offset), 102 | __func__, 103 | context, 104 | bytes_written_ptr); 105 | } 106 | 107 | /**********************************************************************/ 108 | int logging_pwrite(int fd, 109 | const void *buf, 110 | size_t count, 111 | off_t offset, 112 | const char *context, 113 | ssize_t *bytes_written_ptr) 114 | { 115 | int result; 116 | do { 117 | result = logging_pwrite_interruptible(fd, buf, count, offset, 118 | context, 119 | bytes_written_ptr); 120 | } while (result == EINTR); 121 | 122 | return result; 123 | } 124 | 125 | /**********************************************************************/ 126 | int logging_close(int fd, const char *context) 127 | { 128 | return check_system_call(close(fd), __func__, context); 129 | } 130 | 131 | /**********************************************************************/ 132 | int process_control(int option, 133 | unsigned long arg2, 134 | unsigned long arg3, 135 | unsigned long arg4, 136 | unsigned long arg5) 137 | { 138 | int result = prctl(option, arg2, arg3, arg4, arg5); 139 | VDO_ASSERT_LOG_ONLY(result >= 0, 140 | "option: %d, arg2: %lu, arg3: %lu, arg4: %lu, arg5: %lu", 141 | option, 142 | arg2, 143 | arg3, 144 | arg4, 145 | arg5); 146 | return errno; 147 | } 148 | -------------------------------------------------------------------------------- /utils/uds/syscalls.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef SYSCALLS_H 7 | #define SYSCALLS_H 8 | 9 | #include 10 | #include 11 | 12 | #include "errors.h" 13 | #include "logger.h" 14 | 15 | /** 16 | * Wrap the read(2) system call, looping as long as errno is EINTR. 17 | * 18 | * @param fd The descriptor from which to read 19 | * @param buf The buffer to read into 20 | * @param count The maximum number of bytes to read 21 | * @param context The calling context (for logging) 22 | * @param bytes_read_ptr A pointer to hold the number of bytes read 23 | * 24 | * @return UDS_SUCCESS or an error code 25 | **/ 26 | int __must_check logging_read(int fd, 27 | void *buf, 28 | size_t count, 29 | const char *context, 30 | ssize_t *bytes_read_ptr); 31 | 32 | /** 33 | * Wrap the pread(2) system call, looping as long as errno is EINTR. 34 | * 35 | * @param fd The descriptor from which to read 36 | * @param buf The buffer to read into 37 | * @param count The maximum number of bytes to read 38 | * @param offset The offset into the file at which to read 39 | * @param context The calling context (for logging) 40 | * @param bytes_read_ptr A pointer to hold the number of bytes read 41 | * 42 | * @return UDS_SUCCESS or an error code 43 | **/ 44 | int __must_check logging_pread(int fd, 45 | void *buf, 46 | size_t count, 47 | off_t offset, 48 | const char *context, 49 | ssize_t *bytes_read_ptr); 50 | 51 | /** 52 | * Wrap the write(2) system call, looping as long as errno is EINTR. 53 | * 54 | * @param fd The descriptor from which to write 55 | * @param buf The buffer to write from 56 | * @param count The maximum number of bytes to write 57 | * @param context The calling context (for logging) 58 | * @param bytes_written_ptr A pointer to hold the number of bytes written; 59 | * on error, -1 is returned 60 | * 61 | * @return UDS_SUCCESS or an error code 62 | **/ 63 | int __must_check logging_write(int fd, 64 | const void *buf, 65 | size_t count, 66 | const char *context, 67 | ssize_t *bytes_written_ptr); 68 | 69 | /** 70 | * Wrap the pwrite(2) system call, looping as long as errno is EINTR. 71 | * 72 | * @param fd The descriptor from which to write 73 | * @param buf The buffer to write into 74 | * @param count The maximum number of bytes to write 75 | * @param offset The offset into the file at which to write 76 | * @param context The calling context (for logging) 77 | * @param bytes_written_ptr A pointer to hold the number of bytes written; 78 | * on error, -1 is returned 79 | * 80 | * @return UDS_SUCCESS or an error code 81 | **/ 82 | int __must_check logging_pwrite(int fd, 83 | const void *buf, 84 | size_t count, 85 | off_t offset, 86 | const char *context, 87 | ssize_t *bytes_written_ptr); 88 | 89 | /** 90 | * Wrap the close(2) system call. 91 | * 92 | * @param fd The descriptor to close 93 | * @param context The calling context (for logging) 94 | * 95 | * @return UDS_SUCCESS or an error code 96 | **/ 97 | int __must_check logging_close(int fd, const char *context); 98 | 99 | /** 100 | * Perform operations on a process. 101 | * This wraps the prctl(2) function, q.v. 102 | * 103 | * @param option The operation to perform. 104 | * @param arg2 Specific to option 105 | * @param arg3 Specific to option 106 | * @param arg4 Specific to option 107 | * @param arg5 Specific to option 108 | * 109 | * @return UDS_SUCCESS or an error code 110 | **/ 111 | int process_control(int option, 112 | unsigned long arg2, 113 | unsigned long arg3, 114 | unsigned long arg4, 115 | unsigned long arg5); 116 | 117 | /**********************************************************************/ 118 | static inline int log_system_call_errno(const char *function, 119 | const char *context) 120 | { 121 | return vdo_log_strerror(((errno == EINTR) ? VDO_LOG_DEBUG 122 | : VDO_LOG_ERR), 123 | errno, 124 | "%s failed in %s", 125 | function, 126 | context); 127 | } 128 | 129 | /**********************************************************************/ 130 | static inline int 131 | check_system_call(int result, const char *function, const char *context) 132 | { 133 | return (result == 0) ? UDS_SUCCESS : 134 | log_system_call_errno(function, context); 135 | } 136 | 137 | /**********************************************************************/ 138 | static inline int check_io_errors(ssize_t bytes, 139 | const char *function, 140 | const char *context, 141 | ssize_t *bytes_ptr) 142 | { 143 | if (bytes_ptr != NULL) 144 | *bytes_ptr = bytes; 145 | if (bytes < 0) 146 | return log_system_call_errno(function, context); 147 | return UDS_SUCCESS; 148 | } 149 | 150 | #endif /* SYSCALLS_H */ 151 | -------------------------------------------------------------------------------- /utils/uds/thread-utils.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #include "thread-utils.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "logger.h" 14 | #include "memory-alloc.h" 15 | #include "permassert.h" 16 | #include "syscalls.h" 17 | 18 | enum { 19 | ONCE_NOT_DONE = 0, 20 | ONCE_IN_PROGRESS = 1, 21 | ONCE_COMPLETE = 2, 22 | }; 23 | 24 | /**********************************************************************/ 25 | unsigned int num_online_cpus(void) 26 | { 27 | cpu_set_t cpu_set; 28 | unsigned int n_cpus = 0; 29 | unsigned int i; 30 | 31 | if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) != 0) { 32 | vdo_log_warning_strerror(errno, 33 | "sched_getaffinity() failed, using 1 as number of cores."); 34 | return 1; 35 | } 36 | 37 | for (i = 0; i < CPU_SETSIZE; i++) 38 | n_cpus += CPU_ISSET(i, &cpu_set); 39 | return n_cpus; 40 | } 41 | 42 | /**********************************************************************/ 43 | void uds_get_thread_name(char *name) 44 | { 45 | process_control(PR_GET_NAME, (unsigned long) name, 0, 0, 0); 46 | } 47 | 48 | /**********************************************************************/ 49 | pid_t uds_get_thread_id(void) 50 | { 51 | return syscall(SYS_gettid); 52 | } 53 | 54 | /* Run a function once only, and record that fact in the atomic value. */ 55 | void vdo_perform_once(atomic_t *once, void (*function)(void)) 56 | { 57 | for (;;) { 58 | switch (atomic_cmpxchg(once, ONCE_NOT_DONE, ONCE_IN_PROGRESS)) { 59 | case ONCE_NOT_DONE: 60 | function(); 61 | atomic_set_release(once, ONCE_COMPLETE); 62 | return; 63 | case ONCE_IN_PROGRESS: 64 | sched_yield(); 65 | break; 66 | case ONCE_COMPLETE: 67 | return; 68 | default: 69 | return; 70 | } 71 | } 72 | } 73 | 74 | struct thread_start_info { 75 | void (*thread_function)(void *); 76 | void *thread_data; 77 | const char *name; 78 | }; 79 | 80 | /**********************************************************************/ 81 | static void *thread_starter(void *arg) 82 | { 83 | struct thread_start_info *info = arg; 84 | void (*thread_function)(void *) = info->thread_function; 85 | void *thread_data = info->thread_data; 86 | 87 | /* 88 | * The name is just advisory for humans examining it, so we don't 89 | * care much if this fails. 90 | */ 91 | process_control(PR_SET_NAME, (unsigned long) info->name, 0, 0, 0); 92 | vdo_free(info); 93 | thread_function(thread_data); 94 | return NULL; 95 | } 96 | 97 | /**********************************************************************/ 98 | int vdo_create_thread(void (*thread_function)(void *), 99 | void *thread_data, 100 | const char *name, 101 | struct thread **new_thread) 102 | { 103 | int result; 104 | struct thread_start_info *info; 105 | struct thread *thread; 106 | 107 | result = vdo_allocate(1, struct thread_start_info, __func__, &info); 108 | if (result != VDO_SUCCESS) 109 | return result; 110 | info->thread_function = thread_function; 111 | info->thread_data = thread_data; 112 | info->name = name; 113 | 114 | result = vdo_allocate(1, struct thread, __func__, &thread); 115 | if (result != VDO_SUCCESS) { 116 | vdo_log_warning("Error allocating memory for %s", name); 117 | vdo_free(info); 118 | return result; 119 | } 120 | 121 | result = pthread_create(&thread->thread, NULL, thread_starter, info); 122 | if (result != 0) { 123 | result = -errno; 124 | vdo_log_error_strerror(result, "could not create %s thread", 125 | name); 126 | vdo_free(thread); 127 | vdo_free(info); 128 | return result; 129 | } 130 | 131 | *new_thread = thread; 132 | return VDO_SUCCESS; 133 | } 134 | 135 | /**********************************************************************/ 136 | void vdo_join_threads(struct thread *thread) 137 | { 138 | int result; 139 | pthread_t pthread; 140 | 141 | result = pthread_join(thread->thread, NULL); 142 | pthread = thread->thread; 143 | vdo_free(thread); 144 | VDO_ASSERT_LOG_ONLY((result == 0), "thread: %p", (void *) pthread); 145 | } 146 | 147 | /**********************************************************************/ 148 | void initialize_threads_barrier(struct threads_barrier *barrier, 149 | unsigned int thread_count) 150 | { 151 | int result; 152 | 153 | result = pthread_barrier_init(&barrier->barrier, NULL, thread_count); 154 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_barrier_init error"); 155 | } 156 | 157 | /**********************************************************************/ 158 | void destroy_threads_barrier(struct threads_barrier *barrier) 159 | { 160 | int result; 161 | 162 | result = pthread_barrier_destroy(&barrier->barrier); 163 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_barrier_destroy error"); 164 | } 165 | 166 | /**********************************************************************/ 167 | void enter_threads_barrier(struct threads_barrier *barrier) 168 | { 169 | int result; 170 | 171 | result = pthread_barrier_wait(&barrier->barrier); 172 | if (result == PTHREAD_BARRIER_SERIAL_THREAD) 173 | return; 174 | 175 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_barrier_wait error"); 176 | } 177 | -------------------------------------------------------------------------------- /utils/uds/thread-utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef THREAD_UTILS_H 7 | #define THREAD_UTILS_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "errors.h" 16 | #include "time-utils.h" 17 | 18 | /* Thread and synchronization utilities */ 19 | 20 | struct mutex { 21 | pthread_mutex_t mutex; 22 | }; 23 | 24 | struct semaphore { 25 | sem_t semaphore; 26 | }; 27 | 28 | struct thread { 29 | pthread_t thread; 30 | }; 31 | 32 | struct threads_barrier { 33 | pthread_barrier_t barrier; 34 | }; 35 | 36 | #ifndef NDEBUG 37 | #define UDS_MUTEX_INITIALIZER { .mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP } 38 | #else 39 | #define UDS_MUTEX_INITIALIZER { .mutex = PTHREAD_MUTEX_INITIALIZER } 40 | #endif 41 | 42 | extern const bool UDS_DO_ASSERTIONS; 43 | 44 | unsigned int num_online_cpus(void); 45 | pid_t __must_check uds_get_thread_id(void); 46 | 47 | void vdo_perform_once(atomic_t *once_state, void (*function) (void)); 48 | 49 | int __must_check vdo_create_thread(void (*thread_function)(void *), void *thread_data, 50 | const char *name, struct thread **new_thread); 51 | void vdo_join_threads(struct thread *thread); 52 | 53 | void uds_get_thread_name(char *name); 54 | 55 | static inline void cond_resched(void) 56 | { 57 | /* 58 | * On Linux sched_yield always succeeds so the result can be 59 | * safely ignored. 60 | */ 61 | (void) sched_yield(); 62 | } 63 | 64 | int uds_initialize_mutex(struct mutex *mutex, bool assert_on_error); 65 | int __must_check uds_init_mutex(struct mutex *mutex); 66 | int uds_destroy_mutex(struct mutex *mutex); 67 | void uds_lock_mutex(struct mutex *mutex); 68 | void uds_unlock_mutex(struct mutex *mutex); 69 | 70 | void initialize_threads_barrier(struct threads_barrier *barrier, 71 | unsigned int thread_count); 72 | void destroy_threads_barrier(struct threads_barrier *barrier); 73 | void enter_threads_barrier(struct threads_barrier *barrier); 74 | 75 | int __must_check uds_initialize_semaphore(struct semaphore *semaphore, 76 | unsigned int value); 77 | int uds_destroy_semaphore(struct semaphore *semaphore); 78 | void uds_acquire_semaphore(struct semaphore *semaphore); 79 | bool __must_check uds_attempt_semaphore(struct semaphore *semaphore, ktime_t timeout); 80 | void uds_release_semaphore(struct semaphore *semaphore); 81 | 82 | #endif /* UDS_THREADS_H */ 83 | -------------------------------------------------------------------------------- /utils/uds/threadCondVar.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #include "indexer.h" 21 | #include "permassert.h" 22 | 23 | /**********************************************************************/ 24 | void uds_init_cond(struct cond_var *cond) 25 | { 26 | int result; 27 | 28 | result = pthread_cond_init(&cond->condition, NULL); 29 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_cond_init error"); 30 | } 31 | 32 | /**********************************************************************/ 33 | void uds_signal_cond(struct cond_var *cond) 34 | { 35 | int result; 36 | 37 | result = pthread_cond_signal(&cond->condition); 38 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_cond_signal error"); 39 | } 40 | 41 | /**********************************************************************/ 42 | void uds_broadcast_cond(struct cond_var *cond) 43 | { 44 | int result; 45 | 46 | result = pthread_cond_broadcast(&cond->condition); 47 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_cond_broadcast error"); 48 | } 49 | 50 | /**********************************************************************/ 51 | void uds_wait_cond(struct cond_var *cond, struct mutex *mutex) 52 | { 53 | int result; 54 | 55 | result = pthread_cond_wait(&cond->condition, &mutex->mutex); 56 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_cond_wait error"); 57 | } 58 | 59 | /**********************************************************************/ 60 | void uds_destroy_cond(struct cond_var *cond) 61 | { 62 | int result; 63 | 64 | result = pthread_cond_destroy(&cond->condition); 65 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_cond_destroy error"); 66 | } 67 | -------------------------------------------------------------------------------- /utils/uds/threadMutex.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "permassert.h" 10 | #include "string-utils.h" 11 | #include "thread-utils.h" 12 | 13 | static enum mutex_kind { 14 | fast_adaptive, 15 | error_checking 16 | } hidden_mutex_kind = error_checking; 17 | 18 | const bool UDS_DO_ASSERTIONS = true; 19 | 20 | /**********************************************************************/ 21 | static void initialize_mutex_kind(void) 22 | { 23 | static const char UDS_MUTEX_KIND_ENV[] = "UDS_MUTEX_KIND"; 24 | const char *mutex_kind_string = getenv(UDS_MUTEX_KIND_ENV); 25 | 26 | #ifdef NDEBUG 27 | /* 28 | * Enabling error checking on mutexes enables a great performance loss, 29 | * so we only enable it in certain circumstances. 30 | */ 31 | hidden_mutex_kind = fast_adaptive; 32 | #endif 33 | if (mutex_kind_string != NULL) { 34 | if (strcmp(mutex_kind_string, "error-checking") == 0) 35 | hidden_mutex_kind = error_checking; 36 | else if (strcmp(mutex_kind_string, "fast-adaptive") == 0) 37 | hidden_mutex_kind = fast_adaptive; 38 | else 39 | VDO_ASSERT_LOG_ONLY(false, 40 | "environment variable %s had unexpected value '%s'", 41 | UDS_MUTEX_KIND_ENV, 42 | mutex_kind_string); 43 | } 44 | } 45 | 46 | /**********************************************************************/ 47 | static enum mutex_kind get_mutex_kind(void) 48 | { 49 | static atomic_t once_state = ATOMIC_INIT(0); 50 | 51 | vdo_perform_once(&once_state, initialize_mutex_kind); 52 | return hidden_mutex_kind; 53 | } 54 | 55 | /* 56 | * This function should only be called directly in places where making 57 | * assertions is not safe. 58 | */ 59 | int uds_initialize_mutex(struct mutex *mutex, bool assert_on_error) 60 | { 61 | pthread_mutexattr_t attr; 62 | int result; 63 | int result2; 64 | 65 | result = pthread_mutexattr_init(&attr); 66 | if (result != 0) { 67 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_mutexattr_init error"); 68 | return result; 69 | } 70 | 71 | if (get_mutex_kind() == error_checking) 72 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); 73 | 74 | result = pthread_mutex_init(&mutex->mutex, &attr); 75 | if ((result != 0) && assert_on_error) 76 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_mutex_init error"); 77 | 78 | result2 = pthread_mutexattr_destroy(&attr); 79 | if (result2 != 0) { 80 | VDO_ASSERT_LOG_ONLY((result2 == 0), 81 | "pthread_mutexattr_destroy error"); 82 | if (result == UDS_SUCCESS) 83 | result = result2; 84 | } 85 | 86 | return result; 87 | } 88 | 89 | /**********************************************************************/ 90 | int uds_init_mutex(struct mutex *mutex) 91 | { 92 | return uds_initialize_mutex(mutex, UDS_DO_ASSERTIONS); 93 | } 94 | 95 | /**********************************************************************/ 96 | int uds_destroy_mutex(struct mutex *mutex) 97 | { 98 | int result; 99 | 100 | result = pthread_mutex_destroy(&mutex->mutex); 101 | VDO_ASSERT_LOG_ONLY((result == 0), "pthread_mutex_destroy error"); 102 | return result; 103 | } 104 | 105 | /**********************************************************************/ 106 | void uds_lock_mutex(struct mutex *mutex) 107 | { 108 | int result __attribute__((unused)); 109 | 110 | result = pthread_mutex_lock(&mutex->mutex); 111 | #ifndef NDEBUG 112 | VDO_ASSERT_LOG_ONLY((result == 0), 113 | "pthread_mutex_lock error %d", result); 114 | #endif 115 | } 116 | 117 | /**********************************************************************/ 118 | void uds_unlock_mutex(struct mutex *mutex) 119 | { 120 | int result __attribute__((unused)); 121 | 122 | result = pthread_mutex_unlock(&mutex->mutex); 123 | #ifndef NDEBUG 124 | VDO_ASSERT_LOG_ONLY((result == 0), 125 | "pthread_mutex_unlock error %d", result); 126 | #endif 127 | } 128 | -------------------------------------------------------------------------------- /utils/uds/threadSemaphore.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #include 7 | 8 | #include "logger.h" 9 | #include "permassert.h" 10 | #include "thread-utils.h" 11 | #include "time-utils.h" 12 | 13 | /**********************************************************************/ 14 | int uds_initialize_semaphore(struct semaphore *semaphore, unsigned int value) 15 | { 16 | int result; 17 | 18 | result = sem_init(&semaphore->semaphore, false, value); 19 | VDO_ASSERT_LOG_ONLY((result == 0), "sem_init error"); 20 | return result; 21 | } 22 | 23 | /**********************************************************************/ 24 | int uds_destroy_semaphore(struct semaphore *semaphore) 25 | { 26 | int result; 27 | 28 | result = sem_destroy(&semaphore->semaphore); 29 | VDO_ASSERT_LOG_ONLY((result == 0), "sem_destroy error"); 30 | return result; 31 | } 32 | 33 | /**********************************************************************/ 34 | void uds_acquire_semaphore(struct semaphore *semaphore) 35 | { 36 | int result; 37 | 38 | do { 39 | result = sem_wait(&semaphore->semaphore); 40 | } while ((result == -1) && (errno == EINTR)); 41 | 42 | #ifndef NDEBUG 43 | VDO_ASSERT_LOG_ONLY((result == 0), "sem_wait error %d", errno); 44 | #endif 45 | } 46 | 47 | /**********************************************************************/ 48 | bool uds_attempt_semaphore(struct semaphore *semaphore, ktime_t timeout) 49 | { 50 | if (timeout > 0) { 51 | struct timespec ts = future_time(timeout); 52 | 53 | do { 54 | if (sem_timedwait(&semaphore->semaphore, &ts) == 0) 55 | return true; 56 | } while (errno == EINTR); 57 | #ifndef NDEBUG 58 | 59 | VDO_ASSERT_LOG_ONLY((errno == ETIMEDOUT), 60 | "sem_timedwait error %d", 61 | errno); 62 | #endif 63 | } else { 64 | do { 65 | if (sem_trywait(&semaphore->semaphore) == 0) 66 | return true; 67 | } while (errno == EINTR); 68 | #ifndef NDEBUG 69 | 70 | VDO_ASSERT_LOG_ONLY((errno == EAGAIN), 71 | "sem_trywait error %d", 72 | errno); 73 | #endif 74 | } 75 | 76 | return false; 77 | } 78 | 79 | /**********************************************************************/ 80 | void uds_release_semaphore(struct semaphore *semaphore) 81 | { 82 | int result __attribute__((unused)); 83 | 84 | result = sem_post(&semaphore->semaphore); 85 | #ifndef NDEBUG 86 | VDO_ASSERT_LOG_ONLY((result == 0), "sem_post error %d", errno); 87 | #endif 88 | } 89 | -------------------------------------------------------------------------------- /utils/uds/time-utils.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #include "time-utils.h" 7 | 8 | ktime_t current_time_ns(clockid_t clock) 9 | { 10 | struct timespec ts; 11 | 12 | if (clock_gettime(clock, &ts) != 0) 13 | ts = (struct timespec) { 0, 0 }; 14 | return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; 15 | } 16 | 17 | struct timespec future_time(ktime_t offset) 18 | { 19 | ktime_t future = current_time_ns(CLOCK_REALTIME) + offset; 20 | 21 | return (struct timespec) { 22 | .tv_sec = future / NSEC_PER_SEC, 23 | .tv_nsec = future % NSEC_PER_SEC, 24 | }; 25 | } 26 | 27 | int64_t current_time_us(void) 28 | { 29 | return current_time_ns(CLOCK_REALTIME) / NSEC_PER_USEC; 30 | } 31 | -------------------------------------------------------------------------------- /utils/uds/time-utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef UDS_TIME_UTILS_H 7 | #define UDS_TIME_UTILS_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /* Some constants that are defined in kernel headers. */ 15 | #define NSEC_PER_SEC 1000000000L 16 | #define NSEC_PER_MSEC 1000000L 17 | #define NSEC_PER_USEC 1000L 18 | 19 | typedef s64 ktime_t; 20 | 21 | static inline s64 ktime_to_seconds(ktime_t reltime) 22 | { 23 | return reltime / NSEC_PER_SEC; 24 | } 25 | 26 | ktime_t __must_check current_time_ns(clockid_t clock); 27 | 28 | ktime_t __must_check current_time_us(void); 29 | 30 | /* Return a timespec for the current time plus an offset. */ 31 | struct timespec future_time(ktime_t offset); 32 | 33 | static inline ktime_t ktime_sub(ktime_t a, ktime_t b) 34 | { 35 | return a - b; 36 | } 37 | 38 | static inline s64 ktime_to_ms(ktime_t abstime) 39 | { 40 | return abstime / NSEC_PER_MSEC; 41 | } 42 | 43 | static inline ktime_t ms_to_ktime(u64 milliseconds) 44 | { 45 | return (ktime_t) milliseconds * NSEC_PER_MSEC; 46 | } 47 | 48 | static inline s64 ktime_to_us(ktime_t reltime) 49 | { 50 | return reltime / NSEC_PER_USEC; 51 | } 52 | 53 | static inline ktime_t us_to_ktime(u64 microseconds) 54 | { 55 | return (ktime_t) microseconds * NSEC_PER_USEC; 56 | } 57 | 58 | #endif /* UDS_TIME_UTILS_H */ 59 | -------------------------------------------------------------------------------- /utils/vdo/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Red Hat 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | # 02110-1301, USA. 18 | # 19 | 20 | VDO_VERSION = 8.3.1.1 21 | 22 | UDS_DIR = ../uds 23 | 24 | ifdef LLVM 25 | export CC := clang 26 | export LD := ld.ldd 27 | endif 28 | 29 | ifeq ($(origin CC), default) 30 | CC := gcc 31 | endif 32 | 33 | ifeq ($(findstring clang, $(CC)),clang) 34 | # Ignore additional warnings for clang 35 | WARNS = -Wno-compare-distinct-pointer-types \ 36 | -Wno-gnu-statement-expression \ 37 | -Wno-gnu-zero-variadic-macro-arguments \ 38 | -Wno-implicit-const-int-float-conversion \ 39 | -Wno-language-extension-token 40 | else 41 | WARNS = -Wcast-align \ 42 | -Wcast-qual \ 43 | -Wformat=2 \ 44 | -Wlogical-op 45 | endif 46 | 47 | WARNS += \ 48 | -Wall \ 49 | -Werror \ 50 | -Wextra \ 51 | -Winit-self \ 52 | -Wmissing-include-dirs \ 53 | -Wpointer-arith \ 54 | -Wredundant-decls \ 55 | -Wunused \ 56 | -Wwrite-strings \ 57 | 58 | C_WARNS = \ 59 | -Wbad-function-cast \ 60 | -Wfloat-equal \ 61 | -Wmissing-declarations \ 62 | -Wmissing-format-attribute \ 63 | -Wmissing-prototypes \ 64 | -Wnested-externs \ 65 | -Wold-style-definition \ 66 | -Wswitch-default \ 67 | 68 | ifeq ($(AR), ar) 69 | ifeq ($(origin AR), default) 70 | AR := gcc-ar 71 | endif 72 | endif 73 | 74 | OPT_FLAGS = -O3 -fno-omit-frame-pointer 75 | DEBUG_FLAGS = 76 | RPM_OPT_FLAGS ?= -fpic 77 | GLOBAL_FLAGS = $(RPM_OPT_FLAGS) -D_GNU_SOURCE -g $(OPT_FLAGS) $(WARNS) \ 78 | $(shell getconf LFS_CFLAGS) $(DEBUG_FLAGS) 79 | GLOBAL_CFLAGS = $(GLOBAL_FLAGS) -std=gnu11 -pedantic $(C_WARNS) \ 80 | $(EXTRA_CFLAGS) 81 | EXTRA_FLAGS = 82 | EXTRA_CFLAGS = $(EXTRA_FLAGS) 83 | GLOBAL_LDFLAGS = $(RPM_LD_FLAGS) $(EXTRA_LDFLAGS) 84 | EXTRA_LDFLAGS = 85 | 86 | DEPDIR = .deps 87 | 88 | MV = mv -f 89 | 90 | INCLUDES = -I. -I$(UDS_DIR) 91 | CFLAGS = -fPIC $(GLOBAL_CFLAGS) $(INCLUDES) -Wno-write-strings \ 92 | -DCURRENT_VERSION="\"$(VDO_VERSION)\"" 93 | 94 | LDFLAGS = $(GLOBAL_LDFLAGS) 95 | LDPRFLAGS = -ldl -pthread -lz -lrt -lm -luuid 96 | 97 | DEPLIBS = $(UDS_DIR)/libuds.a 98 | LIBFLAGS = -pthread -lrt 99 | 100 | PROGS = vdoaudit \ 101 | vdodebugmetadata \ 102 | vdodumpblockmap \ 103 | vdodumpmetadata \ 104 | vdoforcerebuild \ 105 | vdoformat \ 106 | vdolistmetadata \ 107 | vdoreadonly \ 108 | vdostats 109 | 110 | COMPLETIONS=vdostats 111 | 112 | NOBUILDPROGS = adaptlvm \ 113 | vdorecover 114 | PROG_SOURCES := $(PROGS:%=%.c) 115 | C_FILES := $(filter-out $(PROG_SOURCES),$(wildcard *.c)) 116 | LIB_OBJECTS := $(C_FILES:%.c=%.o) 117 | 118 | .PHONY: all 119 | all: libvdo.a $(PROGS) 120 | 121 | .PHONY: clean 122 | clean: 123 | $(MAKE) -C man clean 124 | rm -f *.o *.a 125 | rm -rf $(DEPDIR) $(PROGS) 126 | 127 | libvdo.a: $(LIB_OBJECTS) 128 | $(RM) $@ 129 | $(AR) cr $@ $(LIB_OBJECTS) 130 | 131 | INSTALL = install 132 | INSTALLOWNER ?= -o root -g root 133 | bindir ?= /usr/bin 134 | INSTALLDIR=$(DESTDIR)$(bindir) 135 | bash_completions_dir ?= /usr/share/bash-completion/completions 136 | COMPLETIONINSTALLDIR=$(DESTDIR)$(bash_completions_dir)/ 137 | 138 | .PHONY: install 139 | install: 140 | $(INSTALL) $(INSTALLOWNER) -d $(INSTALLDIR) 141 | for i in $(PROGS) $(NOBUILDPROGS); do \ 142 | $(INSTALL) $(INSTALLOWNER) -m 755 $$i $(INSTALLDIR); \ 143 | done 144 | $(MAKE) -C man install 145 | $(INSTALL) $(INSTALLOWNER) -d $(COMPLETIONINSTALLDIR) 146 | for c in $(COMPLETIONS); do \ 147 | $(INSTALL) $(INSTALLOWNER) -m 644 $$c.bash \ 148 | $(COMPLETIONINSTALLDIR)/$$c; \ 149 | done 150 | 151 | ######################################################################## 152 | # Dependency processing 153 | 154 | %.o: %.c 155 | $(COMPILE.c) -MMD -MF $(DEPDIR)/$*.d.new -MP -MT $@ -o $@ $< 156 | if cmp -s $(DEPDIR)/$*.d $(DEPDIR)/$*.d.new ; \ 157 | then \ 158 | $(RM) $(DEPDIR)/$*.d.new ; \ 159 | else \ 160 | $(MV) $(DEPDIR)/$*.d.new $(DEPDIR)/$*.d ; \ 161 | fi 162 | 163 | $(DEPDIR)/%.d: %.c 164 | @mkdir -p $(DEPDIR) 165 | $(CC) $(CFLAGS) -MM -MF $@ -MP -MT $*.o $< 166 | 167 | .SECONDEXPANSION: 168 | $(PROGS): $$@.o libvdo.a $(DEPLIBS) 169 | echo "Building $@ from $^" 170 | $(CC) $(LDFLAGS) $^ $(LDPRFLAGS) -o $@ 171 | 172 | vdoformat: LDPRFLAGS += "-lblkid" 173 | 174 | ifneq ($(MAKECMDGOALS),clean) 175 | DEPSOURCES = $(wildcard *.c) 176 | -include $(DEPSOURCES:%.c=$(DEPDIR)/%.d) 177 | endif 178 | -------------------------------------------------------------------------------- /utils/vdo/adaptlvm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2021 Red Hat, Inc. All rights reserved. 4 | # 5 | # This copyrighted material is made available to anyone wishing to use, 6 | # modify, copy, or redistribute it subject to the terms and conditions 7 | # of the GNU General Public License v.2. 8 | # 9 | # You should have received a copy of the GNU General Public License 10 | # along with this program; if not, write to the Free Software Foundation, 11 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 12 | # 13 | # Author: Andy Walsh 14 | # 15 | # Script for marking an LVMVDO backing volume as Read/Write 16 | # 17 | 18 | set -euE -o pipefail 19 | 20 | TOOL=$(basename $0) 21 | 22 | LVM_EXTRA_ARGS=${EXTRA_LVM_ARGS:-} 23 | 24 | BACKINGTABLE= 25 | DEV_VG_LV= 26 | LV= 27 | LVMVDO= 28 | OPERATION= 29 | VG= 30 | VPOOL_NAME= 31 | 32 | # Expand the arguments provided into the necessary parameters to operate on 33 | # setRO or setRW. 34 | # Make sure that we actually received the arguments we need and exit if we didn't. 35 | applyConversion() { 36 | if [ -z "$1" ] || [ -z "$2" ]; then 37 | printUsage 38 | fi 39 | 40 | OPERATION=$1 41 | LVMVDO=$2 42 | 43 | # Break apart the LVMVDO argument into separate components for use later as 44 | # well as the full R/O device path. 45 | LV=$(echo ${LVMVDO} | awk -F/ '{print $2}') 46 | VG=$(echo ${LVMVDO} | awk -F/ '{print $1}') 47 | 48 | DEV_VG_LV=/dev/${VG}/${LV} 49 | 50 | echo "Found LV: ${LV}" 51 | echo "Found VG: ${VG}" 52 | echo "Found VPOOL_NAME: ${VPOOL_NAME}" 53 | 54 | case "$OPERATION" in 55 | "setro"|"setRO") 56 | setRO 57 | ;; 58 | "setrw"|"setRW") 59 | setRW 60 | ;; 61 | *) 62 | echo "Invalid operation requested" 63 | printUsage 64 | ;; 65 | esac 66 | } 67 | 68 | printUsage() { 69 | echo "${TOOL}: Mark the backing storage for a LVMVDO volume as read only or read write" 70 | echo 71 | echo "${TOOL} [ setRO | setRW ] /" 72 | echo 73 | echo " Options:" 74 | echo " setRO Revert a R/W LVMVDO volume to its original R/O configuration" 75 | echo " setRW Modify an LVMVDO volume to present the backing store as R/W" 76 | echo 77 | exit 78 | } 79 | 80 | # Disassemble the temporary Read/Write volume and re-activate the original volume. 81 | setRO() { 82 | dmsetup remove ${VG}-${LV} 83 | lvchange -ay ${LVM_EXTRA_ARGS} ${VG}/${LV} 84 | 85 | if [ -b ${DEV_VG_LV} ]; then 86 | echo "LVMVDO volume re-activated at ${DEV_VG_LV}" 87 | else 88 | echo "There was a problem re-activating ${DEV_VG_LV}" 89 | fi 90 | 91 | exit 0 92 | } 93 | 94 | # Disassemble the original Read/Only volume and start a temporary Read/Write 95 | # volume in /dev/mapper 96 | setRW() { 97 | if [ ! -b "${DEV_VG_LV}" ]; then 98 | echo "${DEV_VG_LV} is not a block device" 99 | printUsage 100 | fi 101 | 102 | VPOOL_NAME=$(lvdisplay ${LVMVDO} | awk '/LV VDO Pool name/ {print $NF}') 103 | DM_VDATA="${VG}-${VPOOL_NAME}_vdata" 104 | 105 | # Look in the list of dm devices and find the appropriate backing device 106 | # If we don't find one, then there's something wrong, it's best to just exit. 107 | if [ "$(dmsetup ls | grep -q "${DM_VDATA}")" != "" ]; then 108 | echo "vdata device not found, is this an LVMVDO volume?" 109 | exit 110 | fi 111 | 112 | # Capture the DM table for the backing device so we can reuse it on the 113 | # temporary device. 114 | BACKINGTABLE="$(dmsetup table ${DM_VDATA})" 115 | 116 | # Deactivate the existing volume so that it is only being used from one 117 | # place. 118 | lvchange -an ${LVM_EXTRA_ARGS} ${DEV_VG_LV} 119 | 120 | # Create the temporary device with the name containing the parameters we need 121 | # to undo this operation later. 122 | dmsetup create ${VG}-${LV} --table "${BACKINGTABLE}" 123 | 124 | echo "Writable backing device is now available at /dev/mapper/${VG}-${LV}" 125 | echo "To undo this operation, run ${TOOL} setro ${VG}/${LV}" 126 | 127 | exit 0 128 | } 129 | 130 | ############################################################################### 131 | # main() 132 | trap "cleanup 2" 2 133 | 134 | test "$#" -ne 2 && printUsage 135 | 136 | echo "Received extra LVM Args '${LVM_EXTRA_ARGS}'" 137 | 138 | applyConversion $1 $2 139 | 140 | exit 141 | -------------------------------------------------------------------------------- /utils/vdo/blockMapUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef BLOCK_MAP_UTILS_H 21 | #define BLOCK_MAP_UTILS_H 22 | 23 | #include "encodings.h" 24 | 25 | #include "physicalLayer.h" 26 | #include "userVDO.h" 27 | 28 | /** 29 | * A function which examines a block map page entry. Functions of this type are 30 | * passed to examineBlockMapPages() which will iterate over the entire block 31 | * map and call this function once for each non-empty mapping. 32 | * 33 | * @param slot The block_map_slot where this entry was found 34 | * @param height The height of the block map entry in the tree 35 | * @param pbn The PBN encoded in the entry 36 | * @param state The mapping state encoded in the entry 37 | * 38 | * @return VDO_SUCCESS or an error code 39 | **/ 40 | typedef int __must_check 41 | MappingExaminer(struct block_map_slot slot, 42 | height_t height, 43 | physical_block_number_t pbn, 44 | enum block_mapping_state state); 45 | 46 | /** 47 | * Apply a mapping examiner to each mapped block map entry in a VDO. 48 | * 49 | * @param vdo The VDO containing the block map to be examined 50 | * @param examiner The examiner to apply to each defined mapping 51 | * 52 | * @return VDO_SUCCESS or an error code 53 | **/ 54 | int __must_check 55 | examineBlockMapEntries(UserVDO *vdo, MappingExaminer *examiner); 56 | 57 | /** 58 | * Find the PBN for the block map page encoding a particular LBN mapping. 59 | * This will return the zero block if there is no mapping. 60 | * 61 | * @param [in] vdo The VDO 62 | * @param [in] lbn The logical block number to look up 63 | * @param [out] pbnPtr A pointer to the PBN of the requested block map page 64 | * 65 | * @return VDO_SUCCESS or an error code 66 | **/ 67 | int __must_check findLBNPage(UserVDO *vdo, 68 | logical_block_number_t lbn, 69 | physical_block_number_t *pbnPtr); 70 | 71 | /** 72 | * Look up the mapping for a single LBN in the block map. 73 | * 74 | * @param [in] vdo The VDO 75 | * @param [in] lbn The logical block number to look up 76 | * @param [out] pbnPtr A pointer to the mapped PBN 77 | * @param [out] statePtr A pointer to the mapping state 78 | * 79 | * @return VDO_SUCCESS or an error code 80 | **/ 81 | int __must_check findLBNMapping(UserVDO *vdo, 82 | logical_block_number_t lbn, 83 | physical_block_number_t *pbnPtr, 84 | enum block_mapping_state *statePtr); 85 | 86 | /** 87 | * Read a single block map page into the buffer. The page will be marked 88 | * initialized iff the page is valid. 89 | * 90 | * @param [in] layer The layer from which to read the page 91 | * @param [in] pbn The absolute physical block number of the page to 92 | * read 93 | * @param [in] nonce The VDO nonce 94 | * @param [out] page The page structure to read into 95 | * 96 | * @return VDO_SUCCESS or an error code 97 | **/ 98 | int __must_check readBlockMapPage(PhysicalLayer *layer, 99 | physical_block_number_t pbn, 100 | nonce_t nonce, 101 | struct block_map_page *page); 102 | 103 | #endif // BLOCK_MAP_UTILS_H 104 | -------------------------------------------------------------------------------- /utils/vdo/constants.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef VDO_CONSTANTS_H 7 | #define VDO_CONSTANTS_H 8 | 9 | 10 | #include "types.h" 11 | 12 | enum { 13 | /* 14 | * The maximum number of contiguous PBNs which will go to a single bio submission queue, 15 | * assuming there is more than one queue. 16 | */ 17 | VDO_BIO_ROTATION_INTERVAL_LIMIT = 1024, 18 | 19 | /* The number of entries on a block map page */ 20 | VDO_BLOCK_MAP_ENTRIES_PER_PAGE = 812, 21 | 22 | /* The origin of the flat portion of the block map */ 23 | VDO_BLOCK_MAP_FLAT_PAGE_ORIGIN = 1, 24 | 25 | /* 26 | * The height of a block map tree. Assuming a root count of 60 and 812 entries per page, 27 | * this is big enough to represent almost 95 PB of logical space. 28 | */ 29 | VDO_BLOCK_MAP_TREE_HEIGHT = 5, 30 | 31 | /* The default number of bio submission queues. */ 32 | DEFAULT_VDO_BIO_SUBMIT_QUEUE_COUNT = 4, 33 | 34 | /* The number of contiguous PBNs to be submitted to a single bio queue. */ 35 | DEFAULT_VDO_BIO_SUBMIT_QUEUE_ROTATE_INTERVAL = 64, 36 | 37 | /* The number of trees in the arboreal block map */ 38 | DEFAULT_VDO_BLOCK_MAP_TREE_ROOT_COUNT = 60, 39 | 40 | /* The default size of the recovery journal, in blocks */ 41 | DEFAULT_VDO_RECOVERY_JOURNAL_SIZE = 32 * 1024, 42 | 43 | /* The default size of each slab journal, in blocks */ 44 | DEFAULT_VDO_SLAB_JOURNAL_SIZE = 224, 45 | 46 | /* Unit test minimum */ 47 | MINIMUM_VDO_SLAB_JOURNAL_BLOCKS = 2, 48 | 49 | /* 50 | * The initial size of lbn_operations and pbn_operations, which is based upon the expected 51 | * maximum number of outstanding VIOs. This value was chosen to make it highly unlikely 52 | * that the maps would need to be resized. 53 | */ 54 | VDO_LOCK_MAP_CAPACITY = 10000, 55 | 56 | /* The maximum number of logical zones */ 57 | MAX_VDO_LOGICAL_ZONES = 60, 58 | 59 | /* The maximum number of physical zones */ 60 | MAX_VDO_PHYSICAL_ZONES = 16, 61 | 62 | /* The base-2 logarithm of the maximum blocks in one slab */ 63 | MAX_VDO_SLAB_BITS = 23, 64 | 65 | /* The maximum number of slabs the slab depot supports */ 66 | MAX_VDO_SLABS = 8192, 67 | 68 | /* 69 | * The maximum number of block map pages to load simultaneously during recovery or rebuild. 70 | */ 71 | MAXIMUM_SIMULTANEOUS_VDO_BLOCK_MAP_RESTORATION_READS = 1024, 72 | 73 | /* The maximum number of entries in the slab summary */ 74 | MAXIMUM_VDO_SLAB_SUMMARY_ENTRIES = MAX_VDO_SLABS * MAX_VDO_PHYSICAL_ZONES, 75 | 76 | /* The maximum number of total threads in a VDO thread configuration. */ 77 | MAXIMUM_VDO_THREADS = 100, 78 | 79 | /* The maximum number of VIOs in the system at once */ 80 | MAXIMUM_VDO_USER_VIOS = 2048, 81 | 82 | /* The only physical block size supported by VDO */ 83 | VDO_BLOCK_SIZE = 4096, 84 | 85 | /* The number of sectors per block */ 86 | VDO_SECTORS_PER_BLOCK = 8, 87 | 88 | /* The size of a sector that will not be torn */ 89 | VDO_SECTOR_SIZE = 512, 90 | 91 | /* The physical block number reserved for storing the zero block */ 92 | VDO_ZERO_BLOCK = 0, 93 | }; 94 | 95 | #endif /* VDO_CONSTANTS_H */ 96 | -------------------------------------------------------------------------------- /utils/vdo/fileLayer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef FILE_LAYER_H 21 | #define FILE_LAYER_H 22 | 23 | #include "physicalLayer.h" 24 | 25 | /** 26 | * Make a file layer implementation of a physical layer. 27 | * 28 | * @param [in] name the name of the underlying file 29 | * @param [in] blockCount the span of the file, in blocks 30 | * @param [out] layerPtr the pointer to hold the result 31 | * 32 | * @return a success or error code 33 | **/ 34 | int __must_check makeFileLayer(const char *name, 35 | block_count_t blockCount, 36 | PhysicalLayer **layerPtr); 37 | 38 | /** 39 | * Make a read only file layer implementation of a physical layer. 40 | * 41 | * @param [in] name the name of the underlying file 42 | * @param [out] layerPtr the pointer to hold the result 43 | * 44 | * @return a success or error code 45 | **/ 46 | int __must_check 47 | makeReadOnlyFileLayer(const char *name, PhysicalLayer **layerPtr); 48 | 49 | /** 50 | * Make an offset file layer implementation of a physical layer. 51 | * 52 | * @param [in] name the name of the underlying file 53 | * @param [in] blockCount the span of the file, in blocks 54 | * @param [in] fileOffset the block offset to apply to I/O operations 55 | * @param [out] layerPtr the pointer to hold the result 56 | * 57 | * @return a success or error code 58 | **/ 59 | int makeOffsetFileLayer(const char *name, 60 | block_count_t blockCount, 61 | block_count_t fileOffset, 62 | PhysicalLayer **layerPtr) 63 | __attribute__((warn_unused_result)); 64 | 65 | #endif // FILE_LAYER_H 66 | -------------------------------------------------------------------------------- /utils/vdo/man/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Red Hat 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either version 2 7 | # of the License, or (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program; if not, write to the Free Software 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | # 02110-1301, USA. 18 | # 19 | 20 | INSTALLFILES= \ 21 | adaptlvm.8 \ 22 | vdoaudit.8 \ 23 | vdodebugmetadata.8 \ 24 | vdodumpblockmap.8 \ 25 | vdodumpmetadata.8 \ 26 | vdoforcerebuild.8 \ 27 | vdoformat.8 \ 28 | vdolistmetadata.8 \ 29 | vdoreadonly.8 \ 30 | vdorecover.8 \ 31 | vdostats.8 32 | 33 | INSTALL = install 34 | INSTALLOWNER ?= -o root -g root 35 | mandir ?= /usr/man 36 | 37 | INSTALLDIR=$(DESTDIR)/$(mandir) 38 | 39 | .PHONY: all clean install 40 | all:; 41 | 42 | clean:; 43 | 44 | install: 45 | $(INSTALL) $(INSTALLOWNER) -d $(INSTALLDIR)/man8 46 | for i in $(INSTALLFILES); do \ 47 | $(INSTALL) $(INSTALLOWNER) -m 644 $$i $(INSTALLDIR)/man8; \ 48 | done 49 | -------------------------------------------------------------------------------- /utils/vdo/man/adaptlvm.8: -------------------------------------------------------------------------------- 1 | .TH ADAPTLVM 8 "2022-01-27" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | adaptlvm \- Adapts an LVMVDO base storage to RW 4 | .SH SYNOPSIS 5 | .B adaptlvm 6 | .I filename 7 | .SH DESCRIPTION 8 | .B adaptlvm 9 | Tears down an LVMVDO stack to expose the VDO backing device as read only. 10 | .PP 11 | .SH OPTIONS 12 | .TP 13 | .B setRW 14 | Set the backing storage as Read/Write 15 | .TP 16 | .B setRO 17 | Sets the backing storage back to Read-Only 18 | .TP 19 | .B volume_group/logical_volume 20 | The volume group name and logical volume name for the LVMVDO volume 21 | . 22 | .SH SEE ALSO 23 | .BR vdo (8). 24 | -------------------------------------------------------------------------------- /utils/vdo/man/vdoaudit.8: -------------------------------------------------------------------------------- 1 | .TH VDOAUDIT 8 "2023-03-28" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | vdoaudit \- confirm the reference counts of a VDO device 4 | .SH SYNOPSIS 5 | .B vdoaudit 6 | .RI [ options... ] 7 | .I filename 8 | .SH DESCRIPTION 9 | .B vdoaudit 10 | adds up the logical block references to all physical blocks of a VDO device 11 | found in \fIfilename\fP, then compares that sum to the stored number of 12 | logical blocks. It also confirms all of the actual reference counts on all 13 | physical blocks against the stored reference counts. Finally, it validates 14 | that the slab summary approximation of the free blocks in each slab is 15 | correct. 16 | .PP 17 | .I filename 18 | must be the path of the VDODataLV as described in \fBlvmvdo\fP(7). 19 | .PP 20 | If \-\-verbose is specified, a line item will be reported for each 21 | inconsistency; otherwise a summary of the problems will be displayed. 22 | .SH OPTIONS 23 | .TP 24 | .B \-\-help 25 | Print this help message and exit. 26 | .TP 27 | .B \-\-summary 28 | Display a summary of any problems found on the volume. 29 | .TP 30 | .B \-\-verbose 31 | Display a line item for each inconsistency found on the volume. 32 | .TP 33 | .B \-\-version 34 | Show the version of vdoaudit. 35 | . 36 | .SH EXAMPLE 37 | .nf 38 | # lvchange -ay vdo1/vdo0pool_vdata 39 | # vdoaudit --verbose /dev/mapper/vdo1-vdo0pool_vdata 40 | # lvchange -an vdo1/vdo0pool_vdata 41 | .fi 42 | .\" .SH NOTES 43 | .SH SEE ALSO 44 | .BR lvmvdo (7), 45 | .BR lvchange (8) 46 | -------------------------------------------------------------------------------- /utils/vdo/man/vdodebugmetadata.8: -------------------------------------------------------------------------------- 1 | .TH VDODEBUGMETADATA 8 "2020-05-08" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | vdodebugmetadata \- load a metadata dump of a VDO device 4 | .SH SYNOPSIS 5 | .B vdodebugmetadata 6 | .RB [ \-\-pbn=\fIpbn\fP 7 | \&.\|.\|.\&] 8 | .RB [ \-\-searchLBN=\fIlbn\fP 9 | \&.\|.\|.\&] 10 | .I filename 11 | .SH DESCRIPTION 12 | .B vdodebugmetadata 13 | loads the metadata regions dumped by \fBvdodumpmetadata\fP. It should be run 14 | under GDB, with a breakpoint on the function \%doNothing. 15 | .PP 16 | Variables \%vdo, \%slabSummary, \%slabs, and \%recoveryJournal are available, 17 | providing access to the VDO super block state, the slab summary blocks, all 18 | slab journal and reference blocks per slab, and all recovery journal blocks. 19 | .PP 20 | Please note that this tool does not provide access to block map pages. 21 | .SH OPTIONS 22 | .TP 23 | \-\-pbn 24 | Print the slab journal entries for the given PBN. This option may be specified 25 | up to 255 times. 26 | .TP 27 | \-\-searchLBN 28 | Print the recovery journal entries for the given LBN. This includes PBN, 29 | increment/decrement, mapping state, recovery journal position information, and 30 | whether the recovery journal block is valid. This option may be specified up 31 | to 255 times. 32 | .SH SEE ALSO 33 | .BR vdo (8), 34 | .BR vdodumpmetadata(8). 35 | -------------------------------------------------------------------------------- /utils/vdo/man/vdodumpblockmap.8: -------------------------------------------------------------------------------- 1 | .TH VDODUMPBLOCKMAP 8 "2023-03-28" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | vdodumpblockmap \- dump the LBA->PBA mappings of a VDO device 4 | .SH SYNOPSIS 5 | .B vdodumpblockmap 6 | .RB [ \-\-lba=\fIlba\fP ] 7 | .I filename 8 | .SH DESCRIPTION 9 | .B vdodumpblockmap 10 | dumps all (or only the specified) LBA->PBA mappings from a cleanly 11 | shut down VDO device. 12 | .PP 13 | .I filename 14 | must be the path of the VDODataLV as described in \fBlvmvdo\fP(7). 15 | .SH OPTIONS 16 | .TP 17 | .B \-\-help 18 | Print this help message and exit. 19 | .TP 20 | .B \-\-lba 21 | Dump only the mapping for the specified LBA. 22 | .TP 23 | .B \-\-version 24 | Show the version of vdodumpblockmap. 25 | . 26 | .SH EXAMPLE 27 | .nf 28 | # lvchange -ay vdo1/vdo0pool_vdata 29 | # vdodumpblockmap /dev/mapper/vdo1-vdo0pool_vdata 30 | # lvchange -an vdo1/vdo0pool_vdata 31 | .fi 32 | .SH SEE ALSO 33 | .BR lvmvdo (7), 34 | .BR lvchange (8) 35 | -------------------------------------------------------------------------------- /utils/vdo/man/vdodumpmetadata.8: -------------------------------------------------------------------------------- 1 | .TH VDODUMPMETADATA 8 "2023-03-38" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | vdodumpmetadata \- dump the metadata regions from a VDO device 4 | .SH SYNOPSIS 5 | .B vdodumpmetadata 6 | .RB [ \-\-no\-block\-map ] 7 | .RB [ \-\-lbn=\fIlbn\fP ] 8 | .I vdoBacking outputFile 9 | .SH DESCRIPTION 10 | .B vdodumpmetadata 11 | dumps the metadata regions of a VDO device to 12 | another file, to enable save and transfer of metadata from 13 | a VDO without transfer of the entire backing store. 14 | .PP 15 | .I vdoBacking 16 | must be the path of the VDODataLV as described in \fBlvmvdo\fP(7). 17 | .PP 18 | .B vdodumpmetadata 19 | will produce a large output file. The expected size is 20 | roughly equal to VDO's metadata size. A rough estimate of the storage 21 | needed is 1.4 GB per TB of logical space. 22 | .SH OPTIONS 23 | .TP 24 | \-\-no\-block\-map 25 | Omit the block map. The output file will be of size no higher than 26 | 130MB + (9 MB per slab). 27 | .TP 28 | \-\-lbn 29 | Saves the block map page associated with the specified LBN in the 30 | output file. This option may be specified up to 255 times. 31 | Implies \-\-no\-block\-map. 32 | .SH EXAMPLE 33 | .nf 34 | # lvchange -ay vdo1/vdo0pool_vdata 35 | # vdodumpmetadata /dev/mapper/vdo1-vdo0pool_vdata vdo1-meta-dump 36 | # lvchange -an vdo1/vdo0pool_vdata 37 | .fi 38 | .SH SEE ALSO 39 | .BR lvmvdo (7), 40 | .BR lvchange (8), 41 | .BR vdodebugmetadata (8) 42 | -------------------------------------------------------------------------------- /utils/vdo/man/vdoforcerebuild.8: -------------------------------------------------------------------------------- 1 | .TH VDOFORCEREBUILD 8 "2023-04-14" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | vdoforcerebuild \- prepare a VDO device to exit read-only mode 4 | .SH SYNOPSIS 5 | .B vdoforcerebuild 6 | .I filename 7 | .SH DESCRIPTION 8 | .B vdoforcerebuild 9 | forces an existing VDO device to exit read-only 10 | mode and to attempt to regenerate as much metadata as possible. 11 | .PP 12 | .I filename 13 | must be the path of the VDODataLV as described in \fBlvmvdo\fP(7). 14 | Since \fBlvchange\fP(8) will only mount that as read-only, a writable version 15 | of that device must be manually created, as shown in the example below. 16 | .PP 17 | .SH OPTIONS 18 | .TP 19 | .B \-\-help 20 | Print this help message and exit. 21 | .TP 22 | .B \-\-version 23 | Show the version of vdoforcerebuild. 24 | .SH EXAMPLE 25 | .nf 26 | # lvchange -ay vdo1/vdo0pool_vdata 27 | # dmsetup table vdo1-vdo0pool_vdata > vdata.table 28 | # lvchange -an vdo1/vdo0pool_vdata 29 | # dmsetup create vdo1-vdo0pool_vdata --table "`cat vdata.table`" 30 | # vdoforcerebuild /dev/mapper/vdo1-vdo0pool_vdata 31 | # dmsetup remove vdo1-vdo0pool_vdata 32 | .fi 33 | .SH SEE ALSO 34 | .BR lvmvdo (7), 35 | .BR lvchange (8), 36 | .BR dmsetup (8) 37 | -------------------------------------------------------------------------------- /utils/vdo/man/vdoformat.8: -------------------------------------------------------------------------------- 1 | .TH VDOFORMAT 8 "2017-09-12" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | vdoformat \- format a VDO device 4 | .SH SYNOPSIS 5 | .B vdoformat 6 | .RI [ options... ] 7 | .I filename 8 | .SH DESCRIPTION 9 | .B vdoformat 10 | formats the file named by 11 | .I filename 12 | as a VDO device. This is analogous to low-level device formatting. 13 | The device will not be formatted if it already contains a VDO, unless 14 | the --force flag is used. 15 | .PP 16 | .B vdoformat 17 | can also modify some of the formatting parameters. 18 | .SH OPTIONS 19 | .TP 20 | .B \-\-format 21 | Format the block device, even if there is already a VDO formatted thereupon. 22 | .TP 23 | .B \-\-help 24 | Print this help message and exit. 25 | .TP 26 | .B \-\-logical\-size=\fIsize\fP 27 | Set the logical (provisioned) size of the VDO device to \fIsize\fP. 28 | A size suffix of K for kilobytes, M for megabytes, G for 29 | gigabytes, T for terabytes, or P for petabytes is optional. The 30 | default unit is megabytes. 31 | .TP 32 | .B \-\-slab\-bits=\fIbits\fP 33 | Set the free space allocator's slab size to 2^\fIbits\fP 4 KB blocks. 34 | \fIbits\fP must be a value between 13 and 23 (inclusive), corresponding 35 | to a slab size between 32 MB and 32 GB. The default value is 19 36 | which results in a slab size of 2 GB. This allocator manages the 37 | space VDO uses to store user data. 38 | 39 | The maximum number of slabs in the system is 8192, so this value 40 | determines the maximum physical size of a VDO volume. One slab is 41 | the minimum amount by which a VDO volume can be grown. Smaller 42 | slabs also increase the potential for parallelism if the device 43 | has multiple physical threads. Therefore, this value should be set 44 | as small as possible, given the eventual maximal size of the 45 | volume. 46 | .TP 47 | .B \-\-uds\-memory\-size=\fIgigabytes\fP 48 | Specify the amount of memory, in gigabytes, to devote to the 49 | index. Accepted options are .25, .5, .75, and all positive 50 | integers. 51 | .TP 52 | .B \-\-uds\-sparse 53 | Specify whether or not to use a sparse index. 54 | .TP 55 | .B \-\-verbose 56 | Describe what is being formatted and with what parameters. 57 | .TP 58 | .B \-\-version 59 | Show the version of vdoformat. 60 | . 61 | .\" .SH EXAMPLES 62 | .\" .SH NOTES 63 | .SH SEE ALSO 64 | .BR vdo (8). 65 | -------------------------------------------------------------------------------- /utils/vdo/man/vdolistmetadata.8: -------------------------------------------------------------------------------- 1 | .TH VDOLISTMETADATA 8 "2023-03-28" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | vdolistmetadata \- list the metadata regions on a VDO device 4 | .SH SYNOPSIS 5 | .B vdolistmetadata 6 | .I filename 7 | .SH DESCRIPTION 8 | .B vdolistmetadata 9 | lists the metadata regions of a VDO device as ranges of block numbers. 10 | Each range is on a separate line of the form: 11 | .EX 12 | startBlock .. endBlock: label 13 | .EE 14 | Both endpoints are included in the range, and are the zero-based 15 | indexes of 4KB VDO metadata blocks on the backing device. 16 | 17 | .PP 18 | .I filename 19 | must be the path of the VDODataLV as described in \fBlvmvdo\fP(7). 20 | .SH OPTIONS 21 | .TP 22 | .B \-\-help 23 | Print this help message and exit. 24 | .TP 25 | .B \-\-version 26 | Show the version of vdolistmetadata. 27 | . 28 | .SH EXAMPLE 29 | .nf 30 | # lvchange -ay vdo1/vdo0pool_vdata 31 | # vdolistmetadata /dev/mapper/vdo1-vdo0pool_vdata 32 | # lvchange -an vdo1/vdo0pool_vdata 33 | .fi 34 | .SH SEE ALSO 35 | .BR lvmvdo (7), 36 | .BR lvchange (8) 37 | -------------------------------------------------------------------------------- /utils/vdo/man/vdoreadonly.8: -------------------------------------------------------------------------------- 1 | .TH VDOREADONLY 8 "2023-04-14" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | vdoreadonly \- puts a VDO device into read-only mode 4 | .SH SYNOPSIS 5 | .B vdoreadonly 6 | .I filename 7 | .SH DESCRIPTION 8 | .B vdoreadonly 9 | forces an existing VDO device into read-only mode. 10 | .PP 11 | .I filename 12 | must be the path of the VDODataLV as described in \fBlvmvdo\fP(7). 13 | Since \fBlvchange\fP(8) will only mount that as read-only, a writable version 14 | of that device must be manually created, as shown in the example below. 15 | .PP 16 | .SH OPTIONS 17 | .TP 18 | .B \-\-help 19 | Print this help message and exit. 20 | .TP 21 | .B \-\-version 22 | Show the version of vdoreadonly. 23 | . 24 | .SH EXAMPLE 25 | .nf 26 | # lvchange -ay vdo1/vdo0pool_vdata 27 | # dmsetup table vdo1-vdo0pool_vdata > vdata.table 28 | # lvchange -an vdo1/vdo0pool_vdata 29 | # dmsetup create vdo1-vdo0pool_vdata --table "`cat vdata.table`" 30 | # vdoreadonly /dev/mapper/vdo1-vdo0pool_vdata 31 | # dmsetup remove vdo1-vdo0pool_vdata 32 | .fi 33 | .SH SEE ALSO 34 | .BR lvmvdo (7), 35 | .BR lvchange (8), 36 | .BR dmsetup (8) 37 | -------------------------------------------------------------------------------- /utils/vdo/man/vdorecover.8: -------------------------------------------------------------------------------- 1 | .TH VDORECOVER 8 "2022-07-15" "Red Hat" \" -*- nroff -*- 2 | .SH NAME 3 | vdorecover \- Recovers available storage by discarding a full VDO volume. 4 | .SH SYNOPSIS 5 | .B vdorecover 6 | .I vdo_device 7 | .SH DESCRIPTION 8 | .B vdorecover 9 | Recovers available physical space on a full VDO volume by mounting it 10 | temporarily with snapshots and sending discards to it. 11 | .PP 12 | .SH OPTIONS 13 | .TP 14 | .B vdo_device 15 | The VDO device to recover 16 | . 17 | .SH SEE ALSO 18 | .BR vdo (8). 19 | -------------------------------------------------------------------------------- /utils/vdo/parseUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef PARSE_UTILS_H 21 | #define PARSE_UTILS_H 22 | 23 | #include 24 | #include 25 | 26 | #include "indexer.h" 27 | 28 | #include "encodings.h" 29 | 30 | typedef struct { 31 | char *sparse; 32 | char *memorySize; 33 | } UdsConfigStrings; 34 | 35 | /** 36 | * Parse a string argument as an unsigned int. 37 | * 38 | * @param [in] arg The argument to parse 39 | * @param [in] lowest The lowest allowed value 40 | * @param [in] highest The highest allowed value 41 | * @param [out] numPtr A pointer to return the parsed integer. 42 | * 43 | * @return VDO_SUCCESS or VDO_OUT_OF_RANGE. 44 | **/ 45 | int __must_check parseUInt(const char *arg, 46 | unsigned int lowest, 47 | unsigned int highest, 48 | unsigned int *numPtr); 49 | 50 | /** 51 | * Parse a string argument as a signed int. 52 | * 53 | * @param [in] arg The argument to parse 54 | * @param [out] numPtr A pointer to return the parsed integer. 55 | * 56 | * @return VDO_SUCCESS or VDO_OUT_OF_RANGE. 57 | **/ 58 | int parseInt(const char *arg, int *numPtr); 59 | 60 | /** 61 | * Parse a string argument as a decimal uint64_t. 62 | * 63 | * @param [in] arg The argument to parse 64 | * @param [out] numPtr A pointer to return the parsed value. 65 | * 66 | * @return VDO_SUCCESS or VDO_OUT_OF_RANGE. 67 | **/ 68 | int __must_check parseUInt64(const char *arg, uint64_t *numPtr); 69 | 70 | /** 71 | * Parse a string argument as a size, optionally using LVM's concept 72 | * of size suffixes. 73 | * 74 | * @param [in] arg The argument to parse 75 | * @param [in] lvmMode Whether to parse suffixes as LVM or SI. 76 | * @param [out] sizePtr A pointer to return the parsed size, in bytes 77 | * 78 | * @return VDO_SUCCESS or VDO_OUT_OF_RANGE. 79 | **/ 80 | int __must_check parseSize(const char *arg, bool lvmMode, uint64_t *sizePtr); 81 | 82 | /** 83 | * Parse UdsConfigStrings into a index_config. 84 | * 85 | * @param [in] configStrings The UDS config strings read. 86 | * @param [out] configPtr A pointer to return the struct index_config. 87 | **/ 88 | int __must_check parseIndexConfig(UdsConfigStrings *configStrings, 89 | struct index_config *configPtr); 90 | 91 | #endif // PARSE_UTILS_H 92 | -------------------------------------------------------------------------------- /utils/vdo/physicalLayer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef PHYSICAL_LAYER_H 21 | #define PHYSICAL_LAYER_H 22 | 23 | #include "types.h" 24 | 25 | typedef struct physicalLayer PhysicalLayer; 26 | 27 | /** 28 | * A function to destroy a physical layer and NULL out the reference to it. 29 | * 30 | * @param layer_ptr A pointer to the layer to destroy 31 | **/ 32 | typedef void layer_destructor(PhysicalLayer **layer_ptr); 33 | 34 | /** 35 | * A function to report the block count of a physicalLayer. 36 | * 37 | * @param layer The layer 38 | * 39 | * @return The block count of the layer 40 | **/ 41 | typedef block_count_t block_count_getter(PhysicalLayer *layer); 42 | 43 | /** 44 | * A function which can allocate a buffer suitable for use in an 45 | * extent_reader or extent_writer. 46 | * 47 | * @param [in] layer The physical layer in question 48 | * @param [in] bytes The size of the buffer, in bytes. 49 | * @param [in] why The occasion for allocating the buffer 50 | * @param [out] buffer_ptr A pointer to hold the buffer 51 | * 52 | * @return a success or error code 53 | **/ 54 | typedef int buffer_allocator(PhysicalLayer *layer, 55 | size_t bytes, 56 | const char *why, 57 | char **buffer_ptr); 58 | 59 | /** 60 | * A function which can read an extent from a physicalLayer. 61 | * 62 | * @param [in] layer The physical layer from which to read 63 | * @param [in] startBlock The physical block number of the start of the 64 | * extent 65 | * @param [in] blockCount The number of blocks in the extent 66 | * @param [out] buffer A buffer to hold the extent 67 | * 68 | * @return a success or error code 69 | **/ 70 | typedef int extent_reader(PhysicalLayer *layer, 71 | physical_block_number_t startBlock, 72 | size_t blockCount, 73 | char *buffer); 74 | 75 | /** 76 | * A function which can write an extent to a physicalLayer. 77 | * 78 | * @param [in] layer The physical layer to which to write 79 | * @param [in] startBlock The physical block number of the start of the 80 | * extent 81 | * @param [in] blockCount The number of blocks in the extent 82 | * @param [in] buffer The buffer which contains the data 83 | * 84 | * @return a success or error code 85 | **/ 86 | typedef int extent_writer(PhysicalLayer *layer, 87 | physical_block_number_t startBlock, 88 | size_t blockCount, 89 | char *buffer); 90 | 91 | /** 92 | * An abstraction representing the underlying physical layer. 93 | **/ 94 | struct physicalLayer { 95 | /* Management interface */ 96 | layer_destructor *destroy; 97 | 98 | /* Synchronous interface */ 99 | block_count_getter *getBlockCount; 100 | 101 | /* Synchronous IO interface */ 102 | buffer_allocator *allocateIOBuffer; 103 | extent_reader *reader; 104 | extent_writer *writer; 105 | }; 106 | 107 | #endif /* PHYSICAL_LAYER_H */ 108 | -------------------------------------------------------------------------------- /utils/vdo/slabSummaryReader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #include "slabSummaryReader.h" 21 | 22 | #include 23 | 24 | #include "memory-alloc.h" 25 | 26 | #include "encodings.h" 27 | #include "status-codes.h" 28 | #include "types.h" 29 | 30 | #include "physicalLayer.h" 31 | #include "userVDO.h" 32 | 33 | /**********************************************************************/ 34 | int readSlabSummary(UserVDO *vdo, struct slab_summary_entry **entriesPtr) 35 | { 36 | zone_count_t zones = vdo->states.slab_depot.zone_count; 37 | if (zones == 0) { 38 | return VDO_SUCCESS; 39 | } 40 | 41 | struct slab_summary_entry *entries; 42 | block_count_t summary_blocks = VDO_SLAB_SUMMARY_BLOCKS_PER_ZONE; 43 | int result = vdo->layer->allocateIOBuffer(vdo->layer, 44 | summary_blocks * VDO_BLOCK_SIZE, 45 | "slab summary entries", 46 | (char **) &entries); 47 | if (result != VDO_SUCCESS) { 48 | warnx("Could not create in-memory slab summary"); 49 | return result; 50 | } 51 | 52 | struct partition *slab_summary_partition; 53 | result = vdo_get_partition(&vdo->states.layout, 54 | VDO_SLAB_SUMMARY_PARTITION, 55 | &slab_summary_partition); 56 | if (result != VDO_SUCCESS) { 57 | warnx("Could not find slab summary partition"); 58 | return result; 59 | } 60 | 61 | physical_block_number_t origin = slab_summary_partition->offset; 62 | result = vdo->layer->reader(vdo->layer, origin, summary_blocks, (char *) entries); 63 | if (result != VDO_SUCCESS) { 64 | warnx("Could not read summary data"); 65 | vdo_free(entries); 66 | return result; 67 | } 68 | 69 | // If there is more than one zone, read and combine the other zone's data 70 | // with the data already read from the first zone. 71 | if (zones > 1) { 72 | struct slab_summary_entry *buffer; 73 | result = vdo->layer->allocateIOBuffer(vdo->layer, 74 | summary_blocks * VDO_BLOCK_SIZE, 75 | "slab summary entries", 76 | (char **) &buffer); 77 | if (result != VDO_SUCCESS) { 78 | warnx("Could not create slab summary buffer"); 79 | vdo_free(entries); 80 | return result; 81 | } 82 | 83 | for (zone_count_t zone = 1; zone < zones; zone++) { 84 | origin += summary_blocks; 85 | result = vdo->layer->reader(vdo->layer, origin, summary_blocks, 86 | (char *) buffer); 87 | if (result != VDO_SUCCESS) { 88 | warnx("Could not read summary data"); 89 | vdo_free(buffer); 90 | vdo_free(entries); 91 | return result; 92 | } 93 | 94 | for (slab_count_t entry_number = zone; entry_number < MAX_VDO_SLABS; 95 | entry_number += zones) { 96 | memcpy(entries + entry_number, buffer + entry_number, 97 | sizeof(struct slab_summary_entry)); 98 | } 99 | } 100 | 101 | vdo_free(buffer); 102 | } 103 | 104 | *entriesPtr = entries; 105 | return VDO_SUCCESS; 106 | } 107 | -------------------------------------------------------------------------------- /utils/vdo/slabSummaryReader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef SLAB_SUMMARY_READER_H 21 | #define SLAB_SUMMARY_READER_H 22 | 23 | #include "encodings.h" 24 | #include "types.h" 25 | 26 | #include "userVDO.h" 27 | 28 | /** 29 | * Read the contents of the slab summary into a single set of summary entries. 30 | * 31 | * @param [in] vdo The vdo from which to read the summary 32 | * @param [out] entries_ptr A pointer to hold the loaded entries 33 | * 34 | * @return VDO_SUCCESS or an error code 35 | **/ 36 | int __must_check 37 | readSlabSummary(UserVDO *vdo, struct slab_summary_entry **entriesPtr); 38 | 39 | #endif // SLAB_SUMMARY_UTILS_H 40 | -------------------------------------------------------------------------------- /utils/vdo/status-codes.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #include "status-codes.h" 7 | 8 | #include 9 | 10 | #include "errors.h" 11 | #include "logger.h" 12 | #include "permassert.h" 13 | #include "thread-utils.h" 14 | 15 | const struct error_info vdo_status_list[] = { 16 | { "VDO_NOT_IMPLEMENTED", "Not implemented" }, 17 | { "VDO_OUT_OF_RANGE", "Out of range" }, 18 | { "VDO_REF_COUNT_INVALID", "Reference count would become invalid" }, 19 | { "VDO_NO_SPACE", "Out of space" }, 20 | { "VDO_BAD_CONFIGURATION", "Bad configuration option" }, 21 | { "VDO_COMPONENT_BUSY", "Prior operation still in progress" }, 22 | { "VDO_BAD_PAGE", "Corrupt or incorrect page" }, 23 | { "VDO_UNSUPPORTED_VERSION", "Unsupported component version" }, 24 | { "VDO_INCORRECT_COMPONENT", "Component id mismatch in decoder" }, 25 | { "VDO_PARAMETER_MISMATCH", "Parameters have conflicting values" }, 26 | { "VDO_UNKNOWN_PARTITION", "No partition exists with a given id" }, 27 | { "VDO_PARTITION_EXISTS", "A partition already exists with a given id" }, 28 | { "VDO_INCREMENT_TOO_SMALL", "Physical block growth of too few blocks" }, 29 | { "VDO_CHECKSUM_MISMATCH", "Incorrect checksum" }, 30 | { "VDO_LOCK_ERROR", "A lock is held incorrectly" }, 31 | { "VDO_READ_ONLY", "The device is in read-only mode" }, 32 | { "VDO_SHUTTING_DOWN", "The device is shutting down" }, 33 | { "VDO_CORRUPT_JOURNAL", "Recovery journal corrupted" }, 34 | { "VDO_TOO_MANY_SLABS", "Exceeds maximum number of slabs supported" }, 35 | { "VDO_INVALID_FRAGMENT", "Compressed block fragment is invalid" }, 36 | { "VDO_RETRY_AFTER_REBUILD", "Retry operation after rebuilding finishes" }, 37 | { "VDO_BAD_MAPPING", "Invalid page mapping" }, 38 | { "VDO_BIO_CREATION_FAILED", "Bio creation failed" }, 39 | { "VDO_BAD_MAGIC", "Bad magic number" }, 40 | { "VDO_BAD_NONCE", "Bad nonce" }, 41 | { "VDO_JOURNAL_OVERFLOW", "Journal sequence number overflow" }, 42 | { "VDO_INVALID_ADMIN_STATE", "Invalid operation for current state" }, 43 | { "VDO_UNEXPECTED_EOF", "Unexpected EOF on block read" }, 44 | { "VDO_NOT_READ_ONLY", "The device is not in read-only mode" }, 45 | }; 46 | 47 | static atomic_t vdo_status_codes_registered = ATOMIC_INIT(0); 48 | static int status_code_registration_result; 49 | 50 | static void do_status_code_registration(void) 51 | { 52 | int result; 53 | 54 | BUILD_BUG_ON((VDO_STATUS_CODE_LAST - VDO_STATUS_CODE_BASE) != 55 | ARRAY_SIZE(vdo_status_list)); 56 | 57 | result = uds_register_error_block("VDO Status", VDO_STATUS_CODE_BASE, 58 | VDO_STATUS_CODE_BLOCK_END, vdo_status_list, 59 | sizeof(vdo_status_list)); 60 | /* 61 | * The following test handles cases where libvdo is statically linked against both the test 62 | * modules and the test driver (because multiple instances of this module call their own 63 | * copy of this function once each, resulting in multiple calls to register_error_block 64 | * which is shared in libuds). 65 | */ 66 | if (result == UDS_DUPLICATE_NAME) 67 | result = UDS_SUCCESS; 68 | 69 | status_code_registration_result = (result == UDS_SUCCESS) ? VDO_SUCCESS : result; 70 | } 71 | 72 | /** 73 | * vdo_register_status_codes() - Register the VDO status codes if needed. 74 | * Return: A success or error code. 75 | */ 76 | int vdo_register_status_codes(void) 77 | { 78 | vdo_perform_once(&vdo_status_codes_registered, do_status_code_registration); 79 | return status_code_registration_result; 80 | } 81 | 82 | /** 83 | * vdo_status_to_errno() - Given an error code, return a value we can return to the OS. 84 | * @error: The error code to convert. 85 | * 86 | * The input error code may be a system-generated value (such as -EIO), an errno macro used in our 87 | * code (such as EIO), or a UDS or VDO status code; the result must be something the rest of the OS 88 | * can consume (negative errno values such as -EIO, in the case of the kernel). 89 | * 90 | * Return: A system error code value. 91 | */ 92 | int vdo_status_to_errno(int error) 93 | { 94 | char error_name[VDO_MAX_ERROR_NAME_SIZE]; 95 | char error_message[VDO_MAX_ERROR_MESSAGE_SIZE]; 96 | 97 | /* 0 is success, negative a system error code */ 98 | if (likely(error <= 0)) 99 | return error; 100 | if (error < 1024) 101 | return -error; 102 | 103 | /* VDO or UDS error */ 104 | switch (error) { 105 | case VDO_NO_SPACE: 106 | return -ENOSPC; 107 | case VDO_READ_ONLY: 108 | return -EIO; 109 | default: 110 | vdo_log_info("%s: mapping internal status code %d (%s: %s) to EIO", 111 | __func__, error, 112 | uds_string_error_name(error, error_name, sizeof(error_name)), 113 | uds_string_error(error, error_message, sizeof(error_message))); 114 | return -EIO; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /utils/vdo/status-codes.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright 2023 Red Hat 4 | */ 5 | 6 | #ifndef VDO_STATUS_CODES_H 7 | #define VDO_STATUS_CODES_H 8 | 9 | #include "errors.h" 10 | 11 | enum { 12 | UDS_ERRORS_BLOCK_SIZE = UDS_ERROR_CODE_BLOCK_END - UDS_ERROR_CODE_BASE, 13 | VDO_ERRORS_BLOCK_START = UDS_ERROR_CODE_BLOCK_END, 14 | VDO_ERRORS_BLOCK_END = VDO_ERRORS_BLOCK_START + UDS_ERRORS_BLOCK_SIZE, 15 | }; 16 | 17 | /* VDO-specific status codes. */ 18 | enum vdo_status_codes { 19 | /* base of all VDO errors */ 20 | VDO_STATUS_CODE_BASE = VDO_ERRORS_BLOCK_START, 21 | /* we haven't written this yet */ 22 | VDO_NOT_IMPLEMENTED = VDO_STATUS_CODE_BASE, 23 | /* input out of range */ 24 | VDO_OUT_OF_RANGE, 25 | /* an invalid reference count would result */ 26 | VDO_REF_COUNT_INVALID, 27 | /* a free block could not be allocated */ 28 | VDO_NO_SPACE, 29 | /* improper or missing configuration option */ 30 | VDO_BAD_CONFIGURATION, 31 | /* prior operation still in progress */ 32 | VDO_COMPONENT_BUSY, 33 | /* page contents incorrect or corrupt data */ 34 | VDO_BAD_PAGE, 35 | /* unsupported version of some component */ 36 | VDO_UNSUPPORTED_VERSION, 37 | /* component id mismatch in decoder */ 38 | VDO_INCORRECT_COMPONENT, 39 | /* parameters have conflicting values */ 40 | VDO_PARAMETER_MISMATCH, 41 | /* no partition exists with a given id */ 42 | VDO_UNKNOWN_PARTITION, 43 | /* a partition already exists with a given id */ 44 | VDO_PARTITION_EXISTS, 45 | /* physical block growth of too few blocks */ 46 | VDO_INCREMENT_TOO_SMALL, 47 | /* incorrect checksum */ 48 | VDO_CHECKSUM_MISMATCH, 49 | /* a lock is held incorrectly */ 50 | VDO_LOCK_ERROR, 51 | /* the VDO is in read-only mode */ 52 | VDO_READ_ONLY, 53 | /* the VDO is shutting down */ 54 | VDO_SHUTTING_DOWN, 55 | /* the recovery journal has corrupt entries or corrupt metadata */ 56 | VDO_CORRUPT_JOURNAL, 57 | /* exceeds maximum number of slabs supported */ 58 | VDO_TOO_MANY_SLABS, 59 | /* a compressed block fragment is invalid */ 60 | VDO_INVALID_FRAGMENT, 61 | /* action is unsupported while rebuilding */ 62 | VDO_RETRY_AFTER_REBUILD, 63 | /* a block map entry is invalid */ 64 | VDO_BAD_MAPPING, 65 | /* bio_add_page failed */ 66 | VDO_BIO_CREATION_FAILED, 67 | /* bad magic number */ 68 | VDO_BAD_MAGIC, 69 | /* bad nonce */ 70 | VDO_BAD_NONCE, 71 | /* sequence number overflow */ 72 | VDO_JOURNAL_OVERFLOW, 73 | /* the VDO is not in a state to perform an admin operation */ 74 | VDO_INVALID_ADMIN_STATE, 75 | /* unexpected EOF on block read */ 76 | VDO_UNEXPECTED_EOF, 77 | /* the VDO is not in read-only mode */ 78 | VDO_NOT_READ_ONLY, 79 | /* one more than last error code */ 80 | VDO_STATUS_CODE_LAST, 81 | VDO_STATUS_CODE_BLOCK_END = VDO_ERRORS_BLOCK_END 82 | }; 83 | 84 | extern const struct error_info vdo_status_list[]; 85 | 86 | int vdo_register_status_codes(void); 87 | 88 | int vdo_status_to_errno(int error); 89 | 90 | #endif /* VDO_STATUS_CODES_H */ 91 | -------------------------------------------------------------------------------- /utils/vdo/vdoStats.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef VDO_STATS_H 21 | #define VDO_STATS_H 22 | 23 | #include "types.h" 24 | 25 | /** 26 | * Read vdo statistics from a buffer 27 | * 28 | * @param buf pointer to the buffer 29 | * @param stats pointer to the statistics 30 | * 31 | * @return VDO_SUCCESS or an error 32 | */ 33 | int read_vdo_stats(char *buf, struct vdo_statistics *stats); 34 | 35 | /** 36 | * Write vdo statistics to stdout 37 | * 38 | * @param stats pointer to the statistics 39 | * 40 | * @return VDO_SUCCESS or an error 41 | */ 42 | int vdo_write_stats(struct vdo_statistics *stats); 43 | 44 | #endif /* VDO_STATS_H */ 45 | -------------------------------------------------------------------------------- /utils/vdo/vdoVolumeUtils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #include "vdoVolumeUtils.h" 21 | 22 | #include 23 | 24 | #include "errors.h" 25 | #include "permassert.h" 26 | 27 | #include "status-codes.h" 28 | 29 | #include "fileLayer.h" 30 | #include "userVDO.h" 31 | 32 | static char errBuf[VDO_MAX_ERROR_MESSAGE_SIZE]; 33 | 34 | /** 35 | * Load a VDO from a file. 36 | * 37 | * @param [in] filename The file name 38 | * @param [in] readOnly Whether the layer should be read-only. 39 | * @param [in] validateConfig Whether the VDO should validate its config 40 | * @param [out] vdoPtr A pointer to hold the VDO 41 | * 42 | * @return VDO_SUCCESS or an error code 43 | **/ 44 | static int __must_check loadVDOFromFile(const char *filename, 45 | bool readOnly, 46 | bool validateConfig, 47 | UserVDO **vdoPtr) 48 | { 49 | int result = VDO_ASSERT(validateConfig || readOnly, 50 | "Cannot make a writable VDO" 51 | " without validating its config"); 52 | if (result != VDO_SUCCESS) { 53 | return result; 54 | } 55 | 56 | PhysicalLayer *layer; 57 | if (readOnly) { 58 | result = makeReadOnlyFileLayer(filename, &layer); 59 | } else { 60 | result = makeFileLayer(filename, 0, &layer); 61 | } 62 | 63 | if (result != VDO_SUCCESS) { 64 | warnx("Failed to make FileLayer from '%s' with %s", filename, 65 | uds_string_error(result, errBuf, VDO_MAX_ERROR_MESSAGE_SIZE)); 66 | return result; 67 | } 68 | 69 | // Create the VDO. 70 | UserVDO *vdo; 71 | result = loadVDO(layer, validateConfig, &vdo); 72 | if (result != VDO_SUCCESS) { 73 | layer->destroy(&layer); 74 | warnx("loading VDO failed with: %s", 75 | uds_string_error(result, errBuf, VDO_MAX_ERROR_MESSAGE_SIZE)); 76 | return result; 77 | } 78 | 79 | *vdoPtr = vdo; 80 | return VDO_SUCCESS; 81 | } 82 | 83 | /**********************************************************************/ 84 | int makeVDOFromFile(const char *filename, bool readOnly, UserVDO **vdoPtr) 85 | { 86 | return loadVDOFromFile(filename, readOnly, true, vdoPtr); 87 | } 88 | 89 | /**********************************************************************/ 90 | int readVDOWithoutValidation(const char *filename, UserVDO **vdoPtr) 91 | { 92 | return loadVDOFromFile(filename, true, false, vdoPtr); 93 | } 94 | 95 | /**********************************************************************/ 96 | void freeVDOFromFile(UserVDO **vdoPtr) 97 | { 98 | UserVDO *vdo = *vdoPtr; 99 | if (vdo == NULL) { 100 | return; 101 | } 102 | 103 | PhysicalLayer *layer = vdo->layer; 104 | freeUserVDO(&vdo); 105 | layer->destroy(&layer); 106 | *vdoPtr = NULL; 107 | } 108 | -------------------------------------------------------------------------------- /utils/vdo/vdoVolumeUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #ifndef VDO_VOLUME_UTILS_H 21 | #define VDO_VOLUME_UTILS_H 22 | 23 | #include "types.h" 24 | 25 | #include "userVDO.h" 26 | 27 | /** 28 | * Load a VDO from a file. 29 | * 30 | * @param [in] filename The file name 31 | * @param [in] readOnly Whether the layer should be read-only. 32 | * @param [out] vdoPtr A pointer to hold the VDO 33 | * 34 | * @return VDO_SUCCESS or an error code 35 | **/ 36 | int __must_check 37 | makeVDOFromFile(const char *filename, bool readOnly, UserVDO **vdoPtr); 38 | 39 | /** 40 | * Load a VDO from a file without validating the config. 41 | * 42 | * @param [in] filename The file name 43 | * @param [out] vdoPtr A pointer to hold the VDO 44 | * 45 | * @return VDO_SUCCESS or an error code 46 | **/ 47 | int __must_check 48 | readVDOWithoutValidation(const char *filename, UserVDO **vdoPtr); 49 | 50 | /** 51 | * Free the VDO made with makeVDOFromFile(). 52 | * 53 | * @param vdoPtr The pointer to the VDO to free 54 | **/ 55 | void freeVDOFromFile(UserVDO **vdoPtr); 56 | 57 | #endif // VDO_VOLUME_UTILS_H 58 | -------------------------------------------------------------------------------- /utils/vdo/vdoforcerebuild.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "errors.h" 27 | #include "logger.h" 28 | 29 | #include "constants.h" 30 | #include "status-codes.h" 31 | #include "types.h" 32 | #include "vdoConfig.h" 33 | 34 | #include "fileLayer.h" 35 | 36 | static const char usageString[] = 37 | " [--help] filename"; 38 | 39 | static const char helpString[] = 40 | "vdoforcerebuild - prepare a VDO device to exit read-only mode\n" 41 | "\n" 42 | "SYNOPSIS\n" 43 | " vdoforcerebuild filename\n" 44 | "\n" 45 | "DESCRIPTION\n" 46 | " vdoforcerebuild forces an existing VDO device to exit read-only\n" 47 | " mode and to attempt to regenerate as much metadata as possible.\n" 48 | "\n" 49 | "OPTIONS\n" 50 | " --help\n" 51 | " Print this help message and exit.\n" 52 | "\n" 53 | " --version\n" 54 | " Show the version of vdoforcerebuild.\n" 55 | "\n"; 56 | 57 | // N.B. the option array must be in sync with the option string. 58 | static struct option options[] = { 59 | { "help", no_argument, NULL, 'h' }, 60 | { "version", no_argument, NULL, 'V' }, 61 | { NULL, 0, NULL, 0 }, 62 | }; 63 | static char optionString[] = "h"; 64 | 65 | static void usage(const char *progname, const char *usageOptionsString) 66 | { 67 | errx(1, "Usage: %s%s\n", progname, usageOptionsString); 68 | } 69 | 70 | int main(int argc, char *argv[]) 71 | { 72 | static char errBuf[VDO_MAX_ERROR_MESSAGE_SIZE]; 73 | 74 | int result = vdo_register_status_codes(); 75 | if (result != VDO_SUCCESS) { 76 | errx(1, "Could not register status codes: %s", 77 | uds_string_error(result, errBuf, VDO_MAX_ERROR_MESSAGE_SIZE)); 78 | } 79 | 80 | int c; 81 | while ((c = getopt_long(argc, argv, optionString, options, NULL)) != -1) { 82 | switch (c) { 83 | case 'h': 84 | printf("%s", helpString); 85 | exit(0); 86 | break; 87 | 88 | case 'V': 89 | fprintf(stdout, "vdoforcerebuild version is: %s\n", CURRENT_VERSION); 90 | exit(0); 91 | break; 92 | 93 | default: 94 | usage(argv[0], usageString); 95 | break; 96 | }; 97 | } 98 | 99 | if (optind != (argc - 1)) { 100 | usage(argv[0], usageString); 101 | } 102 | 103 | char *filename = argv[optind]; 104 | PhysicalLayer *layer; 105 | // Passing 0 physical blocks will make a filelayer to fit the file. 106 | result = makeFileLayer(filename, 0, &layer); 107 | if (result != VDO_SUCCESS) { 108 | errx(result, "makeFileLayer failed on '%s'", filename); 109 | } 110 | 111 | result = forceVDORebuild(layer); 112 | if (result != VDO_SUCCESS) { 113 | char buf[VDO_MAX_ERROR_MESSAGE_SIZE]; 114 | errx(result, "forceRebuild failed on '%s': %s", 115 | filename, uds_string_error(result, buf, sizeof(buf))); 116 | } 117 | 118 | layer->destroy(&layer); 119 | } 120 | -------------------------------------------------------------------------------- /utils/vdo/vdoreadonly.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Red Hat 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | * 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "errors.h" 27 | #include "fileUtils.h" 28 | #include "logger.h" 29 | #include "string-utils.h" 30 | 31 | #include "constants.h" 32 | #include "status-codes.h" 33 | 34 | #include "fileLayer.h" 35 | #include "physicalLayer.h" 36 | #include "vdoConfig.h" 37 | #include "vdoVolumeUtils.h" 38 | 39 | static const char usageString[] = 40 | " [--help] filename"; 41 | 42 | static const char helpString[] = 43 | "vdoreadonly - Puts a VDO device into read-only mode\n" 44 | "\n" 45 | "SYNOPSIS\n" 46 | " vdoreadonly filename\n" 47 | "\n" 48 | "DESCRIPTION\n" 49 | " vdoreadonly forces an existing VDO device into read-only\n" 50 | " mode.\n" 51 | "\n" 52 | "OPTIONS\n" 53 | " --help\n" 54 | " Print this help message and exit.\n" 55 | "\n" 56 | " --version\n" 57 | " Show the version of vdoreadonly.\n" 58 | "\n"; 59 | 60 | // N.B. the option array must be in sync with the option string. 61 | static struct option options[] = { 62 | { "help", no_argument, NULL, 'h' }, 63 | { "version", no_argument, NULL, 'V' }, 64 | { NULL, 0, NULL, 0 }, 65 | }; 66 | static char optionString[] = "h"; 67 | 68 | static void usage(const char *progname, const char *usageOptionsString) 69 | { 70 | errx(1, "Usage: %s%s\n", progname, usageOptionsString); 71 | } 72 | 73 | /**********************************************************************/ 74 | int main(int argc, char *argv[]) 75 | { 76 | static char errBuf[VDO_MAX_ERROR_MESSAGE_SIZE]; 77 | 78 | int result = vdo_register_status_codes(); 79 | if (result != VDO_SUCCESS) { 80 | errx(1, "Could not register status codes: %s", 81 | uds_string_error(result, errBuf, VDO_MAX_ERROR_MESSAGE_SIZE)); 82 | } 83 | 84 | int c; 85 | while ((c = getopt_long(argc, argv, optionString, options, NULL)) != -1) { 86 | switch (c) { 87 | case 'h': 88 | printf("%s", helpString); 89 | exit(0); 90 | break; 91 | 92 | case 'V': 93 | fprintf(stdout, "vdoreadonly version is: %s\n", CURRENT_VERSION); 94 | exit(0); 95 | break; 96 | 97 | default: 98 | usage(argv[0], usageString); 99 | break; 100 | }; 101 | } 102 | 103 | if (optind != (argc - 1)) { 104 | usage(argv[0], usageString); 105 | } 106 | 107 | char *filename = argv[optind]; 108 | PhysicalLayer *layer; 109 | result = makeFileLayer(filename, 0, &layer); 110 | if (result != VDO_SUCCESS) { 111 | errx(result, "makeFileLayer failed on '%s'", filename); 112 | } 113 | 114 | result = setVDOReadOnlyMode(layer); 115 | if (result != VDO_SUCCESS) { 116 | char buf[VDO_MAX_ERROR_MESSAGE_SIZE]; 117 | errx(result, "setting read-only mode failed on '%s': %s", 118 | filename, uds_string_error(result, buf, sizeof(buf))); 119 | } 120 | 121 | // Close and sync the underlying file. 122 | layer->destroy(&layer); 123 | } 124 | -------------------------------------------------------------------------------- /utils/vdo/vdostats.bash: -------------------------------------------------------------------------------- 1 | # bash completion for vdostats 2 | # 3 | # Copyright Red Hat 4 | # 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; either version 2 8 | # of the License, or (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | # 02110-1301, USA. 19 | # 20 | # TODO : Add device name at the end of completion of the commands. 21 | 22 | _vdostats() 23 | { 24 | local opts cur 25 | _init_completion || return 26 | COMPREPLY=() 27 | opts="--help --all --human-readable --si --verbose --version" 28 | cur="${COMP_WORDS[COMP_CWORD]}" 29 | case "${cur}" in 30 | *) 31 | COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) 32 | ;; 33 | esac 34 | } 35 | 36 | complete -F _vdostats vdostats 37 | -------------------------------------------------------------------------------- /vdo.spec: -------------------------------------------------------------------------------- 1 | %define spec_release 1 2 | %define bash_completions_dir %{_datadir}/bash-completion/completions 3 | 4 | Summary: Management tools for Virtual Data Optimizer 5 | Name: vdo 6 | Version: 8.3.1.1 7 | Release: %{spec_release}%{?dist} 8 | 9 | License: GPL-2.0-only 10 | URL: http://github.com/dm-vdo/vdo 11 | Source0: %{name}-%{version}.tgz 12 | 13 | Requires: kmod-kvdo >= 8.2 14 | ExcludeArch: s390 15 | ExcludeArch: ppc 16 | ExcludeArch: ppc64 17 | ExcludeArch: i686 18 | BuildRequires: device-mapper-devel 19 | BuildRequires: device-mapper-event-devel 20 | BuildRequires: gcc 21 | BuildRequires: libblkid-devel 22 | BuildRequires: libuuid-devel 23 | BuildRequires: make 24 | %ifarch %{valgrind_arches} 25 | BuildRequires: valgrind-devel 26 | %endif 27 | BuildRequires: zlib-devel 28 | 29 | # Disable an automatic dependency due to a file in examples/monitor. 30 | %define __requires_exclude perl 31 | 32 | %description 33 | Virtual Data Optimizer (VDO) is a device mapper target that delivers 34 | block-level deduplication, compression, and thin provisioning. 35 | 36 | This package provides the user-space management tools for VDO. 37 | 38 | %package support 39 | Summary: Support tools for Virtual Data Optimizer 40 | License: GPL-2.0-only 41 | 42 | Requires: libuuid >= 2.23 43 | ExcludeArch: s390 44 | ExcludeArch: ppc 45 | ExcludeArch: ppc64 46 | ExcludeArch: i686 47 | 48 | %description support 49 | Virtual Data Optimizer (VDO) is a device mapper target that delivers 50 | block-level deduplication, compression, and thin provisioning. 51 | 52 | This package provides the user-space support tools for VDO. 53 | 54 | %prep 55 | %setup -q 56 | 57 | %build 58 | make 59 | 60 | %install 61 | make install DESTDIR=$RPM_BUILD_ROOT INSTALLOWNER= name=%{name} bindir=%{_bindir} \ 62 | mandir=%{_mandir} defaultdocdir=%{_defaultdocdir} libexecdir=%{_libexecdir} \ 63 | presetdir=%{_presetdir} python3_sitelib=/%{python3_sitelib} \ 64 | sysconfdir=%{_sysconfdir} unitdir=%{_unitdir} 65 | 66 | %files 67 | %license COPYING 68 | %{_bindir}/vdoforcerebuild 69 | %{_bindir}/vdoformat 70 | %{_bindir}/vdostats 71 | %{bash_completions_dir}/vdostats 72 | %dir %{_defaultdocdir}/%{name} 73 | %dir %{_defaultdocdir}/%{name}/examples 74 | %dir %{_defaultdocdir}/%{name}/examples/monitor 75 | %doc %{_defaultdocdir}/%{name}/examples/monitor/monitor_check_vdostats_logicalSpace.pl 76 | %doc %{_defaultdocdir}/%{name}/examples/monitor/monitor_check_vdostats_physicalSpace.pl 77 | %doc %{_defaultdocdir}/%{name}/examples/monitor/monitor_check_vdostats_savingPercent.pl 78 | %{_mandir}/man8/vdoforcerebuild.8* 79 | %{_mandir}/man8/vdoformat.8* 80 | %{_mandir}/man8/vdostats.8* 81 | 82 | %files support 83 | %{_bindir}/adaptlvm 84 | %{_bindir}/vdoaudit 85 | %{_bindir}/vdodebugmetadata 86 | %{_bindir}/vdodumpblockmap 87 | %{_bindir}/vdodumpmetadata 88 | %{_bindir}/vdolistmetadata 89 | %{_bindir}/vdoreadonly 90 | %{_bindir}/vdorecover 91 | %{_mandir}/man8/adaptlvm.8* 92 | %{_mandir}/man8/vdoaudit.8* 93 | %{_mandir}/man8/vdodebugmetadata.8* 94 | %{_mandir}/man8/vdodumpblockmap.8* 95 | %{_mandir}/man8/vdodumpmetadata.8* 96 | %{_mandir}/man8/vdolistmetadata.8* 97 | %{_mandir}/man8/vdoreadonly.8* 98 | %{_mandir}/man8/vdorecover.8* 99 | 100 | %changelog 101 | * Thu Mar 13 2025 - Red Hat VDO Team - 8.3.1.1-1 102 | - See https://github.com/dm-vdo/vdo.git 103 | --------------------------------------------------------------------------------