pax_global_header00006660000000000000000000000064122277245050014520gustar00rootroot0000000000000052 comment=c7b67659a56752b10d1019d235c3d30463c3e2f8 thin-provisioning-tools-0.2.8/000077500000000000000000000000001222772450500163535ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/.gitignore000066400000000000000000000006141222772450500203440ustar00rootroot00000000000000*~ *.o *.a *.gmo *_t *.d *.d.[0-9]* test.data cachegrind.* \#*\# thin_check thin_dump thin_restore thin_repair thin_rmap thin_metadata_size cache_check cache_dump cache_restore cache_repair *.metadata bad-metadata Makefile unit-tests/Makefile unit-tests/unit_tests gmock-1.6.0.zip gmock-1.6.0/ autom4te.cache/ *.xml *.bin *.patch version.h config.cache config.log config.status configure thin-provisioning-tools-0.2.8/.ruby-version000066400000000000000000000000131222772450500210120ustar00rootroot000000000000001.9.3-p392 thin-provisioning-tools-0.2.8/COPYING000066400000000000000000001045131222772450500174120ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . thin-provisioning-tools-0.2.8/Gemfile000066400000000000000000000001431222772450500176440ustar00rootroot00000000000000source 'https://rubygems.org' group :test do gem 'cucumber' gem 'aruba' gem 'thinp_xml' end thin-provisioning-tools-0.2.8/Gemfile.lock000066400000000000000000000013361222772450500206000ustar00rootroot00000000000000GEM remote: https://rubygems.org/ specs: aruba (0.5.3) childprocess (>= 0.3.6) cucumber (>= 1.1.1) rspec-expectations (>= 2.7.0) builder (3.2.2) childprocess (0.3.9) ffi (~> 1.0, >= 1.0.11) cucumber (1.3.8) builder (>= 2.1.2) diff-lcs (>= 1.1.3) gherkin (~> 2.12.1) multi_json (>= 1.7.5, < 2.0) multi_test (>= 0.0.2) diff-lcs (1.2.4) ejt_command_line (0.0.2) ffi (1.9.0) gherkin (2.12.2) multi_json (~> 1.3) multi_json (1.8.2) multi_test (0.0.2) rspec-expectations (2.14.3) diff-lcs (>= 1.1.3, < 2.0) thinp_xml (0.0.12) ejt_command_line (= 0.0.2) PLATFORMS ruby DEPENDENCIES aruba cucumber thinp_xml thin-provisioning-tools-0.2.8/Makefile.in000066400000000000000000000232321222772450500204220ustar00rootroot00000000000000# Copyright (C) 2011 Red Hat, Inc. All rights reserved. # # This file is part of the thin-provisioning-tools source. # # thin-provisioning-tools is free software: you can redistribute it # and/or modify it under the terms of the GNU General Public License # as published by the Free Software Foundation, either version 3 of # the License, or (at your option) any later version. # # thin-provisioning-tools is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied warranty # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with thin-provisioning-tools. If not, see # . .PHONY: all V=@ PROGRAMS=\ cache_check \ cache_dump \ cache_restore \ cache_repair \ \ thin_check \ thin_dump \ thin_restore \ thin_repair \ thin_rmap \ thin_metadata_size all: $(PROGRAMS) SOURCE=\ base/base64.cc \ base/error_state.cc \ \ caching/hint_array.cc \ caching/superblock.cc \ caching/mapping_array.cc \ caching/metadata.cc \ caching/metadata_dump.cc \ caching/restore_emitter.cc \ caching/xml_format.cc \ \ persistent-data/checksum.cc \ persistent-data/endian_utils.cc \ persistent-data/error_set.cc \ persistent-data/file_utils.cc \ persistent-data/hex_dump.cc \ persistent-data/lock_tracker.cc \ persistent-data/transaction_manager.cc \ \ persistent-data/data-structures/bitset.cc \ persistent-data/data-structures/btree.cc \ \ persistent-data/space_map.cc \ persistent-data/space-maps/disk.cc \ persistent-data/space-maps/recursive.cc \ persistent-data/space-maps/careful_alloc.cc \ \ thin-provisioning/device_tree.cc \ thin-provisioning/human_readable_format.cc \ thin-provisioning/mapping_tree.cc \ thin-provisioning/metadata.cc \ thin-provisioning/metadata_checker.cc \ thin-provisioning/metadata_dumper.cc \ thin-provisioning/restore_emitter.cc \ thin-provisioning/rmap_visitor.cc \ thin-provisioning/superblock.cc \ thin-provisioning/thin_pool.cc \ thin-provisioning/xml_format.cc PDATA_OBJECTS=$(subst .cc,.o,$(SOURCE)) CXX_PROGRAM_SOURCE=\ caching/cache_check.cc \ caching/cache_restore.cc \ \ thin-provisioning/thin_check.cc \ thin-provisioning/thin_dump.cc \ thin-provisioning/thin_restore.cc \ thin-provisioning/thin_repair.cc \ thin-provisioning/thin_rmap.cc C_PROGRAM_SOURCE=\ thin-provisioning/thin_metadata_size.c CC:=@CC@ CXX:=@CXX@ OBJECTS:=$(subst .cc,.o,$(SOURCE)) TOP_DIR:=@top_srcdir@ TOP_BUILDDIR:=@top_builddir@ CFLAGS+=-g -Wall -O3 CXXFLAGS+=-g -Wall -fno-strict-aliasing CXXFLAGS+=@CXXOPTIMISE_FLAG@ CXXFLAGS+=@CXXDEBUG_FLAG@ INCLUDES+=-I$(TOP_BUILDDIR) -I$(TOP_DIR) -I$(TOP_DIR)/thin-provisioning LIBS:=-lstdc++ LIBEXPAT:=-lexpat INSTALL:=@INSTALL@ PREFIX:=@prefix@ BINDIR:=$(DESTDIR)$(PREFIX)/sbin MANPATH:=$(DESTDIR)$(MANDIR) vpath %.cc $(TOP_DIR) INSTALL_DIR = $(INSTALL) -m 755 -d INSTALL_PROGRAM = $(INSTALL) -m 755 INSTALL_DATA = $(INSTALL) -p -m 644 ifeq ("@TESTING@", "yes") TEST_INCLUDES=\ -Igmock-1.6.0/include \ -Igmock-1.6.0/gtest/include else TEST_INCLUDES= endif .SUFFIXES: .d %.o: %.c @echo " [CC] $<" $(V) $(CC) -c $(INCLUDES) $(CFLAGS) -o $@ $< @echo " [DEP] $<" $(V) $(CC) -MM -MT $(subst .c,.o,$<) $(INCLUDES) $(CFLAGS) $< > $*.$$$$; \ sed 's,\([^ :]*\)\.o[ :]*,\1.o \1.gmo $* : Makefile ,g' < $*.$$$$ > $*.d; \ $(RM) $*.$$$$ %.o: %.cc @echo " [CXX] $<" $(V) $(CXX) -c $(INCLUDES) $(CXXFLAGS) -o $@ $< @echo " [DEP] $<" $(V) $(CXX) -MM -MT $(subst .cc,.o,$<) $(INCLUDES) $(TEST_INCLUDES) $(CXXFLAGS) $< > $*.$$$$; \ sed 's,\([^ :]*\)\.o[ :]*,\1.o \1.gmo $* : Makefile ,g' < $*.$$$$ > $*.d; \ $(RM) $*.$$$$ #---------------------------------------------------------------- lib/libpdata.a: $(PDATA_OBJECTS) @echo " [AR] $<" $(V)ar -rv $@ $(PDATA_OBJECTS) > /dev/null 2>&1 #---------------------------------------------------------------- # Thin provisioning tools THIN_DEBUG_SOURCE=$(SOURCE) THIN_DUMP_SOURCE=$(SOURCE) THIN_REPAIR_SOURCE=$(SOURCE) THIN_RESTORE_SOURCE=$(SOURCE) THIN_CHECK_SOURCE=\ base/error_state.cc \ persistent-data/checksum.cc \ persistent-data/endian_utils.cc \ persistent-data/error_set.cc \ persistent-data/file_utils.cc \ persistent-data/hex_dump.cc \ persistent-data/lock_tracker.cc \ persistent-data/data-structures/btree.cc \ persistent-data/space_map.cc \ persistent-data/space-maps/disk.cc \ persistent-data/space-maps/recursive.cc \ persistent-data/space-maps/careful_alloc.cc \ persistent-data/transaction_manager.cc \ thin-provisioning/device_tree.cc \ thin-provisioning/mapping_tree.cc \ thin-provisioning/metadata.cc \ thin-provisioning/metadata_checker.cc \ thin-provisioning/superblock.cc THIN_RMAP_SOURCE=\ persistent-data/checksum.cc \ persistent-data/endian_utils.cc \ persistent-data/error_set.cc \ persistent-data/file_utils.cc \ persistent-data/hex_dump.cc \ persistent-data/lock_tracker.cc \ persistent-data/data-structures/btree.cc \ persistent-data/space_map.cc \ persistent-data/space-maps/disk.cc \ persistent-data/space-maps/recursive.cc \ persistent-data/space-maps/careful_alloc.cc \ persistent-data/transaction_manager.cc \ thin-provisioning/device_tree.cc \ thin-provisioning/mapping_tree.cc \ thin-provisioning/metadata.cc \ thin-provisioning/metadata_checker.cc \ thin-provisioning/rmap_visitor.cc \ thin-provisioning/superblock.cc THIN_DEBUG_OBJECTS=$(subst .cc,.o,$(THIN_DEBUG_SOURCE)) THIN_DUMP_OBJECTS=$(subst .cc,.o,$(THIN_DUMP_SOURCE)) THIN_REPAIR_OBJECTS=$(subst .cc,.o,$(THIN_REPAIR_SOURCE)) THIN_RESTORE_OBJECTS=$(subst .cc,.o,$(THIN_RESTORE_SOURCE)) THIN_CHECK_OBJECTS=$(subst .cc,.o,$(THIN_CHECK_SOURCE)) THIN_RMAP_OBJECTS=$(subst .cc,.o,$(THIN_RMAP_SOURCE)) thin_debug: $(THIN_DEBUG_OBJECTS) thin-provisioning/thin_debug.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) thin_repair: $(THIN_REPAIR_OBJECTS) thin-provisioning/thin_repair.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) thin_dump: $(THIN_DUMP_OBJECTS) thin-provisioning/thin_dump.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) thin_restore: $(THIN_RESTORE_OBJECTS) thin-provisioning/thin_restore.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) thin_check: $(THIN_CHECK_OBJECTS) thin-provisioning/thin_check.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) thin_rmap: $(THIN_RMAP_OBJECTS) thin-provisioning/thin_rmap.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) thin_metadata_size: thin-provisioning/thin_metadata_size.o @echo " [LD] $@" $(V) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ -lm #---------------------------------------------------------------- # Cache tools CACHE_CHECK_SOURCE=\ base/base64.cc \ base/error_state.cc \ persistent-data/checksum.cc \ persistent-data/endian_utils.cc \ persistent-data/error_set.cc \ persistent-data/file_utils.cc \ persistent-data/hex_dump.cc \ persistent-data/lock_tracker.cc \ persistent-data/data-structures/btree.cc \ persistent-data/data-structures/bitset.cc \ persistent-data/space_map.cc \ persistent-data/space-maps/disk.cc \ persistent-data/space-maps/recursive.cc \ persistent-data/space-maps/careful_alloc.cc \ persistent-data/transaction_manager.cc \ caching/hint_array.cc \ caching/superblock.cc \ caching/mapping_array.cc \ caching/metadata.cc \ caching/metadata_dump.cc \ caching/restore_emitter.cc \ caching/xml_format.cc CACHE_CHECK_OBJECTS=$(subst .cc,.o,$(CACHE_CHECK_SOURCE)) CACHE_DUMP_SOURCE=$(SOURCE) CACHE_DUMP_OBJECTS=$(subst .cc,.o,$(CACHE_DUMP_SOURCE)) CACHE_REPAIR_SOURCE=$(SOURCE) CACHE_REPAIR_OBJECTS=$(subst .cc,.o,$(CACHE_REPAIR_SOURCE)) CACHE_RESTORE_SOURCE=$(SOURCE) CACHE_RESTORE_OBJECTS=$(subst .cc,.o,$(CACHE_RESTORE_SOURCE)) cache_check: $(CACHE_CHECK_OBJECTS) caching/cache_check.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) cache_dump: $(CACHE_DUMP_OBJECTS) caching/cache_dump.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) cache_repair: $(CACHE_REPAIR_OBJECTS) caching/cache_repair.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) cache_restore: $(CACHE_RESTORE_OBJECTS) caching/cache_restore.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) DEPEND_FILES=\ $(subst .cc,.d,$(SOURCE)) \ $(subst .cc,.d,$(TEST_SOURCE)) \ $(subst .cc,.d,$(CXX_PROGRAM_SOURCE)) \ $(subst .c,.d,$(C_PROGRAM_SOURCE)) .PHONY: clean distclean clean: find . -name \*.o -delete find . -name \*.gmo -delete find . -name \*.d -delete $(RM) $(TEST_PROGRAMS) $(PROGRAMS) $(GMOCK_OBJECTS) lib/*.a distclean: clean $(RM) config.cache config.log config.status configure.h version.h Makefile unit-tests/Makefile install: $(PROGRAMS) $(INSTALL_DIR) $(BINDIR) $(INSTALL_PROGRAM) thin_check $(BINDIR) $(INSTALL_PROGRAM) thin_dump $(BINDIR) $(INSTALL_PROGRAM) thin_repair $(BINDIR) $(INSTALL_PROGRAM) thin_restore $(BINDIR) $(INSTALL_PROGRAM) thin_rmap $(BINDIR) $(INSTALL_PROGRAM) thin_metadata_size $(BINDIR) $(INSTALL_DIR) $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_check.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_dump.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_repair.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_restore.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_rmap.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_metadata_size.8 $(MANPATH)/man8 .PHONY: install ifeq ("@TESTING@", "yes") include unit-tests/Makefile .PHONEY: features features: $(PROGRAMS) cucumber --no-color --format progress test: features unit-test endif -include $(DEPEND_FILES) thin-provisioning-tools-0.2.8/README.md000066400000000000000000000065431222772450500176420ustar00rootroot00000000000000Introduction ============ A suite of tools for manipulating the metadata of the dm-thin device-mapper target. Requirements ============ A C++ compiler that supports the c++11 standard (eg, g++). The [Boost C++ library](http://www.boost.org/). The [expat](http://expat.sourceforge.net/) xml parser library (version 1). make, autoconf etc. There are more requirements for testing, detailed below. Building ======== ./configure make sudo make install Quick examples ============== These tools introduce an xml format for the metadata. This is useful for making backups, or allowing scripting languages to generate or manipulate metadata. A Ruby library for this available; [thinp_xml](https://rubygems.org/gems/thinp_xml). To convert the binary metadata format that the kernel uses to this xml format use _thin\_dump_. thin_dump --format xml /dev/mapper/my_thinp_metadata To convert xml back to the binary form use _thin\_restore_. thin_restore -i my_xml -o /dev/mapper/my_thinp_metadata You should periodically check the health of your metadata, much as you fsck a filesystem. Your volume manager (eg, LVM2) should be doing this for you behind the scenes. thin_check /dev/mapper/my_thinp_metadata Checking all the mappings can take some time, you can omit this part of the check if you wish. thin_check --skip-mappings /dev/mapper/my_thinp_metadata If your metadata has become corrupt for some reason (device failure, user error, kernel bug), thin_check will tell you what the effects of the corruption are (eg, which thin devices are effected, which mappings). There are two ways to repair metadata. The simplest is via the _thin\_repair_ tool. thin_repair -i /dev/mapper/broken_metadata_dev -o /dev/mapper/new_metadata_dev This is a non-destructive operation that writes corrected metadata to a new metadata device. Alternatively you can go via the xml format (perhaps you want to inspect the repaired metadata before restoring). thin_dump --repair /dev/mapper/my_metadata > repaired.xml thinp_restore -i repaired.xml -o /dev/mapper/my_metadata Development =========== Autoconf -------- If you've got the source from github you'll need to create the configure script with autoconf. I do this by running: autoreconf Enable tests ------------ You will need to enable tests when you configure. ./configure --enable-testing Unit tests ---------- Unit tests are implemented using the google mock framework. This is a source library that you will have to download. A script is provided to do this for you. ./get-gmock.sh All tests can be run via: make unit-test Alternatively you may want to run a subset of the tests: make unit-tests/unit_tests unit-tests/unit_tests --gtest_filter=BtreeTests.* Functional tests ---------------- These top level tests are implemented using the [cucumber](http://cukes.info/) tool. They check the user interface of the tools (eg, command line switches are accepted and effective). I've provided a Gemfile, so installing this should be easy: - Install Ruby 1.9.x. I recommend doing this via RVM. - Make sure _bundler_ is installed: gem install bundler - Install dependencies (including _cucumber_ and _thinp\_xml_) bundle Once you've done this you can run the tests with a simple: cucumber Or specific tests with: cucumber features/thin_restore -n 'print help' thin-provisioning-tools-0.2.8/TODO.org000066400000000000000000000002421222772450500176270ustar00rootroot00000000000000* restoring an xml file that specifies 0 data blocks fails in an unexpected way. Need to check the case where blocks past the end are specified in the ranges. thin-provisioning-tools-0.2.8/VERSION000066400000000000000000000000061222772450500174170ustar00rootroot000000000000000.2.8 thin-provisioning-tools-0.2.8/autoconf/000077500000000000000000000000001222772450500201715ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/autoconf/config.guess000077500000000000000000001276151222772450500225250ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. timestamp='2009-11-20' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: thin-provisioning-tools-0.2.8/autoconf/config.sub000077500000000000000000001031671222772450500221640ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. timestamp='2009-11-20' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | ubicom32 \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tile*) basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: thin-provisioning-tools-0.2.8/autoconf/install-sh000077500000000000000000000316001222772450500221750ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2006-10-14.15 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" posix_glob= posix_mkdir= # Desired mode of installed file. mode=0755 chmodcmd=$chmodprog chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit $?;; -m) mode=$2 shift shift case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac done if test $# -ne 0 && test -z "$dir_arg$dstarg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix=/ ;; -*) prefix=./ ;; *) prefix= ;; esac case $posix_glob in '') if (set -f) 2>/dev/null; then posix_glob=true else posix_glob=false fi ;; esac oIFS=$IFS IFS=/ $posix_glob && set -f set fnord $dstdir shift $posix_glob && set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dst"; then $doit $rmcmd -f "$dst" 2>/dev/null \ || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } } || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: thin-provisioning-tools-0.2.8/base/000077500000000000000000000000001222772450500172655ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/base/base64.cc000066400000000000000000000073561222772450500206730ustar00rootroot00000000000000#include "base/base64.h" #include #include #include using namespace base; using namespace boost; using namespace std; //---------------------------------------------------------------- namespace { char const *table_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; struct index_set { unsigned nr_valid_; unsigned index_[4]; }; index_set split1(unsigned char c) { index_set r; r.nr_valid_ = 2; r.index_[0] = c >> 2; r.index_[1] = (c & 3) << 4; return r; } index_set split2(unsigned char c1, unsigned char c2) { index_set r; r.nr_valid_ = 3; r.index_[0] = c1 >> 2; r.index_[1] = ((c1 & 3) << 4) | (c2 >> 4); r.index_[2] = (c2 & 15) << 2; return r; } index_set split3(unsigned char c1, unsigned char c2, unsigned c3) { index_set r; r.nr_valid_ = 4; r.index_[0] = c1 >> 2; r.index_[1] = ((c1 & 3) << 4) | (c2 >> 4); r.index_[2] = ((c2 & 15) << 2) | (c3 >> 6); r.index_[3] = c3 & 63; return r; } index_set split(vector const &raw, unsigned index) { unsigned remaining = std::min(raw.size() - index, 3); switch (remaining) { case 1: return split1(raw.at(index)); case 2: return split2(raw.at(index), raw.at(index + 1)); case 3: return split3(raw.at(index), raw.at(index + 1), raw.at(index + 2)); } throw std::runtime_error("internal error, in split"); } optional char_to_index(char c) { // FIXME: very slow for (unsigned i = 0; i < 64; i++) if (table_[i] == c) return optional(i); return optional(); } decoded_or_error success(vector const &decoded) { return decoded_or_error(decoded); } decoded_or_error fail(string msg) { return decoded_or_error(msg); } decoded_or_error fail_char(char c) { ostringstream msg; msg << "bad input character: '" << c << "'"; return fail(msg.str()); } decoded_or_error decode_quad(char c1, char c2, char c3, char c4) { typedef optional oi; unsigned char d1, d2, d3; vector decoded; oi i1 = char_to_index(c1); if (!i1) return fail_char(c1); oi i2 = char_to_index(c2); if (!i2) return fail_char(c2); d1 = (*i1 << 2) | (*i2 >> 4); decoded.push_back(d1); d2 = (*i2 & 15) << 4; if (c3 == '=') { // FIXME: I really think the push should be here // decoded.push_back(d2); return success(decoded); } oi i3 = char_to_index(c3); if (!i3) return fail_char(c3); d2 = d2 | (*i3 >> 2); decoded.push_back(d2); d3 = (*i3 & 3) << 6; if (c4 == '=') { // FIXME: I really think the push should be here // decoded.push_back(d3); return success(decoded); } oi i4 = char_to_index(c4); if (!i4) return fail_char(c4); d3 = d3 | *i4; decoded.push_back(d3); return success(decoded); } } //---------------------------------------------------------------- string base::base64_encode(vector const &raw) { string r; for (unsigned i = 0; i < raw.size(); i += 3) { unsigned j; index_set is = split(raw, i); for (j = 0; j < is.nr_valid_; j++) r.push_back(table_[is.index_[j]]); for (; j < 4; j++) r.push_back('='); } return r; } base::decoded_or_error base::base64_decode(string const &encoded) { if (encoded.length() % 4) return decoded_or_error("bad input length"); vector decoded; for (unsigned i = 0; i < encoded.length(); i += 4) { decoded_or_error doe = decode_quad(encoded[i], encoded[i + 1], encoded[i + 2], encoded[i + 3]); vector *v = get >(&doe); if (!v) return doe; decoded.insert(decoded.end(), v->begin(), v->end()); } return decoded_or_error(decoded); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/base/base64.h000066400000000000000000000010351222772450500205210ustar00rootroot00000000000000#ifndef BASE_BASE64_H #define BASE_BASE64_H #include #include #include //---------------------------------------------------------------- namespace base { std::string base64_encode(std::vector const &raw); // Returns either the decoded data or an error string typedef boost::variant, std::string> decoded_or_error; decoded_or_error base64_decode(std::string const &encoded); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/base/error_state.cc000066400000000000000000000005671222772450500221350ustar00rootroot00000000000000#include "base/error_state.h" //---------------------------------------------------------------- base::error_state base::combine_errors(error_state lhs, error_state rhs) { switch (lhs) { case NO_ERROR: return rhs; case NON_FATAL: return (rhs == FATAL) ? FATAL : lhs; default: return lhs; } } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/base/error_state.h000066400000000000000000000006241222772450500217710ustar00rootroot00000000000000#ifndef BASE_ERROR_STATE_H #define BASE_ERROR_STATE_H //---------------------------------------------------------------- namespace base { enum error_state { NO_ERROR, NON_FATAL, // eg, lost blocks FATAL // needs fixing before pool can be activated }; error_state combine_errors(error_state lhs, error_state rhs); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/base/nested_output.h000066400000000000000000000026121222772450500223410ustar00rootroot00000000000000#ifndef BASE_NESTED_OUTPUT_H #define BASE_NESTED_OUTPUT_H #include //---------------------------------------------------------------- namespace base { class end_message {}; class nested_output { public: nested_output(std::ostream &out, unsigned step) : out_(out), step_(step), beginning_of_line_(true), enabled_(true), indent_(0) { } template nested_output &operator <<(T const &t) { if (beginning_of_line_) { beginning_of_line_ = false; indent(); } if (enabled_) out_ << t; return *this; } nested_output &operator <<(end_message const &m) { beginning_of_line_ = true; if (enabled_) out_ << std::endl; return *this; } void inc_indent() { indent_ += step_; } void dec_indent() { indent_ -= step_; } struct nest { nest(nested_output &out) : out_(out) { out_.inc_indent(); } ~nest() { out_.dec_indent(); } nested_output &out_; }; nest push() { return nest(*this); } void enable() { enabled_ = true; } void disable() { enabled_ = false; } private: void indent() { if (enabled_) for (unsigned i = 0; i < indent_; i++) out_ << ' '; } std::ostream &out_; unsigned step_; bool beginning_of_line_; bool enabled_; unsigned indent_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/000077500000000000000000000000001222772450500177475ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/caching/cache_check.cc000066400000000000000000000205141222772450500224600ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include "base/error_state.h" #include "base/nested_output.h" #include "caching/metadata.h" #include "persistent-data/block.h" #include "persistent-data/file_utils.h" #include "persistent-data/space-maps/core.h" #include "version.h" using namespace boost; using namespace caching; using namespace persistent_data; using namespace std; //---------------------------------------------------------------- namespace { class reporter_base { public: reporter_base(nested_output &o) : out_(o), err_(NO_ERROR) { } virtual ~reporter_base() {} nested_output &out() { return out_; } nested_output::nest push() { return out_.push(); } base::error_state get_error() const { return err_; } void mplus_error(error_state err) { err_ = combine_errors(err_, err); } private: nested_output &out_; error_state err_; }; class superblock_reporter : public superblock_damage::damage_visitor, reporter_base { public: superblock_reporter(nested_output &o) : reporter_base(o) { } virtual void visit(superblock_damage::superblock_corrupt const &d) { out() << "superblock is corrupt" << end_message(); { nested_output::nest _ = push(); out() << d.get_desc() << end_message(); } mplus_error(FATAL); } virtual void visit(superblock_damage::superblock_invalid const &d) { out() << "superblock is invalid" << end_message(); { nested_output::nest _ = push(); out() << d.get_desc() << end_message(); } mplus_error(FATAL); } using reporter_base::get_error; }; class mapping_reporter : public mapping_array_damage::damage_visitor, reporter_base { public: mapping_reporter(nested_output &o) : reporter_base(o) { } virtual void visit(mapping_array_damage::missing_mappings const &d) { out() << "missing mappings " << d.keys_ << ":" << end_message(); { nested_output::nest _ = push(); out() << d.get_desc() << end_message(); } mplus_error(FATAL); } virtual void visit(mapping_array_damage::invalid_mapping const &d) { out() << "invalid mapping:" << end_message(); { nested_output::nest _ = push(); out() << d.get_desc() << " [cblock = " << d.cblock_ << ", oblock = " << d.m_.oblock_ << ", flags = " << d.m_.flags_ << "]" << end_message(); } mplus_error(FATAL); } using reporter_base::get_error; }; class hint_reporter : public hint_array_damage::damage_visitor, reporter_base { public: hint_reporter(nested_output &o) : reporter_base(o) { } virtual void visit(hint_array_damage::missing_hints const &d) { out() << "missing mappings " << d.keys_ << ":" << end_message(); { nested_output::nest _ = push(); out() << d.get_desc() << end_message(); } mplus_error(FATAL); } using reporter_base::get_error; }; class discard_reporter : public bitset_detail::bitset_visitor, reporter_base { public: discard_reporter(nested_output &o) : reporter_base(o) { } virtual void visit(uint32_t index, bool value) { // no op } virtual void visit(bitset_detail::missing_bits const &d) { out() << "missing discard bits " << d.keys_ << end_message(); mplus_error(FATAL); } using reporter_base::get_error; }; //-------------------------------- transaction_manager::ptr open_tm(block_manager<>::ptr bm) { space_map::ptr sm(new core_map(bm->get_nr_blocks())); sm->inc(SUPERBLOCK_LOCATION); transaction_manager::ptr tm(new transaction_manager(bm, sm)); return tm; } //-------------------------------- struct flags { flags() : check_mappings_(true), check_hints_(true), check_discards_(true), ignore_non_fatal_errors_(false), quiet_(false) { } bool check_mappings_; bool check_hints_; bool check_discards_; bool ignore_non_fatal_errors_; bool quiet_; }; struct stat guarded_stat(string const &path) { struct stat info; int r = ::stat(path.c_str(), &info); if (r) { ostringstream msg; char buffer[128], *ptr; ptr = ::strerror_r(errno, buffer, sizeof(buffer)); msg << path << ": " << ptr; throw runtime_error(msg.str()); } return info; } error_state metadata_check(block_manager<>::ptr bm, flags const &fs) { nested_output out(cerr, 2); if (fs.quiet_) out.disable(); superblock_reporter sb_rep(out); mapping_reporter mapping_rep(out); hint_reporter hint_rep(out); discard_reporter discard_rep(out); out << "examining superblock" << end_message(); { nested_output::nest _ = out.push(); check_superblock(bm, bm->get_nr_blocks(), sb_rep); } if (sb_rep.get_error() == FATAL) return FATAL; superblock sb = read_superblock(bm); transaction_manager::ptr tm = open_tm(bm); if (fs.check_mappings_) { out << "examining mapping array" << end_message(); { nested_output::nest _ = out.push(); mapping_array ma(tm, mapping_array::ref_counter(), sb.mapping_root, sb.cache_blocks); check_mapping_array(ma, mapping_rep); } } if (fs.check_hints_) { if (!sb.hint_root) out << "no hint array present" << end_message(); else { out << "examining hint array" << end_message(); { nested_output::nest _ = out.push(); hint_array ha(tm, sb.policy_hint_size, sb.hint_root, sb.cache_blocks); ha.check(hint_rep); } } } if (fs.check_discards_) { if (!sb.discard_root) out << "no discard bitset present" << end_message(); else { out << "examining discard bitset" << end_message(); { nested_output::nest _ = out.push(); bitset discards(tm, sb.discard_root, sb.discard_nr_blocks); } } } // FIXME: make an error class that's an instance of mplus return combine_errors(sb_rep.get_error(), combine_errors(mapping_rep.get_error(), combine_errors(hint_rep.get_error(), discard_rep.get_error()))); } int check(string const &path, flags const &fs) { error_state err; struct stat info = guarded_stat(path); if (!S_ISREG(info.st_mode) && !S_ISBLK(info.st_mode)) { ostringstream msg; msg << path << ": " << "Not a block device or regular file"; throw runtime_error(msg.str()); } block_manager<>::ptr bm = open_bm(path, block_io<>::READ_ONLY); err = metadata_check(bm, fs); return err == NO_ERROR ? 0 : 1; } int check_with_exception_handling(string const &path, flags const &fs) { int r; try { r = check(path, fs); } catch (std::exception &e) { if (!fs.quiet_) cerr << e.what() << endl; r = 1; } return r; } void usage(ostream &out, string const &cmd) { out << "Usage: " << cmd << " [options] {device|file}" << endl << "Options:" << endl << " {-q|--quiet}" << endl << " {-h|--help}" << endl << " {-V|--version}" << endl << " {--super-block-only}" << endl << " {--skip-mappings}" << endl << " {--skip-hints}" << endl << " {--skip-discards}" << endl; } } //---------------------------------------------------------------- int main(int argc, char **argv) { int c; flags fs; const char shortopts[] = "qhV"; const struct option longopts[] = { { "quiet", no_argument, NULL, 'q' }, { "superblock-only", no_argument, NULL, 1 }, { "skip-mappings", no_argument, NULL, 2 }, { "skip-hints", no_argument, NULL, 3 }, { "skip-discards", no_argument, NULL, 4 }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, no_argument, NULL, 0 } }; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 1: fs.check_mappings_ = false; fs.check_hints_ = false; break; case 2: fs.check_mappings_ = false; break; case 3: fs.check_hints_ = false; break; case 4: fs.check_discards_ = false; break; case 'h': usage(cout, basename(argv[0])); return 0; case 'q': fs.quiet_ = true; break; case 'V': cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; default: usage(cerr, basename(argv[0])); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; usage(cerr, basename(argv[0])); return 1; } return check_with_exception_handling(argv[optind], fs); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/cache_dump.cc000066400000000000000000000046441222772450500223560ustar00rootroot00000000000000#include #include #include #include #include "version.h" #include "caching/mapping_array.h" #include "caching/metadata.h" #include "caching/metadata_dump.h" #include "caching/xml_format.h" #include "persistent-data/file_utils.h" using namespace std; using namespace caching; //---------------------------------------------------------------- namespace { struct flags { flags() : repair_(false) { } bool repair_; }; //-------------------------------- string const STDOUT_PATH("-"); bool want_stdout(string const &output) { return output == STDOUT_PATH; } int dump(string const &dev, string const &output, flags const &fs) { try { block_manager<>::ptr bm = open_bm(dev, block_io<>::READ_ONLY); metadata::ptr md(new metadata(bm, metadata::OPEN)); if (want_stdout(output)) { emitter::ptr e = create_xml_emitter(cout); metadata_dump(md, e, fs.repair_); } else { ofstream out(output.c_str()); emitter::ptr e = create_xml_emitter(out); metadata_dump(md, e, fs.repair_); } } catch (std::exception &e) { cerr << e.what() << endl; return 1; } return 0; } void usage(ostream &out, string const &cmd) { out << "Usage: " << cmd << " [options] {device|file}" << endl << "Options:" << endl << " {-h|--help}" << endl << " {-o }" << endl << " {-V|--version}" << endl << " {--repair}" << endl; } } //---------------------------------------------------------------- int main(int argc, char **argv) { int c; flags fs; string output("-"); char const shortopts[] = "ho:V"; option const longopts[] = { { "help", no_argument, NULL, 'h' }, { "output", required_argument, NULL, 'o' }, { "version", no_argument, NULL, 'V' }, { "repair", no_argument, NULL, 1 }, { NULL, no_argument, NULL, 0 } }; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 1: fs.repair_ = true; break; case 'h': usage(cout, basename(argv[0])); return 0; case 'o': output = optarg; break; case 'V': cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; default: usage(cerr, basename(argv[0])); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; usage(cerr, basename(argv[0])); return 1; } return dump(argv[optind], output, fs); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/cache_metadata.h000066400000000000000000000072141222772450500230270ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef CACHE_METADATA_H #define CACHE_METADATA_H #include "block.h" #include "array.h" #include "endian_utils.h" #include "space_map_disk.h" #include "transaction_manager.h" //---------------------------------------------------------------- namespace cache { // FIXME: don't use namespaces in a header using namespace base; using namespace persistent_data; block_address const SUPERBLOCK_LOCATION = 0; typedef uint64_t sector_t; //------------------------------------------------ class space_map_ref_counter { public: space_map_ref_counter(space_map::ptr sm) : sm_(sm) { } void inc(block_address b) { sm_->inc(b); } void dec(block_address b) { sm_->dec(b); } private: space_map::ptr sm_; }; struct block_flags { uint64_t block_; uint32_t flags_; }; class block_flags_ref_counter { public: block_flags_ref_counter(space_map::ptr sm) : sm_(sm) { } void inc(block_flags bf) { sm_->inc(bf.block_); } void dec(block_flags bf) { sm_->dec(bf.block_); } private: space_map::ptr sm_; }; struct block_traits { typedef base::__le64 disk_type; typedef block_flags value_type; typedef block_flags_ref_counter ref_counter; static void unpack(disk_type const &disk, value_type &value) { uint64_t v = to_cpu(disk); value.block_ = v >> 24; value.flags_ = v & ((1 << 24) - 1); } static void pack(value_type const &value, disk_type &disk) { uint64_t v = (value.block_ << 24) | value.flags_; disk = base::to_disk(v); } }; //------------------------------------------------ // FIXME: should these be in a sub-namespace? typedef persistent_data::transaction_manager::ptr tm_ptr; typedef persistent_data::btree<1, device_details_traits> detail_tree; typedef persistent_data::btree<1, mtree_traits> dev_tree; typedef persistent_data::btree<2, block_traits> mapping_tree; typedef persistent_data::btree<1, block_traits> single_mapping_tree; // The tools require different interfaces onto the metadata than // the in kernel driver. This class gives access to the low-level // implementation of metadata. Implement more specific interfaces // on top of this. struct metadata { enum open_type { CREATE, OPEN }; metadata(std::string const &dev_path, open_type ot, sector_t data_block_size = 128, block_address nr_cache_blocks = 0); // Only used if CREATE metadata(std::string const &dev_path, block_address metadata_snap); void commit(); typedef block_manager<>::read_ref read_ref; typedef block_manager<>::write_ref write_ref; typedef boost::shared_ptr ptr; tm_ptr tm_; superblock sb_; checked_space_map::ptr metadata_sm_; checked_space_map::ptr data_sm_; detail_tree::ptr details_; dev_tree::ptr mappings_top_level_; mapping_tree::ptr mappings_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/cache_repair.cc000066400000000000000000000050221222772450500226620ustar00rootroot00000000000000#include #include #include #include "caching/metadata.h" #include "caching/metadata_dump.h" #include "caching/restore_emitter.h" #include "persistent-data/file_utils.h" #include "version.h" using namespace persistent_data; using namespace std; using namespace caching; //---------------------------------------------------------------- namespace { metadata::ptr open_metadata_for_read(string const &path) { block_manager<>::ptr bm = open_bm(path, block_io<>::READ_ONLY); return metadata::ptr(new metadata(bm, metadata::OPEN)); } emitter::ptr output_emitter(string const &path) { block_manager<>::ptr bm = open_bm(path, block_io<>::READ_WRITE); metadata::ptr md(new metadata(bm, metadata::CREATE)); return create_restore_emitter(md); } int repair(string const &old_path, string const &new_path) { try { metadata_dump(open_metadata_for_read(old_path), output_emitter(new_path), true); } catch (std::exception &e) { cerr << e.what() << endl; return 1; } return 0; } void usage(ostream &out, string const &cmd) { out << "Usage: " << cmd << " [options] {device|file}" << endl << "Options:" << endl << " {-h|--help}" << endl << " {-i|--input} " << endl << " {-o|--output} " << endl << " {-V|--version}" << endl; } } //---------------------------------------------------------------- int main(int argc, char **argv) { int c; boost::optional input_path, output_path; const char shortopts[] = "hi:o:V"; const struct option longopts[] = { { "help", no_argument, NULL, 'h'}, { "input", required_argument, NULL, 'i'}, { "output", required_argument, NULL, 'o'}, { "version", no_argument, NULL, 'V'}, { NULL, no_argument, NULL, 0 } }; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 'h': usage(cout, basename(argv[0])); return 0; case 'i': input_path = optarg; break; case 'o': output_path = optarg; break; case 'V': cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; default: usage(cerr, basename(argv[0])); return 1; } } if (!input_path) { cerr << "no input file provided" << endl; usage(cerr, basename(argv[0])); return 1; } if (!output_path) { cerr << "no output file provided" << endl; usage(cerr, basename(argv[0])); return 1; } return repair(*input_path, *output_path); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/cache_restore.cc000066400000000000000000000057041222772450500230720ustar00rootroot00000000000000#include "version.h" #include "caching/metadata.h" #include "caching/restore_emitter.h" #include "caching/xml_format.h" #include "persistent-data/file_utils.h" #include #include #include #include #include #include using namespace boost; using namespace caching; using namespace persistent_data; using namespace std; //---------------------------------------------------------------- namespace { struct flags { flags() : metadata_version(1), override_metadata_version(false) { } optional input; optional output; uint32_t metadata_version; bool override_metadata_version; }; int restore(flags const &fs) { try { block_manager<>::ptr bm = open_bm(*fs.output, block_io<>::READ_WRITE); metadata::ptr md(new metadata(bm, metadata::CREATE)); emitter::ptr restorer = create_restore_emitter(md); if (fs.override_metadata_version) { cerr << "overriding" << endl; md->sb_.version = fs.metadata_version; } check_file_exists(*fs.input); ifstream in(fs.input->c_str(), ifstream::in); parse_xml(in, restorer); } catch (std::exception &e) { cerr << e.what() << endl; return 1; } return 0; } void usage(ostream &out, string const &cmd) { out << "Usage: " << cmd << " [options]" << endl << "Options:" << endl << " {-h|--help}" << endl << " {-i|--input} " << endl << " {-o|--output} " << endl << " {-V|--version}" << endl << endl << " {--debug-override-metadata-version} " << endl; } } int main(int argc, char **argv) { int c; flags fs; char const *prog_name = basename(argv[0]); char const *short_opts = "hi:o:V"; option const long_opts[] = { { "debug-override-metadata-version", required_argument, NULL, 0 }, { "help", no_argument, NULL, 'h'}, { "input", required_argument, NULL, 'i' }, { "output", required_argument, NULL, 'o'}, { "version", no_argument, NULL, 'V'}, { NULL, no_argument, NULL, 0 } }; while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { switch(c) { case 0: fs.metadata_version = lexical_cast(optarg); fs.override_metadata_version = true; break; case 'h': usage(cout, prog_name); return 0; case 'i': fs.input = optional(string(optarg)); break; case 'o': fs.output = optional(string(optarg)); break; case 'V': cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; default: usage(cerr, prog_name); return 1; } } if (argc != optind) { usage(cerr, prog_name); return 1; } if (!fs.input) { cerr << "No input file provided." << endl << endl; usage(cerr, prog_name); return 1; } if (!fs.output) { cerr << "No output file provided." << endl << endl; usage(cerr, prog_name); return 1; } return restore(fs); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/dump.cc000066400000000000000000000057771222772450500212430ustar00rootroot00000000000000// Copyright (C) 2012 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include #include #include #if 0 #include "human_readable_format.h" #include "cache_metadata_dumper.h" #include "cache_metadata.h" #include "xml_format.h" #include "version.h" using namespace persistent_data; using namespace std; using namespace thin_provisioning; namespace { int dump(string const &path, string const &format, bool repair, block_address metadata_snap = 0) { try { metadata::ptr md(metadata_snap ? new metadata(path, metadata_snap) : new metadata(path, metadata::OPEN)); emitter::ptr e; if (format == "xml") e = create_xml_emitter(cout); else if (format == "human_readable") e = create_human_readable_emitter(cout); else { cerr << "unknown format '" << format << "'" << endl; exit(1); } metadata_dump(md, e, repair); } catch (std::exception &e) { cerr << e.what() << endl; return 1; } return 0; } void usage(ostream &out, string const &cmd) { out << "Usage: " << cmd << " [options] {device|file}" << endl << "Options:" << endl << " {-h|--help}" << endl << " {-f|--format} {xml|human_readable}" << endl << " {-r|--repair}" << endl << " {-m|--metadata-snap}" << endl << " {-V|--version}" << endl; } } int main(int argc, char **argv) { int c; bool repair = false; const char shortopts[] = "hm:f:rV"; string format = "xml"; char *end_ptr; const struct option longopts[] = { { "help", no_argument, NULL, 'h'}, { "format", required_argument, NULL, 'f' }, { "repair", no_argument, NULL, 'r'}, { "version", no_argument, NULL, 'V'}, { NULL, no_argument, NULL, 0 } }; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 'h': usage(cout, basename(argv[0])); return 0; case 'f': format = optarg; break; case 'r': repair = true; break; case 'V': cout << THIN_PROVISIONING_TOOLS_VERSION << endl; return 0; default: usage(cerr, basename(argv[0])); return 1; } } if (argc == optind) { cerr << "No input file provided." << endl; usage(cerr, basename(argv[0])); return 1; } return dump(argv[optind], format, repair, metadata_snap); } #else int main(int argc, char **argv) { return 1; } #endif thin-provisioning-tools-0.2.8/caching/emitter.h000066400000000000000000000022731222772450500215750ustar00rootroot00000000000000#ifndef CACHE_EMITTER_H #define CACHE_EMITTER_H #include "persistent-data/block.h" #include #include //---------------------------------------------------------------- namespace caching { namespace pd = persistent_data; class emitter { public: typedef boost::shared_ptr ptr; virtual ~emitter() {} virtual void begin_superblock(std::string const &uuid, pd::block_address block_size, pd::block_address nr_cache_blocks, std::string const &policy, size_t hint_width) = 0; virtual void end_superblock() = 0; virtual void begin_mappings() = 0; virtual void end_mappings() = 0; virtual void mapping(pd::block_address cblock, pd::block_address oblock, bool dirty) = 0; virtual void begin_hints() = 0; virtual void end_hints() = 0; virtual void hint(pd::block_address cblock, std::vector const &data) = 0; virtual void begin_discards() = 0; virtual void end_discards() = 0; virtual void discard(pd::block_address dblock_begin, pd::block_address dblock_end) = 0; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/hint_array.cc000066400000000000000000000161611222772450500224230ustar00rootroot00000000000000#include "caching/hint_array.h" using namespace boost; using namespace caching; using namespace caching::hint_array_damage; using namespace persistent_data; //---------------------------------------------------------------- namespace { template struct hint_traits { typedef unsigned char byte; typedef byte disk_type[WIDTH]; typedef vector value_type; typedef no_op_ref_counter ref_counter; // FIXME: slow copying for now static void unpack(disk_type const &disk, value_type &value) { value.resize(WIDTH); for (unsigned byte = 0; byte < WIDTH; byte++) value.at(byte) = disk[byte]; } static void pack(value_type const &value, disk_type &disk) { for (unsigned byte = 0; byte < WIDTH; byte++) disk[byte] = value.at(byte); } }; // We've got into a bit of a mess here. Templates are compile // time, and we don't know the hint width until run time. We're // going to have to provide specialisation for all legal widths and // use the appropriate one. #define all_widths \ xx(4); xx(8); xx(12); xx(16); xx(20); xx(24); xx(28); xx(32);\ xx(36); xx(40); xx(44); xx(48); xx(52); xx(56); xx(60); xx(64); \ xx(68); xx(72); xx(76); xx(80); xx(84); xx(88); xx(92); xx(96); \ xx(100); xx(104); xx(108); xx(112); xx(116); xx(120); xx(124); xx(128); template shared_ptr mk_array(transaction_manager::ptr tm) { typedef hint_traits traits; typedef array ha; shared_ptr r = typename ha::ptr(new ha(tm, typename traits::ref_counter())); return r; } shared_ptr mk_array(transaction_manager::ptr tm, uint32_t width) { switch (width) { #define xx(n) case n: return mk_array(tm) all_widths #undef xx default: throw runtime_error("invalid hint width"); } // never get here return shared_ptr(); } //-------------------------------- template shared_ptr downcast_array(shared_ptr base) { shared_ptr a = dynamic_pointer_cast(base); if (!a) throw runtime_error("internal error: couldn't cast hint array"); return a; } //-------------------------------- template shared_ptr mk_array(transaction_manager::ptr tm, block_address root, unsigned nr_entries) { typedef hint_traits traits; typedef array ha; shared_ptr r = typename ha::ptr(new ha(tm, typename traits::ref_counter(), root, nr_entries)); return r; } shared_ptr mk_array(transaction_manager::ptr tm, uint32_t width, block_address root, unsigned nr_entries) { switch (width) { #define xx(n) case n: return mk_array(tm, root, nr_entries) all_widths #undef xx default: throw runtime_error("invalid hint width"); } // never get here return shared_ptr(); } //-------------------------------- template void get_hint(shared_ptr base, unsigned index, vector &data) { typedef hint_traits traits; typedef array ha; shared_ptr a = downcast_array(base); data = a->get(index); } void get_hint_(uint32_t width, shared_ptr base, unsigned index, vector &data) { switch (width) { #define xx(n) case n: return get_hint(base, index, data) all_widths #undef xx } } //-------------------------------- template void set_hint(shared_ptr base, unsigned index, vector const &data) { typedef hint_traits traits; typedef array ha; shared_ptr a = downcast_array(base); a->set(index, data); } void set_hint_(uint32_t width, shared_ptr base, unsigned index, vector const &data) { switch (width) { #define xx(n) case n: return set_hint(base, index, data) all_widths #undef xx } } //-------------------------------- template void grow(shared_ptr base, unsigned new_nr_entries, vector const &value) { typedef hint_traits traits; typedef array ha; shared_ptr a = downcast_array(base); a->grow(new_nr_entries, value); } void grow_(uint32_t width, shared_ptr base, unsigned new_nr_entries, vector const &value) { switch (width) { #define xx(n) case n: return grow(base, new_nr_entries, value) all_widths #undef xx } } //-------------------------------- class value_adapter { public: value_adapter(hint_visitor &v) : v_(v) { } virtual void visit(uint32_t index, std::vector const &v) { v_.visit(static_cast(index), v); } private: hint_visitor &v_; }; struct no_op_visitor : public hint_visitor { virtual void visit(block_address cblock, std::vector const &v) { } }; class ll_damage_visitor { public: ll_damage_visitor(damage_visitor &v) : v_(v) { } virtual void visit(array_detail::damage const &d) { v_.visit(missing_hints(d.desc_, d.lost_keys_)); } private: damage_visitor &v_; }; template void walk_hints(shared_ptr base, hint_visitor &hv, damage_visitor &dv) { typedef hint_traits traits; typedef array ha; shared_ptr a = downcast_array(base); value_adapter vv(hv); ll_damage_visitor ll(dv); a->visit_values(vv, ll); } void walk_hints_(uint32_t width, shared_ptr base, hint_visitor &hv, damage_visitor &dv) { switch (width) { #define xx(n) case n: walk_hints(base, hv, dv); break all_widths #undef xx } } } //---------------------------------------------------------------- missing_hints::missing_hints(std::string const desc, run const &keys) : damage(desc), keys_(keys) { } void missing_hints::visit(damage_visitor &v) const { v.visit(*this); } //---------------------------------------------------------------- hint_array::hint_array(tm_ptr tm, unsigned width) : width_(check_width(width)), impl_(mk_array(tm, width)) { } hint_array::hint_array(typename hint_array::tm_ptr tm, unsigned width, block_address root, unsigned nr_entries) : width_(check_width(width)), impl_(mk_array(tm, width, root, nr_entries)) { } block_address hint_array::get_root() const { return impl_->get_root(); } void hint_array::get_hint(unsigned index, vector &data) const { get_hint_(width_, impl_, index, data); } void hint_array::set_hint(unsigned index, vector const &data) { set_hint_(width_, impl_, index, data); } void hint_array::grow(unsigned new_nr_entries, vector const &value) { grow_(width_, impl_, new_nr_entries, value); } void hint_array::walk(hint_visitor &hv, hint_array_damage::damage_visitor &dv) { walk_hints_(width_, impl_, hv, dv); } void hint_array::check(hint_array_damage::damage_visitor &visitor) { no_op_visitor vv; walk(vv, visitor); } uint32_t hint_array::check_width(uint32_t width) { if (width % 4 || width == 0 || width > 128) { ostringstream msg; msg << "invalid hint width: " << width; throw runtime_error(msg.str()); } return width; } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/hint_array.h000066400000000000000000000037311222772450500222640ustar00rootroot00000000000000#ifndef CACHE_HINT_ARRAY_H #define CACHE_HINT_ARRAY_H #include "persistent-data/data-structures/array.h" #include //---------------------------------------------------------------- namespace caching { namespace hint_array_damage { class damage_visitor; class damage { public: damage(std::string const &desc) : desc_(desc) { } virtual ~damage() {} virtual void visit(damage_visitor &v) const = 0; std::string get_desc() const { return desc_; } private: std::string desc_; }; struct missing_hints : public damage { missing_hints(std::string const desc, run const &keys); virtual void visit(damage_visitor &v) const; run keys_; }; class damage_visitor { public: virtual ~damage_visitor() {} void visit(damage const &d) { d.visit(*this); } virtual void visit(missing_hints const &d) = 0; }; } class hint_visitor { public: virtual ~hint_visitor() {} virtual void visit(block_address cblock, std::vector const &data) = 0; }; class hint_array { public: typedef boost::shared_ptr ptr; typedef typename persistent_data::transaction_manager::ptr tm_ptr; hint_array(tm_ptr tm, unsigned width); hint_array(tm_ptr tm, unsigned width, block_address root, unsigned nr_entries); unsigned get_nr_entries() const; void grow(unsigned new_nr_entries, void const *v); block_address get_root() const; void get_hint(unsigned index, vector &data) const; void set_hint(unsigned index, vector const &data); void grow(unsigned new_nr_entries, vector const &value); void walk(hint_visitor &hv, hint_array_damage::damage_visitor &dv); void check(hint_array_damage::damage_visitor &visitor); private: static uint32_t check_width(uint32_t width); unsigned width_; boost::shared_ptr impl_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/mapping_array.cc000066400000000000000000000053601222772450500231130ustar00rootroot00000000000000#include "caching/mapping_array.h" #include "persistent-data/endian_utils.h" #include using namespace caching; using namespace caching::mapping_array_damage; using namespace std; //---------------------------------------------------------------- namespace { const uint64_t FLAGS_MASK = (1 << 16) - 1; } void mapping_traits::unpack(disk_type const &disk, value_type &value) { uint64_t v = base::to_cpu(disk); value.oblock_ = v >> 16; value.flags_ = v & FLAGS_MASK; } void mapping_traits::pack(value_type const &value, disk_type &disk) { uint64_t packed = value.oblock_ << 16; packed = packed | (value.flags_ & FLAGS_MASK); disk = base::to_disk(packed); } //---------------------------------------------------------------- missing_mappings::missing_mappings(std::string const &desc, run const &keys) : damage(desc), keys_(keys) { } void missing_mappings::visit(damage_visitor &v) const { v.visit(*this); } invalid_mapping::invalid_mapping(std::string const &desc, block_address cblock, mapping const &m) : damage(desc), cblock_(cblock), m_(m) { } void invalid_mapping::visit(damage_visitor &v) const { v.visit(*this); } namespace { class check_mapping_visitor : public mapping_visitor { public: check_mapping_visitor(damage_visitor &visitor) : visitor_(visitor) { } virtual void visit(block_address cblock, mapping const &m) { if (!valid_mapping(m)) return; if (seen_oblock(m)) visitor_.visit(invalid_mapping("origin block already mapped", cblock, m)); else record_oblock(m); if (unknown_flags(m)) visitor_.visit(invalid_mapping("unknown flags in mapping", cblock, m)); } private: static bool valid_mapping(mapping const &m) { return !!(m.flags_ & M_VALID); } bool seen_oblock(mapping const &m) const { return seen_oblocks_.find(m.oblock_) != seen_oblocks_.end(); } void record_oblock(mapping const &m) { seen_oblocks_.insert(m.oblock_); } static bool unknown_flags(mapping const &m) { return (m.flags_ & ~(M_VALID | M_DIRTY)); } damage_visitor &visitor_; set seen_oblocks_; }; class ll_damage_visitor { public: ll_damage_visitor(damage_visitor &v) : v_(v) { } virtual void visit(array_detail::damage const &d) { v_.visit(missing_mappings(d.desc_, d.lost_keys_)); } private: damage_visitor &v_; }; } void caching::walk_mapping_array(mapping_array const &array, mapping_visitor &mv, damage_visitor &dv) { ll_damage_visitor ll(dv); array.visit_values(mv, ll); } void caching::check_mapping_array(mapping_array const &array, damage_visitor &visitor) { check_mapping_visitor mv(visitor); walk_mapping_array(array, mv, visitor); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/mapping_array.h000066400000000000000000000042441222772450500227550ustar00rootroot00000000000000#ifndef CACHE_MAPPING_ARRAY_H #define CACHE_MAPPING_ARRAY_H #include "persistent-data/data-structures/array.h" //---------------------------------------------------------------- namespace caching { enum mapping_flags { M_VALID = 1, M_DIRTY = 2 }; struct mapping { uint64_t oblock_; uint32_t flags_; }; struct mapping_traits { typedef base::le64 disk_type; typedef mapping value_type; typedef no_op_ref_counter ref_counter; static void unpack(disk_type const &disk, value_type &value); static void pack(value_type const &value, disk_type &disk); }; namespace mapping_array_damage { class damage_visitor; class damage { public: damage(std::string const &desc) : desc_(desc) { } virtual ~damage() {} virtual void visit(damage_visitor &v) const = 0; std::string get_desc() const { return desc_; } private: std::string desc_; }; struct missing_mappings : public damage { missing_mappings(std::string const &desc, run const &keys); virtual void visit(damage_visitor &v) const; run keys_; }; struct invalid_mapping : public damage { invalid_mapping(std::string const &desc, block_address cblock, mapping const &m); virtual void visit(damage_visitor &v) const; block_address cblock_; mapping m_; }; class damage_visitor { public: virtual ~damage_visitor() {} void visit(mapping_array_damage::damage const &d) { d.visit(*this); } virtual void visit(missing_mappings const &d) = 0; virtual void visit(invalid_mapping const &d) = 0; }; } typedef persistent_data::array mapping_array; class mapping_visitor { public: virtual ~mapping_visitor() {} void visit(uint32_t index, mapping const &m) { visit(static_cast(index), m); } virtual void visit(block_address cblock, mapping const &m) = 0; }; void walk_mapping_array(mapping_array const &array, mapping_visitor &mv, mapping_array_damage::damage_visitor &dv); void check_mapping_array(mapping_array const &array, mapping_array_damage::damage_visitor &visitor); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/metadata.cc000066400000000000000000000054411222772450500220420ustar00rootroot00000000000000#include "caching/metadata.h" #include "caching/superblock.h" #include "persistent-data/space-maps/core.h" using namespace caching; //---------------------------------------------------------------- namespace { unsigned const METADATA_CACHE_SIZE = 1024; // FIXME: duplication transaction_manager::ptr open_tm(block_manager<>::ptr bm) { space_map::ptr sm(new core_map(bm->get_nr_blocks())); sm->inc(SUPERBLOCK_LOCATION); transaction_manager::ptr tm(new transaction_manager(bm, sm)); return tm; } void copy_space_maps(space_map::ptr lhs, space_map::ptr rhs) { for (block_address b = 0; b < rhs->get_nr_blocks(); b++) { uint32_t count = rhs->get_count(b); if (count > 0) lhs->set_count(b, rhs->get_count(b)); } } } //---------------------------------------------------------------- metadata::metadata(block_manager<>::ptr bm, open_type ot) { switch (ot) { case CREATE: create_metadata(bm); break; case OPEN: open_metadata(bm); break; default: throw runtime_error("unhandled open_type"); } } void metadata::commit() { commit_space_map(); commit_mappings(); commit_hints(); commit_discard_bits(); commit_superblock(); } void metadata::setup_hint_array(size_t width) { if (width > 0) hints_ = hint_array::ptr( new hint_array(tm_, width)); } void metadata::create_metadata(block_manager<>::ptr bm) { tm_ = open_tm(bm); space_map::ptr core = tm_->get_sm(); metadata_sm_ = create_metadata_sm(tm_, tm_->get_bm()->get_nr_blocks()); copy_space_maps(metadata_sm_, core); tm_->set_sm(metadata_sm_); mappings_ = mapping_array::ptr(new mapping_array(tm_, mapping_array::ref_counter())); // We can't instantiate the hint array yet, since we don't know the // hint width. discard_bits_ = bitset::ptr(new bitset(tm_)); } void metadata::open_metadata(block_manager<>::ptr bm) { tm_ = open_tm(bm); sb_ = read_superblock(tm_->get_bm()); mappings_ = mapping_array::ptr( new mapping_array(tm_, mapping_array::ref_counter(), sb_.mapping_root, sb_.cache_blocks)); if (sb_.hint_root) hints_ = hint_array::ptr( new hint_array(tm_, sb_.policy_hint_size, sb_.hint_root, sb_.cache_blocks)); if (sb_.discard_root) discard_bits_ = bitset::ptr( new bitset(tm_, sb_.discard_root, sb_.discard_nr_blocks)); } void metadata::commit_space_map() { metadata_sm_->commit(); metadata_sm_->copy_root(&sb_.metadata_space_map_root, sizeof(sb_.metadata_space_map_root)); } void metadata::commit_mappings() { sb_.mapping_root = mappings_->get_root(); } void metadata::commit_hints() { sb_.hint_root = hints_->get_root(); } void metadata::commit_discard_bits() { sb_.discard_root = discard_bits_->get_root(); } void metadata::commit_superblock() { write_superblock(tm_->get_bm(), sb_); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/metadata.h000066400000000000000000000025631222772450500217060ustar00rootroot00000000000000#ifndef CACHE_METADATA_H #define CACHE_METADATA_H #include "persistent-data/block.h" #include "persistent-data/data-structures/array.h" #include "persistent-data/data-structures/bitset.h" #include "persistent-data/endian_utils.h" #include "persistent-data/space-maps/disk.h" #include "persistent-data/transaction_manager.h" #include "caching/superblock.h" #include "caching/hint_array.h" #include "caching/mapping_array.h" //---------------------------------------------------------------- namespace caching { class metadata { public: enum open_type { CREATE, OPEN }; typedef block_manager<>::read_ref read_ref; typedef block_manager<>::write_ref write_ref; typedef boost::shared_ptr ptr; metadata(block_manager<>::ptr bm, open_type ot); void commit(); void setup_hint_array(size_t width); typedef persistent_data::transaction_manager tm; tm::ptr tm_; superblock sb_; checked_space_map::ptr metadata_sm_; mapping_array::ptr mappings_; hint_array::ptr hints_; bitset::ptr discard_bits_; private: void init_superblock(); void create_metadata(block_manager<>::ptr bm); void open_metadata(block_manager<>::ptr bm); void commit_space_map(); void commit_mappings(); void commit_hints(); void commit_discard_bits(); void commit_superblock(); }; }; //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/metadata_disk_structures.cc000066400000000000000000000020101222772450500253440ustar00rootroot00000000000000// Copyright (C) 2012 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "metadata_disk_structures.h" #include using namespace cache_tools; //---------------------------------------------------------------- //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/metadata_disk_structures.h000066400000000000000000000023661222772450500252240ustar00rootroot00000000000000// Copyright (C) 2012 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef CACHE_METADATA_DISK_STRUCTURES_H #define CACHE_METADATA_DISK_STRUCTURES_H #include "persistent-data/endian_utils.h" #include "persistent-data/data-structures/btree.h" //---------------------------------------------------------------- // FIXME: rename to just METADATA_DISK_STRUCTURES namespace cache_tools { using namespace base; // FIXME: don't use namespaces in headers. } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/metadata_dump.cc000066400000000000000000000070331222772450500230660ustar00rootroot00000000000000#include "caching/metadata_dump.h" #include using namespace std; using namespace caching; //---------------------------------------------------------------- namespace { string to_string(unsigned char const *data) { // FIXME: we're assuming the data is zero terminated here return std::string(reinterpret_cast(data)); } void raise_metadata_damage() { throw std::runtime_error("metadata contains errors (run cache_check for details).\n" "perhaps you wanted to run with --repair"); } //-------------------------------- class mapping_emitter : public mapping_visitor { public: mapping_emitter(emitter::ptr e, set &valid_blocks) : e_(e), valid_blocks_(valid_blocks) { } void visit(block_address cblock, mapping const &m) { if (m.flags_ & M_VALID) { e_->mapping(cblock, m.oblock_, m.flags_ & M_DIRTY); mark_valid(cblock); } } private: void mark_valid(block_address cblock) { valid_blocks_.insert(cblock); } emitter::ptr e_; set &valid_blocks_; }; struct ignore_mapping_damage : public mapping_array_damage::damage_visitor { virtual void visit(mapping_array_damage::missing_mappings const &d) {} virtual void visit(mapping_array_damage::invalid_mapping const &d) {} }; class fatal_mapping_damage : public mapping_array_damage::damage_visitor { public: virtual void visit(mapping_array_damage::missing_mappings const &d) { raise_metadata_damage(); } virtual void visit(mapping_array_damage::invalid_mapping const &d) { raise_metadata_damage(); } }; //-------------------------------- class hint_emitter : public hint_visitor { public: hint_emitter(emitter::ptr e, set &valid_blocks) : e_(e), valid_blocks_(valid_blocks) { } virtual void visit(block_address cblock, std::vector const &data) { if (valid(cblock)) e_->hint(cblock, data); } private: bool valid(block_address cblock) const { return valid_blocks_.find(cblock) != valid_blocks_.end(); } emitter::ptr e_; set &valid_blocks_; }; struct ignore_hint_damage : public hint_array_damage::damage_visitor { virtual void visit(hint_array_damage::missing_hints const &d) {} }; class fatal_hint_damage : public hint_array_damage::damage_visitor { virtual void visit(hint_array_damage::missing_hints const &d) { raise_metadata_damage(); } }; } //---------------------------------------------------------------- void caching::metadata_dump(metadata::ptr md, emitter::ptr e, bool repair) { set valid_blocks; superblock const &sb = md->sb_; e->begin_superblock(to_string(sb.uuid), sb.data_block_size, sb.cache_blocks, to_string(sb.policy_name), sb.policy_hint_size); e->begin_mappings(); { namespace mad = mapping_array_damage; mapping_emitter me(e, valid_blocks); ignore_mapping_damage ignore; fatal_mapping_damage fatal; mad::damage_visitor &dv = repair ? static_cast(ignore) : static_cast(fatal); walk_mapping_array(*md->mappings_, me, dv); } e->end_mappings(); // walk hints e->begin_hints(); { using namespace hint_array_damage; hint_emitter he(e, valid_blocks); ignore_hint_damage ignore; fatal_hint_damage fatal; damage_visitor &dv = repair ? static_cast(ignore) : static_cast(fatal); md->hints_->walk(he, dv); } e->end_hints(); // FIXME: walk discards e->end_superblock(); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/metadata_dump.h000066400000000000000000000007351222772450500227320ustar00rootroot00000000000000#ifndef CACHING_METADATA_DUMP_H #define CACHING_METADATA_DUMP_H #include "caching/metadata.h" #include "caching/emitter.h" //---------------------------------------------------------------- namespace caching { // If 'repair' is set then any metadata damage will be stepped // around. Otherwise an exception will be thrown. void metadata_dump(metadata::ptr md, emitter::ptr out, bool repair); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/restore_emitter.cc000066400000000000000000000046531222772450500235020ustar00rootroot00000000000000#include "caching/restore_emitter.h" #include "caching/superblock.h" #include "caching/mapping_array.h" using namespace caching; using namespace std; using namespace superblock_damage; //---------------------------------------------------------------- namespace { class restorer : public emitter { public: restorer(metadata::ptr md) : in_superblock_(false), md_(md) { } virtual ~restorer() { } virtual void begin_superblock(std::string const &uuid, pd::block_address block_size, pd::block_address nr_cache_blocks, std::string const &policy, size_t hint_width) { superblock &sb = md_->sb_; strncpy((char *) sb.policy_name, policy.c_str(), sizeof(sb.policy_name)); memset(sb.policy_version, 0, sizeof(sb.policy_version)); // FIXME: should come from xml sb.policy_hint_size = hint_width; md_->setup_hint_array(hint_width); sb.data_block_size = block_size; sb.cache_blocks = nr_cache_blocks; struct mapping unmapped_value; unmapped_value.oblock_ = 0; unmapped_value.flags_ = 0; md_->mappings_->grow(nr_cache_blocks, unmapped_value); vector hint_value(hint_width, '\0'); md_->hints_->grow(nr_cache_blocks, hint_value); } virtual void end_superblock() { md_->commit(); } virtual void begin_mappings() { // noop } virtual void end_mappings() { // noop } virtual void mapping(pd::block_address cblock, pd::block_address oblock, bool dirty) { typename caching::mapping m; m.oblock_ = oblock; m.flags_ = M_VALID; if (dirty) m.flags_ = m.flags_ | M_DIRTY; md_->mappings_->set(cblock, m); } virtual void begin_hints() { // noop } virtual void end_hints() { // noop } virtual void hint(pd::block_address cblock, vector const &data) { md_->hints_->set_hint(cblock, data); } virtual void begin_discards() { // noop } virtual void end_discards() { // noop } virtual void discard(block_address dblock, block_address dblock_e) { while (dblock != dblock_e) { md_->discard_bits_->set(dblock, true); dblock++; } } private: bool in_superblock_; metadata::ptr md_; }; } //---------------------------------------------------------------- emitter::ptr caching::create_restore_emitter(metadata::ptr md) { return emitter::ptr(new restorer(md)); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/restore_emitter.h000066400000000000000000000005131222772450500233330ustar00rootroot00000000000000#ifndef CACHE_RESTORE_EMITTER_H #define CACHE_RESTORE_EMITTER_H #include "emitter.h" #include "metadata.h" //---------------------------------------------------------------- namespace caching { emitter::ptr create_restore_emitter(metadata::ptr md); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/superblock.cc000066400000000000000000000251051222772450500224320ustar00rootroot00000000000000#include "caching/superblock.h" using namespace caching; using namespace superblock_damage; //---------------------------------------------------------------- namespace { using namespace base; struct superblock_disk { le32 csum; le32 flags; le64 blocknr; __u8 uuid[16]; le64 magic; le32 version; __u8 policy_name[CACHE_POLICY_NAME_SIZE]; le32 policy_hint_size; __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; le64 mapping_root; le64 hint_root; le64 discard_root; le64 discard_block_size; le64 discard_nr_blocks; le32 data_block_size; /* in 512-byte sectors */ le32 metadata_block_size; /* in 512-byte sectors */ le32 cache_blocks; le32 compat_flags; le32 compat_ro_flags; le32 incompat_flags; le32 read_hits; le32 read_misses; le32 write_hits; le32 write_misses; le32 policy_version[CACHE_POLICY_VERSION_SIZE]; } __attribute__ ((packed)); struct superblock_traits { typedef superblock_disk disk_type; typedef superblock value_type; static void unpack(superblock_disk const &disk, superblock &value); static void pack(superblock const &value, superblock_disk &disk); }; uint32_t const SUPERBLOCK_MAGIC = 06142003; uint32_t const VERSION_BEGIN = 1; uint32_t const VERSION_END = 2; } //---------------------------------------------------------------- superblock_flags::superblock_flags() : unhandled_flags_(0) { } superblock_flags::superblock_flags(uint32_t bits) { if (bits & (1 << CLEAN_SHUTDOWN_BIT)) { flags_.insert(CLEAN_SHUTDOWN); bits &= ~(1 << CLEAN_SHUTDOWN_BIT); } unhandled_flags_ = bits; } void superblock_flags::set_flag(superblock_flags::flag f) { flags_.insert(f); } bool superblock_flags::get_flag(flag f) const { return flags_.find(f) != flags_.end(); } uint32_t superblock_flags::encode() const { uint32_t r = 0; if (get_flag(CLEAN_SHUTDOWN)) r = r | (1 << CLEAN_SHUTDOWN_BIT); return r; } uint32_t superblock_flags::get_unhandled_flags() const { return unhandled_flags_; } //---------------------------------------------------------------- superblock::superblock() : csum(0), blocknr(SUPERBLOCK_LOCATION), magic(SUPERBLOCK_MAGIC), version(VERSION_END - 1u), policy_hint_size(0), mapping_root(0), hint_root(0), discard_root(0), discard_block_size(0), discard_nr_blocks(0), data_block_size(0), metadata_block_size(8), cache_blocks(0), compat_flags(0), compat_ro_flags(0), incompat_flags(0), read_hits(0), read_misses(0), write_hits(0), write_misses(0) { ::memset(uuid, 0, sizeof(uuid)); ::memset(policy_name, 0, sizeof(policy_name)); ::memset(policy_version, 0, sizeof(policy_version)); ::memset(metadata_space_map_root, 0, sizeof(metadata_space_map_root)); } //---------------------------------------------------------------- void superblock_traits::unpack(superblock_disk const &disk, superblock &core) { core.csum = to_cpu(disk.csum); core.flags = superblock_flags(to_cpu(disk.flags)); core.blocknr = to_cpu(disk.blocknr); ::memcpy(core.uuid, disk.uuid, sizeof(core.uuid)); core.magic = to_cpu(disk.magic); core.version = to_cpu(disk.version); ::memcpy(core.policy_name, disk.policy_name, sizeof(core.policy_name)); for (unsigned i = 0; i < CACHE_POLICY_VERSION_SIZE; i++) core.policy_version[i] = to_cpu(disk.policy_version[i]); core.policy_hint_size = core.version == 1 ? 4 : to_cpu(disk.policy_hint_size); ::memcpy(core.metadata_space_map_root, disk.metadata_space_map_root, sizeof(core.metadata_space_map_root)); core.mapping_root = to_cpu(disk.mapping_root); core.hint_root = to_cpu(disk.hint_root); core.discard_root = to_cpu(disk.discard_root); core.discard_block_size = to_cpu(disk.discard_block_size); core.discard_nr_blocks = to_cpu(disk.discard_nr_blocks); core.data_block_size = to_cpu(disk.data_block_size); core.metadata_block_size = to_cpu(disk.metadata_block_size); core.cache_blocks = to_cpu(disk.cache_blocks); core.compat_flags = to_cpu(disk.compat_flags); core.compat_ro_flags = to_cpu(disk.compat_ro_flags); core.incompat_flags = to_cpu(disk.incompat_flags); core.read_hits = to_cpu(disk.read_hits); core.read_misses = to_cpu(disk.read_misses); core.write_hits = to_cpu(disk.write_hits); core.write_misses = to_cpu(disk.write_misses); } void superblock_traits::pack(superblock const &core, superblock_disk &disk) { disk.csum = to_disk(core.csum); disk.flags = to_disk(core.flags.encode()); disk.blocknr = to_disk(core.blocknr); ::memcpy(disk.uuid, core.uuid, sizeof(disk.uuid)); disk.magic = to_disk(core.magic); disk.version = to_disk(core.version); ::memcpy(disk.policy_name, core.policy_name, sizeof(disk.policy_name)); for (unsigned i = 0; i < CACHE_POLICY_VERSION_SIZE; i++) disk.policy_version[i] = to_disk(core.policy_version[i]); disk.policy_hint_size = to_disk(core.policy_hint_size); ::memcpy(disk.metadata_space_map_root, core.metadata_space_map_root, sizeof(disk.metadata_space_map_root)); disk.mapping_root = to_disk(core.mapping_root); disk.hint_root = to_disk(core.hint_root); disk.discard_root = to_disk(core.discard_root); disk.discard_block_size = to_disk(core.discard_block_size); disk.discard_nr_blocks = to_disk(core.discard_nr_blocks); disk.data_block_size = to_disk(core.data_block_size); disk.metadata_block_size = to_disk(core.metadata_block_size); disk.cache_blocks = to_disk(core.cache_blocks); disk.compat_flags = to_disk(core.compat_flags); disk.compat_ro_flags = to_disk(core.compat_ro_flags); disk.incompat_flags = to_disk(core.incompat_flags); disk.read_hits = to_disk(core.read_hits); disk.read_misses = to_disk(core.read_misses); disk.write_hits = to_disk(core.write_hits); disk.write_misses = to_disk(core.write_misses); } //-------------------------------- superblock_corrupt::superblock_corrupt(std::string const &desc) : damage(desc) { } void superblock_corrupt::visit(damage_visitor &v) const { v.visit(*this); } superblock_invalid::superblock_invalid(std::string const &desc) : damage(desc) { } void superblock_invalid::visit(damage_visitor &v) const { v.visit(*this); } //-------------------------------- // anonymous namespace doesn't work for some reason namespace validator { using namespace persistent_data; uint32_t const VERSION = 1; unsigned const SECTOR_TO_BLOCK_SHIFT = 3; uint32_t const SUPERBLOCK_CSUM_SEED = 9031977; struct sb_validator : public block_manager<>::validator { virtual void check(buffer<> const &b, block_address location) const { superblock_disk const *sbd = reinterpret_cast(&b); crc32c sum(SUPERBLOCK_CSUM_SEED); sum.append(&sbd->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); if (sum.get_sum() != to_cpu(sbd->csum)) throw checksum_error("bad checksum in superblock"); } virtual void prepare(buffer<> &b, block_address location) const { superblock_disk *sbd = reinterpret_cast(&b); crc32c sum(SUPERBLOCK_CSUM_SEED); sum.append(&sbd->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); sbd->csum = to_disk(sum.get_sum()); } }; block_manager<>::validator::ptr mk_v() { return block_manager<>::validator::ptr(new sb_validator); } } //-------------------------------- superblock caching::read_superblock(block_manager<>::ptr bm, block_address location) { superblock sb; block_manager<>::read_ref r = bm->read_lock(location, validator::mk_v()); superblock_disk const *sbd = reinterpret_cast(&r.data()); superblock_traits::unpack(*sbd, sb); return sb; } void caching::write_superblock(block_manager<>::ptr bm, superblock const &sb, block_address location) { block_manager<>::write_ref w = bm->superblock_zero(location, validator::mk_v()); superblock_traits::pack(sb, *reinterpret_cast(w.data().raw())); } void caching::check_superblock(superblock const &sb, block_address nr_metadata_blocks, damage_visitor &visitor) { if (sb.flags.get_unhandled_flags()) { ostringstream msg; msg << "invalid flags: " << sb.flags.get_unhandled_flags(); visitor.visit(superblock_invalid(msg.str())); } if (sb.blocknr >= nr_metadata_blocks) { ostringstream msg; msg << "blocknr out of bounds: " << sb.blocknr << " >= " << nr_metadata_blocks; visitor.visit(superblock_invalid(msg.str())); } if (sb.magic != SUPERBLOCK_MAGIC) { ostringstream msg; msg << "magic in incorrect: " << sb.magic; visitor.visit(superblock_invalid(msg.str())); } if (sb.version >= VERSION_END) { ostringstream msg; msg << "version incorrect: " << sb.version; visitor.visit(superblock_invalid(msg.str())); } if (sb.version < VERSION_BEGIN) { ostringstream msg; msg << "version incorrect: " << sb.version; visitor.visit(superblock_invalid(msg.str())); } if (::strnlen((char const *) sb.policy_name, CACHE_POLICY_NAME_SIZE) == CACHE_POLICY_NAME_SIZE) { visitor.visit(superblock_invalid("policy name is not null terminated")); } if (sb.policy_hint_size % 4 || sb.policy_hint_size > 128) { ostringstream msg; msg << "policy hint size invalid: " << sb.policy_hint_size; visitor.visit(superblock_invalid(msg.str())); } if (sb.metadata_block_size != 8) { ostringstream msg; msg << "metadata block size incorrect: " << sb.metadata_block_size; visitor.visit(superblock_invalid(msg.str())); } if (sb.compat_flags != 0) { ostringstream msg; msg << "compat_flags invalid (can only be 0): " << sb.compat_flags; visitor.visit(superblock_invalid(msg.str())); } if (sb.compat_ro_flags != 0) { ostringstream msg; msg << "compat_ro_flags invalid (can only be 0): " << sb.compat_ro_flags; visitor.visit(superblock_invalid(msg.str())); } if (sb.incompat_flags != 0) { ostringstream msg; msg << "incompat_flags invalid (can only be 0): " << sb.incompat_flags; visitor.visit(superblock_invalid(msg.str())); } } void caching::check_superblock(persistent_data::block_manager<>::ptr bm, block_address nr_metadata_blocks, damage_visitor &visitor) { superblock sb; try { sb = read_superblock(bm, SUPERBLOCK_LOCATION); } catch (std::exception const &e) { // FIXME: what if it fails due to a zero length file? Not // really a corruption, so much as an io error. Should we // separate these? visitor.visit(superblock_corrupt(e.what())); } check_superblock(sb, nr_metadata_blocks, visitor); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/superblock.h000066400000000000000000000064131222772450500222750ustar00rootroot00000000000000#ifndef CACHE_SUPERBLOCK_H #define CACHE_SUPERBLOCK_H #include "persistent-data/endian_utils.h" #include "persistent-data/data-structures/btree.h" #include //---------------------------------------------------------------- namespace caching { typedef unsigned char __u8; unsigned const SPACE_MAP_ROOT_SIZE = 128; unsigned const CACHE_POLICY_NAME_SIZE = 16; unsigned const CACHE_POLICY_VERSION_SIZE = 3; block_address const SUPERBLOCK_LOCATION = 0; class superblock_flags { public: enum flag { CLEAN_SHUTDOWN }; enum flag_bits { CLEAN_SHUTDOWN_BIT = 0 }; superblock_flags(); superblock_flags(uint32_t bits); void set_flag(flag f); bool get_flag(flag f) const; uint32_t encode() const; uint32_t get_unhandled_flags() const; private: uint32_t unhandled_flags_; std::set flags_; }; struct superblock { superblock(); uint32_t csum; superblock_flags flags; uint64_t blocknr; __u8 uuid[16]; uint64_t magic; uint32_t version; __u8 policy_name[CACHE_POLICY_NAME_SIZE]; uint32_t policy_version[CACHE_POLICY_VERSION_SIZE]; uint32_t policy_hint_size; __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; uint64_t mapping_root; uint64_t hint_root; uint64_t discard_root; uint64_t discard_block_size; uint64_t discard_nr_blocks; uint32_t data_block_size; /* in 512-byte sectors */ uint32_t metadata_block_size; /* in 512-byte sectors */ uint32_t cache_blocks; uint32_t compat_flags; uint32_t compat_ro_flags; uint32_t incompat_flags; uint32_t read_hits; uint32_t read_misses; uint32_t write_hits; uint32_t write_misses; }; //-------------------------------- namespace superblock_damage { class damage_visitor; class damage { public: damage(std::string const &desc) : desc_(desc) { } virtual ~damage() {} virtual void visit(damage_visitor &v) const = 0; std::string const &get_desc() const { return desc_; } private: std::string desc_; }; struct superblock_corrupt : public damage { superblock_corrupt(std::string const &desc); void visit(damage_visitor &v) const; }; struct superblock_invalid : public damage { superblock_invalid(std::string const &desc); void visit(damage_visitor &v) const; }; class damage_visitor { public: virtual ~damage_visitor() {} void visit(damage const &d); virtual void visit(superblock_corrupt const &d) = 0; virtual void visit(superblock_invalid const &d) = 0; }; } //-------------------------------- persistent_data::block_manager<>::validator::ptr superblock_validator(); superblock read_superblock(persistent_data::block_manager<>::ptr bm, persistent_data::block_address location = SUPERBLOCK_LOCATION); void write_superblock(persistent_data::block_manager<>::ptr bm, superblock const &sb, persistent_data::block_address location = SUPERBLOCK_LOCATION); void check_superblock(superblock const &sb, persistent_data::block_address nr_metadata_blocks, superblock_damage::damage_visitor &visitor); void check_superblock(persistent_data::block_manager<>::ptr bm, persistent_data::block_address nr_metadata_blocks, superblock_damage::damage_visitor &visitor); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/caching/xml_format.cc000066400000000000000000000162461222772450500224370ustar00rootroot00000000000000#include "base/base64.h" #include "caching/xml_format.h" #include #include using namespace boost; using namespace caching; using namespace persistent_data; using namespace std; //---------------------------------------------------------------- namespace { //-------------------------------- // Emitter //-------------------------------- class xml_emitter : public emitter { public: xml_emitter(ostream &out) : out_(out), indent_(0) { } void begin_superblock(std::string const &uuid, block_address block_size, block_address nr_cache_blocks, std::string const &policy, size_t hint_width) { indent(); out_ << "" << endl; inc(); } virtual void end_superblock() { dec(); indent(); out_ << "" << endl; } virtual void begin_mappings() { indent(); out_ << "" << endl; inc(); } virtual void end_mappings() { dec(); indent(); out_ << "" << endl; } virtual void mapping(block_address cblock, block_address oblock, bool dirty) { indent(); out_ << "" << endl; } virtual void begin_hints() { indent(); out_ << "" << endl; inc(); } virtual void end_hints() { dec(); indent(); out_ << "" << endl; } virtual void hint(block_address cblock, vector const &data) { using namespace base; indent(); out_ << "" << endl; } virtual void begin_discards() { indent(); out_ << "" << endl; inc(); } virtual void end_discards() { dec(); indent(); out_ << "" << endl; } virtual void discard(block_address dblock_b, block_address dblock_e) { indent(); out_ << "" << endl; } private: string as_truth(bool v) const { return v ? "true" : "false"; } // FIXME: factor out a common class with the thin_provisioning emitter void indent() { for (unsigned i = 0; i < indent_ * 2; i++) out_ << ' '; } void inc() { indent_++; } void dec() { indent_--; } ostream &out_; unsigned indent_; }; //-------------------------------- // Parser //-------------------------------- // FIXME: factor out common code with thinp one typedef std::map attributes; void build_attributes(attributes &a, char const **attr) { while (*attr) { char const *key = *attr; attr++; if (!*attr) { ostringstream out; out << "No value given for xml attribute: " << key; throw runtime_error(out.str()); } char const *value = *attr; a.insert(make_pair(string(key), string(value))); attr++; } } template T get_attr(attributes const &attr, string const &key) { attributes::const_iterator it = attr.find(key); if (it == attr.end()) { ostringstream out; out << "could not find attribute: " << key; throw runtime_error(out.str()); } return boost::lexical_cast(it->second); } template boost::optional get_opt_attr(attributes const &attr, string const &key) { typedef boost::optional rtype; attributes::const_iterator it = attr.find(key); if (it == attr.end()) return rtype(); return rtype(boost::lexical_cast(it->second)); } void parse_superblock(emitter *e, attributes const &attr) { e->begin_superblock(get_attr(attr, "uuid"), get_attr(attr, "block_size"), get_attr(attr, "nr_cache_blocks"), get_attr(attr, "policy"), get_attr(attr, "hint_width")); } bool to_bool(string const &str) { if (str == "true") return true; else if (str == "false") return false; throw runtime_error("bad boolean value"); } void parse_mapping(emitter *e, attributes const &attr) { e->mapping(get_attr(attr, "cache_block"), get_attr(attr, "origin_block"), to_bool(get_attr(attr, "dirty"))); } void parse_hint(emitter *e, attributes const &attr) { using namespace base; block_address cblock = get_attr(attr, "cache_block"); decoded_or_error doe = base64_decode(get_attr(attr, "data")); if (!get >(&doe)) { ostringstream msg; msg << "invalid base64 encoding of hint for cache block " << cblock << ": " << get(doe); throw runtime_error(msg.str()); } e->hint(cblock, get >(doe)); } // FIXME: why passing e by ptr? void parse_discard(emitter *e, attributes const &attr) { e->discard(get_attr(attr, "dbegin"), get_attr(attr, "dend")); } void start_tag(void *data, char const *el, char const **attr) { emitter *e = static_cast(data); attributes a; build_attributes(a, attr); if (!strcmp(el, "superblock")) parse_superblock(e, a); else if (!strcmp(el, "mappings")) e->begin_mappings(); else if (!strcmp(el, "mapping")) parse_mapping(e, a); else if (!strcmp(el, "hints")) e->begin_hints(); else if (!strcmp(el, "hint")) parse_hint(e, a); else if (!strcmp(el, "discards")) e->begin_discards(); else if (!strcmp(el, "discard")) parse_discard(e, a); else throw runtime_error("unknown tag type"); } void end_tag(void *data, const char *el) { emitter *e = static_cast(data); if (!strcmp(el, "superblock")) e->end_superblock(); else if (!strcmp(el, "mappings")) e->end_mappings(); else if (!strcmp(el, "mapping")) // do nothing ; else if (!strcmp(el, "hints")) e->end_hints(); else if (!strcmp(el, "hint")) // do nothing ; else if (!strcmp(el, "discards")) e->end_discards(); else if (!strcmp(el, "discard")) // do nothing ; else throw runtime_error("unknown tag close"); } } //---------------------------------------------------------------- caching::emitter::ptr caching::create_xml_emitter(ostream &out) { return emitter::ptr(new xml_emitter(out)); } void caching::parse_xml(istream &in, emitter::ptr e) { XML_Parser parser = XML_ParserCreate(NULL); if (!parser) throw runtime_error("couldn't create xml parser"); XML_SetUserData(parser, e.get()); XML_SetElementHandler(parser, start_tag, end_tag); while (!in.eof()) { char buffer[4096]; in.read(buffer, sizeof(buffer)); size_t len = in.gcount(); int done = in.eof(); if (!XML_Parse(parser, buffer, len, done)) { ostringstream out; out << "Parse error at line " << XML_GetCurrentLineNumber(parser) << ":\n" << XML_ErrorString(XML_GetErrorCode(parser)) << endl; throw runtime_error(out.str()); } } } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/caching/xml_format.h000066400000000000000000000005561222772450500222760ustar00rootroot00000000000000#ifndef CACHE_XML_FORMAT_H #define CACHE_XML_FORMAT_H #include "emitter.h" #include //---------------------------------------------------------------- namespace caching { emitter::ptr create_xml_emitter(std::ostream &out); void parse_xml(std::istream &in, emitter::ptr e); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/configure.in000066400000000000000000000123741222772450500206730ustar00rootroot00000000000000################################################################ ## Copyright (C) 2011 Red Hat, Inc. All rights reserved. ## ## This file is part of the thin-provisioning-tools source. ## ## thin-provisioning-tools is free software: you can redistribute it ## and/or modify it under the terms of the GNU General Public License ## as published by the Free Software Foundation, either version 3 of ## the License, or (at your option) any later version. ## ## thin-provisioning-tools is distributed in the hope that it will be ## useful, but WITHOUT ANY WARRANTY; without even the implied warranty ## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License along ## with thin-provisioning-tools. If not, see ## . ################################################################ AC_PREREQ(2.61) ################################################################ dnl -- Process this file with autoconf to produce a configure script. AC_INIT # AC_CONFIG_HEADERS([configure.h]) ################################################################################ dnl -- Setup the directory where autoconf has auxilary files AC_CONFIG_AUX_DIR(autoconf) AC_CANONICAL_TARGET([]) AC_PROG_CXX([g++]) AC_PROG_CC([gcc]) AC_LANG(C++) ################################################################ dnl -- Checks for programs. AC_PROG_SED AC_PROG_AWK AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_MKDIR_P AC_PROG_INSTALL ################################################################################ dnl -- Prefix is /usr by default, the exec_prefix default is setup later AC_PREFIX_DEFAULT(/usr) AC_CHECK_HEADERS([expat.h \ iostream \ boost/bind.hpp \ boost/crc.hpp \ boost/intrusive/circular_list_algorithms.hpp \ boost/intrusive/rbtree_algorithms.hpp \ boost/lexical_cast.hpp \ boost/noncopyable.hpp \ boost/optional.hpp \ boost/shared_ptr.hpp \ boost/static_assert.hpp], [], [AC_MSG_ERROR(bailing out)]) ################################################################################ dnl -- Setup the ownership of the files AC_MSG_CHECKING(file owner) AC_ARG_WITH(user, AC_HELP_STRING([--with-user=USER], [set the owner of installed files [[USER=]]]), OWNER=$withval) AC_MSG_RESULT($OWNER) if test x$OWNER != x; then INSTALL="$INSTALL -o $OWNER" fi ################################################################################ dnl -- Setup the group ownership of the files AC_MSG_CHECKING(group owner) AC_ARG_WITH(group, AC_HELP_STRING([--with-group=GROUP], [set the group owner of installed files [[GROUP=]]]), INSTALL_GROUP=$withval) AC_MSG_RESULT($INSTALL_GROUP) if test x$INSTALL_GROUP != x; then INSTALL="$INSTALL -g $INSTALL_GROUP" fi ################################################################################ dnl -- Enable debugging AC_MSG_CHECKING(whether to enable debugging) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable debugging]), DEBUG=$enableval, DEBUG=no) AC_MSG_RESULT($DEBUG) if test x$DEBUG = xyes; then CXXDEBUG_FLAG=-g fi ################################################################################ dnl -- Override optimisation AC_MSG_CHECKING(for C++ optimisation flag) CXXOPTIMISE_FLAG="-O8" AC_ARG_WITH(optimisation, AC_HELP_STRING([--with-optimisation=OPT], [C++ optimisation flag [[OPT=-O8]]]), CXXOPTIMISE_FLAG=$withval) AC_MSG_RESULT($CXXOPTIMISE_FLAG) if test x$CXXOPTIMISE_FLAG = xyes; then CXXOPTIMISE_FLAG=-O8 fi ################################################################################ dnl -- Enable testing AC_MSG_CHECKING(whether to enable unit testing) AC_ARG_ENABLE(testing, AC_HELP_STRING(--enable-testing, [enable testing targets in the makefile]), TESTING=$enableval, TESTING=no) AC_MSG_RESULT($TESTING) ################################################################################ dnl -- Check for getopt AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.])) ################################################################################ THIN_PROVISIONING_TOOLS_VERSION="\"`cat "$srcdir"/VERSION 2>/dev/null || echo Unknown`\"" VER=`cat "$srcdir"/VERSION` RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\"" VER=`echo "$VER" | $AWK '{print $1}'` RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\"" VER=`echo "$VER" | $AWK -F '-' '{print $1}'` VERSION_MAJOR=`echo "$VER" | $AWK -F '.' '{print $1}'` VERSION_MINOR=`echo "$VER" | $AWK -F '.' '{print $2}'` VERSION_PATCHLEVEL=`echo "$VER" | $AWK -F '[[(.]]' '{print $3}'` ################################################################ AC_SUBST(CXXDEBUG_FLAG) AC_SUBST(CXXOPTIMISE_FLAG) AC_SUBST(INSTALL) AC_SUBST(prefix) AC_SUBST(RELEASE_DATE) AC_SUBST(RELEASE_DATE) AC_SUBST(TESTING) AC_SUBST(THIN_PROVISIONING_TOOLS_VERSION) ################################################################################ dnl -- First and last lines should not contain files to generate in order to dnl -- keep utility scripts running properly AC_CONFIG_FILES([ Makefile unit-tests/Makefile version.h ]) AC_OUTPUT thin-provisioning-tools-0.2.8/features/000077500000000000000000000000001222772450500201715ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/features/cache_check.feature000066400000000000000000000043021222772450500237450ustar00rootroot00000000000000Feature: cache_check Scenario: print version (-V flag) When I run `cache_check -V` Then it should pass with version Scenario: print version (--version flag) When I run `cache_check --version` Then it should pass with version Scenario: print help When I run `cache_check --help` Then it should pass And usage to stdout Scenario: print help When I run `cache_check -h` Then it should pass And usage to stdout Scenario: Metadata file must be specified When I run `cache_check` Then it should fail And usage to stderr And the stderr should contain: """ No input file provided. """ Scenario: Metadata file doesn't exist When I run `cache_check /arbitrary/filename` Then it should fail And the stderr should contain: """ /arbitrary/filename: No such file or directory """ Scenario: Metadata file cannot be a directory Given a directory called foo When I run `cache_check foo` Then it should fail And the stderr should contain: """ foo: Not a block device or regular file """ Scenario: Metadata file exists, but can't be opened Given input without read permissions When I run `cache_check input` Then it should fail And the stderr should contain: """ Permission denied """ Scenario: Metadata file full of zeroes Given input file And block 1 is zeroed When I run `cache_check input` Then it should fail Scenario: --quiet is observed Given input file And block 1 is zeroed When I run `cache_check --quiet input` Then it should fail And it should give no output Scenario: -q is observed Given input file And block 1 is zeroed When I run `cache_check -q input` Then it should fail And it should give no output Scenario: A valid metadata area passes Given valid cache metadata When I run `cache_check metadata.bin` Then it should pass Scenario: Invalid metadata version causes a fail Given a small xml file And input file And I run cache_restore with -i metadata.xml -o input --debug-override-metadata-version 12345 When I run `cache_check input` Then it should fail thin-provisioning-tools-0.2.8/features/cache_dump.feature000066400000000000000000000022471222772450500236430ustar00rootroot00000000000000Feature: cache_dump Scenario: print version (-V flag) When I run cache_dump with -V Then it should pass with version Scenario: print version (--version flag) When I run cache_dump with --version Then it should pass with version @announce Scenario: print help (-h) When I run cache_dump with -h Then it should pass with: """ Usage: cache_dump [options] {device|file} Options: {-h|--help} {-o } {-V|--version} """ Scenario: print help (--help) When I run cache_dump with -h Then it should pass with: """ Usage: cache_dump [options] {device|file} Options: {-h|--help} {-o } {-V|--version} """ Scenario: accepts an output file Given valid cache metadata When I run cache_dump with -o metadata.xml metadata.bin Then it should pass Scenario: missing input file When I run cache_dump Then it should fail with: """ No input file provided. """ Scenario: dump/restore is a noop Given valid cache metadata When I cache_dump And I cache_restore And I cache_dump Then cache dumps 1 and 2 should be identical thin-provisioning-tools-0.2.8/features/cache_restore.feature000066400000000000000000000036251222772450500243620ustar00rootroot00000000000000Feature: thin_restore Scenario: print version (-V flag) When I run cache_restore with -V Then it should pass with version Scenario: print version (--version flag) When I run cache_restore with --version Then it should pass with version Scenario: print help (-h) When I run cache_restore with -h Then it should pass And the output should contain exactly: """ Usage: cache_restore [options] Options: {-h|--help} {-i|--input} {-o|--output} {-V|--version} {--debug-override-metadata-version} """ Scenario: print help (--help) When I run cache_restore with -h Then it should pass And the output should contain exactly: """ Usage: cache_restore [options] Options: {-h|--help} {-i|--input} {-o|--output} {-V|--version} {--debug-override-metadata-version} """ Scenario: missing input file Given the dev file metadata.bin When I run cache_restore with -o metadata.bin Then it should fail with: """ No input file provided. """ Scenario: input file not found Given the dev file metadata.bin When I run cache_restore with -i foo.xml -o metadata.bin Then it should fail Scenario: missing output file When I run cache_restore with -i metadata.xml Then it should fail with: """ No output file provided. """ Scenario: successfully restores a valid xml file Given a small xml file And an empty dev file When I run cache_restore with -i metadata.xml -o metadata.bin Then it should pass Scenario: accepts --debug-override-metadata-version Given a small xml file And an empty dev file When I run cache_restore with -i metadata.xml -o metadata.bin --debug-override-metadata-version 10298 Then it should pass thin-provisioning-tools-0.2.8/features/step_definitions/000077500000000000000000000000001222772450500235375ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/features/step_definitions/cache_steps.rb000066400000000000000000000044141222772450500263500ustar00rootroot00000000000000DEFAULT_INPUT = 'input' BLOCK_SIZE = 4096 Given /^a directory called (.*)\s*$/ do |dir| create_dir(dir) end Given /^input without read permissions$/ do write_file(DEFAULT_INPUT, "\0" * 4096) in_current_dir do f = File.new(DEFAULT_INPUT) f.chmod(0000) end end Given(/^input file$/) do write_file(DEFAULT_INPUT, "\0" * BLOCK_SIZE * 1024) end Given(/^block (\d+) is zeroed$/) do |b| in_current_dir do File.open(DEFAULT_INPUT, 'w') do |f| f.seek(BLOCK_SIZE * b.to_i, IO::SEEK_SET) f.write("\0" * BLOCK_SIZE) end end end Then /^it should pass$/ do assert_success(true) end Then /^it should fail$/ do assert_success(false) end USAGE =< #{xml_file}") end run_simple("dd if=/dev/zero of=#{dev_file} bs=4k count=1024") run_simple("cache_restore -i #{xml_file} -o #{dev_file}") end Then(/^cache dumps (\d+) and (\d+) should be identical$/) do |d1, d2| run_simple("diff -ub #{dump_files[d1.to_i]} #{dump_files[d2.to_i]}", true) end Given(/^a small xml file$/) do in_current_dir do system("cache_xml create --nr-cache-blocks 3 --nr-mappings 3 --layout linear --dirty-percent 100 > #{xml_file}") end end Given(/^an empty dev file$/) do run_simple("dd if=/dev/zero of=#{dev_file} bs=4k count=1024") end When(/^I cache_dump$/) do run_simple("cache_dump #{dev_file} -o #{new_dump_file}", true) end When(/^I cache_restore$/) do run_simple("cache_restore -i #{dump_files[-1]} -o #{dev_file}", true) end thin-provisioning-tools-0.2.8/features/step_definitions/thin_steps.rb000066400000000000000000000034141222772450500262460ustar00rootroot00000000000000Given(/^valid metadata$/) do in_current_dir do system("thinp_xml create --nr-thins uniform[4..9] --nr-mappings uniform[1000..10000] > #{xml_file}") end run_simple("dd if=/dev/zero of=#{dev_file} bs=4k count=1024") run_simple("thin_restore -i #{xml_file} -o #{dev_file}") end Given(/^the dev file metadata\.bin$/) do run_simple("dd if=/dev/zero of=#{dev_file} bs=4k count=1024") end Given(/^a corrupt superblock$/) do in_current_dir do write_valid_xml(xml_file) end run_simple("dd if=/dev/zero of=#{dev_file} bs=4k count=1024") run_simple("thin_restore -i #{xml_file} -o #{dev_file}") in_current_dir do corrupt_block(0) end end When(/^I run thin_check with (.*?)$/) do |opts| run_simple("thin_check #{opts} #{dev_file}", false) end When(/^I run thin_rmap with (.*?)$/) do |opts| run_simple("thin_rmap #{opts} #{dev_file}", false) end When(/^I run thin_restore with (.*?)$/) do |opts| run_simple("thin_restore #{opts}", false) end Then /^it should give no output$/ do ps = only_processes.last output = ps.stdout + ps.stderr output.should == "" end Then(/^it should pass with version$/) do only_processes.last.stdout.chomp.should == tools_version end When(/^I dump$/) do run_simple("thin_dump #{dev_file} -o #{new_dump_file}", true) end When(/^I restore$/) do run_simple("thin_restore -i #{dump_files[-1]} -o #{dev_file}", true) end Then(/^dumps ([0-9]+) and ([0-9]+) should be identical$/) do |d1, d2| run_simple("diff -ub #{dump_files[d1.to_i]} #{dump_files[d2.to_i]}", true) end Given(/^small metadata$/) do in_current_dir do system("thinp_xml create --nr-thins 2 --nr-mappings 1 > #{xml_file}") end run_simple("dd if=/dev/zero of=#{dev_file} bs=4k count=1024") run_simple("thin_restore -i #{xml_file} -o #{dev_file}") end thin-provisioning-tools-0.2.8/features/support/000077500000000000000000000000001222772450500217055ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/features/support/aruba.rb000066400000000000000000000001051222772450500233200ustar00rootroot00000000000000require 'aruba/cucumber' ENV['PATH'] = "#{Dir::pwd}:#{ENV['PATH']}" thin-provisioning-tools-0.2.8/features/support/world_extensions.rb000066400000000000000000000022421222772450500256400ustar00rootroot00000000000000Before do @aruba_timeout_seconds = 120 end module ThinpWorld def tools_version version = '' File.open('VERSION', 'r') do |f| version = f.readline version.chomp! end version end def xml_file 'metadata.xml' end def dev_file 'metadata.bin' end def dump_files @dump_files ||= [xml_file] end def new_dump_file fn = "dump_#{dump_files.size}.xml" @dump_files << fn fn end def corrupt_block(n) write_block(n, change_random_byte(read_block(n))) end # FIXME: we should really break out the xml stuff from # thinp-test-suite and put in a gem in this repo. def write_valid_xml(path) `thinp_xml create --nr-thins uniform[4..9] --nr-mappings uniform[1000..5000] > #{path}` end private def read_block(n) b = nil File.open(dev_file, "r") do |f| f.seek(n * 4096) b = f.read(4096) end b end def write_block(n, b) File.open(dev_file, "w") do |f| f.seek(n * 4096) f.write(b) end end def change_random_byte(b) i = rand(b.size) puts "changing byte #{i}" b.setbyte(i, (b.getbyte(i) + 1) % 256) b end end World(ThinpWorld) thin-provisioning-tools-0.2.8/features/thin_check.feature000066400000000000000000000040521222772450500236460ustar00rootroot00000000000000Feature: thin_check Scenario: print version (-V flag) When I run `thin_check -V` Then it should pass with version Scenario: print version (--version flag) When I run `thin_check --version` Then it should pass with version Scenario: print help When I run `thin_check --help` Then it should pass with: """ Usage: thin_check [options] {device|file} Options: {-q|--quiet} {-h|--help} {-V|--version} {--super-block-only} {--skip-mappings} {--ignore-non-fatal-errors} """ Scenario: print help When I run `thin_check -h` Then it should pass with: """ Usage: thin_check [options] {device|file} Options: {-q|--quiet} {-h|--help} {-V|--version} {--super-block-only} {--skip-mappings} {--ignore-non-fatal-errors} """ Scenario: Unrecognised option should cause failure When I run `thin_check --hedeghogs-only` Then it should fail Scenario: --super-block-only check passes on valid metadata Given valid metadata When I run thin_check with --super-block-only Then it should pass Scenario: --super-block-only check fails with corrupt superblock Given a corrupt superblock When I run thin_check with --super-block-only Then it should fail with: """ examining superblock superblock is corrupt bad checksum in superblock """ Scenario: --skip-mappings check passes on valid metadata Given valid metadata When I run thin_check with --skip-mappings Then it should pass Scenario: --ignore-non-fatal-errors check passes on valid metadata Given valid metadata When I run thin_check with --ignore-non-fatal-errors Then it should pass Scenario: -q should give no output Given a corrupt superblock When I run thin_check with --quiet Then it should fail And it should give no output Scenario: --quiet should give no output Given a corrupt superblock When I run thin_check with --quiet Then it should fail And it should give no output thin-provisioning-tools-0.2.8/features/thin_restore.feature000066400000000000000000000033061222772450500242550ustar00rootroot00000000000000Feature: thin_restore Scenario: print version (-V flag) When I run thin_restore with -V Then it should pass with version Scenario: print version (--version flag) When I run thin_restore with --version Then it should pass with version Scenario: print help (-h) When I run thin_restore with -h Then it should pass with: """ Usage: thin_restore [options] Options: {-h|--help} {-i|--input} {-o|--output} {-V|--version} """ Scenario: print help (--help) When I run thin_restore with -h Then it should pass with: """ Usage: thin_restore [options] Options: {-h|--help} {-i|--input} {-o|--output} {-V|--version} """ Scenario: missing input file Given the dev file metadata.bin When I run thin_restore with -o metadata.bin Then it should fail with: """ No input file provided. """ Scenario: input file not found Given the dev file metadata.bin When I run thin_restore with -i foo.xml -o metadata.bin Then it should fail Scenario: missing output file When I run thin_restore with -i metadata.xml Then it should fail with: """ No output file provided. """ Scenario: dump/restore is a noop Given valid metadata When I dump And I restore And I dump Then dumps 1 and 2 should be identical Scenario: dump matches original metadata Given valid metadata When I dump Then dumps 0 and 1 should be identical Scenario: dump matches original metadata (small) Given small metadata When I dump Then dumps 0 and 1 should be identical thin-provisioning-tools-0.2.8/features/thin_rmap.feature000066400000000000000000000055011222772450500235300ustar00rootroot00000000000000Feature: thin_rmap Scenario: print version (-V flag) When I run `thin_rmap -V` Then it should pass with version Scenario: print version (--version flag) When I run `thin_rmap --version` Then it should pass with version Scenario: print help When I run `thin_rmap --help` Then it should pass with: """ Usage: thin_rmap [options] {device|file} Options: {-h|--help} {-V|--version} {--region }* Where: is of the form .. for example 5..45 denotes blocks 5 to 44 inclusive, but not block 45 """ Scenario: print help When I run `thin_rmap -h` Then it should pass with: """ Usage: thin_rmap [options] {device|file} Options: {-h|--help} {-V|--version} {--region }* Where: is of the form .. for example 5..45 denotes blocks 5 to 44 inclusive, but not block 45 """ Scenario: Unrecognised option should cause failure When I run `thin_rmap --unleash-the-hedeghogs` Then it should fail @announce Scenario: Valid region format should pass Given valid metadata When I run thin_rmap with --region 23..7890 Then it should pass Scenario: Invalid region format should fail (comma instean of dots) Given valid metadata When I run thin_rmap with --region 23,7890 Then it should fail Scenario: Invalid region format should fail (second number a word) Given valid metadata When I run thin_rmap with --region 23..six Then it should fail Scenario: Invalid region format should fail (first number a word) Given valid metadata When I run thin_rmap with --region four..7890 Then it should fail Scenario: Invalid region format should fail (end is lower than begin) Given valid metadata When I run thin_rmap with --region 89..88 Then it should fail Scenario: Invalid region format should fail (end is equal to begin) Given valid metadata When I run thin_rmap with --region 89..89 Then it should fail Scenario: Invalid region format should fail (no begin) Given valid metadata When I run thin_rmap with --region ..89 Then it should fail Scenario: Invalid region format should fail (no end) Given valid metadata When I run thin_rmap with --region 89.. Then it should fail Scenario: Invalid region format should fail (no region at all) Given valid metadata When I run thin_rmap with --region Then it should fail Scenario: Invalid region format should fail (three dots) Given valid metadata When I run thin_rmap with --region 89...99 Then it should fail Scenario: Multiple regions should pass Given valid metadata When I run thin_rmap with --region 1..23 --region 45..78 Then it should pass thin-provisioning-tools-0.2.8/get-gmock.sh000077500000000000000000000001741222772450500205710ustar00rootroot00000000000000#!/bin/sh -e wget https://googlemock.googlecode.com/files/gmock-1.6.0.zip unzip gmock-1.6.0.zip cd gmock-1.6.0 ./configure thin-provisioning-tools-0.2.8/lib/000077500000000000000000000000001222772450500171215ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/lib/.ignore_me000066400000000000000000000000001222772450500210540ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/man8/000077500000000000000000000000001222772450500172165ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/man8/thin_check.8000066400000000000000000000030561222772450500214120ustar00rootroot00000000000000.TH THIN_CHECK 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- .SH NAME thin_check \- repair thin provisioning metadata on device or file .SH SYNOPSIS .B thin_check .RB [ options ] .I {device|file} .SH DESCRIPTION .B thin_check checks thin provisioning metadata created by the device-mapper thin provisioning target on a .I device or .I file. .SH OPTIONS .IP "\fB\-q, \-\-quiet\fP" Suppress output messages, return only exit code. .IP "\fB\-h, \-\-help\fP" Print help and exit. .IP "\fB\-V, \-\-version\fP" Output version information and exit. .IP "\fB\-\-super\-block\-only\fP" Only check the superblock is present. .IP "\fB\-\-skip-mappings\fP" Skip checking of the block mappings which make up the bulk of the metadata. .IP "\fB\-\-ignore\-non\-fatal\-errors\fP" .B thin_check will only return a non-zero exit code if it finds a fatal error. An example of a on fatal error is an incorrect data block reference count causing a block to be considered allocated when it in fact isn't. Ignoring errors for a long time is not advised, you really should be using thin_repair to fix them. .SH EXAMPLE Analyses and repairs thin provisioning metadata on logical volume /dev/vg/metadata: .sp .B thin_check /dev/vg/metadata The device may not be actively used by the target when running. .SH DIAGNOSTICS .B thin_check returns an exit code of 0 for success or 1 for error. .SH SEE ALSO .B thin_dump(8) .B thin_repair(8) .B thin_restore(8) .B thin_rmap(8) .B thin_metadata_size(8) .SH AUTHOR Joe Thornber .br Heinz Mauelshagen thin-provisioning-tools-0.2.8/man8/thin_dump.8000066400000000000000000000043111222772450500212750ustar00rootroot00000000000000.TH THIN_DUMP 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- .SH NAME thin_dump \- dump thin provisioning metadata from device or file to standard output .SH SYNOPSIS .B thin_dump .RB [options] .I {device|file} .SH DESCRIPTION .B thin_dump dumps binary thin provisioning metadata (optionally from alternate block; see option \-\-metadata-snap) created by the device-mapper thin provisioning target on a .I device or .I file to standard output for analysis or postprocessing in either XML or human readable format. XML formated metadata can be fed into thin_restore (see .BR thin_restore(8) ) in order to put it back onto a metadata .I device (to process by the device-mapper target) or .I file. .IP "\fB\-f, \-\-format\fP \fI{xml|human_readable}\fP". Print output in XML or human readable format. .IP "\fB\-r, \-\-repair\fP". Repair the metadata whilst dumping it. .IP "\fB\-m, \-\-metadata_snap\fP [block#]". Dump metadata snapshot created by device-mapper thin provisioning target. If block is not provided, access the default metadata snapshot created by the thin provisioning device-mapper target, else try the one at block#. See the thin provisioning target documentation on how to create or release a metadata snapshot and retrieve the block number from the kernel. .IP "\fB\-h, \-\-help\fP". Print help and exit. .IP "\fB\-V, \-\-version\fP". Output version information and exit. .SH EXAMPLES Dumps the thin provisioning metadata on logical volume /dev/vg/metadata to standard output in human readable format: .sp .B thin_dump -f human_redable /dev/vg/metadata Dumps the thin provisioning metadata on logical volume /dev/vg/metadata to standard output in XML format: .sp .B thin_dump /dev/vg/metadata Dumps the thin provisioning metadata snapshot on logical volume /dev/vg/metadata to standard output in human readable format (not processable by .B thin_restore(8) ): .sp .B thin_dump --format human_readable --metadata-snap /dev/vg/metadata .SH DIAGNOSTICS .B thin_dump returns an exit code of 0 for success or 1 for error. .SH SEE ALSO .B thin_check(8) .B thin_repair(8) .B thin_restore(8) .B thin_rmap(8) .B thin_metadata_size(8) .SH AUTHOR Joe Thornber .br Heinz Mauelshagen thin-provisioning-tools-0.2.8/man8/thin_metadata_size.8000066400000000000000000000060431222772450500231460ustar00rootroot00000000000000.TH THIN_METADATA_SIZE 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- .SH NAME thin_metadata_size \- thin provisioning metadata device/file size calculator. .SH SYNOPSIS .B thin_metadata_size .RB [ options ] .SH DESCRIPTION .B thin_metadata_size calculates the size of the thin provisioning metadata based on the block size of the thin provisioned devices, the size of the thin provisioning pool and the maximum number of all thin prisioned devices and snapshots. Because thin provisioning pools are holding widely variable contents, this tool is needed to provide sensible initial default size. .IP "\fB\-b, \-\-block-size\fP \fIBLOCKSIZE[bskKmMgGtTpPeEzZyY]\fP" Block size of thin provisioned devices in units of bytes,sectors,kilobytes,kibibytes,... respectively. Default is in sectors without a block size unit specifier. Size/number option arguments can be followed by unit specifiers in short one character and long form (eg. -b1m or -b1megabytes). .IP "\fB\-s, \-\-pool-size\fP \fIPOOLSIZE[bskKmMgGtTpPeEzZyY]\fP" Thin provisioning pool size in units of bytes,sectors,kilobytes,kibibytes,... respectively. Default is in sectors without a pool size unit specifier. .IP "\fB\-m, \-\-max-thins\fP \fI#[bskKmMgGtTpPeEzZyY]\fP" Maximum sum of all thin provisioned devices and snapshots. Unit identifier supported to allow for convenient entry of large quantities, eg. 1000000 = 1M. Default is absolute quantity without a number unit specifier. .IP "\fB\-u, \-\-unit\fP \fI{bskKmMgGtTpPeEzZyY}\fP" Output unit specifier in units of bytes,sectors,kilobytes,kibibytes,... respectively. Default is in sectors without an output unit specifier. .IP "\fB\-n, \-\-numeric-only [short|long]\fP" Limit output to just the size number with the optional unit specifier character/string. .IP "\fB\-h, \-\-help\fP" Print help and exit. .IP "\fB\-V, \-\-version\fP" Output version information and exit. .SH EXAMPLES Calculates the thin provisioning metadata device size for block size 64 kilobytes, pool size 1 terabytes and maximum number of thin provisioned devices and snapshots of 1000 in units of sectors with long output: .sp .B thin_metadata_size -b64k -s1t -m1000 Or (using the long options instead) for block size 1 gigabyte, pool size 1 petabytes and maximum number of thin provisioned devices and snapshots of 1 million with numeric only output in units of gigabytes: .sp .B thin_metadata_size --block-size=1g --pool-size=1p --max-thins=1M --unit=g --numeric-only Same as before (1g,1p,1M,numeric-only) but with unit specifier character appended: .sp .B thin_metadata_size --block-size=1giga --pool-size=1petabytes --max-thins=1mebi --unit=g --numeric-only=short Or with unit specifier string appended: .sp .B thin_metadata_size --block-size=1giga --pool-size=1petabytes --max-thins=1mebi --unit=g -nlong .SH DIAGNOSTICS .B thin_metadata_size returns an exit code of 0 for success or 1 for error. .SH SEE ALSO .B thin_dump(8) .B thin_check(8) .B thin_repair(8) .B thin_restore(8) .B thin_rmap(8) .SH AUTHOR Joe Thornber .br Heinz Mauelshagen thin-provisioning-tools-0.2.8/man8/thin_repair.8000066400000000000000000000026031222772450500216140ustar00rootroot00000000000000.TH THIN_REPAIR 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- .SH NAME thin_repair \- repair thin provisioning binary metadata from device/file to device/file .SH SYNOPSIS .B thin_repair .RB [ options ] .RB -i .I {device|file} .RB -o .I {device|file} .SH DESCRIPTION .B thin_repair reads binary thin provisioning metadata created by the respective device-mapper target from one .I device or .I file , repairs it and writes it to another .I device or .I file. If written to a metadata .I device , the metadata can be processed by the device-mapper target. .IP "\fB\-i, \-\-input\fP \fI{device|file}\fP" Input file or device with binary metadata. .IP "\fB\-o, \-\-output\fP \fI{device|file}\fP" Output file or device for repaired binary metadata. .IP "\fB\-h, \-\-help\fP" Print help and exit. .IP "\fB\-V, \-\-version\fP" Output version information and exit. .SH EXAMPLE Reads the binary thin provisioning metadata from file .B metadata , repairs it and writes it to logical volume /dev/vg/metadata for further processing by the respective device-mapper target: .sp .B thin_repair -i metadata -o /dev/vg/metadata .SH DIAGNOSTICS .B thin_repair returns an exit code of 0 for success or 1 for error. .SH SEE ALSO .B thin_dump(8) .B thin_check(8) .B thin_restore(8) .B thin_rmap(8) .B thin_metadata_size(8) .SH AUTHOR Joe Thornber .br Heinz Mauelshagen thin-provisioning-tools-0.2.8/man8/thin_restore.8000066400000000000000000000025751222772450500220250ustar00rootroot00000000000000.TH THIN_RESTORE 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- .SH NAME thin_restore \- restore thin provisioning metadata file to device or file .SH SYNOPSIS .B thin_restore .RB [ options ] .RB -i .I {device|file} .RB -o .I {device|file} .SH DESCRIPTION .B thin_restore restores thin provisioning metadata created by the respective device-mapper target dumped into an XML formatted (see .BR thin_dump(8) ) .I file , which optionally can be preprocessed before the restore to another .I device or .I file. If restored to a metadata .I device , the metadata can be processed by the device-mapper target. .IP "\fB\-i, \-\-input\fP \fI{device|file}\fP" Input file or device with metadata. .IP "\fB\-o, \-\-output\fP \fI{device|file}\fP" Output file or device. .IP "\fB\-h, \-\-help\fP" Print help and exit. .IP "\fB\-V, \-\-version\fP" Output version information and exit. .SH EXAMPLE Restores the XML formatted thin provisioning metadata on file .B metadata to logical volume /dev/vg/metadata for further processing by the respective device-mapper target: .sp .B thin_restore -i metadata -o /dev/vg/metadata .SH DIAGNOSTICS .B thin_restore returns an exit code of 0 for success or 1 for error. .SH SEE ALSO .B thin_dump(8) .B thin_check(8) .B thin_repair(8) .B thin_rmap(8) .B thin_metadata_size(8) .SH AUTHOR Joe Thornber .br Heinz Mauelshagen thin-provisioning-tools-0.2.8/man8/thin_rmap.8000066400000000000000000000020341222772450500212670ustar00rootroot00000000000000.TH THIN_RMAP(g 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- .SH NAME thin_rmap \- output reverse map of a thin provisioned region of blocks from metadata device or file .SH SYNOPSIS .B thin_rmap .RB [options] .I {device|file} .SH DESCRIPTION .B thin_rmap outputs the reverse mapping stored in the metadata on a .I device or .I file between a region of thin provisioned pool blocks and the associated thin provisioned devices. .IP "\fB\\-\-region\fP \fI\fP". output reverse map .IP "\fB\-h, \-\-help\fP". Print help and exit. .IP "\fB\-V, \-\-version\fP". Output version information and exit. .SH EXAMPLES output reverse map for pool blocks 5..45 (denotes blocks 5 to 44 inclusive, but not block 45) .sp .B thin_rmap -r 5..45 /dev/vg/pool .SH DIAGNOSTICS .B thin_rmap returns an exit code of 0 for success or 1 for error. .SH SEE ALSO .B thin_check(8) .B thin_dump(8) .B thin_repair(8) .B thin_restore(8) .B thin_metadata_size(8) .SH AUTHOR Joe Thornber .br Heinz Mauelshagen thin-provisioning-tools-0.2.8/mk_release000077500000000000000000000005701222772450500204120ustar00rootroot00000000000000#!/bin/sh set -e orig_dir=$(pwd) # usage: mk_release tag=$1 echo "creating release tarball for tag '"$tag"'" tmp=$(mktemp -d) dir=$tmp/thin-provisioning-tools-$tag mkdir $dir git clone . $dir cd $dir git checkout $tag autoreconf rm -rf .git cd $tmp tar jcvf $orig_dir/thin-provisioning-tools-$tag.tar.bz2 thin-provisioning-tools-$tag cd $orig_dir rm -rf $tmp thin-provisioning-tools-0.2.8/persistent-data/000077500000000000000000000000001222772450500214625ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/persistent-data/block.h000066400000000000000000000141251222772450500227300ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef BLOCK_H #define BLOCK_H #include "persistent-data/buffer.h" #include "persistent-data/cache.h" #include "persistent-data/lock_tracker.h" #include #include #include #include #include #include #include //---------------------------------------------------------------- namespace persistent_data { uint32_t const MD_BLOCK_SIZE = 4096; typedef uint64_t block_address; template class block_io : private boost::noncopyable { public: typedef boost::shared_ptr ptr; enum mode { READ_ONLY, READ_WRITE, CREATE }; block_io(std::string const &path, block_address nr_blocks, mode m); ~block_io(); block_address get_nr_blocks() const { return nr_blocks_; } void read_buffer(block_address location, buffer &buf) const; void write_buffer(block_address location, buffer const &buf); private: int fd_; block_address nr_blocks_; mode mode_; }; template class block_manager : private boost::noncopyable { public: typedef boost::shared_ptr ptr; block_manager(std::string const &path, block_address nr_blocks, unsigned max_concurrent_locks, typename block_io::mode m); class validator { public: typedef boost::shared_ptr ptr; virtual ~validator() {} virtual void check(buffer const &b, block_address location) const = 0; virtual void prepare(buffer &b, block_address location) const = 0; }; class noop_validator : public validator { public: void check(buffer const &b, block_address location) const {} void prepare(buffer &b, block_address location) const {} }; enum block_type { BT_SUPERBLOCK, BT_NORMAL }; struct block : private boost::noncopyable { typedef boost::shared_ptr ptr; block(typename block_io::ptr io, block_address location, block_type bt, typename validator::ptr v, bool zero = false); ~block(); void check_read_lockable() const { // FIXME: finish } void check_write_lockable() const { // FIXME: finish } void flush(); void change_validator(typename block_manager::validator::ptr v, bool check = true); typename block_io::ptr io_; block_address location_; std::auto_ptr > data_; typename validator::ptr validator_; block_type bt_; bool dirty_; }; class read_ref { public: static uint32_t const BLOCK_SIZE = BlockSize; read_ref(block_manager const &bm, typename block::ptr b); read_ref(read_ref const &rhs); virtual ~read_ref(); read_ref const &operator =(read_ref const &rhs); block_address get_location() const; buffer const &data() const; protected: block_manager const *bm_; typename block::ptr block_; unsigned *holders_; }; // Inherited from read_ref, since you can read a block that's write // locked. class write_ref : public read_ref { public: write_ref(block_manager const &bm, typename block::ptr b); using read_ref::data; buffer &data(); }; // Locking methods read_ref read_lock(block_address location, typename validator::ptr v = typename validator::ptr(new noop_validator())) const; write_ref write_lock(block_address location, typename validator::ptr v = typename validator::ptr(new noop_validator())); write_ref write_lock_zero(block_address location, typename validator::ptr v = typename validator::ptr(new noop_validator())); // The super block is the one that should be written last. // Unlocking this block triggers the following events: // // i) synchronous write of all dirty blocks _except_ the // superblock. // // ii) synchronous write of superblock // // If any locks are held at the time of the superblock // being unlocked then an exception will be thrown. write_ref superblock(block_address b, typename validator::ptr v = typename validator::ptr(new noop_validator())); write_ref superblock_zero(block_address b, typename validator::ptr v = typename validator::ptr(new noop_validator())); block_address get_nr_blocks() const; void flush() const; // This is just for unit tests, don't call in application // code. bool is_locked(block_address b) const; private: void check(block_address b) const; void write_block(typename block::ptr b) const; enum lock_type { READ_LOCK, WRITE_LOCK }; struct cache_traits { typedef typename block::ptr value_type; typedef block_address key_type; static key_type get_key(value_type const &v) { return v->location_; } }; typename block_io::ptr io_; mutable base::cache cache_; // FIXME: we need a dirty list as well as a cache mutable lock_tracker tracker_; }; // A little utility to help build validators inline block_manager<>::validator::ptr mk_validator(block_manager<>::validator *v) { return block_manager<>::validator::ptr(v); } } #include "block.tcc" //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/block.tcc000066400000000000000000000313601222772450500232520ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "block.h" #include #include #include #include #include #include #include #include #include #include //---------------------------------------------------------------- // FIXME: give this namesace a name namespace { using namespace std; int const DEFAULT_MODE = 0666; // FIXME: these will slow it down until we start doing async io. int const OPEN_FLAGS = O_DIRECT | O_SYNC; // FIXME: introduce a new exception for this, or at least lift this // to exception.h void syscall_failed(char const *call) { char buffer[128]; char *msg = strerror_r(errno, buffer, sizeof(buffer)); ostringstream out; out << "syscall '" << call << "' failed: " << msg; throw runtime_error(out.str()); } int open_file(string const &path, int flags) { int fd = ::open(path.c_str(), OPEN_FLAGS | flags, DEFAULT_MODE); if (fd < 0) syscall_failed("open"); return fd; } bool file_exists(string const &path) { struct ::stat info; int r = ::stat(path.c_str(), &info); if (r) { if (errno == ENOENT) return false; syscall_failed("stat"); return false; // never get here } else return S_ISREG(info.st_mode) || S_ISBLK(info.st_mode); } int create_block_file(string const &path, off_t file_size) { if (file_exists(path)) { ostringstream out; out << __FUNCTION__ << ": file '" << path << "' already exists"; throw runtime_error(out.str()); } int fd = open_file(path, O_CREAT | O_RDWR); // fallocate didn't seem to work int r = ::lseek(fd, file_size, SEEK_SET); if (r < 0) syscall_failed("lseek"); return fd; } int open_block_file(string const &path, off_t min_size, bool writeable) { if (!file_exists(path)) { ostringstream out; out << __FUNCTION__ << ": file '" << path << "' doesn't exist"; throw runtime_error(out.str()); } return open_file(path, writeable ? O_RDWR : O_RDONLY); } }; namespace persistent_data { template block_io::block_io(std::string const &path, block_address nr_blocks, mode m) : nr_blocks_(nr_blocks), mode_(m) { off_t file_size = nr_blocks * BlockSize; switch (m) { case READ_ONLY: fd_ = open_block_file(path, file_size, false); break; case READ_WRITE: fd_ = open_block_file(path, file_size, true); break; case CREATE: fd_ = create_block_file(path, file_size); break; default: throw runtime_error("unsupported mode"); } } template block_io::~block_io() { if (::close(fd_) < 0) syscall_failed("close"); } template void block_io::read_buffer(block_address location, buffer &buffer) const { off_t r; r = ::lseek(fd_, BlockSize * location, SEEK_SET); if (r == (off_t) -1) throw std::runtime_error("lseek failed"); ssize_t n; size_t remaining = BlockSize; unsigned char *buf = buffer.raw(); do { n = ::read(fd_, buf, remaining); if (n > 0) { remaining -= n; buf += n; } } while (remaining && ((n > 0) || (n == EINTR) || (n == EAGAIN))); if (n < 0) throw std::runtime_error("read failed"); } template void block_io::write_buffer(block_address location, buffer const &buffer) { off_t r; r = ::lseek(fd_, BlockSize * location, SEEK_SET); if (r == (off_t) -1) throw std::runtime_error("lseek failed"); ssize_t n; size_t remaining = BlockSize; unsigned char const *buf = buffer.raw(); do { n = ::write(fd_, buf, remaining); if (n > 0) { remaining -= n; buf += n; } } while (remaining && ((n > 0) || (n == EINTR) || (n == EAGAIN))); if (n < 0) { std::ostringstream out; out << "write failed to block " << location << ", block size = " << BlockSize << ", remaining = " << remaining << ", n = " << n << ", errno = " << errno << ", fd_ = " << fd_ << std::endl; throw std::runtime_error(out.str()); } } //---------------------------------------------------------------- template block_manager::block::block(typename block_io::ptr io, block_address location, block_type bt, typename validator::ptr v, bool zero) : io_(io), location_(location), data_(new buffer()), validator_(v), bt_(bt), dirty_(false) { if (zero) { // FIXME: duplicate memset memset(data_->raw(), 0, BlockSize); dirty_ = true; // redundant? } else { io_->read_buffer(location_, *data_); validator_->check(*data_, location_); } } template block_manager::block::~block() { flush(); } template void block_manager::block::flush() { if (dirty_) { validator_->prepare(*data_, location_); io_->write_buffer(location_, *data_); dirty_ = false; } } template void block_manager::block::change_validator(typename block_manager::validator::ptr v, bool check) { if (v.get() != validator_.get()) { if (dirty_) // It may have already happened, by calling // this we ensure we're consistent. validator_->prepare(*data_, location_); validator_ = v; if (check) validator_->check(*data_, location_); } } //---------------------------------------------------------------- template block_manager::read_ref::read_ref(block_manager const &bm, typename block::ptr b) : bm_(&bm), block_(b), holders_(new unsigned) { *holders_ = 1; } template block_manager::read_ref::read_ref(read_ref const &rhs) : bm_(rhs.bm_), block_(rhs.block_), holders_(rhs.holders_) { (*holders_)++; } template block_manager::read_ref::~read_ref() { if (!--(*holders_)) { if (block_->bt_ == BT_SUPERBLOCK) { bm_->flush(); bm_->cache_.put(block_); bm_->flush(); } else bm_->cache_.put(block_); bm_->tracker_.unlock(block_->location_); delete holders_; } } template typename block_manager::read_ref const & block_manager::read_ref::operator =(read_ref const &rhs) { if (this != &rhs) { block_ = rhs.block_; bm_ = rhs.bm_; holders_ = rhs.holders_; (*holders_)++; } return *this; } template block_address block_manager::read_ref::get_location() const { return block_->location_; } template buffer const & block_manager::read_ref::data() const { return *block_->data_; } //-------------------------------- template block_manager::write_ref::write_ref(block_manager const &bm, typename block::ptr b) : read_ref(bm, b) { b->dirty_ = true; } template buffer & block_manager::write_ref::data() { return *read_ref::block_->data_; } //---------------------------------------------------------------- template block_manager::block_manager(std::string const &path, block_address nr_blocks, unsigned max_concurrent_blocks, typename block_io::mode mode) : io_(new block_io(path, nr_blocks, mode)), cache_(max(64u, max_concurrent_blocks)), tracker_(0, nr_blocks) { } template typename block_manager::read_ref block_manager::read_lock(block_address location, typename block_manager::validator::ptr v) const { tracker_.read_lock(location); try { check(location); boost::optional cached_block = cache_.get(location); if (cached_block) { typename block::ptr cb = *cached_block; cb->check_read_lockable(); cb->change_validator(v); return read_ref(*this, *cached_block); } typename block::ptr b(new block(io_, location, BT_NORMAL, v)); cache_.insert(b); return read_ref(*this, b); } catch (...) { tracker_.unlock(location); throw; } } template typename block_manager::write_ref block_manager::write_lock(block_address location, typename block_manager::validator::ptr v) { tracker_.write_lock(location); try { check(location); boost::optional cached_block = cache_.get(location); if (cached_block) { typename block::ptr cb = *cached_block; cb->check_write_lockable(); cb->change_validator(v); return write_ref(*this, *cached_block); } typename block::ptr b(new block(io_, location, BT_NORMAL, v)); cache_.insert(b); return write_ref(*this, b); } catch (...) { tracker_.unlock(location); throw; } } template typename block_manager::write_ref block_manager::write_lock_zero(block_address location, typename block_manager::validator::ptr v) { tracker_.write_lock(location); try { check(location); boost::optional cached_block = cache_.get(location); if (cached_block) { typename block::ptr cb = *cached_block; cb->check_write_lockable(); cb->change_validator(v, false); memset((*cached_block)->data_->raw(), 0, BlockSize); return write_ref(*this, *cached_block); } typename block::ptr b(new block(io_, location, BT_NORMAL, v, true)); cache_.insert(b); return write_ref(*this, b); } catch (...) { tracker_.unlock(location); throw; } } template typename block_manager::write_ref block_manager::superblock(block_address location, typename block_manager::validator::ptr v) { tracker_.superblock_lock(location); try { check(location); boost::optional cached_block = cache_.get(location); if (cached_block) { typename block::ptr cb = *cached_block; cb->check_write_lockable(); cb->bt_ = BT_SUPERBLOCK; cb->change_validator(v); return write_ref(*this, *cached_block); } typename block::ptr b(new block(io_, location, BT_SUPERBLOCK, v)); cache_.insert(b); return write_ref(*this, b); } catch (...) { tracker_.unlock(location); throw; } } template typename block_manager::write_ref block_manager::superblock_zero(block_address location, typename block_manager::validator::ptr v) { tracker_.superblock_lock(location); try { check(location); boost::optional cached_block = cache_.get(location); if (cached_block) { typename block::ptr cb = *cached_block; cb->check_write_lockable(); cb->bt_ = BT_SUPERBLOCK; cb->change_validator(v, false); memset(cb->data_->raw(), 0, BlockSize); // FIXME: add a zero method to buffer return write_ref(*this, *cached_block); } typename block::ptr b(new block(io_, location, BT_SUPERBLOCK, v, true)); cache_.insert(b); return write_ref(*this, b); } catch (...) { tracker_.unlock(location); throw; } } template void block_manager::check(block_address b) const { if (b >= io_->get_nr_blocks()) throw std::runtime_error("block address out of bounds"); } template block_address block_manager::get_nr_blocks() const { return io_->get_nr_blocks(); } template void block_manager::write_block(typename block::ptr b) const { b->flush(); } template void block_manager::flush() const { cache_.iterate_unheld( boost::bind(&block_manager::write_block, this, _1)); } template bool block_manager::is_locked(block_address b) const { return tracker_.is_locked(b); } } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/block_counter.h000066400000000000000000000033651222772450500244730ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef BLOCK_COUNTER_H #define BLOCK_COUNTER_H #include "block.h" //---------------------------------------------------------------- namespace persistent_data { //---------------------------------------------------------------- // Little helper class that keeps track of how many times blocks // are referenced. //---------------------------------------------------------------- class block_counter { public: typedef std::map count_map; void inc(block_address b) { count_map::iterator it = counts_.find(b); if (it == counts_.end()) counts_.insert(make_pair(b, 1)); else it->second++; } unsigned get_count(block_address b) const { count_map::const_iterator it = counts_.find(b); return (it == counts_.end()) ? 0 : it->second; } count_map const &get_counts() const { return counts_; } private: count_map counts_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/buffer.h000066400000000000000000000053331222772450500231100ustar00rootroot00000000000000// Copyright (C) 2013 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef BUFFER_H #define BUFFER_H #include // #include #include #include #include #include #include #include //---------------------------------------------------------------- namespace persistent_data { uint32_t const DEFAULT_BUFFER_SIZE = 4096; // Allocate buffer of Size with Alignment imposed. // // Allocation needs to be on the heap in order to provide alignment // guarantees. // // Alignment must be a power of two. template class buffer : private boost::noncopyable { public: BOOST_STATIC_ASSERT((Alignment > 1) & !(Alignment & (Alignment - 1))); static uint32_t const ALIGNMENT = Alignment; typedef boost::shared_ptr ptr; typedef boost::shared_ptr const_ptr; size_t size() const { return Size; } unsigned char &operator[](unsigned index) { check_index(index); return data_[index]; } unsigned char const &operator[](unsigned index) const { check_index(index); return data_[index]; } unsigned char *raw() { return data_; } unsigned char const *raw() const { return data_; } static void *operator new(size_t s) { // void *r; // return posix_memalign(&r, Alignment, s) ? NULL : r; // Allocates size bytes and returns a pointer to the // allocated memory. The memory address will be a // multiple of 'Alignment', which must be a power of two void *mem = memalign(Alignment, s); if (!mem) throw std::bad_alloc(); return mem; } static void operator delete(void *p) { free(p); } private: unsigned char data_[Size]; static void check_index(unsigned index) { if (index >= Size) throw std::range_error("buffer index out of bounds"); } }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/cache.h000066400000000000000000000154121222772450500227010ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef CACHE_H #define CACHE_H #include "deleter.h" #include #include #include #include #include #include #include //---------------------------------------------------------------- namespace base { // ValueTraits needs to define value_type, key_type and a get_key() // static function. Commonly you will want value_type to be a // shared_ptr, with any teardown specific stuff in the destructor. template class cache { public: typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::key_type key_type; cache(unsigned max_entries); ~cache(); void insert(value_type const &v); boost::optional get(key_type const &k); void put(value_type const &k); template void iterate_unheld(T fn) const; private: void make_space(); struct value_entry { // FIXME: this means the cached object must have a // default constructor also, which is a shame. // so we can construct the headers. value_entry() : ref_count_(1) { } explicit value_entry(value_type v) : ref_count_(1), v_(v) { } struct lru { lru() : next_(0), prev_(0) { } value_entry *next_, *prev_; }; struct lookup { lookup() : parent_(0), left_(0), right_(0), color_() { } value_entry *parent_, *left_, *right_; int color_; }; lru lru_; lookup lookup_; unsigned ref_count_; value_type v_; }; struct value_ptr_cmp { bool operator() (value_entry const *lhs, value_entry const *rhs) { key_type k1 = ValueTraits::get_key(lhs->v_); key_type k2 = ValueTraits::get_key(rhs->v_); return k1 < k2; } }; struct key_value_ptr_cmp { bool operator() (key_type const &k1, value_entry const *rhs) { key_type k2 = ValueTraits::get_key(rhs->v_); return k1 < k2; } bool operator() (value_entry const *lhs, key_type const &k2) { key_type k1 = ValueTraits::get_key(lhs->v_); return k1 < k2; } }; struct list_node_traits { typedef value_entry node; typedef value_entry *node_ptr; typedef const value_entry *const_node_ptr; static node_ptr get_next(const_node_ptr n) { return n->lru_.next_; } static void set_next(node_ptr n, node_ptr next) { n->lru_.next_ = next; } static node_ptr get_previous(const_node_ptr n) { return n->lru_.prev_; } static void set_previous(node_ptr n, node_ptr prev) { n->lru_.prev_ = prev; } }; struct rbtree_node_traits { typedef value_entry node; typedef value_entry *node_ptr; typedef const value_entry * const_node_ptr; typedef int color; static node_ptr get_parent(const_node_ptr n) { return n->lookup_.parent_; } static void set_parent(node_ptr n, node_ptr parent) { n->lookup_.parent_ = parent; } static node_ptr get_left(const_node_ptr n) { return n->lookup_.left_; } static void set_left(node_ptr n, node_ptr left) { n->lookup_.left_ = left; } static node_ptr get_right(const_node_ptr n) { return n->lookup_.right_; } static void set_right(node_ptr n, node_ptr right) { n->lookup_.right_ = right; } static int get_color(const_node_ptr n) { return n->lookup_.color_; } static void set_color(node_ptr n, color c) { n->lookup_.color_ = c; } static color red() { return 0; } static color black() { return 1; } }; typedef boost::intrusive::circular_list_algorithms lru_algo; typedef boost::intrusive::rbtree_algorithms lookup_algo; unsigned max_entries_; unsigned current_entries_; value_entry lru_header_; value_entry lookup_header_; }; template cache::cache(unsigned max_entries) : max_entries_(max_entries), current_entries_(0) { lru_algo::init_header(&lru_header_); lookup_algo::init_header(&lookup_header_); } template cache::~cache() { utils::deleter d; lookup_algo::clear_and_dispose(&lookup_header_, d); } template void cache::insert(value_type const &v) { make_space(); std::auto_ptr node(new value_entry(v)); value_ptr_cmp cmp; lookup_algo::insert_equal(&lookup_header_, &lookup_header_, node.get(), cmp); node.release(); current_entries_++; } template boost::optional cache::get(key_type const &k) { key_value_ptr_cmp cmp; value_entry *node = lookup_algo::find(&lookup_header_, k, cmp); if (node == &lookup_header_) return boost::optional(); if (!node->ref_count_++) lru_algo::unlink(node); return boost::optional(node->v_); } template void cache::put(value_type const &v) { // FIXME: the lookup will go once we use a proper hook key_value_ptr_cmp cmp; key_type k = ValueTraits::get_key(v); value_entry *node = lookup_algo::find(&lookup_header_, k, cmp); if (node == &lookup_header_) throw std::runtime_error("invalid put"); if (node->ref_count_ == 0) throw std::runtime_error("invalid put"); if (!--node->ref_count_) lru_algo::link_after(&lru_header_, node); } template void cache::make_space() { if (current_entries_ == max_entries_) { value_entry *node = lru_header_.lru_.prev_; if (node == &lru_header_) throw std::runtime_error("cache full"); lru_algo::unlink(node); lookup_algo::unlink(node); delete node; current_entries_--; } } template template void cache::iterate_unheld(T fn) const { value_entry *n = lru_header_.lru_.next_; while (n != &lru_header_) { fn(n->v_); n = n->lru_.next_; } } } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/checksum.cc000066400000000000000000000025331222772450500235760ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "checksum.h" #include using namespace base; //---------------------------------------------------------------- crc32c::crc32c(uint32_t xor_value) : xor_value_(xor_value), sum_(0) { } void crc32c::append(void const *buffer, unsigned len) { uint32_t const powers = 0x1EDC6F41; boost::crc_basic<32> crc(powers, 0xffffffff, 0, true, true); crc.process_bytes(buffer, len); sum_ = crc.checksum(); } uint32_t crc32c::get_sum() const { return sum_ ^ xor_value_; } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/checksum.h000066400000000000000000000023011222772450500234310ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef CHECKSUM_H #define CHECKSUM_H #include //---------------------------------------------------------------- namespace base { class crc32c { public: crc32c(uint32_t xor_value); void append(void const *buffer, unsigned len); uint32_t get_sum() const; private: uint32_t xor_value_; uint32_t sum_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/data-structures/000077500000000000000000000000001222772450500246145ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/persistent-data/data-structures/array.h000066400000000000000000000262001222772450500261030ustar00rootroot00000000000000// Copyright (C) 2012 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef ARRAY_H #define ARRAY_H #include "persistent-data/math_utils.h" #include "persistent-data/data-structures/btree.h" #include "persistent-data/data-structures/btree_damage_visitor.h" #include "persistent-data/data-structures/array_block.h" //---------------------------------------------------------------- namespace persistent_data { namespace array_detail { uint32_t const ARRAY_CSUM_XOR = 595846735; struct array_block_validator : public block_manager<>::validator { virtual void check(buffer<> const &b, block_address location) const { array_block_disk const *data = reinterpret_cast(&b); crc32c sum(ARRAY_CSUM_XOR); sum.append(&data->max_entries, MD_BLOCK_SIZE - sizeof(uint32_t)); if (sum.get_sum() != to_cpu(data->csum)) throw checksum_error("bad checksum in array block node"); if (to_cpu(data->blocknr) != location) throw checksum_error("bad block nr in array block"); } virtual void prepare(buffer<> &b, block_address location) const { array_block_disk *data = reinterpret_cast(&b); data->blocknr = to_disk(location); crc32c sum(ARRAY_CSUM_XOR); sum.append(&data->max_entries, MD_BLOCK_SIZE - sizeof(uint32_t)); data->csum = to_disk(sum.get_sum()); } }; struct array_dim { array_dim(unsigned nr_entries, unsigned entries_per_block) : nr_full_blocks(nr_entries / entries_per_block), nr_entries_in_last_block(nr_entries % entries_per_block), nr_total_blocks(nr_full_blocks + (nr_entries_in_last_block ? 1 : 0)) { } unsigned nr_full_blocks; unsigned nr_entries_in_last_block; unsigned nr_total_blocks; }; struct damage { typedef boost::shared_ptr ptr; damage(run lost_keys, std::string const &desc) : lost_keys_(lost_keys), desc_(desc) { } run lost_keys_; std::string desc_; }; inline std::ostream &operator <<(std::ostream &out, damage const &d) { out << "array damage[lost_keys = " << d.lost_keys_ << ", \"" << d.desc_ << "\"]"; return out; } } class array_base { public: virtual ~array_base() {} virtual void set_root(block_address root) = 0; virtual block_address get_root() const = 0; }; template class array : public array_base { public: class block_ref_counter : public ref_counter { public: block_ref_counter(space_map::ptr sm, array &a) : sm_(sm), a_(a) { } virtual void set(uint64_t b, uint32_t rc) { sm_->set_count(b, rc); if (rc == 0) dec_values(b); } virtual void inc(uint64_t b) { sm_->inc(b); } virtual void dec(uint64_t b) { sm_->dec(b); if (sm_->get_count(b) == 0) dec_values(b); } private: void dec_values(uint64_t b) { a_.dec_ablock_entries(b); } space_map::ptr sm_; array &a_; }; friend class block_ref_counter; struct block_traits { typedef base::le64 disk_type; typedef block_address value_type; typedef block_ref_counter ref_counter; static void unpack(disk_type const &disk, value_type &value) { value = base::to_cpu(disk); } static void pack(value_type const &value, disk_type &disk) { disk = base::to_disk(value); } }; template struct block_value_visitor { block_value_visitor(array const &a, ValueVisitor &vv) : a_(a), vv_(vv) { } void visit(btree_path const &p, typename block_traits::value_type const &v) { a_.visit_value(vv_, p, v); } private: array const &a_; ValueVisitor &vv_; }; template void visit_value(ValueVisitor &vv, btree_path const &p, typename block_traits::value_type const &v) const { rblock rb(tm_->read_lock(v, validator_), rc_); for (uint32_t i = 0; i < rb.nr_entries(); i++) vv.visit(p[0] * rb.max_entries() + i, rb.get(i)); } template struct block_damage_visitor { block_damage_visitor(DamageVisitor &dv, unsigned entries_per_block) : dv_(dv), entries_per_block_(entries_per_block) { } void visit(btree_path const &path, btree_detail::damage const &d) { dv_.visit(array_detail::damage(convert_run(d.lost_keys_), d.desc_)); } private: run::maybe convert_maybe(run::maybe const &v) const { if (v) return run::maybe(*v * entries_per_block_); return run::maybe(); } run convert_run(run const &v) const { return run(convert_maybe(v.begin_), convert_maybe(v.end_)); } DamageVisitor &dv_; unsigned entries_per_block_; }; typedef typename persistent_data::transaction_manager::ptr tm_ptr; typedef block_manager<>::write_ref write_ref; typedef block_manager<>::read_ref read_ref; typedef array_block::write_ref> wblock; typedef array_block::read_ref> rblock; typedef boost::shared_ptr > ptr; typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::ref_counter ref_counter; array(tm_ptr tm, ref_counter rc) : tm_(tm), entries_per_block_(rblock::calc_max_entries()), nr_entries_(0), block_rc_(tm->get_sm(), *this), block_tree_(tm, block_rc_), rc_(rc), validator_(new array_detail::array_block_validator) { } array(tm_ptr tm, ref_counter rc, block_address root, unsigned nr_entries) : tm_(tm), entries_per_block_(rblock::calc_max_entries()), nr_entries_(nr_entries), block_rc_(tm->get_sm(), *this), block_tree_(tm, root, block_rc_), rc_(rc), validator_(new array_detail::array_block_validator) { } unsigned get_nr_entries() const { return nr_entries_; } // FIXME: why is this needed? void set_root(block_address root) { block_tree_.set_root(root); } block_address get_root() const { return block_tree_.get_root(); } void destroy() { block_tree_.destroy(); // FIXME: not implemented } void grow(unsigned new_nr_entries, value_type const &v) { resizer r(*this, nr_entries_, new_nr_entries, entries_per_block_, v); r.grow(new_nr_entries, v); } value_type get(unsigned index) const { rblock b = get_ablock(index / entries_per_block_); return b.get(index % entries_per_block_); } void set(unsigned index, value_type const &value) { wblock b = shadow_ablock(index / entries_per_block_); b.set(index % entries_per_block_, value); } template void visit_values(ValueVisitor &value_visitor, DamageVisitor &damage_visitor) const { block_counter counter; block_value_visitor bvisitor(*this, value_visitor); block_damage_visitor dvisitor(damage_visitor, entries_per_block_); btree_visit_values(block_tree_, counter, bvisitor, dvisitor); } private: struct resizer { resizer(array &a, unsigned old_size, unsigned new_size, unsigned entries_per_block, typename ValueTraits::value_type const &v) : a_(a), old_dim_(old_size, entries_per_block), new_dim_(new_size, entries_per_block), entries_per_block_(entries_per_block), v_(v) { } void grow(unsigned new_nr_entries, value_type const &v) { if (new_dim_.nr_full_blocks > old_dim_.nr_full_blocks) grow_needs_more_blocks(); else if (old_dim_.nr_entries_in_last_block > 0) grow_extend_tail_block(new_dim_.nr_entries_in_last_block); else if (new_dim_.nr_entries_in_last_block) grow_add_tail_block(); a_.nr_entries_ = new_nr_entries; } private: void insert_full_ablocks(unsigned begin_index, unsigned end_index) { while (begin_index != end_index) { wblock b = a_.new_ablock(begin_index); b.grow(entries_per_block_, v_); begin_index++; } } void grow_add_tail_block() { wblock b = a_.new_ablock(new_dim_.nr_full_blocks); b.grow(new_dim_.nr_entries_in_last_block, v_); } void grow_needs_more_blocks() { if (old_dim_.nr_entries_in_last_block > 0) grow_extend_tail_block(entries_per_block_); insert_full_ablocks(old_dim_.nr_total_blocks, new_dim_.nr_full_blocks); if (new_dim_.nr_entries_in_last_block > 0) grow_add_tail_block(); } void grow_extend_tail_block(unsigned new_nr_entries) { uint64_t last_block = a_.nr_entries_ / entries_per_block_; wblock b = a_.shadow_ablock(last_block); b.grow(new_nr_entries, v_); } array &a_; array_detail::array_dim old_dim_; array_detail::array_dim new_dim_; unsigned entries_per_block_; typename ValueTraits::value_type const &v_; }; friend class resizer; //-------------------------------- block_address lookup_block_address(unsigned array_index) const { uint64_t key[1] = {array_index}; boost::optional addr = block_tree_.lookup(key); if (!addr) { std::ostringstream str; str << "lookup of array block " << array_index << " failed"; throw runtime_error(str.str()); } return *addr; } wblock new_ablock(unsigned ablock_index) { uint64_t key[1] = {ablock_index}; write_ref b = tm_->new_block(validator_); block_address location = b.get_location(); wblock wb(b, rc_); wb.setup_empty(); block_tree_.insert(key, location); return wblock(b, rc_); } rblock get_ablock(unsigned ablock_index) const { block_address addr = lookup_block_address(ablock_index); return rblock(tm_->read_lock(addr, validator_), rc_); } wblock shadow_ablock(unsigned ablock_index) { uint64_t key[1] = {ablock_index}; block_address addr = lookup_block_address(ablock_index); std::pair p = tm_->shadow(addr, validator_); wblock wb = wblock(p.first, rc_); if (p.second) wb.inc_all_entries(); block_tree_.insert(key, p.first.get_location()); return wb; } void dec_ablock_entries(block_address addr) { rblock b(tm_->read_lock(addr, validator_), rc_); b.dec_all_entries(); } tm_ptr tm_; unsigned entries_per_block_; unsigned nr_entries_; block_ref_counter block_rc_; btree<1, block_traits> block_tree_; typename ValueTraits::ref_counter rc_; block_manager<>::validator::ptr validator_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/data-structures/array_block.h000066400000000000000000000123351222772450500272610ustar00rootroot00000000000000// Copyright (C) 2012 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef ARRAY_BLOCK_H #define ARRAY_BLOCK_H #include "persistent-data/endian_utils.h" //---------------------------------------------------------------- namespace persistent_data { struct array_block_disk { base::le32 csum; base::le32 max_entries; base::le32 nr_entries; base::le32 value_size; base::le64 blocknr; } __attribute__((packed)); // RefType should be either a read_ref or write_ref from block_manager template class array_block { public: typedef boost::shared_ptr ptr; typedef typename ValueTraits::disk_type disk_type; typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::ref_counter ref_counter; enum block_state { BLOCK_NEW, BLOCK_EXISTS }; array_block(RefType ref, ref_counter rc) : ref_(ref), rc_(rc) { } // I hate separate initialisation. But we can't have the // constructor using non-const methods (get_header()) // otherwise we can't instance this with a read_ref. void setup_empty() { using namespace base; struct array_block_disk *header = get_header(); header->max_entries = to_disk(calc_max_entries()); header->nr_entries = to_disk(static_cast(0)); header->value_size = to_disk(static_cast(sizeof(disk_type))); } uint32_t max_entries() const { return base::to_cpu(get_header()->max_entries); } uint32_t nr_entries() const { return base::to_cpu(get_header()->nr_entries); } uint32_t value_size() const { return base::to_cpu(get_header()->value_size); } void grow(uint32_t nr, value_type const &default_value) { uint32_t old_nr = nr_entries(); if (nr > max_entries()) { std::ostringstream out; out << "array_block::grow called with more than max_entries (" << nr << " > " << max_entries(); throw runtime_error(out.str()); } if (nr <= old_nr) throw runtime_error("array_block grow method called with smaller size"); grow_(nr, default_value); } void shrink(uint32_t nr) { uint32_t old_nr = nr_entries(); if (nr >= old_nr) throw runtime_error("array_block shrink called with larger size"); shrink_(nr); } value_type get(unsigned index) const { value_type v; ValueTraits::unpack(element_at(index), v); return v; } void set(unsigned index, value_type const &new_value) { value_type const old_value = get(index); rc_.inc(new_value); ValueTraits::pack(new_value, element_at(index)); rc_.dec(old_value); } void inc_all_entries() { unsigned e = nr_entries(); for (unsigned index = 0; index < e; index++) rc_.inc(get(index)); } void dec_all_entries() { unsigned e = nr_entries(); for (unsigned index = 0; index < e; index++) rc_.dec(get(index)); } ref_counter const &get_ref_counter() const { return rc_; } static uint32_t calc_max_entries() { return (RefType::BLOCK_SIZE - sizeof(array_block_disk)) / sizeof(typename ValueTraits::disk_type); } private: void set_nr_entries(uint32_t nr) { using namespace base; array_block_disk *h = get_header(); h->nr_entries = to_disk(nr); } void grow_(uint32_t nr, value_type const &default_value) { uint32_t old_nr_entries = nr_entries(); set_nr_entries(nr); for (unsigned i = old_nr_entries; i < nr; i++) { ValueTraits::pack(default_value, element_at(i)); rc_.inc(default_value); } } void shrink_(uint32_t nr) { for (unsigned i = nr_entries() - 1; i >= nr; i--) rc_.dec(get(i)); set_nr_entries(nr); } array_block_disk *get_header() { return reinterpret_cast(ref_.data().raw()); } array_block_disk const *get_header() const { return reinterpret_cast(ref_.data().raw()); } disk_type &element_at(unsigned int index) { if (index >= nr_entries()) throw runtime_error("array_block index out of bounds"); array_block_disk *a = get_header(); disk_type *elts = reinterpret_cast(a + 1); return elts[index]; } disk_type const &element_at(unsigned int index) const { if (index >= nr_entries()) throw runtime_error("array_block index out of bounds"); array_block_disk const *a = get_header(); disk_type const *elts = reinterpret_cast(a + 1); return elts[index]; } RefType ref_; ref_counter rc_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/data-structures/bitset.cc000066400000000000000000000124361222772450500264230ustar00rootroot00000000000000#include "persistent-data/data-structures/array.h" #include "persistent-data/data-structures/bitset.h" #include "persistent-data/math_utils.h" using namespace boost; using namespace persistent_data; using namespace persistent_data::bitset_detail; using namespace std; //---------------------------------------------------------------- namespace { struct bitset_traits { typedef base::le64 disk_type; typedef uint64_t value_type; typedef no_op_ref_counter ref_counter; static void unpack(disk_type const &disk, value_type &value) { value = base::to_cpu(disk); } static void pack(value_type const &value, disk_type &disk) { disk = base::to_disk(value); } }; } namespace persistent_data { namespace bitset_detail { class bitset_impl { public: typedef boost::shared_ptr ptr; typedef typename persistent_data::transaction_manager::ptr tm_ptr; bitset_impl(tm_ptr tm) : nr_bits_(0), array_(tm, rc_) { } bitset_impl(tm_ptr tm, block_address root, unsigned nr_bits) : nr_bits_(nr_bits), array_(tm, rc_, root, nr_bits) { } block_address get_root() const { return array_.get_root(); } void grow(unsigned new_nr_bits, bool default_value) { pad_last_block(default_value); resize_array(new_nr_bits, default_value); nr_bits_ = new_nr_bits; } void destroy() { throw runtime_error("bitset.destroy() not implemented"); } // May trigger a flush, so cannot be const bool get(unsigned n) { check_bounds(n); return get_bit(array_.get(word(n)), bit(n)); } void set(unsigned n, bool value) { check_bounds(n); unsigned w_index = word(n); uint64_t w = array_.get(w_index); if (value) w = set_bit(w, bit(n)); else w = clear_bit(w, bit(n)); array_.set(w_index, w); } void flush() { } void walk_bitset(bitset_visitor &v) const { bit_visitor vv(v); damage_visitor dv(v); array_.visit_values(vv, dv); } private: class bit_visitor { public: bit_visitor(bitset_visitor &v) : v_(v) { } void visit(uint32_t word_index, uint64_t word) { uint32_t bit_index = word_index * 64; for (unsigned bit = 0; bit < 64; bit++, bit_index++) v_.visit(bit_index, !!(word & (1 << bit))); } private: bitset_visitor &v_; }; class damage_visitor { public: damage_visitor(bitset_visitor &v) : v_(v) { } void visit(array_detail::damage const &d) { run bits(lifted_mult64(d.lost_keys_.begin_), lifted_mult64(d.lost_keys_.end_)); v_.visit(bits); } private: optional lifted_mult64(optional const &m) { if (!m) return m; return optional(*m * 64); } bitset_visitor &v_; }; void pad_last_block(bool default_value) { // Set defaults in the final word if (bit(nr_bits_)) { unsigned w_index = word(nr_bits_); uint64_t w = array_.get(w_index); for (unsigned b = bit(nr_bits_); b < 64; b++) if (default_value) w = set_bit(w, b); else w = clear_bit(w, b); array_.set(w_index, w); } } void resize_array(unsigned new_nr_bits, bool default_value) { unsigned old_nr_words = words_needed(nr_bits_); unsigned new_nr_words = words_needed(new_nr_bits); if (new_nr_words < old_nr_words) throw runtime_error("bitset grow actually asked to shrink"); if (new_nr_words > old_nr_words) array_.grow(new_nr_words, default_value ? ~0 : 0); } unsigned words_needed(unsigned nr_bits) const { return base::div_up(nr_bits, 64u); } unsigned word(unsigned bit) const { return bit / 64; } uint64_t mask(unsigned bit) const { return 1ull << bit; } bool get_bit(uint64_t w, unsigned bit) const { return w & mask(bit); } uint64_t set_bit(uint64_t w, unsigned bit) const { return w | mask(bit); } uint64_t clear_bit(uint64_t w, unsigned bit) const { return w & (~mask(bit)); } unsigned bit(unsigned bit) const { return bit % 64; } // The last word may be only partially full, so we have to // do our own bounds checking rather than relying on array // to do it. void check_bounds(unsigned n) const { if (n >= nr_bits_) { std::ostringstream str; str << "bitset index out of bounds (" << n << " >= " << nr_bits_ << endl; throw runtime_error(str.str()); } } unsigned nr_bits_; no_op_ref_counter rc_; array array_; }; } } //---------------------------------------------------------------- bitset::bitset(tm_ptr tm) : impl_(new bitset_impl(tm)) { } bitset::bitset(tm_ptr tm, block_address root, unsigned nr_bits) : impl_(new bitset_impl(tm, root, nr_bits)) { } block_address bitset::get_root() const { return impl_->get_root(); } void bitset::grow(unsigned new_nr_bits, bool default_value) { impl_->grow(new_nr_bits, default_value); } void bitset::destroy() { impl_->destroy(); } bool bitset::get(unsigned n) { return impl_->get(n); } void bitset::set(unsigned n, bool value) { impl_->set(n, value); } void bitset::flush() { impl_->flush(); } void bitset::walk_bitset(bitset_visitor &v) const { impl_->walk_bitset(v); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/data-structures/bitset.h000066400000000000000000000040021222772450500262530ustar00rootroot00000000000000// Copyright (C) 2013 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef BITSET_H #define BITSET_H #include "persistent-data/run.h" //---------------------------------------------------------------- namespace persistent_data { namespace bitset_detail { class bitset_impl; class missing_bits { public: missing_bits(base::run const &keys) : keys_(keys) { } base::run keys_; }; class bitset_visitor { public: typedef boost::shared_ptr ptr; virtual ~bitset_visitor() {} virtual void visit(uint32_t index, bool value) = 0; virtual void visit(missing_bits const &d) = 0; }; } class bitset { public: typedef boost::shared_ptr ptr; typedef typename persistent_data::transaction_manager::ptr tm_ptr; bitset(tm_ptr tm); bitset(tm_ptr tm, block_address root, unsigned nr_bits); block_address get_root() const; void grow(unsigned new_nr_bits, bool default_value); void destroy(); // May trigger a flush, so cannot be const bool get(unsigned n); void set(unsigned n, bool value); void flush(); void walk_bitset(bitset_detail::bitset_visitor &v) const; private: boost::shared_ptr impl_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/data-structures/btree.cc000066400000000000000000000010231222772450500262200ustar00rootroot00000000000000#include "persistent-data/data-structures/btree.h" using namespace persistent_data; //---------------------------------------------------------------- block_ref_counter::block_ref_counter(space_map::ptr sm) : sm_(sm) { } void block_ref_counter::set(block_address const &b, uint32_t rc) { sm_->set_count(b, rc); } void block_ref_counter::inc(block_address const &b) { sm_->inc(b); } void block_ref_counter::dec(block_address const &b) { sm_->dec(b); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/data-structures/btree.h000066400000000000000000000277111222772450500260760ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef BTREE_H #define BTREE_H #include "persistent-data/endian_utils.h" #include "persistent-data/transaction_manager.h" #include "persistent-data/data-structures/ref_counter.h" #include #include #include #include //---------------------------------------------------------------- namespace persistent_data { class block_ref_counter : public ref_counter { public: block_ref_counter(space_map::ptr sm); virtual void set(block_address const &v, uint32_t rc); virtual void inc(block_address const &v); virtual void dec(block_address const &v); private: space_map::ptr sm_; }; // FIXME: move to sep file. I don't think it's directly used by // the btree code. struct uint64_traits { typedef base::le64 disk_type; typedef uint64_t value_type; typedef no_op_ref_counter ref_counter; static void unpack(disk_type const &disk, value_type &value) { value = base::to_cpu(disk); } static void pack(value_type const &value, disk_type &disk) { disk = base::to_disk(value); } }; struct block_traits { typedef base::le64 disk_type; typedef block_address value_type; typedef block_ref_counter ref_counter; static void unpack(disk_type const &disk, value_type &value) { value = base::to_cpu(disk); } static void pack(value_type const &value, disk_type &disk) { disk = base::to_disk(value); } }; namespace btree_detail { using namespace base; using namespace std; uint32_t const BTREE_CSUM_XOR = 121107; //------------------------------------------------ // On disk data layout for btree nodes enum node_flags { INTERNAL_NODE = 1, LEAF_NODE = 1 << 1 }; struct node_header { le32 csum; le32 flags; le64 blocknr; /* which block this node is supposed to live in */ le32 nr_entries; le32 max_entries; le32 value_size; le32 padding; } __attribute__((packed)); struct disk_node { struct node_header header; le64 keys[0]; } __attribute__((packed)); enum node_type { INTERNAL, LEAF }; //------------------------------------------------ // Class that acts as an interface over the raw little endian btree // node data. template class node_ref { public: explicit node_ref(block_address b, disk_node *raw); uint32_t get_checksum() const; block_address get_location() const { return location_; } block_address get_block_nr() const; node_type get_type() const; void set_type(node_type t); unsigned get_nr_entries() const; void set_nr_entries(unsigned n); unsigned get_max_entries() const; void set_max_entries(unsigned n); // FIXME: remove this, and get the constructor to do it. void set_max_entries(); // calculates the max for you. size_t get_value_size() const; void set_value_size(size_t); uint64_t key_at(unsigned i) const; void set_key(unsigned i, uint64_t k); typename ValueTraits::value_type value_at(unsigned i) const; void set_value(unsigned i, typename ValueTraits::value_type const &v); // Increments the nr_entries field void insert_at(unsigned i, uint64_t key, typename ValueTraits::value_type const &v); // Does not increment nr_entries void overwrite_at(unsigned i, uint64_t key, typename ValueTraits::value_type const &v); // Copies entries from another node, appends them // to the back of this node. Adjusts nr_entries. void copy_entries(node_ref const &rhs, unsigned begin, unsigned end); // Various searches int bsearch(uint64_t key, int want_hi) const; boost::optional exact_search(uint64_t key) const; int lower_bound(uint64_t key) const; template void inc_children(RefCounter &rc); disk_node *raw() { return raw_; } disk_node const *raw() const { return raw_; } private: static unsigned calc_max_entries(void); void *key_ptr(unsigned i) const; void *value_ptr(unsigned i) const; block_address location_; disk_node *raw_; }; //------------------------------------------------ // template node_ref to_node(typename block_manager<>::read_ref &b) { // FIXME: this should return a const read_ref somehow. return node_ref( b.get_location(), reinterpret_cast( const_cast(b.data().raw()))); } template node_ref to_node(typename block_manager<>::write_ref &b) { return node_ref( b.get_location(), reinterpret_cast( const_cast(b.data().raw()))); } class ro_spine : private boost::noncopyable { public: ro_spine(transaction_manager::ptr tm, block_manager<>::validator::ptr v) : tm_(tm), validator_(v) { } void step(block_address b); template node_ref get_node() { return to_node(spine_.back()); } private: transaction_manager::ptr tm_; block_manager<>::validator::ptr validator_; std::list::read_ref> spine_; }; class shadow_spine : private boost::noncopyable { public: typedef transaction_manager::read_ref read_ref; typedef transaction_manager::write_ref write_ref; typedef boost::optional maybe_block; shadow_spine(transaction_manager::ptr tm, block_manager<>::validator::ptr v) : tm_(tm), validator_(v) { } // true if the children of the shadow need incrementing bool step(block_address b); void step(transaction_manager::write_ref b) { spine_.push_back(b); if (spine_.size() == 1) root_ = spine_.front().get_location(); else if (spine_.size() > 2) spine_.pop_front(); } void pop() { spine_.pop_back(); } template node_ref get_node() { return to_node(spine_.back()); } block_address get_block() const { return spine_.back().get_location(); } bool has_parent() const { return spine_.size() > 1; } node_ref get_parent() { if (spine_.size() < 2) throw std::runtime_error("no parent"); return to_node(spine_.front()); } block_address get_parent_location() const { return spine_.front().get_location(); } block_address get_root() const { if (root_) return *root_; throw std::runtime_error("shadow spine has no root"); } private: transaction_manager::ptr tm_; block_manager<>::validator::ptr validator_; std::list::write_ref> spine_; maybe_block root_; }; // Used to keep a record of a nested btree's position. typedef std::vector btree_path; // Used when visiting the nodes that make up a btree. struct node_location { node_location() : depth(0) { } void inc_depth() { depth++; } void push_key(uint64_t k) { path.push_back(k); depth = 0; } bool is_sub_root() const { return depth == 0; // && path.size(); } unsigned level() const { return path.size(); } // Keys used to access this sub tree btree_path path; // in this sub tree unsigned depth; // This is the key from the parent node to this // node. If this node is a root then there will be // no parent, and hence no key. boost::optional key; }; } template class btree { public: typedef boost::shared_ptr > ptr; typedef uint64_t key[Levels]; typedef typename ValueTraits::value_type value_type; typedef boost::optional maybe_value; typedef boost::optional > maybe_pair; typedef typename block_manager<>::read_ref read_ref; typedef typename block_manager<>::write_ref write_ref; typedef typename btree_detail::node_ref leaf_node; typedef typename btree_detail::node_ref internal_node; btree(typename persistent_data::transaction_manager::ptr tm, typename ValueTraits::ref_counter rc); btree(typename transaction_manager::ptr tm, block_address root, typename ValueTraits::ref_counter rc); ~btree(); maybe_value lookup(key const &key) const; maybe_pair lookup_le(key const &key) const; maybe_pair lookup_ge(key const &key) const; void insert(key const &key, typename ValueTraits::value_type const &value); void remove(key const &key); void set_root(block_address root); block_address get_root() const; ptr clone() const; // free the on disk btree when the destructor is called void destroy(); // Derive a class from this base class if you need to // inspect the individual nodes that make up a btree. class visitor { public: typedef boost::shared_ptr ptr; typedef btree_detail::node_location node_location; virtual ~visitor() {} // The bool return values indicate whether the walk // should be continued into sub trees of the node (true == continue). virtual bool visit_internal(node_location const &l, internal_node const &n) = 0; virtual bool visit_internal_leaf(node_location const &l, internal_node const &n) = 0; virtual bool visit_leaf(node_location const &l, leaf_node const &n) = 0; virtual void visit_complete() {} enum error_outcome { EXCEPTION_HANDLED, RETHROW_EXCEPTION }; virtual error_outcome error_accessing_node(node_location const &l, block_address b, std::string const &what) { return RETHROW_EXCEPTION; } }; // Walks the tree in depth first order void visit_depth_first(visitor &visitor) const; private: template boost::optional lookup_raw(btree_detail::ro_spine &spine, block_address block, uint64_t key) const; template void split_node(btree_detail::shadow_spine &spine, block_address parent_index, uint64_t key, bool top); template void split_beneath(btree_detail::shadow_spine &spine, uint64_t key); template void split_sibling(btree_detail::shadow_spine &spine, block_address parent_index, uint64_t key); template bool insert_location(btree_detail::shadow_spine &spine, block_address block, uint64_t key, int *index, RC &leaf_rc); void walk_tree(visitor &visitor, btree_detail::node_location const &loc, block_address b) const; void walk_tree_internal(visitor &visitor, btree_detail::node_location const &loc, block_address b) const; template void inc_children(btree_detail::shadow_spine &spine, RefCounter &leaf_rc); typename persistent_data::transaction_manager::ptr tm_; bool destroy_; block_address root_; block_ref_counter internal_rc_; typename ValueTraits::ref_counter rc_; typename block_manager<>::validator::ptr validator_; }; }; #include "btree.tcc" //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/data-structures/btree.tcc000066400000000000000000000513771222772450500264250ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "btree.h" #include "persistent-data/errors.h" #include "persistent-data/checksum.h" #include "persistent-data/transaction_manager.h" #include //---------------------------------------------------------------- namespace { using namespace base; using namespace persistent_data; using namespace btree_detail; using namespace std; struct btree_node_validator : public block_manager<>::validator { virtual void check(buffer<> const &b, block_address location) const { disk_node const *data = reinterpret_cast(&b); node_header const *n = &data->header; crc32c sum(BTREE_CSUM_XOR); sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); if (sum.get_sum() != to_cpu(n->csum)) throw checksum_error("bad checksum in btree node"); if (to_cpu(n->blocknr) != location) throw checksum_error("bad block nr in btree node"); } virtual void prepare(buffer<> &b, block_address location) const { disk_node *data = reinterpret_cast(&b); node_header *n = &data->header; n->blocknr = to_disk(location); crc32c sum(BTREE_CSUM_XOR); sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t)); n->csum = to_disk(sum.get_sum()); } }; } //---------------------------------------------------------------- namespace persistent_data { inline void ro_spine::step(block_address b) { spine_.push_back(tm_->read_lock(b, validator_)); if (spine_.size() > 2) spine_.pop_front(); } inline bool shadow_spine::step(block_address b) { pair p = tm_->shadow(b, validator_); try { step(p.first); } catch (...) { tm_->get_sm()->dec(p.first.get_location()); throw; } return p.second; } //---------------------------------------------------------------- template node_ref::node_ref(block_address location, disk_node *raw) : location_(location), raw_(raw) { } template uint32_t node_ref::get_checksum() const { return to_cpu(raw_->header.csum); } template block_address node_ref::get_block_nr() const { return to_cpu(raw_->header.blocknr); } template btree_detail::node_type node_ref::get_type() const { uint32_t flags = to_cpu(raw_->header.flags); if (flags & INTERNAL_NODE) { if (flags & LEAF_NODE) throw runtime_error("btree node is both internal and leaf"); return INTERNAL; } else if (flags & LEAF_NODE) return LEAF; else throw runtime_error("unknown node type"); } template void node_ref::set_type(node_type t) { uint32_t flags = to_cpu(raw_->header.flags); switch (t) { case INTERNAL: flags = INTERNAL_NODE; break; case LEAF: flags = LEAF_NODE; break; } raw_->header.flags = to_disk(flags); } template unsigned node_ref::get_nr_entries() const { return to_cpu(raw_->header.nr_entries); } template void node_ref::set_nr_entries(unsigned n) { raw_->header.nr_entries = to_disk(n); } template unsigned node_ref::get_max_entries() const { return to_cpu(raw_->header.max_entries); } template void node_ref::set_max_entries(unsigned n) { raw_->header.max_entries = to_disk(n); } template void node_ref::set_max_entries() { set_max_entries(calc_max_entries()); } template size_t node_ref::get_value_size() const { return to_cpu(raw_->header.value_size); } template void node_ref::set_value_size(size_t s) { raw_->header.value_size = to_disk(static_cast(s)); } template uint64_t node_ref::key_at(unsigned i) const { if (i >= get_nr_entries()) throw runtime_error("key index out of bounds"); return to_cpu(raw_->keys[i]); } template void node_ref::set_key(unsigned i, uint64_t k) { raw_->keys[i] = to_disk(k); } template typename ValueTraits::value_type node_ref::value_at(unsigned i) const { if (i >= get_nr_entries()) throw runtime_error("value index out of bounds"); // We have to copy because of alignment issues. typename ValueTraits::disk_type d; ::memcpy(&d, value_ptr(i), sizeof(d)); typename ValueTraits::value_type v; ValueTraits::unpack(d, v); return v; } template void node_ref::set_value(unsigned i, typename ValueTraits::value_type const &v) { typename ValueTraits::disk_type d; ValueTraits::pack(v, d); ::memcpy(value_ptr(i), &d, sizeof(d)); } template void node_ref::insert_at(unsigned i, uint64_t key, typename ValueTraits::value_type const &v) { unsigned n = get_nr_entries(); if ((n + 1) > get_max_entries()) throw runtime_error("too many entries"); set_nr_entries(n + 1); ::memmove(key_ptr(i + 1), key_ptr(i), sizeof(uint64_t) * (n - i)); ::memmove(value_ptr(i + 1), value_ptr(i), sizeof(typename ValueTraits::disk_type) * (n - i)); overwrite_at(i, key, v); } template void node_ref::overwrite_at(unsigned i, uint64_t key, typename ValueTraits::value_type const &v) { set_key(i, key); set_value(i, v); } template void node_ref::copy_entries(node_ref const &rhs, unsigned begin, unsigned end) { unsigned count = end - begin; unsigned n = get_nr_entries(); if ((n + count) > get_max_entries()) throw runtime_error("too many entries"); ::memcpy(key_ptr(n), rhs.key_ptr(begin), sizeof(uint64_t) * count); ::memcpy(value_ptr(n), rhs.value_ptr(begin), sizeof(typename ValueTraits::disk_type) * count); set_nr_entries(n + count); } template int node_ref::bsearch(uint64_t key, int want_hi) const { int lo = -1, hi = get_nr_entries(); while(hi - lo > 1) { int mid = lo + ((hi - lo) / 2); uint64_t mid_key = key_at(mid); if (mid_key == key) return mid; if (mid_key < key) lo = mid; else hi = mid; } return want_hi ? hi : lo; } template boost::optional node_ref::exact_search(uint64_t key) const { int i = bsearch(key, 0); if (i < 0 || static_cast(i) >= get_nr_entries()) return boost::optional(); if (key != key_at(i)) return boost::optional(); return boost::optional(i); } template int node_ref::lower_bound(uint64_t key) const { return bsearch(key, 0); } template unsigned node_ref::calc_max_entries(void) { uint32_t total; // key + value size_t elt_size = sizeof(uint64_t) + sizeof(typename ValueTraits::disk_type); total = (MD_BLOCK_SIZE - sizeof(struct node_header)) / elt_size; return (total / 3) * 3; // rounds down } template void * node_ref::key_ptr(unsigned i) const { return raw_->keys + i; } template void * node_ref::value_ptr(unsigned i) const { void *value_base = &raw_->keys[to_cpu(raw_->header.max_entries)]; return static_cast(value_base) + sizeof(typename ValueTraits::disk_type) * i; } template template void node_ref::inc_children(RefCounter &rc) { unsigned nr_entries = get_nr_entries(); for (unsigned i = 0; i < nr_entries; i++) { typename ValueTraits::value_type v; typename ValueTraits::disk_type d; ::memcpy(&d, value_ptr(i), sizeof(d)); ValueTraits::unpack(d, v); rc.inc(v); } } //-------------------------------- template btree:: btree(typename transaction_manager::ptr tm, typename ValueTraits::ref_counter rc) : tm_(tm), destroy_(false), internal_rc_(tm->get_sm()), rc_(rc), validator_(new btree_node_validator) { using namespace btree_detail; write_ref root = tm_->new_block(validator_); leaf_node n = to_node(root); n.set_type(btree_detail::LEAF); n.set_nr_entries(0); n.set_max_entries(); n.set_value_size(sizeof(typename ValueTraits::disk_type)); root_ = root.get_location(); } template btree:: btree(typename transaction_manager::ptr tm, block_address root, typename ValueTraits::ref_counter rc) : tm_(tm), destroy_(false), root_(root), internal_rc_(tm->get_sm()), rc_(rc), validator_(new btree_node_validator) { } template btree::~btree() { } namespace { template struct lower_bound_search { static boost::optional search(btree_detail::node_ref n, uint64_t key) { return n.lower_bound(key); } }; template struct exact_search { static boost::optional search(btree_detail::node_ref n, uint64_t key) { return n.exact_search(key); } }; } template typename btree::maybe_value btree::lookup(key const &key) const { using namespace btree_detail; ro_spine spine(tm_, validator_); block_address root = root_; for (unsigned level = 0; level < Levels - 1; ++level) { boost::optional mroot = lookup_raw >(spine, root, key[level]); if (!mroot) return maybe_value(); root = *mroot; } return lookup_raw >(spine, root, key[Levels - 1]); } template typename btree::maybe_pair btree::lookup_le(key const &key) const { using namespace btree_detail; return maybe_pair(); } template typename btree::maybe_pair btree::lookup_ge(key const &key) const { using namespace btree_detail; return maybe_pair(); } template void btree:: insert(key const &key, typename ValueTraits::value_type const &value) { using namespace btree_detail; block_address block = root_; int index = 0; // FIXME: ??? shadow_spine spine(tm_, validator_); for (unsigned level = 0; level < Levels - 1; ++level) { bool need_insert = insert_location(spine, block, key[level], &index, internal_rc_); internal_node n = spine.template get_node(); if (need_insert) { btree new_tree(tm_, rc_); n.insert_at(index, key[level], new_tree.get_root()); } block = n.value_at(index); } bool need_insert = insert_location(spine, block, key[Levels - 1], &index, rc_); leaf_node n = spine.template get_node(); if (need_insert) n.insert_at(index, key[Levels - 1], value); else // FIXME: check if we're overwriting with the same value. n.set_value(index, value); root_ = spine.get_root(); } template void btree::remove(key const &key) { using namespace btree_detail; } template block_address btree::get_root() const { return root_; } template void btree::set_root(block_address root) { using namespace btree_detail; root_ = root; } template typename btree::ptr btree::clone() const { tm_->get_sm()->inc(root_); return ptr(new btree(tm_, root_, rc_)); } #if 0 template void btree::destroy() { using namespace btree_detail; } #endif template template boost::optional btree:: lookup_raw(ro_spine &spine, block_address block, uint64_t key) const { using namespace boost; typedef typename ValueTraits::value_type leaf_type; for (;;) { spine.step(block); node_ref leaf = spine.template get_node(); boost::optional mi; if (leaf.get_type() == btree_detail::LEAF) { mi = Search::search(leaf, key); if (!mi) return boost::optional(); return boost::optional(leaf.value_at(*mi)); } mi = leaf.lower_bound(key); if (!mi || *mi < 0) return boost::optional(); node_ref internal = spine.template get_node(); block = internal.value_at(*mi); } } template template void btree:: split_node(btree_detail::shadow_spine &spine, block_address parent_index, uint64_t key, bool top) { node_ref n = spine.template get_node(); if (n.get_nr_entries() == n.get_max_entries()) { if (top) split_beneath(spine, key); else split_sibling(spine, parent_index, key); } } template template void btree:: split_beneath(btree_detail::shadow_spine &spine, uint64_t key) { using namespace btree_detail; node_type type; unsigned nr_left, nr_right; write_ref left = tm_->new_block(validator_); node_ref l = to_node(left); l.set_nr_entries(0); l.set_max_entries(); l.set_value_size(sizeof(typename ValueTraits::disk_type)); write_ref right = tm_->new_block(validator_); node_ref r = to_node(right); r.set_nr_entries(0); r.set_max_entries(); r.set_value_size(sizeof(typename ValueTraits::disk_type)); { node_ref p = spine.template get_node(); if (p.get_value_size() != sizeof(typename ValueTraits::disk_type)) throw std::runtime_error("bad value_size"); nr_left = p.get_nr_entries() / 2; nr_right = p.get_nr_entries() - nr_left; type = p.get_type(); l.set_type(type); l.copy_entries(p, 0, nr_left); r.set_type(type); r.copy_entries(p, nr_left, nr_left + nr_right); } { // The parent may have changed value type, so we re-get it. internal_node p = spine.template get_node(); p.set_type(btree_detail::INTERNAL); p.set_max_entries(); p.set_nr_entries(2); p.set_value_size(sizeof(typename block_traits::disk_type)); p.overwrite_at(0, l.key_at(0), left.get_location()); p.overwrite_at(1, r.key_at(0), right.get_location()); } if (key < r.key_at(0)) spine.step(left); else spine.step(right); } template template void btree:: split_sibling(btree_detail::shadow_spine &spine, block_address parent_index, uint64_t key) { using namespace btree_detail; node_ref l = spine.template get_node(); block_address left = spine.get_block(); write_ref right = tm_->new_block(validator_); node_ref r = to_node(right); unsigned nr_left = l.get_nr_entries() / 2; unsigned nr_right = l.get_nr_entries() - nr_left; r.set_nr_entries(0); r.set_max_entries(); r.set_type(l.get_type()); r.set_value_size(sizeof(typename ValueTraits::disk_type)); r.copy_entries(l, nr_left, nr_left + nr_right); l.set_nr_entries(nr_left); internal_node p = spine.get_parent(); p.overwrite_at(parent_index, l.key_at(0), left); p.insert_at(parent_index + 1, r.key_at(0), right.get_location()); if (key >= r.key_at(0)) { spine.pop(); spine.step(right); } } // Returns true if we need a new insertion, rather than overwrite. template template bool btree:: insert_location(btree_detail::shadow_spine &spine, block_address block, uint64_t key, int *index, RC &leaf_rc) { using namespace btree_detail; bool top = true; // this isn't the same as spine.has_parent() int i = *index; bool inc = false; for (;;) { inc = spine.step(block); if (inc) inc_children(spine, leaf_rc); // patch up the parent to point to the new shadow if (spine.has_parent()) { internal_node p = spine.get_parent(); p.set_value(i, spine.get_block()); } internal_node internal = spine.template get_node(); // Split the node if we're full if (internal.get_type() == INTERNAL) split_node(spine, i, key, top); else split_node(spine, i, key, top); internal = spine.template get_node(); i = internal.lower_bound(key); if (internal.get_type() == btree_detail::LEAF) break; if (i < 0) { internal.set_key(0, key); i = 0; } block = internal.value_at(i); top = false; } node_ref leaf = spine.template get_node(); // FIXME: gross if (i < 0 || leaf.key_at(i) != key) i++; // do decrement the old value if it already exists // FIXME: I'm not sure about this, I don't understand the |inc| reference if (static_cast(i) < leaf.get_nr_entries() && leaf.key_at(i) == key && inc) { // dec old entry } *index = i; return ((static_cast(i) >= leaf.get_nr_entries()) || (leaf.key_at(i) != key)); } template void btree::visit_depth_first(visitor &v) const { node_location loc; walk_tree(v, loc, root_); v.visit_complete(); } template void btree::walk_tree(visitor &v, node_location const &loc, block_address b) const { try { walk_tree_internal(v, loc, b); } catch (std::runtime_error const &e) { switch (v.error_accessing_node(loc, b, e.what())) { case visitor::EXCEPTION_HANDLED: break; case visitor::RETHROW_EXCEPTION: throw; } } } template void btree::walk_tree_internal(visitor &v, node_location const &loc, block_address b) const { using namespace btree_detail; read_ref blk = tm_->read_lock(b, validator_); internal_node o = to_node(blk); // FIXME: use a switch statement if (o.get_type() == INTERNAL) { if (v.visit_internal(loc, o)) for (unsigned i = 0; i < o.get_nr_entries(); i++) { node_location loc2(loc); loc2.inc_depth(); loc2.key = o.key_at(i); walk_tree(v, loc2, o.value_at(i)); } } else if (loc.path.size() < Levels - 1) { if (v.visit_internal_leaf(loc, o)) for (unsigned i = 0; i < o.get_nr_entries(); i++) { node_location loc2(loc); loc2.push_key(o.key_at(i)); loc2.key = boost::optional(); walk_tree(v, loc2, o.value_at(i)); } } else { leaf_node ov = to_node(blk); v.visit_leaf(loc, ov); } } template template void btree::inc_children(btree_detail::shadow_spine &spine, RefCounter &leaf_rc) { node_ref nr = spine.template get_node(); if (nr.get_type() == INTERNAL) nr.inc_children(internal_rc_); else { node_ref leaf = spine.template get_node(); leaf.inc_children(leaf_rc); } } } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/data-structures/btree_checker.h000066400000000000000000000165351222772450500275640ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef BTREE_CHECKER_H #define BTREE_CHECKER_H #include "btree.h" #include "persistent-data/block_counter.h" #include "persistent-data/checksum.h" #include "persistent-data/error_set.h" #include #include #include using namespace persistent_data; using namespace std; //---------------------------------------------------------------- namespace persistent_data { //---------------------------------------------------------------- // This class implements consistency checking for the btrees in // general. Derive from this if you want some additional checks. // It's worth summarising what is checked: // // Implemented // ----------- // // - block_nr // - nr_entries < max_entries // - max_entries fits in block // - max_entries is divisible by 3 // - nr_entries > minimum (except for root nodes) // // Not implemented // --------------- // // - leaf | internal flags (this can be inferred from siblings) //---------------------------------------------------------------- template class btree_checker : public btree::visitor { public: typedef btree_detail::node_location node_location; btree_checker(block_counter &counter, bool avoid_repeated_visits = true) : counter_(counter), errs_(new error_set("btree errors")), avoid_repeated_visits_(avoid_repeated_visits) { } bool visit_internal(node_location const &loc, btree_detail::node_ref const &n) { return check_internal(loc, n); } bool visit_internal_leaf(node_location const &loc, btree_detail::node_ref const &n) { return check_leaf(loc, n); } bool visit_leaf(node_location const &loc, btree_detail::node_ref const &n) { return check_leaf(loc, n); } error_set::ptr get_errors() const { return errs_; } protected: block_counter &get_counter() { return counter_; } private: bool check_internal(node_location const &loc, btree_detail::node_ref const &n) { if (!already_visited(n) && check_block_nr(n) && check_max_entries(n) && check_nr_entries(n, loc.is_sub_root()) && check_ordered_keys(n) && check_parent_key(loc.is_sub_root() ? boost::optional() : loc.key, n)) { if (loc.is_sub_root()) new_root(loc.level()); return true; } return false; } template bool check_leaf(node_location const &loc, btree_detail::node_ref const &n) { if (!already_visited(n) && check_block_nr(n) && check_max_entries(n) && check_nr_entries(n, loc.is_sub_root()) && check_ordered_keys(n) && check_parent_key(loc.is_sub_root() ? boost::optional() : loc.key, n)) { if (loc.is_sub_root()) new_root(loc.level()); return check_leaf_key(loc.level(), n); } return false; } template bool already_visited(node const &n) { block_address b = n.get_location(); counter_.inc(b); if (avoid_repeated_visits_) { if (seen_.count(b) > 0) return true; seen_.insert(b); } return false; } template bool check_block_nr(node const &n) const { if (n.get_location() != n.get_block_nr()) { std::ostringstream out; out << "block number mismatch: actually " << n.get_location() << ", claims " << n.get_block_nr(); errs_->add_child(out.str()); return false; } return true; } template bool check_max_entries(node const &n) const { size_t elt_size = sizeof(uint64_t) + n.get_value_size(); if (elt_size * n.get_max_entries() + sizeof(node_header) > MD_BLOCK_SIZE) { std::ostringstream out; out << "max entries too large: " << n.get_max_entries(); errs_->add_child(out.str()); return false; } if (n.get_max_entries() % 3) { std::ostringstream out; out << "max entries is not divisible by 3: " << n.get_max_entries(); errs_->add_child(out.str()); return false; } return true; } template bool check_nr_entries(node const &n, bool is_root) const { if (n.get_nr_entries() > n.get_max_entries()) { std::ostringstream out; out << "bad nr_entries: " << n.get_nr_entries() << " < " << n.get_max_entries(); errs_->add_child(out.str()); return false; } block_address min = n.get_max_entries() / 3; if (!is_root && (n.get_nr_entries() < min)) { ostringstream out; out << "too few entries in btree: " << n.get_nr_entries() << ", expected at least " << min << "(max_entries = " << n.get_max_entries() << ")"; errs_->add_child(out.str()); return false; } return true; } template bool check_ordered_keys(node const &n) const { unsigned nr_entries = n.get_nr_entries(); if (nr_entries == 0) return true; // can only happen if a root node uint64_t last_key = n.key_at(0); for (unsigned i = 1; i < nr_entries; i++) { uint64_t k = n.key_at(i); if (k <= last_key) { ostringstream out; out << "keys are out of order, " << k << " <= " << last_key; errs_->add_child(out.str()); return false; } last_key = k; } return true; } template bool check_parent_key(boost::optional key, node const &n) const { if (!key) return true; if (*key > n.key_at(0)) { ostringstream out; out << "parent key mismatch: parent was " << *key << ", but lowest in node was " << n.key_at(0); errs_->add_child(out.str()); return false; } return true; } template bool check_leaf_key(unsigned level, node const &n) { if (n.get_nr_entries() == 0) return true; // can only happen if a root node if (last_leaf_key_[level] && *last_leaf_key_[level] >= n.key_at(0)) { ostringstream out; out << "the last key of the previous leaf was " << *last_leaf_key_[level] << " and the first key of this leaf is " << n.key_at(0); errs_->add_child(out.str()); return false; } last_leaf_key_[level] = n.key_at(n.get_nr_entries() - 1); return true; } void new_root(unsigned level) { // we're starting a new subtree, so should // reset the last_leaf value. last_leaf_key_[level] = boost::optional(); } block_counter &counter_; std::set seen_; error_set::ptr errs_; boost::optional last_leaf_key_[Levels]; bool avoid_repeated_visits_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/data-structures/btree_damage_visitor.cc000066400000000000000000000016451222772450500313070ustar00rootroot00000000000000#include "persistent-data/data-structures/btree_damage_visitor.h" using namespace persistent_data; //---------------------------------------------------------------- damage_tracker::damage_tracker() : damaged_(false), damage_begin_(0) { } void damage_tracker::bad_node() { damaged_ = true; } maybe_range64 damage_tracker::good_internal(block_address begin) { maybe_range64 r; if (damaged_) { r = maybe_range64(range64(damage_begin_, begin)); damaged_ = false; } damage_begin_ = begin; return r; } maybe_range64 damage_tracker::good_leaf(uint64_t begin, uint64_t end) { maybe_range64 r; if (damaged_) { r = maybe_range64(range64(damage_begin_, begin)); damaged_ = false; } damage_begin_ = end; return r; } maybe_range64 damage_tracker::end() { if (damaged_) return maybe_range64(damage_begin_); else return maybe_range64(); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/data-structures/btree_damage_visitor.h000066400000000000000000000274201222772450500311500ustar00rootroot00000000000000#ifndef PERSISTENT_DATA_DATA_STRUCTURES_DAMAGE_VISITOR_H #define PERSISTENT_DATA_DATA_STRUCTURES_DAMAGE_VISITOR_H #include "persistent-data/data-structures/btree.h" #include "persistent-data/run.h" //---------------------------------------------------------------- namespace persistent_data { namespace btree_detail { struct damage { typedef boost::shared_ptr ptr; damage(run lost_keys, std::string const &desc) : lost_keys_(lost_keys), desc_(desc) { } run lost_keys_; std::string desc_; }; inline std::ostream &operator <<(std::ostream &out, damage const &d) { out << "btree damage[lost_keys = " << d.lost_keys_ << ", \"" << d.desc_ << "\"]"; return out; } // Tracks damage in a single level btree. Use multiple // trackers if you have a multilayer tree. class damage_tracker { public: damage_tracker() : damaged_(false), damage_begin_(0) { } typedef run run64; typedef boost::optional maybe_run64; void bad_node() { damaged_ = true; } maybe_run64 good_internal(block_address begin) { maybe_run64 r; if (damaged_) { r = maybe_run64(run64(damage_begin_, begin)); damaged_ = false; } damage_begin_ = begin; return r; } // remember 'end' is the one-past-the-end value, so // take the last key in the leaf and add one. maybe_run64 good_leaf(block_address begin, block_address end) { maybe_run64 r; if (damaged_) { r = maybe_run64(run64(damage_begin_, begin)); damaged_ = false; } damage_begin_ = end; return r; } maybe_run64 end() { if (damaged_) return maybe_run64(damage_begin_); else return maybe_run64(); } private: bool damaged_; block_address damage_begin_; }; // As we walk a btree we need to know if we've moved into a // different sub tree (by looking at the btree_path). class path_tracker { public: // returns the old path if the tree has changed. boost::optional next_path(btree_path const &p) { if (p != path_) { btree_path tmp(path_); path_ = p; return boost::optional(tmp); } return boost::optional(); } btree_path const ¤t_path() const { return path_; } private: btree_path path_; }; //---------------------------------------------------------------- // This class implements consistency checking for the btrees. It // also allows the caller to visit all accessible values. // Derive from this if you want some additional checks. It's worth // summarising what is checked: // // Implemented // ----------- // // - block_nr // - nr_entries < max_entries // - max_entries fits in block // - max_entries is divisible by 3 // - nr_entries > minimum (except for root nodes) // // Not implemented // --------------- // // - leaf | internal flags (this can be inferred from siblings) //---------------------------------------------------------------- template class btree_damage_visitor : public btree::visitor { public: typedef btree_detail::node_location node_location; typedef run run64; typedef boost::optional maybe_run64; btree_damage_visitor(block_counter &counter, ValueVisitor &value_visitor, DamageVisitor &damage_visitor) : counter_(counter), avoid_repeated_visits_(true), value_visitor_(value_visitor), damage_visitor_(damage_visitor) { } bool visit_internal(node_location const &loc, btree_detail::node_ref const &n) { update_path(loc.path); return check_internal(loc, n); } bool visit_internal_leaf(node_location const &loc, btree_detail::node_ref const &n) { update_path(loc.path); return check_leaf(loc, n); } bool visit_leaf(node_location const &loc, btree_detail::node_ref const &n) { update_path(loc.path); bool r = check_leaf(loc, n); // If anything goes wrong with the checks, we skip // the value visiting. if (!r) return false; visit_values(loc.path, n); return true; } void visit_complete() { end_walk(); } typedef typename btree::visitor::error_outcome error_outcome; error_outcome error_accessing_node(node_location const &l, block_address b, std::string const &what) { report_damage(what); return btree::visitor::EXCEPTION_HANDLED; } private: void visit_values(btree_path const &path, node_ref const &n) { unsigned nr = n.get_nr_entries(); for (unsigned i = 0; i < nr; i++) { btree_path p2(path); p2.push_back(n.key_at(i)); value_visitor_.visit(p2, n.value_at(i)); } } bool check_internal(node_location const &loc, btree_detail::node_ref const &n) { if (!already_visited(n) && check_block_nr(n) && check_max_entries(n) && check_nr_entries(n, loc.is_sub_root()) && check_ordered_keys(n) && check_parent_key(loc.is_sub_root() ? boost::optional() : loc.key, n)) { if (loc.is_sub_root()) new_root(loc.level()); good_internal(n.key_at(0)); return true; } return false; } template bool check_leaf(node_location const &loc, btree_detail::node_ref const &n) { if (!already_visited(n) && check_block_nr(n) && check_max_entries(n) && check_nr_entries(n, loc.is_sub_root()) && check_ordered_keys(n) && check_parent_key(loc.is_sub_root() ? boost::optional() : loc.key, n)) { if (loc.is_sub_root()) new_root(loc.level()); bool r = check_leaf_key(loc.level(), n); if (r && n.get_nr_entries() > 0) good_leaf(n.key_at(0), n.key_at(n.get_nr_entries() - 1) + 1); return r; } return false; } template bool already_visited(node const &n) { block_address b = n.get_location(); counter_.inc(b); if (avoid_repeated_visits_) { if (seen_.count(b) > 0) return true; seen_.insert(b); } return false; } template bool check_block_nr(node const &n) { if (n.get_location() != n.get_block_nr()) { std::ostringstream out; out << "block number mismatch: actually " << n.get_location() << ", claims " << n.get_block_nr(); report_damage(out.str()); return false; } return true; } template bool check_max_entries(node const &n) { size_t elt_size = sizeof(uint64_t) + n.get_value_size(); if (elt_size * n.get_max_entries() + sizeof(node_header) > MD_BLOCK_SIZE) { std::ostringstream out; out << "max entries too large: " << n.get_max_entries(); report_damage(out.str()); return false; } if (n.get_max_entries() % 3) { std::ostringstream out; out << "max entries is not divisible by 3: " << n.get_max_entries(); report_damage(out.str()); return false; } return true; } template bool check_nr_entries(node const &n, bool is_root) { if (n.get_nr_entries() > n.get_max_entries()) { std::ostringstream out; out << "bad nr_entries: " << n.get_nr_entries() << " < " << n.get_max_entries(); report_damage(out.str()); return false; } block_address min = n.get_max_entries() / 3; if (!is_root && (n.get_nr_entries() < min)) { ostringstream out; out << "too few entries in btree_node: " << n.get_nr_entries() << ", expected at least " << min << "(max_entries = " << n.get_max_entries() << ")"; report_damage(out.str()); return false; } return true; } template bool check_ordered_keys(node const &n) { unsigned nr_entries = n.get_nr_entries(); if (nr_entries == 0) return true; // can only happen if a root node uint64_t last_key = n.key_at(0); for (unsigned i = 1; i < nr_entries; i++) { uint64_t k = n.key_at(i); if (k <= last_key) { ostringstream out; out << "keys are out of order, " << k << " <= " << last_key; report_damage(out.str()); return false; } last_key = k; } return true; } template bool check_parent_key(boost::optional key, node const &n) { if (!key) return true; if (*key > n.key_at(0)) { ostringstream out; out << "parent key mismatch: parent was " << *key << ", but lowest in node was " << n.key_at(0); report_damage(out.str()); return false; } return true; } template bool check_leaf_key(unsigned level, node const &n) { if (n.get_nr_entries() == 0) return true; // can only happen if a root node if (last_leaf_key_[level] && *last_leaf_key_[level] >= n.key_at(0)) { ostringstream out; out << "the last key of the previous leaf was " << *last_leaf_key_[level] << " and the first key of this leaf is " << n.key_at(0); report_damage(out.str()); return false; } last_leaf_key_[level] = n.key_at(n.get_nr_entries() - 1); return true; } void new_root(unsigned level) { // we're starting a new subtree, so should // reset the last_leaf value. last_leaf_key_[level] = boost::optional(); } //-------------------------------- // damage tracking void report_damage(std::string const &desc) { damage_reasons_.push_back(desc); dt_.bad_node(); } void good_internal(block_address b) { maybe_run64 mr = dt_.good_internal(b); if (mr) issue_damage(path_tracker_.current_path(), *mr); } void good_leaf(block_address b, block_address e) { maybe_run64 mr = dt_.good_leaf(b, e); if (mr) issue_damage(path_tracker_.current_path(), *mr); } void end_walk() { maybe_issue_damage(path_tracker_.current_path()); } void issue_damage(btree_path const &path, run64 const &r) { damage d(r, build_damage_desc()); clear_damage_desc(); damage_visitor_.visit(path, d); } std::string build_damage_desc() const { std::string r; std::list::const_iterator it, end = damage_reasons_.end(); for (it = damage_reasons_.begin(); it != end; ++it) r += *it; return r; } void clear_damage_desc() { damage_reasons_.clear(); } void maybe_issue_damage(btree_path const &path) { maybe_run64 mr = dt_.end(); if (mr) issue_damage(path, *mr); } void update_path(btree_path const &path) { boost::optional old_path = path_tracker_.next_path(path); if (old_path) // we need to emit any errors that // were accrued against the old // path. maybe_issue_damage(*old_path); } //-------------------------------- block_counter &counter_; bool avoid_repeated_visits_; ValueVisitor &value_visitor_; DamageVisitor &damage_visitor_; std::set seen_; boost::optional last_leaf_key_[Levels]; path_tracker path_tracker_; damage_tracker dt_; std::list damage_reasons_; }; } template void btree_visit_values(btree const &tree, block_counter &counter, ValueVisitor &value_visitor, DamageVisitor &damage_visitor) { btree_detail::btree_damage_visitor v(counter, value_visitor, damage_visitor); tree.visit_depth_first(v); } } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/data-structures/ref_counter.h000066400000000000000000000026341222772450500273050ustar00rootroot00000000000000// Copyright (C) 2013 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef REF_COUNTER_H #define REF_COUNTER_H #include //---------------------------------------------------------------- namespace persistent_data { template class ref_counter { public: boost::shared_ptr > ptr; virtual ~ref_counter() {} virtual void set(ValueType const &v, uint32_t rc) {} virtual void inc(ValueType const &v) {} virtual void dec(ValueType const &v) {} }; template class no_op_ref_counter : public ref_counter { }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/deleter.h000066400000000000000000000021071222772450500232570ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef DELETER_H #define DELETER_H //---------------------------------------------------------------- namespace utils { template struct deleter { void operator()(T *t) { delete t; } }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/endian_utils.cc000066400000000000000000000033161222772450500244520ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "endian_utils.h" using namespace base; //---------------------------------------------------------------- bool base::test_bit_le(void const *bits, unsigned b) { le64 const *w = reinterpret_cast(bits); w += b / 64; uint64_t v = to_cpu(*w); uint64_t mask = 1; mask = mask << (b % 64); return (v & mask) ? true : false; } void base::set_bit_le(void *bits, unsigned b) { le64 *w = reinterpret_cast(bits); w += b / 64; uint64_t v = to_cpu(*w); uint64_t mask = 1; mask = mask << (b % 64); v |= mask; *w = to_disk(v); } void base::clear_bit_le(void *bits, unsigned b) { le64 *w = reinterpret_cast(bits); w += b / 64; uint64_t v = to_cpu(*w); uint64_t mask = 1; mask = mask << (b % 64); mask = ~mask; v &= mask; *w = to_disk(v); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/endian_utils.h000066400000000000000000000052021222772450500243100ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef ENDIAN_H #define ENDIAN_H #include #include #include //---------------------------------------------------------------- // FIXME: rename to endian namespace base { // These are just little wrapper types to make the compiler // understand that the le types are not assignable to the // corresponding cpu type. struct le16 { explicit le16(uint16_t v = 0) : v_(v) { } uint16_t v_; } __attribute__((packed)); struct le32 { explicit le32(uint32_t v = 0) : v_(v) { } uint32_t v_; } __attribute__((packed)); struct le64 { explicit le64(uint64_t v = 0) : v_(v) { } uint64_t v_; } __attribute__((packed)); //-------------------------------- // FIXME: actually do the conversions ! template CPUType to_cpu(DiskType const &d) { BOOST_STATIC_ASSERT(sizeof(d) == 0); } template DiskType to_disk(CPUType const &v) { BOOST_STATIC_ASSERT(sizeof(v) == 0); } template <> inline uint16_t to_cpu(le16 const &d) { return le16toh(d.v_); } template <> inline le16 to_disk(uint16_t const &v) { return le16(htole16(v)); } template <> inline uint32_t to_cpu(le32 const &d) { return le32toh(d.v_); } template <> inline le32 to_disk(uint32_t const &v) { return le32(htole32(v)); } template <> inline uint64_t to_cpu(le64 const &d) { return le64toh(d.v_); } template <> inline le64 to_disk(uint64_t const &v) { return le64(htole64(v)); } //-------------------------------- bool test_bit_le(void const *bits, unsigned b); void set_bit_le(void *bits, unsigned b); void clear_bit_le(void *bits, unsigned b); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/error_set.cc000066400000000000000000000047141222772450500240030ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "error_set.h" #include using namespace persistent_data; using namespace std; //---------------------------------------------------------------- error_set::error_set(string const &err) : err_(err) { } string const & error_set::get_description() const { return err_; } list const & error_set::get_children() const { return children_; } void error_set::add_child(error_set::ptr err) { children_.push_back(err); } void error_set::add_child(boost::optional maybe_errs) { if (maybe_errs) children_.push_back(*maybe_errs); } void error_set::add_child(string const &err) { error_set::ptr e(new error_set(err)); add_child(e); } bool error_set::empty() const { return !children_.size(); } //-------------------------------- namespace { void indent_by(ostream &out, unsigned indent) { for (unsigned i = 0; i < indent; i++) out << ' '; } void print_errs(ostream &out, error_set::ptr e, unsigned depth, unsigned indent) { if (depth == 0) return; indent_by(out, indent); out << e->get_description() << endl; if (depth > 1) { list const &children = e->get_children(); for (list::const_iterator it = children.begin(); it != children.end(); ++it) print_errs(out, *it, depth - 1, indent + 2); } } } error_selector::error_selector(error_set::ptr errs, unsigned depth) : errs_(errs), depth_(depth) { } void error_selector::print(ostream &out) const { print_errs(out, errs_, depth_, 0); } ostream & persistent_data::operator << (ostream &out, error_selector const &errs) { errs.print(out); return out; } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/error_set.h000066400000000000000000000042121222772450500236360ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef ERROR_SET_H #define ERROR_SET_H #include #include #include #include #include //---------------------------------------------------------------- namespace persistent_data { // When checking the metadata for a thin device we don't want to // stop at the first error. Instead should collect as much // information as possible. The errors are hierarchical, so the // user can control how much detail is displayed. class error_set { public: typedef boost::shared_ptr ptr; error_set(std::string const &err); std::string const &get_description() const; std::list const &get_children() const; void add_child(error_set::ptr err); void add_child(boost::optional maybe_errs); void add_child(std::string const &err); bool empty() const; private: std::string err_; std::list children_; }; // The error_selector is a little proxy class used when printing // errors to a stream. class error_selector { public: error_selector(error_set::ptr errs, unsigned depth); void print(std::ostream &out) const; private: error_set::ptr errs_; unsigned depth_; }; std::ostream &operator << (std::ostream &out, error_selector const &errs); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/errors.h000066400000000000000000000022541222772450500231520ustar00rootroot00000000000000// Copyright (C) 2012 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef THINP_EXCEPTION_H #define THINP_EXCEPTION_H #include //---------------------------------------------------------------- namespace base { class checksum_error : public std::runtime_error { public: explicit checksum_error(std::string const &what) : std::runtime_error(what) { } }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/file_utils.cc000066400000000000000000000033731222772450500241360ustar00rootroot00000000000000#include "persistent-data/math_utils.h" #include "persistent-data/file_utils.h" #include #include #include #include #include using namespace base; //---------------------------------------------------------------- persistent_data::block_address persistent_data::get_nr_blocks(string const &path) { using namespace persistent_data; struct stat info; block_address nr_blocks; int r = ::stat(path.c_str(), &info); if (r) throw runtime_error("Couldn't stat dev path"); if (S_ISREG(info.st_mode) && info.st_size) nr_blocks = div_up(info.st_size, MD_BLOCK_SIZE); else if (S_ISBLK(info.st_mode)) { // To get the size of a block device we need to // open it, and then make an ioctl call. int fd = ::open(path.c_str(), O_RDONLY); if (fd < 0) throw runtime_error("couldn't open block device to ascertain size"); r = ::ioctl(fd, BLKGETSIZE64, &nr_blocks); if (r) { ::close(fd); throw runtime_error("ioctl BLKGETSIZE64 failed"); } ::close(fd); nr_blocks = div_down(nr_blocks, MD_BLOCK_SIZE); } else // FIXME: needs a better message throw runtime_error("bad path"); return nr_blocks; } persistent_data::block_manager<>::ptr persistent_data::open_bm(std::string const &dev_path, block_io<>::mode m) { block_address nr_blocks = get_nr_blocks(dev_path); return block_manager<>::ptr(new block_manager<>(dev_path, nr_blocks, 1, m)); } void persistent_data::check_file_exists(string const &file) { struct stat info; int r = ::stat(file.c_str(), &info); if (r) throw runtime_error("Couldn't stat file"); if (!S_ISREG(info.st_mode)) throw runtime_error("Not a regular file"); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/file_utils.h000066400000000000000000000010031222772450500237640ustar00rootroot00000000000000#ifndef THIN_FILE_UTILS_H #define THIN_FILE_UTILS_H #include "persistent-data/block.h" #include //---------------------------------------------------------------- // FIXME: move to a different unit namespace persistent_data { persistent_data::block_address get_nr_blocks(string const &path); block_manager<>::ptr open_bm(std::string const &dev_path, block_io<>::mode m); void check_file_exists(std::string const &file); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/hex_dump.cc000066400000000000000000000026351222772450500236100ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "hex_dump.h" #include #include using namespace std; //---------------------------------------------------------------- void base::hex_dump(ostream &out, void const *data_, size_t len) { unsigned char const *data = reinterpret_cast(data_), *end = data + len; ios_base::fmtflags old_flags = out.flags(); out << hex; while (data < end) { for (unsigned i = 0; i < 16 && data < end; i++, data++) out << setw(2) << setfill('0') << (unsigned) *data << " "; out << endl; } out.setf(old_flags); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/hex_dump.h000066400000000000000000000021041222772450500234410ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef HEX_DUMP_H #define HEX_DUMP_H #include //---------------------------------------------------------------- namespace base { void hex_dump(std::ostream &out, void const *data, size_t len); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/lock_tracker.cc000066400000000000000000000052461222772450500244430ustar00rootroot00000000000000// Copyright (C) 2012 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "lock_tracker.h" #include using namespace persistent_data; using namespace std; //---------------------------------------------------------------- lock_tracker::lock_tracker(uint64_t low, uint64_t high) : low_(low), high_(high) { } void lock_tracker::read_lock(uint64_t key) { check_key(key); LockMap::iterator it = locks_.find(key); if (found(it)) { if (it->second < 0) throw runtime_error("already write locked"); it->second++; } else locks_.insert(make_pair(key, 1)); } void lock_tracker::write_lock(uint64_t key) { check_key(key); LockMap::const_iterator it = locks_.find(key); if (found(it)) throw runtime_error("already locked"); locks_.insert(make_pair(key, -1)); } void lock_tracker::superblock_lock(uint64_t key) { if (superblock_) throw runtime_error("superblock already held"); superblock_ = boost::optional(key); try { write_lock(key); } catch (...) { superblock_ = boost::optional(); } } void lock_tracker::unlock(uint64_t key) { check_key(key); LockMap::const_iterator it = locks_.find(key); if (!found(it)) throw runtime_error("not locked"); if (superblock_ && *superblock_ == key) { if (locks_.size() > 1) throw runtime_error("superblock unlocked while other locks still held"); superblock_ = boost::optional(); } if (it->second > 1) locks_.insert(make_pair(key, it->second - 1)); else locks_.erase(key); } bool lock_tracker::found(LockMap::const_iterator it) const { return it != locks_.end(); } bool lock_tracker::valid_key(uint64_t key) const { return (key >= low_ && key <= high_); } void lock_tracker::check_key(uint64_t key) const { if (!valid_key(key)) throw runtime_error("invalid key"); } bool lock_tracker::is_locked(uint64_t key) const { check_key(key); return found(locks_.find(key)); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/lock_tracker.h000066400000000000000000000033111222772450500242740ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef LOCK_TRACKER_H #define LOCK_TRACKER_H #include #include #include #include //---------------------------------------------------------------- namespace persistent_data { class lock_tracker : private boost::noncopyable { public: lock_tracker(uint64_t low, uint64_t high); void read_lock(uint64_t key); void write_lock(uint64_t key); void superblock_lock(uint64_t key); void unlock(uint64_t key); bool is_locked(uint64_t key) const; private: typedef std::map LockMap; bool found(LockMap::const_iterator it) const; bool valid_key(uint64_t key) const; void check_key(uint64_t key) const; // Positive for read lock, negative for write lock LockMap locks_; boost::optional superblock_; uint64_t low_; uint64_t high_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/math_utils.h000066400000000000000000000024521222772450500240070ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef THINP_MATH_H #define THINP_MATH_H //---------------------------------------------------------------- namespace base { // Only works for integral types template T div_up(T const &v, T const &divisor) { return (v + (divisor - 1)) / divisor; } // Seemingly pointless function, but it coerces the arguments // nicely. template T div_down(T const &v, T const &divisor) { return v / divisor; } } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/run.h000066400000000000000000000021301222772450500224330ustar00rootroot00000000000000#ifndef PERSISTENT_DATA_RANGE_H #define PERSISTENT_DATA_RANGE_H #include #include //---------------------------------------------------------------- namespace base { template class run { public: typedef boost::optional maybe; run() { } explicit run(T const &b) : begin_(b) { } run(T const &b, T const &e) : begin_(b), end_(e) { } explicit run(maybe begin, maybe end) : begin_(begin), end_(end) { } bool operator ==(run const &r) const { return (begin_ == r.begin_ && end_ == r.end_); } bool contains(T const &v) const { if (begin_ && v < *begin_) return false; if (end_ && v >= *end_) return false; return true; } maybe begin_; maybe end_; }; template std::ostream & operator <<(std::ostream &out, run const &r) { if (r.begin_) out << "[" << *r.begin_; else out << "[-"; out << ", "; if (r.end_) out << *r.end_ << "]"; else out << "-]"; return out; } } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/run_set.h000066400000000000000000000052701222772450500233160ustar00rootroot00000000000000#ifndef PERSISTENT_DATA_H #define PERSISTENT_DATA_H #include "persistent-data/run.h" #include #include //---------------------------------------------------------------- namespace base { template class run_set { public: void clear() { runs_.clear(); } void add(T const &b) { add(run(b, b + 1)); } void add(T const &b, T const &e) { add(run(b, e)); } void add(run const &r_) { run r(r_); if (runs_.size()) { // Skip all blocks that end before r const_iterator it = runs_.lower_bound(r); if (it != runs_.begin()) --it; while (it != runs_.end() && it->end_ < r.begin_) ++it; // work out which runs overlap if (it != runs_.end()) { r.begin_ = min_maybe(it->begin_, r.begin_); const_iterator first = it; while (it != runs_.end() && it->begin_ <= r.end_) { r.end_ = max_maybe(it->end_, r.end_); ++it; } // remove overlapping runs runs_.erase(first, it); } } runs_.insert(r); } void merge(run_set const &rhs) { for (const_iterator it = rhs.begin(); it != rhs.end(); ++it) add(*it); } bool member(T const &v) const { if (!runs_.size()) return false; typename rset::const_iterator it = runs_.lower_bound(run(v)); if (it->begin_ == v) return true; it--; if (it != runs_.end()) return it->contains(v); return false; } struct compare_begin { bool operator ()(run const &r1, run const &r2) const { return r1.begin_ < r2.begin_; } }; typedef std::set, compare_begin> rset; typedef typename rset::const_iterator const_iterator; const_iterator begin() const { return runs_.begin(); } const_iterator end() const { return runs_.end(); } void negate() { rset replacement; if (runs_.begin() == runs_.end()) replacement.insert(run()); else { typename rset::const_iterator b = runs_.begin(); maybe last = b->end_; if (b->begin_) replacement.insert(run(maybe(), *(b->begin_))); ++b; while (b != runs_.end()) { replacement.insert(run(last, b->begin_)); last = b->end_; ++b; } if (last) replacement.insert(run(last, maybe())); } runs_ = replacement; } private: typedef typename run::maybe maybe; static maybe min_maybe(maybe const &m1, maybe const &m2) { if (!m1 || !m2) return maybe(); return maybe(std::min(*m1, *m2)); } static maybe max_maybe(maybe const &m1, maybe const &m2) { if (!m1 || !m2) return maybe(); return maybe(std::max(*m1, *m2)); } rset runs_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/space-maps/000077500000000000000000000000001222772450500235135ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/persistent-data/space-maps/careful_alloc.cc000066400000000000000000000065271222772450500266270ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "persistent-data/space-maps/careful_alloc.h" #include "persistent-data/space-maps/subtracting_span_iterator.h" #include //---------------------------------------------------------------- namespace { using namespace persistent_data; class sm_careful_alloc : public checked_space_map { public: typedef boost::shared_ptr ptr; sm_careful_alloc(checked_space_map::ptr sm) : sm_(sm) { } virtual block_address get_nr_blocks() const { return sm_->get_nr_blocks(); } virtual block_address get_nr_free() const { return sm_->get_nr_free(); } virtual ref_t get_count(block_address b) const { return sm_->get_count(b); } virtual void set_count(block_address b, ref_t c) { if (!c && sm_->get_count(b)) mark_freed(b); sm_->set_count(b, c); } virtual void commit() { sm_->commit(); clear_freed(); } virtual void inc(block_address b) { if (was_freed(b)) throw runtime_error("inc of block freed within current transaction"); sm_->inc(b); } virtual void dec(block_address b) { sm_->dec(b); if (!sm_->get_count(b)) mark_freed(b); } virtual maybe_block find_free(span_iterator &it) { subtracting_span_iterator filtered_it(get_nr_blocks(), it, freed_blocks_); return sm_->find_free(filtered_it); } virtual bool count_possibly_greater_than_one(block_address b) const { return sm_->count_possibly_greater_than_one(b); } virtual void extend(block_address extra_blocks) { return sm_->extend(extra_blocks); } virtual void iterate(iterator &it) const { sm_->iterate(it); } virtual size_t root_size() const { return sm_->root_size(); } virtual void copy_root(void *dest, size_t len) const { return sm_->copy_root(dest, len); } virtual void check(block_counter &counter) const { return sm_->check(counter); } virtual checked_space_map::ptr clone() const { return checked_space_map::ptr(new sm_careful_alloc(sm_)); } private: void clear_freed() { freed_blocks_.clear(); } void mark_freed(block_address b) { freed_blocks_.add(b, b + 1); } bool was_freed(block_address b) const { return freed_blocks_.member(b) > 0; } checked_space_map::ptr sm_; subtracting_span_iterator::block_set freed_blocks_; }; } //---------------------------------------------------------------- checked_space_map::ptr persistent_data::create_careful_alloc_sm(checked_space_map::ptr sm) { return checked_space_map::ptr(new sm_careful_alloc(sm)); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/space-maps/careful_alloc.h000066400000000000000000000025001222772450500264540ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef SPACE_MAP_CAREFUL_ALLOC_H #define SPACE_MAP_CAREFUL_ALLOC_H #include "persistent-data/space_map.h" //---------------------------------------------------------------- namespace persistent_data { // This space map ensures no blocks are allocated which have been // freed within the current transaction. This is a common // requirement when we want resilience to crashes. checked_space_map::ptr create_careful_alloc_sm(checked_space_map::ptr sm); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/space-maps/core.h000066400000000000000000000060051222772450500246150ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef CORE_MAP_H #define CORE_MAP_H #include "persistent-data/space_map.h" //---------------------------------------------------------------- namespace persistent_data { class core_map : public checked_space_map { public: typedef boost::shared_ptr ptr; core_map(block_address nr_blocks) : counts_(nr_blocks, 0), nr_free_(nr_blocks), search_start_(0ull) { } block_address get_nr_blocks() const { return counts_.size(); } block_address get_nr_free() const { return nr_free_; } ref_t get_count(block_address b) const { return counts_[b]; } void set_count(block_address b, ref_t c) { if (counts_[b] == 0 && c > 0) nr_free_--; else if (counts_[b] > 0 && c == 0) { if (b < search_start_) search_start_ = b; nr_free_++; } counts_[b] = c; } void commit() { } void inc(block_address b) { if (counts_[b] == 0) nr_free_--; counts_[b]++; } void dec(block_address b) { counts_[b]--; if (counts_[b] == 0) { if (b < search_start_) search_start_ = b; nr_free_++; } } maybe_block find_free(span_iterator &it) { for (maybe_span ms = it.first(); ms; ms = it.next()) { if (search_start_ >= ms->second) continue; for (block_address b = max(search_start_, ms->first); b < ms->second; b++) { if (b >= counts_.size()) throw std::runtime_error("block out of bounds"); if (!counts_[b]) return maybe_block(b); } } return maybe_block(); } bool count_possibly_greater_than_one(block_address b) const { return counts_[b] > 1; } void extend(block_address extra_blocks) { throw std::runtime_error("'extend' not implemented"); } // FIXME: meaningless, but this class is only used for testing size_t root_size() const { return 0; } // FIXME: meaningless, but this class is only used for testing virtual void copy_root(void *dest, size_t len) const { throw std::runtime_error("'copy root' not implemented"); } checked_space_map::ptr clone() const { return ptr(new core_map(*this)); } private: std::vector counts_; unsigned nr_free_; block_address search_start_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/space-maps/disk.cc000066400000000000000000000503421222772450500247600ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "persistent-data/space-maps/disk.h" #include "persistent-data/space-maps/disk_structures.h" #include "persistent-data/space-maps/recursive.h" #include "persistent-data/space-maps/careful_alloc.h" #include "persistent-data/checksum.h" #include "persistent-data/endian_utils.h" #include "persistent-data/math_utils.h" #include "persistent-data/transaction_manager.h" using namespace persistent_data; using namespace std; using namespace sm_disk_detail; //---------------------------------------------------------------- namespace { uint64_t const BITMAP_CSUM_XOR = 240779; struct bitmap_block_validator : public block_manager<>::validator { virtual void check(buffer<> const &b, block_address location) const { bitmap_header const *data = reinterpret_cast(&b); crc32c sum(BITMAP_CSUM_XOR); sum.append(&data->not_used, MD_BLOCK_SIZE - sizeof(uint32_t)); if (sum.get_sum() != to_cpu(data->csum)) throw checksum_error("bad checksum in space map bitmap"); if (to_cpu(data->blocknr) != location) throw checksum_error("bad block nr in space map bitmap"); } virtual void prepare(buffer<> &b, block_address location) const { bitmap_header *data = reinterpret_cast(&b); data->blocknr = to_disk(location); crc32c sum(BITMAP_CSUM_XOR); sum.append(&data->not_used, MD_BLOCK_SIZE - sizeof(uint32_t)); data->csum = to_disk(sum.get_sum()); } }; //-------------------------------- uint64_t const INDEX_CSUM_XOR = 160478; // FIXME: factor out the common code in these validators struct index_block_validator : public block_manager<>::validator { virtual void check(buffer<> const &b, block_address location) const { metadata_index const *mi = reinterpret_cast(&b); crc32c sum(INDEX_CSUM_XOR); sum.append(&mi->padding_, MD_BLOCK_SIZE - sizeof(uint32_t)); if (sum.get_sum() != to_cpu(mi->csum_)) throw checksum_error("bad checksum in metadata index block"); if (to_cpu(mi->blocknr_) != location) throw checksum_error("bad block nr in metadata index block"); } virtual void prepare(buffer<> &b, block_address location) const { metadata_index *mi = reinterpret_cast(&b); mi->blocknr_ = to_disk(location); crc32c sum(INDEX_CSUM_XOR); sum.append(&mi->padding_, MD_BLOCK_SIZE - sizeof(uint32_t)); mi->csum_ = to_disk(sum.get_sum()); } }; block_manager<>::validator::ptr index_validator() { return block_manager<>::validator::ptr(new index_block_validator()); } //-------------------------------- class bitmap { public: typedef transaction_manager::read_ref read_ref; typedef transaction_manager::write_ref write_ref; bitmap(transaction_manager::ptr tm, index_entry const &ie, block_manager<>::validator::ptr v) : tm_(tm), validator_(v), ie_(ie) { } ref_t lookup(unsigned b) const { read_ref rr = tm_->read_lock(ie_.blocknr_, validator_); void const *bits = bitmap_data(rr); ref_t b1 = test_bit_le(bits, b * 2); ref_t b2 = test_bit_le(bits, b * 2 + 1); ref_t result = b2 ? 1 : 0; result |= b1 ? 0b10 : 0; return result; } void insert(unsigned b, ref_t n) { write_ref wr = tm_->shadow(ie_.blocknr_, validator_).first; void *bits = bitmap_data(wr); bool was_free = !test_bit_le(bits, b * 2) && !test_bit_le(bits, b * 2 + 1); if (n == 1 || n == 3) set_bit_le(bits, b * 2 + 1); else clear_bit_le(bits, b * 2 + 1); if (n == 2 || n == 3) set_bit_le(bits, b * 2); else clear_bit_le(bits, b * 2); ie_.blocknr_ = wr.get_location(); if (was_free && n > 0) { ie_.nr_free_--; if (b == ie_.none_free_before_) ie_.none_free_before_++; } if (!was_free && n == 0) { ie_.nr_free_++; if (b < ie_.none_free_before_) ie_.none_free_before_ = b; } } boost::optional find_free(unsigned begin, unsigned end) { for (unsigned i = max(begin, ie_.none_free_before_); i < end; i++) if (lookup(i) == 0) return boost::optional(i); return boost::optional(); } index_entry const &get_ie() const { return ie_; } void iterate(block_address offset, block_address hi, space_map::iterator &it) const { read_ref rr = tm_->read_lock(ie_.blocknr_, validator_); void const *bits = bitmap_data(rr); for (unsigned b = 0; b < hi; b++) { ref_t b1 = test_bit_le(bits, b * 2); ref_t b2 = test_bit_le(bits, b * 2 + 1); ref_t result = b2 ? 1 : 0; result |= b1 ? 0b10 : 0; it(offset + b, result); } } private: void *bitmap_data(transaction_manager::write_ref &wr) { bitmap_header *h = reinterpret_cast(&wr.data()[0]); return h + 1; } void const *bitmap_data(transaction_manager::read_ref &rr) const { bitmap_header const *h = reinterpret_cast(&rr.data()[0]); return h + 1; } transaction_manager::ptr tm_; block_manager<>::validator::ptr validator_; index_entry ie_; }; struct ref_count_traits { typedef le32 disk_type; typedef uint32_t value_type; typedef no_op_ref_counter ref_counter; static void unpack(disk_type const &d, value_type &v) { v = to_cpu(d); } static void pack(value_type const &v, disk_type &d) { d = to_disk(v); } }; class ref_count_checker : public btree_checker<1, ref_count_traits> { public: typedef boost::shared_ptr ptr; ref_count_checker(block_counter &counter) : btree_checker<1, ref_count_traits>(counter) { } }; class index_store { public: typedef boost::shared_ptr ptr; virtual void resize(block_address nr_indexes) = 0; virtual index_entry find_ie(block_address b) const = 0; virtual void save_ie(block_address b, struct index_entry ie) = 0; virtual void commit_ies() = 0; virtual ptr clone() const = 0; virtual block_address get_root() const = 0; virtual void check(block_counter &counter, block_address nr_index_entries) const = 0; }; unsigned const ENTRIES_PER_BLOCK = (MD_BLOCK_SIZE - sizeof(bitmap_header)) * 4; class sm_disk : public checked_space_map { public: typedef boost::shared_ptr ptr; typedef transaction_manager::read_ref read_ref; typedef transaction_manager::write_ref write_ref; sm_disk(index_store::ptr indexes, transaction_manager::ptr tm) : tm_(tm), bitmap_validator_(new bitmap_block_validator), indexes_(indexes), nr_blocks_(0), nr_allocated_(0), ref_counts_(tm_, ref_count_traits::ref_counter()) { } sm_disk(index_store::ptr indexes, transaction_manager::ptr tm, sm_root const &root) : tm_(tm), bitmap_validator_(new bitmap_block_validator), indexes_(indexes), nr_blocks_(root.nr_blocks_), nr_allocated_(root.nr_allocated_), ref_counts_(tm_, root.ref_count_root_, ref_count_traits::ref_counter()) { } block_address get_nr_blocks() const { return nr_blocks_; } block_address get_nr_free() const { return nr_blocks_ - nr_allocated_; } ref_t get_count(block_address b) const { ref_t count = lookup_bitmap(b); if (count == 3) return lookup_ref_count(b); return count; } void set_count(block_address b, ref_t c) { ref_t old = get_count(b); if (c == old) return; if (c > 2) { if (old < 3) insert_bitmap(b, 3); insert_ref_count(b, c); } else { if (old > 2) remove_ref_count(b); insert_bitmap(b, c); } if (old == 0) nr_allocated_++; else if (c == 0) nr_allocated_--; } void commit() { indexes_->commit_ies(); } void inc(block_address b) { // FIXME: 2 get_counts ref_t old = get_count(b); set_count(b, old + 1); } void dec(block_address b) { ref_t old = get_count(b); set_count(b, old - 1); } // FIXME: keep track of the lowest free block so we // can start searching from a suitable place. maybe_block find_free(span_iterator &it) { for (maybe_span ms = it.first(); ms; ms = it.next()) { block_address begin = ms->first; block_address end = ms->second; block_address begin_index = begin / ENTRIES_PER_BLOCK; block_address end_index = div_up(end, ENTRIES_PER_BLOCK); for (block_address index = begin_index; index < end_index; index++) { index_entry ie = indexes_->find_ie(index); bitmap bm(tm_, ie, bitmap_validator_); unsigned bit_begin = (index == begin_index) ? (begin % ENTRIES_PER_BLOCK) : 0; unsigned bit_end = (index == end_index - 1) ? (end % ENTRIES_PER_BLOCK) : ENTRIES_PER_BLOCK; boost::optional maybe_b = bm.find_free(bit_begin, bit_end); if (maybe_b) { block_address b = (index * ENTRIES_PER_BLOCK) + *maybe_b; return b; } } } return maybe_block(); } bool count_possibly_greater_than_one(block_address b) const { return get_count(b) > 1; } virtual void extend(block_address extra_blocks) { block_address nr_blocks = nr_blocks_ + extra_blocks; block_address bitmap_count = div_up(nr_blocks, ENTRIES_PER_BLOCK); block_address old_bitmap_count = div_up(nr_blocks_, ENTRIES_PER_BLOCK); indexes_->resize(bitmap_count); for (block_address i = old_bitmap_count; i < bitmap_count; i++) { write_ref wr = tm_->new_block(bitmap_validator_); index_entry ie; ie.blocknr_ = wr.get_location(); ie.nr_free_ = i == (bitmap_count - 1) ? (nr_blocks % ENTRIES_PER_BLOCK) : ENTRIES_PER_BLOCK; ie.none_free_before_ = 0; indexes_->save_ie(i, ie); } nr_blocks_ = nr_blocks; } virtual void check(block_counter &counter) const { ref_count_checker v(counter); ref_counts_.visit_depth_first(v); block_address nr_entries = div_up(get_nr_blocks(), ENTRIES_PER_BLOCK); indexes_->check(counter, nr_entries); } struct look_aside_iterator : public iterator { look_aside_iterator(sm_disk const &smd, iterator &it) : smd_(smd), it_(it) { } virtual void operator () (block_address b, ref_t c) { it_(b, c == 3 ? smd_.lookup_ref_count(b) : c); } sm_disk const &smd_; iterator &it_; }; friend struct look_aside_iterator; virtual void iterate(iterator &it) const { look_aside_iterator wrapper(*this, it); unsigned nr_indexes = div_up(nr_blocks_, ENTRIES_PER_BLOCK); for (unsigned i = 0; i < nr_indexes; i++) { unsigned hi = (i == nr_indexes - 1) ? (nr_blocks_ % ENTRIES_PER_BLOCK) : ENTRIES_PER_BLOCK; index_entry ie = indexes_->find_ie(i); bitmap bm(tm_, ie, bitmap_validator_); bm.iterate(i * ENTRIES_PER_BLOCK, hi, wrapper); } } virtual size_t root_size() const { return sizeof(sm_root_disk); } virtual void copy_root(void *dest, size_t len) const { sm_root_disk d; sm_root v; if (len < sizeof(d)) throw runtime_error("root too small"); v.nr_blocks_ = sm_disk::get_nr_blocks(); v.nr_allocated_ = sm_disk::get_nr_allocated(); v.bitmap_root_ = get_index_store()->get_root(); v.ref_count_root_ = sm_disk::get_ref_count_root(); sm_root_traits::pack(v, d); ::memcpy(dest, &d, sizeof(d)); } virtual checked_space_map::ptr clone() const { sm_root root; root.nr_blocks_ = nr_blocks_; root.nr_allocated_ = nr_allocated_; root.bitmap_root_ = indexes_->get_root(); root.ref_count_root_ = ref_counts_.get_root(); return checked_space_map::ptr( new sm_disk(indexes_->clone(), tm_, root)); } protected: transaction_manager::ptr get_tm() const { return tm_; } block_address get_nr_allocated() const { return nr_allocated_; } block_address get_ref_count_root() const { return ref_counts_.get_root(); } index_store::ptr get_index_store() const { return indexes_; } private: void check_block(block_address b) const { if (b >= nr_blocks_) { std::ostringstream out; out << "space map disk: block out of bounds (" << b << " >= " << nr_blocks_ << ")"; throw std::runtime_error(out.str()); } } ref_t lookup_bitmap(block_address b) const { check_block(b); index_entry ie = indexes_->find_ie(b / ENTRIES_PER_BLOCK); bitmap bm(tm_, ie, bitmap_validator_); return bm.lookup(b % ENTRIES_PER_BLOCK); } void insert_bitmap(block_address b, unsigned n) { check_block(b); if (n > 3) throw runtime_error("bitmap can only hold 2 bit values"); index_entry ie = indexes_->find_ie(b / ENTRIES_PER_BLOCK); bitmap bm(tm_, ie, bitmap_validator_); bm.insert(b % ENTRIES_PER_BLOCK, n); indexes_->save_ie(b / ENTRIES_PER_BLOCK, bm.get_ie()); } ref_t lookup_ref_count(block_address b) const { uint64_t key[1] = {b}; boost::optional mvalue = ref_counts_.lookup(key); if (!mvalue) throw runtime_error("ref count not in tree"); return *mvalue; } void insert_ref_count(block_address b, ref_t count) { uint64_t key[1] = {b}; ref_counts_.insert(key, count); } void remove_ref_count(block_address b) { uint64_t key[1] = {b}; ref_counts_.remove(key); } transaction_manager::ptr tm_; block_manager<>::validator::ptr bitmap_validator_; index_store::ptr indexes_; block_address nr_blocks_; block_address nr_allocated_; btree<1, ref_count_traits> ref_counts_; }; class bitmap_tree_validator : public btree_checker<1, index_entry_traits> { public: typedef btree_detail::node_location node_location; typedef boost::shared_ptr ptr; bitmap_tree_validator(block_counter &counter) : btree_checker<1, index_entry_traits>(counter) { } bool visit_leaf(node_location const &loc, btree_detail::node_ref const &n) { bool r = btree_checker<1, index_entry_traits>::visit_leaf(loc, n); if (!r) return r; for (unsigned i = 0; i < n.get_nr_entries(); i++) { if (seen_indexes_.count(n.key_at(i)) > 0) { ostringstream out; out << "index entry " << i << " is present twice"; throw runtime_error(out.str()); } seen_indexes_.insert(n.key_at(i)); btree_checker<1, index_entry_traits>::get_counter().inc(n.value_at(i).blocknr_); } return true; } void check_all_index_entries_present(block_address nr_entries) { for (block_address i = 0; i < nr_entries; i++) { if (seen_indexes_.count(i) == 0) { ostringstream out; out << "missing index entry " << i; throw runtime_error(out.str()); } } set::const_iterator it; for (it = seen_indexes_.begin(); it != seen_indexes_.end(); ++it) { if (*it >= nr_entries) { ostringstream out; out << "unexpected index entry " << *it; throw runtime_error(out.str()); } } } private: set seen_indexes_; }; class btree_index_store : public index_store { public: typedef boost::shared_ptr ptr; btree_index_store(transaction_manager::ptr tm) : tm_(tm), bitmaps_(tm, index_entry_traits::ref_counter()) { } btree_index_store(transaction_manager::ptr tm, block_address root) : tm_(tm), bitmaps_(tm, root, index_entry_traits::ref_counter()) { } virtual void resize(block_address nr_entries) { // No op } virtual index_entry find_ie(block_address ie_index) const { uint64_t key[1] = {ie_index}; boost::optional mindex = bitmaps_.lookup(key); if (!mindex) throw runtime_error("Couldn't lookup bitmap"); return *mindex; } virtual void save_ie(block_address ie_index, struct index_entry ie) { uint64_t key[1] = {ie_index}; bitmaps_.insert(key, ie); } virtual void commit_ies() { // No op } virtual index_store::ptr clone() const { return index_store::ptr(new btree_index_store(tm_, bitmaps_.get_root())); } virtual block_address get_root() const { return bitmaps_.get_root(); } virtual void check(block_counter &counter, block_address nr_index_entries) const { bitmap_tree_validator v(counter); bitmaps_.visit_depth_first(v); v.check_all_index_entries_present(nr_index_entries); } private: transaction_manager::ptr tm_; btree<1, index_entry_traits> bitmaps_; }; class metadata_index_store : public index_store { public: typedef boost::shared_ptr ptr; metadata_index_store(transaction_manager::ptr tm) : tm_(tm) { block_manager<>::write_ref wr = tm_->new_block(index_validator()); bitmap_root_ = wr.get_location(); } metadata_index_store(transaction_manager::ptr tm, block_address root, block_address nr_indexes) : tm_(tm), bitmap_root_(root) { resize(nr_indexes); load_ies(); } virtual void resize(block_address nr_indexes) { entries_.resize(nr_indexes); } virtual index_entry find_ie(block_address ie_index) const { return entries_[ie_index]; } virtual void save_ie(block_address ie_index, struct index_entry ie) { entries_[ie_index] = ie; } virtual void commit_ies() { std::pair::write_ref, bool> p = tm_->shadow(bitmap_root_, index_validator()); bitmap_root_ = p.first.get_location(); metadata_index *mdi = reinterpret_cast(&p.first.data()); for (unsigned i = 0; i < entries_.size(); i++) index_entry_traits::pack(entries_[i], mdi->index[i]); } virtual index_store::ptr clone() const { return index_store::ptr(new metadata_index_store(tm_, bitmap_root_, entries_.size())); } virtual block_address get_root() const { return bitmap_root_; } virtual void check(block_counter &counter, block_address nr_index_entries) const { counter.inc(bitmap_root_); for (unsigned i = 0; i < entries_.size(); i++) // FIXME: this looks like a hack if (entries_[i].blocknr_ != 0) // superblock counter.inc(entries_[i].blocknr_); } private: void load_ies() { block_manager<>::read_ref rr = tm_->read_lock(bitmap_root_, index_validator()); metadata_index const *mdi = reinterpret_cast(&rr.data()); for (unsigned i = 0; i < entries_.size(); i++) index_entry_traits::unpack(*(mdi->index + i), entries_[i]); } transaction_manager::ptr tm_; block_address bitmap_root_; std::vector entries_; }; } //---------------------------------------------------------------- checked_space_map::ptr persistent_data::create_disk_sm(transaction_manager::ptr tm, block_address nr_blocks) { index_store::ptr store(new btree_index_store(tm)); checked_space_map::ptr sm(new sm_disk(store, tm)); sm->extend(nr_blocks); sm->commit(); return sm; } checked_space_map::ptr persistent_data::open_disk_sm(transaction_manager::ptr tm, void *root) { sm_root_disk d; sm_root v; ::memcpy(&d, root, sizeof(d)); sm_root_traits::unpack(d, v); index_store::ptr store(new btree_index_store(tm, v.bitmap_root_)); return checked_space_map::ptr(new sm_disk(store, tm, v)); } checked_space_map::ptr persistent_data::create_metadata_sm(transaction_manager::ptr tm, block_address nr_blocks) { index_store::ptr store(new metadata_index_store(tm)); checked_space_map::ptr sm(new sm_disk(store, tm)); sm->extend(nr_blocks); sm->commit(); return create_careful_alloc_sm( create_recursive_sm(sm)); } checked_space_map::ptr persistent_data::open_metadata_sm(transaction_manager::ptr tm, void *root) { sm_root_disk d; sm_root v; ::memcpy(&d, root, sizeof(d)); sm_root_traits::unpack(d, v); block_address nr_indexes = div_up(v.nr_blocks_, ENTRIES_PER_BLOCK); index_store::ptr store(new metadata_index_store(tm, v.bitmap_root_, nr_indexes)); return create_careful_alloc_sm( create_recursive_sm( checked_space_map::ptr(new sm_disk(store, tm, v)))); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/space-maps/disk.h000066400000000000000000000027721222772450500246260ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef SPACE_MAP_DISK_H #define SPACE_MAP_DISK_H // FIXME: why is btree_checker needed? #include "persistent-data/data-structures/btree_checker.h" #include "persistent-data/space_map.h" //---------------------------------------------------------------- namespace persistent_data { checked_space_map::ptr create_disk_sm(transaction_manager::ptr tm, block_address nr_blocks); checked_space_map::ptr open_disk_sm(transaction_manager::ptr tm, void *root); checked_space_map::ptr create_metadata_sm(transaction_manager::ptr tm, block_address nr_blocks); checked_space_map::ptr open_metadata_sm(transaction_manager::ptr tm, void *root); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/space-maps/disk_structures.h000066400000000000000000000067201222772450500271260ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef SPACE_MAP_DISK_STRUCTURES_H #define SPACE_MAP_DISK_STRUCTURES_H #include "persistent-data/endian_utils.h" // FIXME: what's this included for? #include "persistent-data/data-structures/btree.h" //---------------------------------------------------------------- namespace persistent_data { using namespace base; namespace sm_disk_detail { struct index_entry_disk { le64 blocknr_; le32 nr_free_; le32 none_free_before_; } __attribute__ ((packed)); struct index_entry { uint64_t blocknr_; uint32_t nr_free_; uint32_t none_free_before_; }; struct index_entry_traits { typedef index_entry_disk disk_type; typedef index_entry value_type; typedef no_op_ref_counter ref_counter; static void unpack(disk_type const &disk, value_type &value) { value.blocknr_ = to_cpu(disk.blocknr_); value.nr_free_ = to_cpu(disk.nr_free_); value.none_free_before_ = to_cpu(disk.none_free_before_); } static void pack(value_type const &value, disk_type &disk) { disk.blocknr_ = to_disk(value.blocknr_); disk.nr_free_ = to_disk(value.nr_free_); disk.none_free_before_ = to_disk(value.none_free_before_); } }; unsigned const MAX_METADATA_BITMAPS = 255; unsigned const ENTRIES_PER_BYTE = 4; struct metadata_index { le32 csum_; le32 padding_; le64 blocknr_; struct index_entry_disk index[MAX_METADATA_BITMAPS]; } __attribute__ ((packed)); struct sm_root_disk { le64 nr_blocks_; le64 nr_allocated_; le64 bitmap_root_; le64 ref_count_root_; } __attribute__ ((packed)); struct sm_root { uint64_t nr_blocks_; uint64_t nr_allocated_; uint64_t bitmap_root_; uint64_t ref_count_root_; }; struct sm_root_traits { typedef sm_root_disk disk_type; typedef sm_root value_type; typedef no_op_ref_counter ref_counter; static void unpack(disk_type const &disk, value_type &value) { value.nr_blocks_ = to_cpu(disk.nr_blocks_); value.nr_allocated_ = to_cpu(disk.nr_allocated_); value.bitmap_root_ = to_cpu(disk.bitmap_root_); value.ref_count_root_ = to_cpu(disk.ref_count_root_); } static void pack(value_type const &value, disk_type &disk) { disk.nr_blocks_ = to_disk(value.nr_blocks_); disk.nr_allocated_ = to_disk(value.nr_allocated_); disk.bitmap_root_ = to_disk(value.bitmap_root_); disk.ref_count_root_ = to_disk(value.ref_count_root_); } }; struct bitmap_header { le32 csum; le32 not_used; le64 blocknr; } __attribute__ ((packed)); } } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/space-maps/recursive.cc000066400000000000000000000151431222772450500260350ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "persistent-data/space-maps/recursive.h" #include "persistent-data/space-maps/subtracting_span_iterator.h" using namespace persistent_data; //---------------------------------------------------------------- namespace { struct block_op { enum op { INC, DEC, SET }; block_op(op o, block_address b) : op_(o), b_(b) { if (o == SET) throw runtime_error("SET must take an operand"); } block_op(op o, block_address b, uint32_t rc) : op_(o), b_(b), rc_(rc) { if (o != SET) throw runtime_error("only SET takes an operand"); } op op_; block_address b_; uint32_t rc_; }; class sm_recursive : public checked_space_map { public: sm_recursive(checked_space_map::ptr sm) : sm_(sm), depth_(0), flush_in_progress_(false) { } virtual block_address get_nr_blocks() const { return sm_->get_nr_blocks(); } virtual block_address get_nr_free() const { return sm_->get_nr_free(); } virtual ref_t get_count(block_address b) const { ref_t count = sm_->get_count(b); op_map::const_iterator ops_it = ops_.find(b); if (ops_it != ops_.end()) { list::const_iterator it, end = ops_it->second.end(); for (it = ops_it->second.begin(); it != end; ++it) { switch (it->op_) { case block_op::INC: count++; break; case block_op::DEC: count--; break; case block_op::SET: count = it->b_; break; } } } return count; } virtual void set_count(block_address b, ref_t c) { if (depth_) add_op(block_op(block_op::SET, b, c)); else { recursing_lock lock(*this); return sm_->set_count(b, c); } } virtual void commit() { cant_recurse("commit"); sm_->commit(); } virtual void inc(block_address b) { if (depth_) add_op(block_op(block_op::INC, b)); else { recursing_lock lock(*this); return sm_->inc(b); } } virtual void dec(block_address b) { if (depth_) add_op(block_op(block_op::DEC, b)); else { recursing_lock lock(*this); return sm_->dec(b); } } virtual maybe_block find_free(span_iterator &it) { recursing_lock lock(*this); subtracting_span_iterator filtered_it(get_nr_blocks(), it, allocated_blocks_); return sm_->find_free(filtered_it); } virtual bool count_possibly_greater_than_one(block_address b) const { recursing_const_lock lock(*this); bool gto = sm_->count_possibly_greater_than_one(b); if (!gto) { ref_t count = 1; // FIXME: duplication op_map::const_iterator ops_it = ops_.find(b); if (ops_it != ops_.end()) { list::const_iterator it, end = ops_it->second.end(); for (it = ops_it->second.begin(); it != end; ++it) { switch (it->op_) { case block_op::INC: count++; break; case block_op::DEC: count--; break; case block_op::SET: count = it->b_; break; } } } gto = count > 1; } return gto; } virtual void extend(block_address extra_blocks) { cant_recurse("extend"); recursing_lock lock(*this); return sm_->extend(extra_blocks); } virtual void iterate(iterator &it) const { sm_->iterate(it); } virtual size_t root_size() const { cant_recurse("root_size"); recursing_const_lock lock(*this); return sm_->root_size(); } virtual void copy_root(void *dest, size_t len) const { cant_recurse("copy_root"); recursing_const_lock lock(*this); return sm_->copy_root(dest, len); } virtual void check(persistent_data::block_counter &counter) const { cant_recurse("check"); recursing_const_lock lock(*this); return sm_->check(counter); } virtual checked_space_map::ptr clone() const { return checked_space_map::ptr(new sm_recursive(sm_->clone())); } void flush_ops() { if (flush_in_progress_) return; flush_in_progress_ = true; flush_ops_(); flush_in_progress_ = false; } private: void flush_ops_() { op_map::const_iterator it, end = ops_.end(); for (it = ops_.begin(); it != end; ++it) { recursing_lock lock(*this); list const &ops = it->second; list::const_iterator op_it, op_end = ops.end(); for (op_it = ops.begin(); op_it != op_end; ++op_it) { switch (op_it->op_) { case block_op::INC: sm_->inc(op_it->b_); break; case block_op::DEC: sm_->dec(op_it->b_); break; case block_op::SET: sm_->set_count(op_it->b_, op_it->rc_); break; } } } ops_.clear(); allocated_blocks_.clear(); } void add_op(block_op const &op) { ops_[op.b_].push_back(op); if (op.op_ == block_op::INC || (op.op_ == block_op::SET && op.rc_ > 0)) allocated_blocks_.add(op.b_, op.b_ + 1); } void cant_recurse(string const &method) const { if (depth_) throw runtime_error("recursive '" + method + "' not supported"); } struct recursing_lock { recursing_lock(sm_recursive &smr) : smr_(smr) { smr_.depth_++; } ~recursing_lock() { if (!--smr_.depth_) smr_.flush_ops(); } private: sm_recursive &smr_; }; struct recursing_const_lock { recursing_const_lock(sm_recursive const &smr) : smr_(smr) { smr_.depth_++; } ~recursing_const_lock() { smr_.depth_--; } private: sm_recursive const &smr_; }; checked_space_map::ptr sm_; mutable int depth_; enum op { BOP_INC, BOP_DEC, BOP_SET }; typedef map > op_map; op_map ops_; subtracting_span_iterator::block_set allocated_blocks_; bool flush_in_progress_; }; } //---------------------------------------------------------------- checked_space_map::ptr persistent_data::create_recursive_sm(checked_space_map::ptr sm) { return checked_space_map::ptr(new sm_recursive(sm)); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/space-maps/recursive.h000066400000000000000000000022011222772450500256660ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef SPACE_MAP_RECURSIVE_H #define SPACE_MAP_RECURSIVE_H #include "persistent-data/space_map.h" //---------------------------------------------------------------- namespace persistent_data { checked_space_map::ptr create_recursive_sm(checked_space_map::ptr sm); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/space-maps/subtracting_span_iterator.h000066400000000000000000000027031222772450500311450ustar00rootroot00000000000000#ifndef SPAN_ITERATOR_H #define SPAN_ITERATOR_H #include "persistent-data/space_map.h" #include "persistent-data/run_set.h" #include //---------------------------------------------------------------- namespace persistent_data { class subtracting_span_iterator : public space_map::span_iterator { public: typedef base::run_set block_set; typedef space_map::span span; subtracting_span_iterator(block_address max, span_iterator &sub_it, block_set const &forbidden_blocks) : max_(max) { for (maybe_span ms = sub_it.first(); ms; ms = sub_it.next()) runs_.add(ms->first, ms->second); block_set bs(forbidden_blocks); runs_.negate(); runs_.merge(bs); runs_.negate(); } virtual maybe_span first() { current_ = runs_.begin(); return get_current(); } virtual maybe_span next() { if (current_ != runs_.end()) ++current_; return get_current(); } private: maybe_span get_current() { return (current_ == runs_.end()) ? maybe_span() : maybe_span(std::make_pair(maybe_default(current_->begin_, 0ULL), maybe_default(current_->end_, max_))); } typedef boost::optional maybe; static block_address maybe_default(maybe const &m, block_address default_) { return m ? *m : default_; } block_address max_; block_set runs_; block_set::const_iterator current_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/space_map.cc000066400000000000000000000023341222772450500237230ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "space_map.h" using namespace persistent_data; //---------------------------------------------------------------- sm_decrementer::sm_decrementer(space_map::ptr sm, block_address b) : sm_(sm), b_(b), released_(false) { } sm_decrementer::~sm_decrementer() { if (!released_) sm_->dec(b_); } void sm_decrementer::dont_bother() { released_ = true; } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/space_map.h000066400000000000000000000103241222772450500235630ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef SPACE_MAP_H #define SPACE_MAP_H #include "block.h" #include "block_counter.h" #include #include #include //---------------------------------------------------------------- namespace persistent_data { typedef uint32_t ref_t; // FIXME: document these methods class space_map { public: typedef boost::shared_ptr ptr; virtual ~space_map() {}; virtual block_address get_nr_blocks() const = 0; virtual block_address get_nr_free() const = 0; virtual ref_t get_count(block_address b) const = 0; virtual void set_count(block_address b, ref_t c) = 0; virtual void commit() = 0; virtual void inc(block_address b) = 0; virtual void dec(block_address b) = 0; // FIXME: change these to return an optional, failure is // not that rare if we're restricting the area that's // searched. typedef boost::optional maybe_block; typedef std::pair span; typedef boost::optional maybe_span; struct span_iterator { typedef boost::optional maybe_span; virtual maybe_span first() = 0; virtual maybe_span next() = 0; }; struct single_span_iterator : public span_iterator { single_span_iterator(span const &s) : s_(s) { } virtual maybe_span first() { return maybe_span(s_); } virtual maybe_span next() { return maybe_span(); } private: span s_; }; // deliberately not virtual maybe_block new_block() { single_span_iterator it(span(0, get_nr_blocks())); return new_block(it); } virtual maybe_block find_free(span_iterator &it) = 0; virtual bool count_possibly_greater_than_one(block_address b) const = 0; virtual void extend(block_address extra_blocks) = 0; struct iterator { virtual ~iterator() {} virtual void operator() (block_address b, ref_t c) = 0; }; virtual void iterate(iterator &it) const { throw std::runtime_error("iterate() not implemented"); } // This is a concrete method maybe_block new_block(span_iterator &it) { maybe_block mb = find_free(it); if (mb) inc(*mb); return mb; } }; class persistent_space_map : public space_map { public: typedef boost::shared_ptr ptr; virtual size_t root_size() const = 0; virtual void copy_root(void *dest, size_t len) const = 0; }; class checked_space_map : public persistent_space_map { public: typedef boost::shared_ptr ptr; virtual void check(block_counter &counter) const { throw std::runtime_error("'check' not implemented"); } // FIXME: should this be in the base space_map class? virtual ptr clone() const = 0; }; class sm_adjust { public: sm_adjust(space_map::ptr sm, block_address b, int delta) : sm_(sm), b_(b), delta_(delta) { adjust_count(delta_); } ~sm_adjust() { adjust_count(-delta_); } void release() { delta_ = 0; } private: void adjust_count(int delta) { if (delta == 1) sm_->inc(b_); else if (delta == -1) sm_->dec(b_); else sm_->set_count(b_, sm_->get_count(b_) + delta); } space_map::ptr sm_; block_address b_; int delta_; }; class sm_decrementer { public: sm_decrementer(space_map::ptr sm, block_address b); ~sm_decrementer(); void dont_bother(); private: space_map::ptr sm_; block_address b_; bool released_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/persistent-data/span.h000066400000000000000000000033201222772450500225720ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef RUN_LIST_H #define RUN_LIST_H #include //---------------------------------------------------------------- namespace base { template struct run { run(T const &b, T const &e) : b_(b), e_(e) { } bool operator< (run const &rhs) const { return b_ < rhs.b_; } T b_, e_; }; template class run_list { public: run_list() : invert_(false) { } void add_run(T const &b, T const &e); void sub_run(T const &b, T const &e); bool in_run(T const &key) const; void invert(); void add(run_list const &rl); void sub(run_list const &rl); typedef std::set >::const_iterator const_iterator; const_iterator begin() const; const_iterator end() const; private: bool in_run_(T const &key) const; bool invert_; std::set > runs_; }; } //---------------------------------------------------------------- #include "run_list.tcc" #endif thin-provisioning-tools-0.2.8/persistent-data/span.tcc000066400000000000000000000075311222772450500231240ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include // FIXME: remove #include //---------------------------------------------------------------- namespace { using namespace base; using namespace boost; using namespace std; template bool overlaps_ordered(run const &lhs, run const &rhs) { return rhs.b_ < lhs.e_; } template bool overlaps(run const &lhs, run const &rhs) { if (lhs.b_ <= rhs.b_) return overlaps_ordered(lhs, rhs); else return overlaps_ordered(rhs, lhs); } template boost::optional > merge_ordered_runs_if_overlapping(run const &lhs, run const &rhs) { typedef optional > result; if (lhs.e_ < rhs.e_) return result(run(lhs.b_, rhs.e_)); if (lhs.e_ <= rhs.e_) return result(lhs); return result(); } template boost::optional > merge_if_overlapping(run const &lhs, run const &rhs) { if (lhs.b_ <= rhs.b_) return merge_ordered_runs_if_overlapping(lhs, rhs); else return merge_ordered_runs_if_overlapping(rhs, lhs); } template pair >::const_iterator, typename set >::const_iterator> overlapping_range(set > const &runs, run const &r) { // FIXME: slow, but correct implementation first typedef typename set >::const_iterator cit; for (cit b = runs.begin(); b != runs.end(); ++b) { if (overlaps(*b, r)) { cit e = b; ++e; while (overlaps(*e, r)) ++e; return make_pair(b, e); } } return make_pair(runs.end(), runs.end()); } } //---------------------------------------------------------------- template void run_list::add_run(T const &b, T const &e) { using namespace std; typedef typename set >::const_iterator cit; run r(b, e); pair range = overlapping_range(runs_, r); for (cit it = range.first; it != range.second; ++it) { optional > mr = merge_if_overlapping(r, *it); if (mr) r = *mr; } runs_.erase(range.first, range.second); runs_.insert(r); } template void run_list::sub_run(T const &b, T const &e) { // FIXME: finish } template bool run_list::in_run_(T const &key) const { using namespace std; run r(key, key + 1); typename set >::const_iterator it = runs_.lower_bound(r); if (it != runs_.end() && it->b_ == key) return true; --it; if (it == runs_.end()) return false; return it->b_ <= key && it->e_ > key; } template bool run_list::in_run(T const &key) const { if (invert_) return !in_run_(key); else return in_run_(key); } template void run_list::invert() { invert_ = !invert_; } template void run_list::add(run_list const &rl) { // FIXME: finish } template void run_list::sub(run_list const &rl) { // FIXME: finish } template const_iterator run_list::begin() const { return runs_.begin(); } const_iterator run_list::end() const { return runs_.end(); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/transaction_manager.cc000066400000000000000000000057531222772450500260220ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #include "persistent-data/transaction_manager.h" #include using namespace boost; using namespace persistent_data; using namespace std; //---------------------------------------------------------------- transaction_manager::transaction_manager(block_manager<>::ptr bm, space_map::ptr sm) : bm_(bm), sm_(sm) { } transaction_manager::~transaction_manager() { } transaction_manager::write_ref transaction_manager::begin(block_address superblock, validator v) { write_ref wr = bm_->superblock(superblock, v); wipe_shadow_table(); return wr; } transaction_manager::write_ref transaction_manager::new_block(validator v) { optional mb = sm_->new_block(); if (!mb) throw runtime_error("transaction_manager::new_block() couldn't allocate new block"); sm_decrementer decrementer(sm_, *mb); write_ref wr = bm_->write_lock_zero(*mb, v); add_shadow(*mb); decrementer.dont_bother(); return wr; } pair transaction_manager::shadow(block_address orig, validator v) { bool need_inc = sm_->count_possibly_greater_than_one(orig); if (is_shadow(orig) && !need_inc) return make_pair(bm_->write_lock(orig, v), need_inc); read_ref src = bm_->read_lock(orig, v); optional mb = sm_->new_block(); if (!mb) throw runtime_error("transaction_manager::shadow() couldn't allocate new block"); write_ref dest = bm_->write_lock_zero(*mb, v); ::memcpy(dest.data().raw(), src.data().raw(), MD_BLOCK_SIZE); // FIXME: use buffer copy method sm_->dec(orig); add_shadow(dest.get_location()); return make_pair(dest, need_inc); } transaction_manager::read_ref transaction_manager::read_lock(block_address b) { return bm_->read_lock(b); } transaction_manager::read_ref transaction_manager::read_lock(block_address b, validator v) { return bm_->read_lock(b, v); } void transaction_manager::add_shadow(block_address b) { shadows_.insert(b); } void transaction_manager::remove_shadow(block_address b) { shadows_.erase(b); } bool transaction_manager::is_shadow(block_address b) const { return shadows_.count(b) > 0; } void transaction_manager::wipe_shadow_table() { shadows_.clear(); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/persistent-data/transaction_manager.h000066400000000000000000000047351222772450500256630ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef TRANSACTION_MANAGER_H #define TRANSACTION_MANAGER_H #include "block.h" #include "space_map.h" #include #include //---------------------------------------------------------------- namespace persistent_data { class transaction_manager : boost::noncopyable { public: typedef boost::shared_ptr ptr; typedef block_manager<>::read_ref read_ref; typedef block_manager<>::write_ref write_ref; typedef block_manager<>::validator::ptr validator; // If the space map is persistent, then the caller should // hold onto a reference and remember to call sm_->commit() // and update the superblock before dropping the superblock // reference. transaction_manager(block_manager<>::ptr bm, space_map::ptr sm); ~transaction_manager(); // Drop the superblock reference to commit write_ref begin(block_address superblock, validator v); write_ref new_block(validator v); // shadowing returns a new write_ref, and a boolean which // indicates whether the children should be incremented. std::pair shadow(block_address orig, validator v); read_ref read_lock(block_address b); read_ref read_lock(block_address b, validator v); space_map::ptr get_sm() { return sm_; } void set_sm(space_map::ptr sm) { sm_ = sm; } block_manager<>::ptr get_bm() { return bm_; } private: void add_shadow(block_address b); void remove_shadow(block_address b); bool is_shadow(block_address b) const; void wipe_shadow_table(); block_manager<>::ptr bm_; space_map::ptr sm_; std::set shadows_; }; } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/thin-provisioning/000077500000000000000000000000001222772450500220415ustar00rootroot00000000000000thin-provisioning-tools-0.2.8/thin-provisioning/create_xml_data000077500000000000000000000062501222772450500251060ustar00rootroot00000000000000#!/usr/bin/env ruby # # Copyright (C) 2013 Red Hat, GmbH # # Simple thinp provisioning XML metadata creation tool # require 'optparse' require 'pathname' #---------------------------------------------------------------- $prg = Pathname.new($0).basename def check_opts(opts) abort "#{$prg} - 3 arguments required!" if opts.length < 3 abort "#{$prg} - block size must be 2^^N with N > 1" if opts[:blocksize] < 2 || (opts[:blocksize] & opts[:blocksize] - 1) != 0 abort "#{$prg} - mappings must be > 0" if opts[:mappings] < 1 abort "#{$prg} - number of thin provisioned devices or snapshots must be > 0" if opts[:thins].nil? || opts[:thins] < 1 abort "#{$prg} - size variation too large!" if !opts[:variation].nil? && (opts[:mappings] < 2 || (opts[:variation] >= 2 * (opts[:mappings] - 1))) end def parse_command_line(argv) opts = {} os = OptionParser.new do |o| o.banner = "Thin Provisioning XML Test Metadata Generator.\nUsage: #{$prg} [opts]" o.on("-b", "--block-size #SECTORS", Integer, "Block size of thin provisioned devices in sectors.") { |bs| opts[:blocksize] = bs } o.on("-m", "--mappings #MAPPINGS", Integer, "Number of mappings per thin device or snapshot.") { |m| opts[:mappings] = m } o.on("-r", "--range-mappings", "Create range mappings") { opts[:range] = true } o.on("-t", "--thin-devices #THINS", Integer, "Sum of thin devices and snapshots.") { |mt| opts[:thins] = mt } o.on("-v", "--variations #MAPPINGS]", Integer, "Mapping variation of thin devices and snapshots.") { |mv| opts[:variation] = mv } o.on("-h", "--help", "Output this help.") { puts o; exit } end begin os.parse!(argv) rescue OptionParser::ParseError => e abort "#{$prg} #{e}\n#{$prg} #{os}" end check_opts(opts) opts end def begin_superblock(blocksize, nr_data_blocks) "" end def end_superblock "" end def begin_device(devid, size) " " end def end_device " " end def single_mapping(from, to) " " end def range_mapping(from, to, length) " " end def this_mappings(opts) opts[:variation].nil? ? opts[:mappings] : ((2 * opts[:mappings] - rand(opts[:variation])) / 2) end def xml_metadata(opts) mappings, dev_id, nr_data_blocks, to = [], 0, 0, 0 0.step(opts[:thins] - 1) do mappings << (m = this_mappings(opts)) nr_data_blocks += m end puts begin_superblock(opts[:blocksize], nr_data_blocks) mappings.each do |b| if opts[:range] puts begin_device(dev_id, b), range_mapping(0, to, b), end_device else puts begin_device(dev_id, b) 0.step(b - 1) { |from| puts single_mapping(from, to + from) } puts end_device end dev_id += 1 to += b end puts end_superblock end #---------------------------------------------------------------- # Main # xml_metadata(parse_command_line(ARGV)) thin-provisioning-tools-0.2.8/thin-provisioning/device_tree.cc000066400000000000000000000051331222772450500246300ustar00rootroot00000000000000#include "thin-provisioning/device_tree.h" #include "persistent-data/data-structures/btree_damage_visitor.h" using namespace persistent_data; using namespace thin_provisioning; //---------------------------------------------------------------- namespace { using namespace device_tree_detail; struct visitor_adapter { visitor_adapter(device_visitor &dv) : dv_(dv) { } void visit(btree_path const &path, device_details const &dd) { dv_.visit(path[0], dd); } private: device_visitor &dv_; }; // No op for now, should add sanity checks in here however. struct noop_visitor : public device_visitor { virtual void visit(block_address dev_id, device_details const &dd) { } }; class ll_damage_visitor { public: // FIXME: is the namespace needed on here? ll_damage_visitor(device_tree_detail::damage_visitor &v) : v_(v) { } virtual void visit(btree_path const &path, btree_detail::damage const &d) { v_.visit(missing_devices(d.desc_, d.lost_keys_)); } private: device_tree_detail::damage_visitor &v_; }; } namespace thin_provisioning { namespace device_tree_detail { void device_details_traits::unpack(device_details_disk const &disk, device_details &value) { value.mapped_blocks_ = to_cpu(disk.mapped_blocks_); value.transaction_id_ = to_cpu(disk.transaction_id_); value.creation_time_ = to_cpu(disk.creation_time_); value.snapshotted_time_ = to_cpu(disk.snapshotted_time_); } void device_details_traits::pack(device_details const &value, device_details_disk &disk) { disk.mapped_blocks_ = to_disk(value.mapped_blocks_); disk.transaction_id_ = to_disk(value.transaction_id_); disk.creation_time_ = to_disk(value.creation_time_); disk.snapshotted_time_ = to_disk(value.snapshotted_time_); } missing_devices::missing_devices(std::string const &desc, run const &keys) : desc_(desc), keys_(keys) { } void missing_devices::visit(damage_visitor &v) const { v.visit(*this); } } } //---------------------------------------------------------------- void thin_provisioning::walk_device_tree(device_tree const &tree, device_tree_detail::device_visitor &vv, device_tree_detail::damage_visitor &dv) { block_counter counter; visitor_adapter av(vv); ll_damage_visitor ll_dv(dv); btree_visit_values(tree, counter, av, ll_dv); } void thin_provisioning::check_device_tree(device_tree const &tree, damage_visitor &visitor) { noop_visitor vv; walk_device_tree(tree, vv, visitor); } //---------------------------------------------------------------- thin-provisioning-tools-0.2.8/thin-provisioning/device_tree.h000066400000000000000000000042461222772450500244760ustar00rootroot00000000000000#ifndef THIN_DEVICE_CHECKER_H #define THIN_DEVICE_CHECKER_H #include "persistent-data/data-structures/btree.h" #include "persistent-data/run.h" using namespace boost; //---------------------------------------------------------------- namespace thin_provisioning { namespace device_tree_detail { struct device_details_disk { le64 mapped_blocks_; le64 transaction_id_; /* when created */ le32 creation_time_; le32 snapshotted_time_; } __attribute__ ((packed)); struct device_details { uint64_t mapped_blocks_; uint64_t transaction_id_; /* when created */ uint32_t creation_time_; uint32_t snapshotted_time_; }; struct device_details_traits { typedef device_details_disk disk_type; typedef device_details value_type; typedef persistent_data::no_op_ref_counter ref_counter; static void unpack(device_details_disk const &disk, device_details &value); static void pack(device_details const &value, device_details_disk &disk); }; class damage_visitor; struct damage { virtual ~damage() {} virtual void visit(damage_visitor &v) const = 0; }; struct missing_devices : public damage { missing_devices(std::string const &desc, run const &keys); virtual void visit(damage_visitor &v) const; std::string desc_; run keys_; }; class damage_visitor { public: typedef shared_ptr ptr; virtual ~damage_visitor() {} void visit(damage const &d) { d.visit(*this); } virtual void visit(missing_devices const &d) = 0; }; // FIXME: need to add some more damage types for bad leaf data class device_visitor { public: virtual ~device_visitor() {} virtual void visit(block_address dev_id, device_details const &v) = 0; }; }; typedef persistent_data::btree<1, device_tree_detail::device_details_traits> device_tree; void walk_device_tree(device_tree const &tree, device_tree_detail::device_visitor &dev_v, device_tree_detail::damage_visitor &dv); void check_device_tree(device_tree const &tree, device_tree_detail::damage_visitor &visitor); } //---------------------------------------------------------------- #endif thin-provisioning-tools-0.2.8/thin-provisioning/emitter.h000066400000000000000000000050421222772450500236640ustar00rootroot00000000000000// Copyright (C) 2011 Red Hat, Inc. All rights reserved. // // This file is part of the thin-provisioning-tools source. // // thin-provisioning-tools is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // thin-provisioning-tools is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with thin-provisioning-tools. If not, see // . #ifndef EMITTER_H #define EMITTER_H #include #include #include #include //---------------------------------------------------------------- namespace thin_provisioning { //------------------------------------------------ // Here's a little grammar for how this all hangs together: // // superblock :=